diff options
Diffstat (limited to 'sql')
70 files changed, 2667 insertions, 712 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index fba1a68fa46..88ec26eb6f6 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -28,8 +28,26 @@ ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.h ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.cc ${CMAKE_CURRENT_BINARY_DIR}/lex_hash.h ) +SET(GEN_DIGEST_SOURCES + ${CMAKE_CURRENT_BINARY_DIR}/lex_token.h +) + +SET_SOURCE_FILES_PROPERTIES(${GEN_SOURCES} + ${GEN_DIGEST_SOURCES} + PROPERTIES GENERATED 1) + +# Gen_lex_token +# Make sure sql_yacc.h is generated before compiling gen_lex_token +IF(NOT CMAKE_CROSSCOMPILING) + ADD_EXECUTABLE(gen_lex_token gen_lex_token.cc) + ADD_DEPENDENCIES(gen_lex_token GenServerSource) +ENDIF() -SET_SOURCE_FILES_PROPERTIES(${GEN_SOURCES} PROPERTIES GENERATED 1) +ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lex_token.h + COMMAND gen_lex_token > lex_token.h + DEPENDS gen_lex_token +) ADD_DEFINITIONS(-DMYSQL_SERVER -DHAVE_EVENT_SCHEDULER) @@ -59,7 +77,8 @@ SET (SQL_SOURCE slave.cc sp.cc sp_cache.cc sp_head.cc sp_pcontext.cc sp_rcontext.cc spatial.cc sql_acl.cc sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc sql_client.cc sql_crypt.cc sql_crypt.h - sql_cursor.cc sql_db.cc sql_delete.cc sql_derived.cc sql_do.cc + sql_cursor.cc sql_db.cc sql_delete.cc sql_derived.cc + sql_digest.cc sql_do.cc sql_error.cc sql_handler.cc sql_get_diagnostics.cc sql_help.cc sql_insert.cc sql_lex.cc sql_list.cc sql_load.cc sql_manager.cc @@ -96,6 +115,7 @@ SET (SQL_SOURCE table_cache.cc ${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc ${GEN_SOURCES} + ${GEN_DIGEST_SOURCES} ${MYSYS_LIBWRAP_SOURCE} ) @@ -116,6 +136,7 @@ RECOMPILE_FOR_EMBEDDED) ADD_LIBRARY(sql STATIC ${SQL_SOURCE}) ADD_DEPENDENCIES(sql GenServerSource) +ADD_DEPENDENCIES(sql GenDigestServerSource) DTRACE_INSTRUMENT(sql) TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATIC_PLUGIN_LIBS} mysys mysys_ssl dbug strings vio pcre ${LIBJEMALLOC} @@ -245,6 +266,11 @@ ADD_CUSTOM_TARGET( DEPENDS ${GEN_SOURCES} ) +ADD_CUSTOM_TARGET( + GenDigestServerSource + DEPENDS ${GEN_DIGEST_SOURCES} +) + #Need this only for embedded SET_TARGET_PROPERTIES(GenServerSource PROPERTIES EXCLUDE_FROM_ALL TRUE) diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index f2b3a77f414..5c4926c830c 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -301,6 +301,9 @@ Event_worker_thread::run(THD *thd, Event_queue_element_for_exec *event) Event_job_data job_data; bool res; + DBUG_ASSERT(thd->m_digest == NULL); + DBUG_ASSERT(thd->m_statement_psi == NULL); + thd->thread_stack= &my_stack; // remember where our stack is res= post_init_event_thread(thd); @@ -329,6 +332,8 @@ Event_worker_thread::run(THD *thd, Event_queue_element_for_exec *event) job_data.definer.str, job_data.dbname.str, job_data.name.str); end: + DBUG_ASSERT(thd->m_statement_psi == NULL); + DBUG_ASSERT(thd->m_digest == NULL); DBUG_PRINT("info", ("Done with Event %s.%s", event->dbname.str, event->name.str)); diff --git a/sql/field.cc b/sql/field.cc index e7e046a8458..c5319ae0b72 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1307,18 +1307,13 @@ int Field_num::check_int(CHARSET_INFO *cs, const char *str, int length, if (str == int_end || error == MY_ERRNO_EDOM) { ErrConvString err(str, length, cs); - push_warning_printf(get_thd(), Sql_condition::WARN_LEVEL_WARN, - ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, - ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), - "integer", err.ptr(), field_name, - (ulong) table->in_use->get_stmt_da()-> - current_row_for_warning()); + set_warning_truncated_wrong_value("integer", err.ptr()); return 1; } /* Test if we have garbage at the end of the given string. */ if (test_if_important_data(cs, int_end, str + length)) { - set_warning(Sql_condition::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + set_warning(WARN_DATA_TRUNCATED, 1); return 2; } return 0; @@ -1387,7 +1382,7 @@ bool Field_num::get_int(CHARSET_INFO *cs, const char *from, uint len, return 0; out_of_range: - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); return 1; } @@ -1408,12 +1403,12 @@ int Field::warn_if_overflow(int op_result) { if (op_result == E_DEC_OVERFLOW) { - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); return 1; } if (op_result == E_DEC_TRUNCATED) { - set_warning(Sql_condition::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1); + set_note(WARN_DATA_TRUNCATED, 1); /* We return 0 here as this is not a critical issue */ } return 0; @@ -1739,7 +1734,7 @@ longlong Field::convert_decimal2longlong(const my_decimal *val, { if (val->sign()) { - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); i= 0; *err= 1; } @@ -2047,7 +2042,7 @@ void Field_decimal::overflow(bool negative) uint len=field_length; uchar *to=ptr, filler= '9'; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); if (negative) { if (!unsigned_flag) @@ -2155,7 +2150,7 @@ int Field_decimal::store(const char *from_arg, uint len, CHARSET_INFO *cs) from++; if (from == end) { - set_warning(Sql_condition::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + set_warning(WARN_DATA_TRUNCATED, 1); is_cuted_fields_incr=1; } else if (*from == '+' || *from == '-') // Found some sign ? @@ -2231,7 +2226,7 @@ int Field_decimal::store(const char *from_arg, uint len, CHARSET_INFO *cs) for (;from != end && my_isspace(&my_charset_bin, *from); from++) ; if (from != end) // If still something left, warn { - set_warning(Sql_condition::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + set_warning(WARN_DATA_TRUNCATED, 1); is_cuted_fields_incr=1; } } @@ -2409,8 +2404,7 @@ int Field_decimal::store(const char *from_arg, uint len, CHARSET_INFO *cs) if (tmp_char != '0') // Losing a non zero digit ? { if (!is_cuted_fields_incr) - set_warning(Sql_condition::WARN_LEVEL_WARN, - WARN_DATA_TRUNCATED, 1); + set_warning(WARN_DATA_TRUNCATED, 1); return 0; } continue; @@ -2432,7 +2426,7 @@ int Field_decimal::store(const char *from_arg, uint len, CHARSET_INFO *cs) This is a note, not a warning, as we don't want to abort when we cut decimals in strict mode */ - set_warning(Sql_condition::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1); + set_note(WARN_DATA_TRUNCATED, 1); } return 0; } @@ -2633,7 +2627,7 @@ void Field_decimal::sql_type(String &res) const if (dec) tmp--; res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), - "decimal(%d,%d)",tmp,dec)); + "decimal(%d,%d)/*old*/",tmp,dec)); add_zerofill_and_unsigned(res); } @@ -2782,7 +2776,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value) if (unsigned_flag && decimal_value->sign()) { DBUG_PRINT("info", ("unsigned overflow")); - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; decimal_value= &decimal_zero; } @@ -2826,32 +2820,22 @@ int Field_new_decimal::store(const char *from, uint length, thd->abort_on_warning) { ErrConvString errmsg(from, length, charset_arg); - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, - ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), - "decimal", errmsg.ptr(), field_name, - static_cast<ulong>(thd->get_stmt_da()-> - current_row_for_warning())); + set_warning_truncated_wrong_value("decimal", errmsg.ptr()); DBUG_RETURN(err); } switch (err) { case E_DEC_TRUNCATED: - set_warning(Sql_condition::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1); + set_note(WARN_DATA_TRUNCATED, 1); break; case E_DEC_OVERFLOW: - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); set_value_on_overflow(&decimal_value, decimal_value.sign()); break; case E_DEC_BAD_NUM: { ErrConvString errmsg(from, length, charset_arg); - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, - ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), - "decimal", errmsg.ptr(), field_name, - static_cast<ulong>(thd->get_stmt_da()-> - current_row_for_warning())); + set_warning_truncated_wrong_value("decimal", errmsg.ptr()); my_decimal_set_zero(&decimal_value); break; } @@ -3158,13 +3142,13 @@ int Field_tiny::store(double nr) if (nr < 0.0) { *ptr=0; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else if (nr > 255.0) { *ptr= (uchar) 255; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else @@ -3175,13 +3159,13 @@ int Field_tiny::store(double nr) if (nr < -128.0) { *ptr= (uchar) -128; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else if (nr > 127.0) { *ptr=127; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else @@ -3201,13 +3185,13 @@ int Field_tiny::store(longlong nr, bool unsigned_val) if (nr < 0 && !unsigned_val) { *ptr= 0; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else if ((ulonglong) nr > (ulonglong) 255) { *ptr= (char) 255; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else @@ -3220,13 +3204,13 @@ int Field_tiny::store(longlong nr, bool unsigned_val) if (nr < -128) { *ptr= (char) -128; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else if (nr > 127) { *ptr=127; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else @@ -3337,13 +3321,13 @@ int Field_short::store(double nr) if (nr < 0) { res=0; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else if (nr > (double) UINT_MAX16) { res=(int16) UINT_MAX16; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else @@ -3354,13 +3338,13 @@ int Field_short::store(double nr) if (nr < (double) INT_MIN16) { res=INT_MIN16; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else if (nr > (double) INT_MAX16) { res=INT_MAX16; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else @@ -3382,13 +3366,13 @@ int Field_short::store(longlong nr, bool unsigned_val) if (nr < 0L && !unsigned_val) { res=0; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else if ((ulonglong) nr > (ulonglong) UINT_MAX16) { res=(int16) UINT_MAX16; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else @@ -3402,13 +3386,13 @@ int Field_short::store(longlong nr, bool unsigned_val) if (nr < INT_MIN16) { res=INT_MIN16; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else if (nr > (longlong) INT_MAX16) { res=INT_MAX16; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else @@ -3525,14 +3509,14 @@ int Field_medium::store(double nr) if (nr < 0) { int3store(ptr,0); - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else if (nr >= (double) (long) (1L << 24)) { uint32 tmp=(uint32) (1L << 24)-1L; int3store(ptr,tmp); - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else @@ -3544,14 +3528,14 @@ int Field_medium::store(double nr) { long tmp=(long) INT_MIN24; int3store(ptr,tmp); - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else if (nr > (double) INT_MAX24) { long tmp=(long) INT_MAX24; int3store(ptr,tmp); - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else @@ -3571,14 +3555,14 @@ int Field_medium::store(longlong nr, bool unsigned_val) if (nr < 0 && !unsigned_val) { int3store(ptr,0); - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else if ((ulonglong) nr >= (ulonglong) (long) (1L << 24)) { long tmp= (long) (1L << 24)-1L; int3store(ptr,tmp); - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else @@ -3593,14 +3577,14 @@ int Field_medium::store(longlong nr, bool unsigned_val) { long tmp= (long) INT_MIN24; int3store(ptr,tmp); - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else if (nr > (longlong) INT_MAX24) { long tmp=(long) INT_MAX24; int3store(ptr,tmp); - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else @@ -3722,7 +3706,7 @@ int Field_long::store(double nr) else if (nr > (double) UINT_MAX32) { res= UINT_MAX32; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else @@ -3744,7 +3728,7 @@ int Field_long::store(double nr) res=(int32) (longlong) nr; } if (error) - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); int4store(ptr,res); return error; @@ -3790,7 +3774,7 @@ int Field_long::store(longlong nr, bool unsigned_val) res=(int32) nr; } if (error) - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); int4store(ptr,res); return error; @@ -3889,7 +3873,7 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs) tmp= cs->cset->strntoull10rnd(cs,from,len,unsigned_flag,&end,&error); if (error == MY_ERRNO_ERANGE) { - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } else if (get_thd()->count_cuted_fields && @@ -3911,7 +3895,7 @@ int Field_longlong::store(double nr) res= double_to_longlong(nr, unsigned_flag, &error); if (error) - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); int8store(ptr,res); return error; @@ -3932,7 +3916,7 @@ int Field_longlong::store(longlong nr, bool unsigned_val) if (unsigned_flag != unsigned_val) { nr= unsigned_flag ? (ulonglong) 0 : (ulonglong) LONGLONG_MAX; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } } @@ -4046,8 +4030,7 @@ int Field_float::store(const char *from,uint len,CHARSET_INFO *cs) if (error || (!len || ((uint) (end-from) != len && get_thd()->count_cuted_fields))) { - set_warning(Sql_condition::WARN_LEVEL_WARN, - (error ? ER_WARN_DATA_OUT_OF_RANGE : WARN_DATA_TRUNCATED), 1); + set_warning(error ? ER_WARN_DATA_OUT_OF_RANGE : WARN_DATA_TRUNCATED, 1); error= error ? 1 : 2; } Field_float::store(nr); @@ -4063,7 +4046,7 @@ int Field_float::store(double nr) unsigned_flag, FLT_MAX); if (error) { - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); if (error < 0) // Wrong double value { error= 1; @@ -4234,8 +4217,7 @@ int Field_double::store(const char *from,uint len,CHARSET_INFO *cs) if (error || (!len || ((uint) (end-from) != len && get_thd()->count_cuted_fields))) { - set_warning(Sql_condition::WARN_LEVEL_WARN, - (error ? ER_WARN_DATA_OUT_OF_RANGE : WARN_DATA_TRUNCATED), 1); + set_warning(error ? ER_WARN_DATA_OUT_OF_RANGE : WARN_DATA_TRUNCATED, 1); error= error ? 1 : 2; } Field_double::store(nr); @@ -4251,7 +4233,7 @@ int Field_double::store(double nr) unsigned_flag, DBL_MAX); if (error) { - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); if (error < 0) // Wrong double value { error= 1; @@ -4612,7 +4594,7 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time, if (MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut) || !have_smth_to_conv) { error= 1; - set_datetime_warning(Sql_condition::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, + set_datetime_warning(WARN_DATA_TRUNCATED, str, MYSQL_TIMESTAMP_DATETIME, 1); } else if (MYSQL_TIME_WARN_HAVE_NOTES(was_cut)) @@ -4630,7 +4612,7 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time, conversion_error= ER_WARN_DATA_OUT_OF_RANGE; if (conversion_error) { - set_datetime_warning(Sql_condition::WARN_LEVEL_WARN, conversion_error, + set_datetime_warning(conversion_error, str, MYSQL_TIMESTAMP_DATETIME, !error); error= 1; } @@ -5128,7 +5110,7 @@ void Field_temporal::set_warnings(Sql_condition::enum_warning_level trunc_level, set_datetime_warning(trunc_level, WARN_DATA_TRUNCATED, str, mysql_type_to_time_type(type()), 1); if (was_cut & MYSQL_TIME_WARN_OUT_OF_RANGE) - set_datetime_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, + set_datetime_warning(ER_WARN_DATA_OUT_OF_RANGE, str, mysql_type_to_time_type(type()), 1); } @@ -5656,7 +5638,7 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs) error == MY_ERRNO_ERANGE) { *ptr=0; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); return 1; } if (get_thd()->count_cuted_fields && @@ -5699,7 +5681,7 @@ int Field_year::store(longlong nr, bool unsigned_val) if (nr < 0 || (nr >= 100 && nr <= 1900) || nr > 2155) { *ptr= 0; - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); return 1; } if (nr != 0 || field_length != 4) // 0000 -> 0; 00 -> 2000 @@ -5720,8 +5702,7 @@ int Field_year::store_time_dec(MYSQL_TIME *ltime, uint dec) if (Field_year::store(ltime->year, 0)) return 1; - set_datetime_warning(Sql_condition::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, - &str, ltime->time_type, 1); + set_datetime_warning(WARN_DATA_TRUNCATED, &str, ltime->time_type, 1); return 0; } @@ -6281,31 +6262,21 @@ bool Field_datetimef::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) TRUE - If an error happened */ -static bool -check_string_copy_error(Field_str *field, - const char *well_formed_error_pos, - const char *cannot_convert_error_pos, - const char *end, - CHARSET_INFO *cs) +bool +Field_longstr::check_string_copy_error(const char *well_formed_error_pos, + const char *cannot_convert_error_pos, + const char *end, + CHARSET_INFO *cs) { const char *pos; char tmp[32]; - THD *thd; - - thd= field->get_thd(); if (!(pos= well_formed_error_pos) && !(pos= cannot_convert_error_pos)) return FALSE; convert_to_printable(tmp, sizeof(tmp), pos, (end - pos), cs, 6); - - push_warning_printf(thd, - Sql_condition::WARN_LEVEL_WARN, - ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, - ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), - "string", tmp, field->field_name, - thd->get_stmt_da()->current_row_for_warning()); + set_warning_truncated_wrong_value("string", tmp); return TRUE; } @@ -6340,14 +6311,14 @@ Field_longstr::report_if_important_data(const char *pstr, const char *end, if (test_if_important_data(field_charset, pstr, end)) { if (thd->abort_on_warning) - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1); + set_warning(ER_DATA_TOO_LONG, 1); else - set_warning(Sql_condition::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + set_warning(WARN_DATA_TRUNCATED, 1); return 2; } else if (count_spaces) { /* If we lost only spaces then produce a NOTE, not a WARNING */ - set_warning(Sql_condition::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1); + set_note(WARN_DATA_TRUNCATED, 1); return 2; } } @@ -6382,7 +6353,7 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) field_length-copy_length, field_charset->pad_char); - if (check_string_copy_error(this, well_formed_error_pos, + if (check_string_copy_error(well_formed_error_pos, cannot_convert_error_pos, from + length, cs)) return 2; @@ -6413,9 +6384,9 @@ int Field_str::store(double nr) if (error) { if (get_thd()->abort_on_warning) - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1); + set_warning(ER_DATA_TOO_LONG, 1); else - set_warning(Sql_condition::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + set_warning(WARN_DATA_TRUNCATED, 1); } return store(buff, length, &my_charset_numeric); } @@ -6891,7 +6862,7 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) else int2store(ptr, copy_length); - if (check_string_copy_error(this, well_formed_error_pos, + if (check_string_copy_error(well_formed_error_pos, cannot_convert_error_pos, from + length, cs)) return 2; @@ -7417,7 +7388,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) tmp= value.ptr(); bmove(ptr+packlength,(uchar*) &tmp,sizeof(char*)); - if (check_string_copy_error(this, well_formed_error_pos, + if (check_string_copy_error(well_formed_error_pos, cannot_convert_error_pos, from + length, cs)) return 2; @@ -7923,6 +7894,14 @@ err_exit: return -1; } +Field::geometry_type Field_geom::geometry_type_merge(geometry_type a, + geometry_type b) +{ + if (a == b) + return a; + return Field::GEOM_GEOMETRY; +} + #endif /*HAVE_SPATIAL*/ /**************************************************************************** @@ -7983,13 +7962,13 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) if (err || end != from+length || tmp > typelib->count) { tmp=0; - set_warning(Sql_condition::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + set_warning(WARN_DATA_TRUNCATED, 1); } if (!get_thd()->count_cuted_fields) err= 0; } else - set_warning(Sql_condition::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + set_warning(WARN_DATA_TRUNCATED, 1); } store_type((ulonglong) tmp); return err; @@ -8008,7 +7987,7 @@ int Field_enum::store(longlong nr, bool unsigned_val) int error= 0; if ((ulonglong) nr > typelib->count || nr == 0) { - set_warning(Sql_condition::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + set_warning(WARN_DATA_TRUNCATED, 1); if (nr != 0 || get_thd()->count_cuted_fields) { nr= 0; @@ -8161,11 +8140,11 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) tmp > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1)) { tmp=0; - set_warning(Sql_condition::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + set_warning(WARN_DATA_TRUNCATED, 1); } } else if (got_warning) - set_warning(Sql_condition::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + set_warning(WARN_DATA_TRUNCATED, 1); store_type(tmp); return err; } @@ -8185,7 +8164,7 @@ int Field_set::store(longlong nr, bool unsigned_val) if ((ulonglong) nr > max_nr) { nr&= max_nr; - set_warning(Sql_condition::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + set_warning(WARN_DATA_TRUNCATED, 1); error=1; } store_type((ulonglong) nr); @@ -8537,9 +8516,9 @@ int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs) set_rec_bits((1 << bit_len) - 1, bit_ptr, bit_ofs, bit_len); memset(ptr, 0xff, bytes_in_rec); if (get_thd()->really_abort_on_warning()) - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1); + set_warning(ER_DATA_TOO_LONG, 1); else - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); return 1; } /* delta is >= -1 here */ @@ -8974,9 +8953,9 @@ int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs) if (bits) *ptr&= ((1 << bits) - 1); /* set first uchar */ if (get_thd()->really_abort_on_warning()) - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1); + set_warning(ER_DATA_TOO_LONG, 1); else - set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); return 1; } bzero(ptr, delta); @@ -9923,35 +9902,52 @@ Create_field::Create_field(Field *old_field,Field *orig_field) char_length= length; /* - Copy the default value from the column object orig_field, if: - 1) The column has a constant default value. - 2) The column type is not a BLOB type. - 3) The original column (old_field) was properly initialized with a record - buffer pointer. - 4) The original column doesn't have a default function to auto-initialize - the column on INSERT + Copy the default (constant/function) from the column object orig_field, if + supplied. We do this if all these conditions are met: + + - The column allows a default. + + - The column type is not a BLOB type. + + - The original column (old_field) was properly initialized with a record + buffer pointer. */ - if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) && // 1) 2) - old_field->ptr && orig_field && // 3) - !old_field->has_insert_default_function()) // 4) - { - char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff), charset); - my_ptrdiff_t diff; - - /* Get the value from default_values */ - diff= (my_ptrdiff_t) (orig_field->table->s->default_values- - orig_field->table->record[0]); - orig_field->move_field_offset(diff); // Points now at default_values - if (!orig_field->is_real_null()) + if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) && + old_field->ptr != NULL && + orig_field != NULL) + { + bool default_now= false; + if (real_type_with_now_as_default(sql_type)) { - char buff[MAX_FIELD_WIDTH], *pos; - String tmp(buff, sizeof(buff), charset), *res; - res= orig_field->val_str(&tmp); - pos= (char*) sql_strmake(res->ptr(), res->length()); - def= new Item_string(pos, res->length(), charset); + // The SQL type of the new field allows a function default: + default_now= orig_field->has_insert_default_function(); + bool update_now= orig_field->has_update_default_function(); + + if (default_now && update_now) + unireg_check= Field::TIMESTAMP_DNUN_FIELD; + else if (default_now) + unireg_check= Field::TIMESTAMP_DN_FIELD; + else if (update_now) + unireg_check= Field::TIMESTAMP_UN_FIELD; + } + if (!default_now) // Give a constant default + { + char buff[MAX_FIELD_WIDTH]; + String tmp(buff,sizeof(buff), charset); + + /* Get the value from default_values */ + my_ptrdiff_t diff= orig_field->table->default_values_offset(); + orig_field->move_field_offset(diff); // Points now at default_values + if (!orig_field->is_real_null()) + { + char buff[MAX_FIELD_WIDTH], *pos; + String tmp(buff, sizeof(buff), charset), *res; + res= orig_field->val_str(&tmp); + pos= (char*) sql_strmake(res->ptr(), res->length()); + def= new Item_string(pos, res->length(), charset); + } + orig_field->move_field_offset(-diff); // Back to record[0] } - orig_field->move_field_offset(-diff); // Back to record[0] } } @@ -10102,6 +10098,19 @@ void Field::set_datetime_warning(Sql_condition::enum_warning_level level, } +void Field::set_warning_truncated_wrong_value(const char *type, + const char *value) +{ + THD *thd= get_thd(); + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, + ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), + type, value, field_name, + static_cast<ulong>(thd->get_stmt_da()-> + current_row_for_warning())); +} + + /* @brief Return possible keys for a field diff --git a/sql/field.h b/sql/field.h index 6f4bcc638c9..a40e2ef9913 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1,7 +1,7 @@ #ifndef FIELD_INCLUDED #define FIELD_INCLUDED /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2008, 2014, SkySQL Ab. + Copyright (c) 2008, 2015, MariaDB 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 @@ -119,6 +119,20 @@ inline bool is_temporal_type_with_date(enum_field_types type) /** + Tests if a field real type can have "DEFAULT CURRENT_TIMESTAMP" + + @param type Field type, as returned by field->real_type(). + @retval true If field real type can have "DEFAULT CURRENT_TIMESTAMP". + @retval false If field real type can not have "DEFAULT CURRENT_TIMESTAMP". +*/ +inline bool real_type_with_now_as_default(enum_field_types type) +{ + return type == MYSQL_TYPE_TIMESTAMP || type == MYSQL_TYPE_TIMESTAMP2 || + type == MYSQL_TYPE_DATETIME || type == MYSQL_TYPE_DATETIME2; +} + + +/** Recognizer for concrete data type (called real_type for some reason), returning true if it is one of the TIMESTAMP types. */ @@ -871,14 +885,32 @@ public: virtual int set_time() { return 1; } bool set_warning(Sql_condition::enum_warning_level, unsigned int code, int cuted_increment) const; +protected: + bool set_warning(unsigned int code, int cuted_increment) const + { + return set_warning(Sql_condition::WARN_LEVEL_WARN, code, cuted_increment); + } + bool set_note(unsigned int code, int cuted_increment) const + { + return set_warning(Sql_condition::WARN_LEVEL_NOTE, code, cuted_increment); + } void set_datetime_warning(Sql_condition::enum_warning_level, uint code, const ErrConv *str, timestamp_type ts_type, int cuted_increment); + void set_datetime_warning(uint code, + const ErrConv *str, timestamp_type ts_type, + int cuted_increment) + { + set_datetime_warning(Sql_condition::WARN_LEVEL_WARN, code, str, ts_type, + cuted_increment); + } + void set_warning_truncated_wrong_value(const char *type, const char *value); inline bool check_overflow(int op_result) { return (op_result == E_DEC_OVERFLOW); } int warn_if_overflow(int op_result); +public: void set_table_name(String *alias) { table_name= &alias->Ptr; @@ -1125,6 +1157,10 @@ class Field_longstr :public Field_str protected: int report_if_important_data(const char *ptr, const char *end, bool count_spaces); + bool check_string_copy_error(const char *well_formed_error_pos, + const char *cannot_convert_error_pos, + const char *end, + CHARSET_INFO *cs); public: Field_longstr(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, @@ -2561,6 +2597,14 @@ public: int store(longlong nr, bool unsigned_val); int store_decimal(const my_decimal *); uint size_of() const { return sizeof(*this); } + /** + Key length is provided only to support hash joins. (compared byte for byte) + Ex: SELECT .. FROM t1,t2 WHERE t1.field_geom1=t2.field_geom2. + + The comparison is not very relevant, as identical geometry might be + represented differently, but we need to support it either way. + */ + uint32 key_length() const { return packlength; } /** Non-nullable GEOMETRY types cannot have defaults, @@ -2569,6 +2613,7 @@ public: int reset(void) { return Field_blob::reset() || !maybe_null(); } geometry_type get_geometry_type() { return geom_type; }; + static geometry_type geometry_type_merge(geometry_type, geometry_type); }; #endif /*HAVE_SPATIAL*/ diff --git a/sql/filesort.cc b/sql/filesort.cc index 027437fca67..a545bb623c0 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. - Copyright (c) 2009, 2014, Monty Program Ab. +/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2009, 2015, MariaDB 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/gen_lex_token.cc b/sql/gen_lex_token.cc new file mode 100644 index 00000000000..3584dd60c62 --- /dev/null +++ b/sql/gen_lex_token.cc @@ -0,0 +1,353 @@ +/* + Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + + 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +/* We only need the tokens here */ +#define YYSTYPE_IS_DECLARED +#include <sql_yacc.h> +#include <lex.h> + +#include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */ + +/* + This is a tool used during build only, + so MY_MAX_TOKEN does not need to be exact, + only big enough to hold: + - 256 character terminal tokens + - YYNTOKENS named terminal tokens + from bison. + See also YYMAXUTOK. +*/ +#define MY_MAX_TOKEN 1000 +/** Generated token. */ +struct gen_lex_token_string +{ + const char *m_token_string; + int m_token_length; + bool m_append_space; + bool m_start_expr; +}; + +gen_lex_token_string compiled_token_array[MY_MAX_TOKEN]; +int max_token_seen= 0; + +char char_tokens[256]; + +int tok_generic_value= 0; +int tok_generic_value_list= 0; +int tok_row_single_value= 0; +int tok_row_single_value_list= 0; +int tok_row_multiple_value= 0; +int tok_row_multiple_value_list= 0; +int tok_unused= 0; + +void set_token(int tok, const char *str) +{ + if (tok <= 0) + { + fprintf(stderr, "Bad token found\n"); + exit(1); + } + + if (tok > max_token_seen) + { + max_token_seen= tok; + } + + if (max_token_seen >= MY_MAX_TOKEN) + { + fprintf(stderr, "Added that many new keywords ? Increase MY_MAX_TOKEN\n"); + exit(1); + } + + compiled_token_array[tok].m_token_string= str; + compiled_token_array[tok].m_token_length= strlen(str); + compiled_token_array[tok].m_append_space= true; + compiled_token_array[tok].m_start_expr= false; +} + +void set_start_expr_token(int tok) +{ + compiled_token_array[tok].m_start_expr= true; +} + +void compute_tokens() +{ + int tok; + unsigned int i; + char *str; + + /* + Default value. + */ + for (tok= 0; tok < MY_MAX_TOKEN; tok++) + { + compiled_token_array[tok].m_token_string= "(unknown)"; + compiled_token_array[tok].m_token_length= 9; + compiled_token_array[tok].m_append_space= true; + compiled_token_array[tok].m_start_expr= false; + } + + /* + Tokens made of just one terminal character + */ + for (tok=0; tok < 256; tok++) + { + str= & char_tokens[tok]; + str[0]= (char) tok; + compiled_token_array[tok].m_token_string= str; + compiled_token_array[tok].m_token_length= 1; + compiled_token_array[tok].m_append_space= true; + } + + max_token_seen= 255; + + /* + String terminal tokens, used in sql_yacc.yy + */ + set_token(NEG, "~"); + set_token(TABLE_REF_PRIORITY, "TABLE_REF_PRIORITY"); + + /* + Tokens hard coded in sql_lex.cc + */ + + set_token(WITH_CUBE_SYM, "WITH CUBE"); + set_token(WITH_ROLLUP_SYM, "WITH ROLLUP"); + set_token(NOT2_SYM, "!"); + set_token(OR2_SYM, "|"); + set_token(PARAM_MARKER, "?"); + set_token(SET_VAR, ":="); + set_token(UNDERSCORE_CHARSET, "(_charset)"); + set_token(END_OF_INPUT, ""); + + /* + Values. + These tokens are all normalized later, + so this strings will never be displayed. + */ + set_token(BIN_NUM, "(bin)"); + set_token(DECIMAL_NUM, "(decimal)"); + set_token(FLOAT_NUM, "(float)"); + set_token(HEX_NUM, "(hex)"); + set_token(LEX_HOSTNAME, "(hostname)"); + set_token(LONG_NUM, "(long)"); + set_token(NUM, "(num)"); + set_token(TEXT_STRING, "(text)"); + set_token(NCHAR_STRING, "(nchar)"); + set_token(ULONGLONG_NUM, "(ulonglong)"); + + /* + Identifiers. + */ + set_token(IDENT, "(id)"); + set_token(IDENT_QUOTED, "(id_quoted)"); + + /* + Unused tokens + */ + set_token(LOCATOR_SYM, "LOCATOR"); + set_token(SERVER_OPTIONS, "SERVER_OPTIONS"); + set_token(UDF_RETURNS_SYM, "UDF_RETURNS"); + + /* + See symbols[] in sql/lex.h + */ + for (i= 0; i< sizeof(symbols)/sizeof(symbols[0]); i++) + { + set_token(symbols[i].tok, symbols[i].name); + } + + /* + See sql_functions[] in sql/lex.h + */ + for (i= 0; i< sizeof(sql_functions)/sizeof(sql_functions[0]); i++) + { + set_token(sql_functions[i].tok, sql_functions[i].name); + } + + /* + Additional FAKE tokens, + used internally to normalize a digest text. + */ + + max_token_seen++; + tok_generic_value= max_token_seen; + set_token(tok_generic_value, "?"); + + max_token_seen++; + tok_generic_value_list= max_token_seen; + set_token(tok_generic_value_list, "?, ..."); + + max_token_seen++; + tok_row_single_value= max_token_seen; + set_token(tok_row_single_value, "(?)"); + + max_token_seen++; + tok_row_single_value_list= max_token_seen; + set_token(tok_row_single_value_list, "(?) /* , ... */"); + + max_token_seen++; + tok_row_multiple_value= max_token_seen; + set_token(tok_row_multiple_value, "(...)"); + + max_token_seen++; + tok_row_multiple_value_list= max_token_seen; + set_token(tok_row_multiple_value_list, "(...) /* , ... */"); + + max_token_seen++; + tok_unused= max_token_seen; + set_token(tok_unused, "UNUSED"); + + /* + Fix whitespace for some special tokens. + */ + + /* + The lexer parses "@@variable" as '@', '@', 'variable', + returning a token for '@' alone. + + This is incorrect, '@' is not really a token, + because the syntax "@ @ variable" (with spaces) is not accepted: + The lexer keeps some internal state after the '@' fake token. + + To work around this, digest text are printed as "@@variable". + */ + compiled_token_array[(int) '@'].m_append_space= false; + + /* + Define additional properties for tokens. + + List all the token that are followed by an expression. + This is needed to differentiate unary from binary + '+' and '-' operators, because we want to: + - reduce <unary +> <NUM> to <?>, + - preserve <...> <binary +> <NUM> as is. + */ + set_start_expr_token('('); + set_start_expr_token(','); + set_start_expr_token(EVERY_SYM); + set_start_expr_token(AT_SYM); + set_start_expr_token(STARTS_SYM); + set_start_expr_token(ENDS_SYM); + set_start_expr_token(DEFAULT); + set_start_expr_token(RETURN_SYM); + set_start_expr_token(IF); + set_start_expr_token(ELSEIF_SYM); + set_start_expr_token(CASE_SYM); + set_start_expr_token(WHEN_SYM); + set_start_expr_token(WHILE_SYM); + set_start_expr_token(UNTIL_SYM); + set_start_expr_token(SELECT_SYM); + + set_start_expr_token(OR_SYM); + set_start_expr_token(OR2_SYM); + set_start_expr_token(XOR); + set_start_expr_token(AND_SYM); + set_start_expr_token(AND_AND_SYM); + set_start_expr_token(NOT_SYM); + set_start_expr_token(BETWEEN_SYM); + set_start_expr_token(LIKE); + set_start_expr_token(REGEXP); + + set_start_expr_token('|'); + set_start_expr_token('&'); + set_start_expr_token(SHIFT_LEFT); + set_start_expr_token(SHIFT_RIGHT); + set_start_expr_token('+'); + set_start_expr_token('-'); + set_start_expr_token(INTERVAL_SYM); + set_start_expr_token('*'); + set_start_expr_token('/'); + set_start_expr_token('%'); + set_start_expr_token(DIV_SYM); + set_start_expr_token(MOD_SYM); + set_start_expr_token('^'); +} + +void print_tokens() +{ + int tok; + + printf("#ifdef LEX_TOKEN_WITH_DEFINITION\n"); + printf("lex_token_string lex_token_array[]=\n"); + printf("{\n"); + printf("/* PART 1: character tokens. */\n"); + + for (tok= 0; tok<256; tok++) + { + printf("/* %03d */ { \"\\x%02x\", 1, %s, %s},\n", + tok, + tok, + compiled_token_array[tok].m_append_space ? "true" : "false", + compiled_token_array[tok].m_start_expr ? "true" : "false"); + } + + printf("/* PART 2: named tokens. */\n"); + + for (tok= 256; tok<= max_token_seen; tok++) + { + printf("/* %03d */ { \"%s\", %d, %s, %s},\n", + tok, + compiled_token_array[tok].m_token_string, + compiled_token_array[tok].m_token_length, + compiled_token_array[tok].m_append_space ? "true" : "false", + compiled_token_array[tok].m_start_expr ? "true" : "false"); + } + + printf("/* DUMMY */ { \"\", 0, false, false}\n"); + printf("};\n"); + printf("#endif /* LEX_TOKEN_WITH_DEFINITION */\n"); + + printf("/* DIGEST specific tokens. */\n"); + printf("#define TOK_GENERIC_VALUE %d\n", tok_generic_value); + printf("#define TOK_GENERIC_VALUE_LIST %d\n", tok_generic_value_list); + printf("#define TOK_ROW_SINGLE_VALUE %d\n", tok_row_single_value); + printf("#define TOK_ROW_SINGLE_VALUE_LIST %d\n", tok_row_single_value_list); + printf("#define TOK_ROW_MULTIPLE_VALUE %d\n", tok_row_multiple_value); + printf("#define TOK_ROW_MULTIPLE_VALUE_LIST %d\n", tok_row_multiple_value_list); + printf("#define TOK_UNUSED %d\n", tok_unused); +} + +int main(int argc,char **argv) +{ + puts("/*"); + puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2011")); + puts("*/"); + + printf("/*\n"); + printf(" This file is generated, do not edit.\n"); + printf(" See file sql/gen_lex_token.cc.\n"); + printf("*/\n"); + printf("struct lex_token_string\n"); + printf("{\n"); + printf(" const char *m_token_string;\n"); + printf(" int m_token_length;\n"); + printf(" bool m_append_space;\n"); + printf(" bool m_start_expr;\n"); + printf("};\n"); + printf("typedef struct lex_token_string lex_token_string;\n"); + + compute_tokens(); + print_tokens(); + + return 0; +} + diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 73513ac9f40..64ae31ce231 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -1,5 +1,4 @@ -/* Copyright (c) 2006, 2013, Oracle and/or its affiliates. - Copyright (c) 2012, 2013, Monty Proram Ab. +/* Copyright (c) 2006, 2015, 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 @@ -2529,7 +2528,8 @@ ndbcluster_check_if_local_tables_in_db(THD *thd, const char *dbname) char path[FN_REFLEN + 1]; build_table_filename(path, sizeof(path) - 1, dbname, "", "", 0); - if (find_files(thd, &files, dbname, path, NullS, 0) != FIND_FILES_OK) + if (find_files(thd, &files, dbname, path, NullS, 0, NULL) != + FIND_FILES_OK) { DBUG_PRINT("info", ("Failed to find files")); DBUG_RETURN(true); diff --git a/sql/handler.cc b/sql/handler.cc index 70bce6f3963..1f8daf3927b 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2298,9 +2298,11 @@ handle_condition(THD *, } -/** @brief - This should return ENOENT if the file doesn't exists. - The .frm file will be deleted only if we return 0 or ENOENT +/** delete a table in the engine + + @note + ENOENT and HA_ERR_NO_SUCH_TABLE are not considered errors. + The .frm file will be deleted only if we return 0. */ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, const char *db, const char *alias, bool generate_warning) @@ -2315,47 +2317,66 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, /* table_type is NULL in ALTER TABLE when renaming only .frm files */ if (table_type == NULL || table_type == view_pseudo_hton || ! (file=get_new_handler((TABLE_SHARE*)0, thd->mem_root, table_type))) - DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); + DBUG_RETURN(0); bzero((char*) &dummy_table, sizeof(dummy_table)); bzero((char*) &dummy_share, sizeof(dummy_share)); dummy_table.s= &dummy_share; path= get_canonical_filename(file, path, tmp_path); - if ((error= file->ha_delete_table(path)) && generate_warning) + if ((error= file->ha_delete_table(path))) { /* - Because file->print_error() use my_error() to generate the error message - we use an internal error handler to intercept it and store the text - in a temporary buffer. Later the message will be presented to user - as a warning. + it's not an error if the table doesn't exist in the engine. + warn the user, but still report DROP being a success */ - Ha_delete_table_error_handler ha_delete_table_error_handler; - - /* Fill up strucutures that print_error may need */ - dummy_share.path.str= (char*) path; - dummy_share.path.length= strlen(path); - dummy_share.normalized_path= dummy_share.path; - dummy_share.db.str= (char*) db; - dummy_share.db.length= strlen(db); - dummy_share.table_name.str= (char*) alias; - dummy_share.table_name.length= strlen(alias); - dummy_table.alias.set(alias, dummy_share.table_name.length, - table_alias_charset); + bool intercept= error == ENOENT || error == HA_ERR_NO_SUCH_TABLE; - file->change_table_ptr(&dummy_table, &dummy_share); - - thd->push_internal_handler(&ha_delete_table_error_handler); - file->print_error(error, 0); + if (!intercept || generate_warning) + { + /* + Because file->print_error() use my_error() to generate the error message + we use an internal error handler to intercept it and store the text + in a temporary buffer. Later the message will be presented to user + as a warning. + */ + Ha_delete_table_error_handler ha_delete_table_error_handler; + + /* Fill up strucutures that print_error may need */ + dummy_share.path.str= (char*) path; + dummy_share.path.length= strlen(path); + dummy_share.normalized_path= dummy_share.path; + dummy_share.db.str= (char*) db; + dummy_share.db.length= strlen(db); + dummy_share.table_name.str= (char*) alias; + dummy_share.table_name.length= strlen(alias); + dummy_table.alias.set(alias, dummy_share.table_name.length, + table_alias_charset); + + file->change_table_ptr(&dummy_table, &dummy_share); + +#if MYSQL_VERSION_ID > 100105 + // XXX as an ugly 10.0-only hack we intercept HA_ERR_ROW_IS_REFERENCED, + // to report it under the old historical error number. +#error remove HA_ERR_ROW_IS_REFERENCED, use ME_JUST_WARNING instead of a handler +#endif + if (intercept || error == HA_ERR_ROW_IS_REFERENCED) + thd->push_internal_handler(&ha_delete_table_error_handler); - thd->pop_internal_handler(); + file->print_error(error, 0); - /* - XXX: should we convert *all* errors to warnings here? - What if the error is fatal? - */ - push_warning(thd, Sql_condition::WARN_LEVEL_WARN, error, - ha_delete_table_error_handler.buff); + if (intercept || error == HA_ERR_ROW_IS_REFERENCED) + { + thd->pop_internal_handler(); + if (error == HA_ERR_ROW_IS_REFERENCED) + my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0)); + else + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, error, + ha_delete_table_error_handler.buff); + } + } + if (intercept) + error= 0; } delete file; diff --git a/sql/item.cc b/sql/item.cc index 132cfa2846a..bffa7e2990d 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2014, Oracle and/or its affiliates. - Copyright (c) 2010, 2014, Monty Program Ab. + Copyright (c) 2010, 2015, MariaDB 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 @@ -1179,6 +1179,42 @@ Item *Item::safe_charset_converter(CHARSET_INFO *tocs) /** + Some pieces of the code do not support changing of + Item_cache to other Item types. + + Example: + Item_singlerow_subselect has "Item_cache **row". + Creating of Item_func_conv_charset followed by THD::change_item_tree() + should not change row[i] from Item_cache directly to Item_func_conv_charset, because Item_singlerow_subselect + because Item_singlerow_subselect later calls Item_cache-specific methods, + e.g. row[i]->store() and row[i]->cache_value(). + + Let's wrap Item_func_conv_charset in a new Item_cache, + so the Item_cache-specific methods can still be used for + Item_singlerow_subselect::row[i] safely. + + As a bonus we cache the converted value, instead of converting every time + + TODO: we should eventually check all other use cases of change_item_tree(). + Perhaps some more potentially dangerous substitution examples exist. +*/ +Item *Item_cache::safe_charset_converter(CHARSET_INFO *tocs) +{ + if (!example) + return Item::safe_charset_converter(tocs); + Item *conv= example->safe_charset_converter(tocs); + if (conv == example) + return this; + Item_cache *cache; + if (!conv || !(cache= new Item_cache_str(conv))) + return NULL; // Safe conversion is not possible, or OEM + cache->setup(conv); + cache->fixed= false; // Make Item::fix_fields() happy + return cache; +} + + +/** @details Created mostly for mysql_prepare_table(). Important when a string ENUM/SET column is described with a numeric default value: @@ -7931,6 +7967,7 @@ bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference) return TRUE; if (view->table && view->table->maybe_null) maybe_null= TRUE; + set_null_ref_table(); return FALSE; } @@ -9470,6 +9507,11 @@ bool Item_type_holder::join_types(THD *thd, Item *item) item_decimals= 0; decimals= MY_MAX(decimals, item_decimals); } + + if (fld_type == FIELD_TYPE_GEOMETRY) + geometry_type= + Field_geom::geometry_type_merge(geometry_type, item->get_geometry_type()); + if (Field::result_merge_type(fld_type) == DECIMAL_RESULT) { decimals= MY_MIN(MY_MAX(decimals, item->decimals), DECIMAL_MAX_SCALE); @@ -9775,13 +9817,30 @@ void Item_ref::update_used_tables() (*ref)->update_used_tables(); } +void Item_direct_view_ref::update_used_tables() +{ + set_null_ref_table(); + Item_direct_ref::update_used_tables(); +} + + table_map Item_direct_view_ref::used_tables() const { - return get_depended_from() ? - OUTER_REF_TABLE_BIT : - ((view->is_merged_derived() || view->merged || !view->table) ? - (*ref)->used_tables() : - view->table->map); + DBUG_ASSERT(null_ref_table); + + if (get_depended_from()) + return OUTER_REF_TABLE_BIT; + + if (view->is_merged_derived() || view->merged || !view->table) + { + table_map used= (*ref)->used_tables(); + return (used ? + used : + ((null_ref_table != NO_NULL_TABLE) ? + null_ref_table->map : + (table_map)0 )); + } + return view->table->map; } table_map Item_direct_view_ref::not_null_tables() const diff --git a/sql/item.h b/sql/item.h index 7c61c5fc65f..171bdb05310 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1,8 +1,8 @@ #ifndef SQL_ITEM_INCLUDED #define SQL_ITEM_INCLUDED -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2009, 2013 Monty Program Ab. +/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2009, 2015, MariaDB 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 @@ -3735,13 +3735,16 @@ class Item_direct_view_ref :public Item_direct_ref #define NO_NULL_TABLE (reinterpret_cast<TABLE *>(0x1)) + void set_null_ref_table() + { + if (!view->is_inner_table_of_outer_join() || + !(null_ref_table= view->get_real_join_table())) + null_ref_table= NO_NULL_TABLE; + } + bool check_null_ref() { - if (null_ref_table == NULL) - { - if (!(null_ref_table= view->get_real_join_table())) - null_ref_table= NO_NULL_TABLE; - } + DBUG_ASSERT(null_ref_table); if (null_ref_table != NO_NULL_TABLE && null_ref_table->null_row) { null_value= 1; @@ -3749,6 +3752,7 @@ class Item_direct_view_ref :public Item_direct_ref } return FALSE; } + public: Item_direct_view_ref(Name_resolution_context *context_arg, Item **item, const char *table_name_arg, @@ -3756,7 +3760,11 @@ public: TABLE_LIST *view_arg) :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg), item_equal(0), view(view_arg), - null_ref_table(NULL) {} + null_ref_table(NULL) + { + if (fixed) + set_null_ref_table(); + } bool fix_fields(THD *, Item **); bool eq(const Item *item, bool binary_cmp) const; @@ -3774,7 +3782,9 @@ public: Item *equal_fields_propagator(uchar *arg); Item *replace_equal_field(uchar *arg); table_map used_tables() const; + void update_used_tables(); table_map not_null_tables() const; + bool const_item() const { return used_tables() == 0; } bool walk(Item_processor processor, bool walk_subquery, uchar *arg) { return (*ref)->walk(processor, walk_subquery, arg) || @@ -4467,7 +4477,6 @@ 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 used by index-based subquery engines to detect and remove the equality injected @@ -4485,7 +4494,7 @@ protected: bool value_cached; public: Item_cache(): - example(0), used_table_map(0), cached_field(0), + example(0), cached_field(0), cached_field_type(MYSQL_TYPE_STRING), value_cached(0) { @@ -4494,7 +4503,7 @@ public: null_value= 1; } Item_cache(enum_field_types field_type_arg): - example(0), used_table_map(0), cached_field(0), + example(0), cached_field(0), cached_field_type(field_type_arg), value_cached(0) { @@ -4503,8 +4512,6 @@ public: null_value= 1; } - void set_used_tables(table_map map) { used_table_map= map; } - virtual bool allocate(uint i) { return 0; } virtual bool setup(Item *item) { @@ -4521,7 +4528,6 @@ public: enum_field_types field_type() const { return cached_field_type; } static Item_cache* get_cache(const Item *item); static Item_cache* get_cache(const Item* item, const Item_result type); - table_map used_tables() const { return used_table_map; } virtual void keep_array() {} virtual void print(String *str, enum_query_type query_type); bool eq_def(Field *field) @@ -4572,6 +4578,7 @@ public: return TRUE; return (this->*processor)(arg); } + virtual Item *safe_charset_converter(CHARSET_INFO *tocs); }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 1f1982ffb80..90eef1ea55c 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -5160,10 +5160,65 @@ bool Regexp_processor_pcre::compile(Item *item, bool send_error) } +/** + Send a warning explaining an error code returned by pcre_exec(). +*/ +void Regexp_processor_pcre::pcre_exec_warn(int rc) const +{ + char buf[64]; + const char *errmsg= NULL; + /* + Make a descriptive message only for those pcre_exec() error codes + that can actually happen in MariaDB. + */ + switch (rc) + { + case PCRE_ERROR_NOMEMORY: + errmsg= "pcre_exec: Out of memory"; + break; + case PCRE_ERROR_BADUTF8: + errmsg= "pcre_exec: Invalid utf8 byte sequence in the subject string"; + break; + case PCRE_ERROR_RECURSELOOP: + errmsg= "pcre_exec: Recursion loop detected"; + break; + default: + /* + As other error codes should normally not happen, + we just report the error code without textual description + of the code. + */ + my_snprintf(buf, sizeof(buf), "pcre_exec: Internal error (%d)", rc); + errmsg= buf; + } + push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, + ER_REGEXP_ERROR, ER(ER_REGEXP_ERROR), errmsg); +} + + +/** + Call pcre_exec() and send a warning if pcre_exec() returned with an error. +*/ +int Regexp_processor_pcre::pcre_exec_with_warn(const pcre *code, + const pcre_extra *extra, + const char *subject, + int length, int startoffset, + int options, int *ovector, + int ovecsize) +{ + int rc= pcre_exec(code, extra, subject, length, + startoffset, options, ovector, ovecsize); + DBUG_EXECUTE_IF("pcre_exec_error_123", rc= -123;); + if (rc < PCRE_ERROR_NOMATCH) + pcre_exec_warn(rc); + return rc; +} + + bool Regexp_processor_pcre::exec(const char *str, int length, int offset) { - m_pcre_exec_rc= pcre_exec(m_pcre, NULL, str, length, - offset, 0, m_SubStrVec, m_subpatterns_needed * 3); + m_pcre_exec_rc= pcre_exec_with_warn(m_pcre, NULL, str, length, offset, 0, + m_SubStrVec, m_subpatterns_needed * 3); return false; } @@ -5173,8 +5228,10 @@ bool Regexp_processor_pcre::exec(String *str, int offset, { if (!(str= convert_if_needed(str, &subject_converter))) return true; - m_pcre_exec_rc= pcre_exec(m_pcre, NULL, str->c_ptr_safe(), str->length(), - offset, 0, m_SubStrVec, m_subpatterns_needed * 3); + m_pcre_exec_rc= pcre_exec_with_warn(m_pcre, NULL, + str->c_ptr_safe(), str->length(), + offset, 0, + m_SubStrVec, m_subpatterns_needed * 3); if (m_pcre_exec_rc > 0) { uint i; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 8611182f32d..c4933e6d7ed 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1549,6 +1549,10 @@ class Regexp_processor_pcre int m_pcre_exec_rc; int m_SubStrVec[30]; uint m_subpatterns_needed; + void pcre_exec_warn(int rc) const; + int pcre_exec_with_warn(const pcre *code, const pcre_extra *extra, + const char *subject, int length, int startoffset, + int options, int *ovector, int ovecsize); public: String *convert_if_needed(String *src, String *converter); String subject_converter; diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index 6d52661e5c9..94be38e26ee 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -2,7 +2,7 @@ #define ITEM_GEOFUNC_INCLUDED /* Copyright (c) 2000, 2010 Oracle and/or its affiliates. - Copyright (C) 2011 Monty Program Ab. + Copyright (C) 2011, 2015 MariaDB 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 @@ -116,7 +116,7 @@ class Item_func_point: public Item_geometry_func public: Item_func_point(Item *a, Item *b): Item_geometry_func(a, b) {} Item_func_point(Item *a, Item *b, Item *srid): Item_geometry_func(a, b, srid) {} - const char *func_name() const { return "st_point"; } + const char *func_name() const { return "point"; } String *val_str(String *); Field::geometry_type get_geometry_type() const; }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 32a19341895..972ae5afb16 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -5122,6 +5122,16 @@ null: void Item_dyncol_get::print(String *str, enum_query_type query_type) { + /* + Parent cast doesn't exist yet, only print dynamic column name. This happens + when called from create_func_cast() / wrong_precision_error(). + */ + if (!str->length()) + { + args[1]->print(str, query_type); + return; + } + /* see create_func_dyncol_get */ DBUG_ASSERT(str->length() >= 5); DBUG_ASSERT(strncmp(str->ptr() + str->length() - 5, "cast(", 5) == 0); diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 8377a20e0a4..2886cb68f9b 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -3,7 +3,7 @@ /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. - Copyright (c) 2009, 2013, Monty Program Ab. + Copyright (c) 2009, 2015, MariaDB 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 @@ -937,7 +937,6 @@ public: Item_func_conv_charset(Item *a, CHARSET_INFO *cs, bool cache_if_const) :Item_str_func(a) { - DBUG_ASSERT(args[0]->fixed); conv_charset= cs; if (cache_if_const && args[0]->const_item() && !args[0]->is_expensive()) { diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 21f14ae8435..1c5682417a5 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2008, 2014, SkySQL Ab. +/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2008, 2015, MariaDB 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 @@ -3311,7 +3311,19 @@ void Item_func_group_concat::cleanup() } DBUG_ASSERT(tree == 0); } - + /* + As the ORDER structures pointed to by the elements of the + 'order' array may be modified in find_order_in_list() called + from Item_func_group_concat::setup() to point to runtime + created objects, we need to reset them back to the original + arguments of the function. + */ + ORDER **order_ptr= order; + for (uint i= 0; i < arg_count_order; i++) + { + (*order_ptr)->item= &args[arg_count_field + i]; + order_ptr++; + } DBUG_VOID_RETURN; } diff --git a/sql/lex.h b/sql/lex.h index 10a52160cf0..a272504c0f2 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -1,7 +1,8 @@ #ifndef LEX_INCLUDED #define LEX_INCLUDED -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. + Copyright (c) 2009, 2015, MariaDB 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 @@ -389,6 +390,7 @@ static SYMBOL symbols[] = { { "MULTIPOINT", SYM(MULTIPOINT)}, { "MULTIPOLYGON", SYM(MULTIPOLYGON)}, { "MUTEX", SYM(MUTEX_SYM)}, + { "MYSQL", SYM(MYSQL_SYM)}, { "MYSQL_ERRNO", SYM(MYSQL_ERRNO_SYM)}, { "NAME", SYM(NAME_SYM)}, { "NAMES", SYM(NAMES_SYM)}, diff --git a/sql/log.cc b/sql/log.cc index 850b685be83..99d3fb69b18 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2009, 2014, SkySQL Ab. + Copyright (c) 2009, 2015, MariaDB 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 @@ -2493,6 +2493,8 @@ bool MYSQL_LOG::open( char buff[FN_REFLEN]; MY_STAT f_stat; File file= -1; + my_off_t seek_offset; + bool is_fifo = false; int open_flags= O_CREAT | O_BINARY; DBUG_ENTER("MYSQL_LOG::open"); DBUG_PRINT("enter", ("log_type: %d", (int) log_type_arg)); @@ -2509,15 +2511,17 @@ bool MYSQL_LOG::open( log_type_arg, io_cache_type_arg)) goto err; - /* File is regular writable file */ - if (my_stat(log_file_name, &f_stat, MYF(0)) && !MY_S_ISREG(f_stat.st_mode)) - goto err; + is_fifo = my_stat(log_file_name, &f_stat, MYF(0)) && + MY_S_ISFIFO(f_stat.st_mode); if (io_cache_type == SEQ_READ_APPEND) open_flags |= O_RDWR | O_APPEND; else open_flags |= O_WRONLY | (log_type == LOG_BIN ? 0 : O_APPEND); + if (is_fifo) + open_flags |= O_NONBLOCK; + db[0]= 0; #ifdef HAVE_PSI_INTERFACE @@ -2525,11 +2529,16 @@ bool MYSQL_LOG::open( m_log_file_key= log_file_key; #endif - if ((file= mysql_file_open(log_file_key, - log_file_name, open_flags, - MYF(MY_WME | ME_WAITTANG))) < 0 || - init_io_cache(&log_file, file, IO_SIZE, io_cache_type, - mysql_file_tell(file, MYF(MY_WME)), 0, + if ((file= mysql_file_open(log_file_key, log_file_name, open_flags, + MYF(MY_WME | ME_WAITTANG))) < 0) + goto err; + + if (is_fifo) + seek_offset= 0; + else if ((seek_offset= mysql_file_tell(file, MYF(MY_WME)))) + goto err; + + if (init_io_cache(&log_file, file, IO_SIZE, io_cache_type, seek_offset, 0, MYF(MY_WME | MY_NABP | ((log_type == LOG_BIN) ? MY_WAIT_IF_FULL : 0)))) goto err; @@ -2618,17 +2627,17 @@ void MYSQL_LOG::close(uint exiting) { end_io_cache(&log_file); - if (mysql_file_sync(log_file.file, MYF(MY_WME)) && ! write_error) + if (log_type == LOG_BIN && mysql_file_sync(log_file.file, MYF(MY_WME)) && ! write_error) { write_error= 1; - sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno); + sql_print_error(ER_THD_OR_DEFAULT(current_thd, ER_ERROR_ON_WRITE), name, errno); } if (!(exiting & LOG_CLOSE_DELAYED_CLOSE) && mysql_file_close(log_file.file, MYF(MY_WME)) && ! write_error) { write_error= 1; - sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno); + sql_print_error(ER_THD_OR_DEFAULT(current_thd, ER_ERROR_ON_WRITE), name, errno); } } @@ -6665,6 +6674,10 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd) if (check_purge) checkpoint_and_purge(prev_binlog_id); } + else + { + mysql_mutex_unlock(&LOCK_log); + } DBUG_RETURN(error); } diff --git a/sql/log.h b/sql/log.h index d3540aa4499..48970f7452a 100644 --- a/sql/log.h +++ b/sql/log.h @@ -990,11 +990,9 @@ uint purge_log_get_error_code(int res); int vprint_msg_to_log(enum loglevel level, const char *format, va_list args); void sql_print_error(const char *format, ...); -void sql_print_warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2); -void sql_print_information(const char *format, ...) - ATTRIBUTE_FORMAT(printf, 1, 2); -typedef void (*sql_print_message_func)(const char *format, ...) - ATTRIBUTE_FORMAT_FPTR(printf, 1, 2); +void sql_print_warning(const char *format, ...); +void sql_print_information(const char *format, ...); +typedef void (*sql_print_message_func)(const char *format, ...); extern sql_print_message_func sql_print_message_handlers[]; int error_log_print(enum loglevel level, const char *format, diff --git a/sql/log_event.cc b/sql/log_event.cc index b8fd02e96d4..69b981f3f47 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -49,6 +49,7 @@ #include <base64.h> #include <my_bitmap.h> #include "rpl_utility.h" +#include "sql_digest.h" #define my_b_write_string(A, B) my_b_write((A), (B), (uint) (sizeof(B) - 1)) @@ -337,10 +338,6 @@ private: flag_set m_flags; }; -#ifndef DBUG_OFF -uint debug_not_change_ts_if_art_event= 1; // bug#29309 simulation -#endif - /* pretty_print_str() */ @@ -879,7 +876,7 @@ Log_event::Log_event() Log_event::Log_event(const char* buf, const Format_description_log_event* description_event) - :temp_buf(0), cache_type(Log_event::EVENT_INVALID_CACHE), + :temp_buf(0), exec_time(0), cache_type(Log_event::EVENT_INVALID_CACHE), crc(0), checksum_alg(BINLOG_CHECKSUM_ALG_UNDEF) { #ifndef MYSQL_CLIENT @@ -970,29 +967,12 @@ int Log_event::do_update_pos(rpl_group_info *rgi) if (rli) { /* - bug#29309 simulation: resetting the flag to force - wrong behaviour of artificial event to update - rli->last_master_timestamp for only one time - - the first FLUSH LOGS in the test. - */ - DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp", - if (debug_not_change_ts_if_art_event == 1 - && is_artificial_event()) - debug_not_change_ts_if_art_event= 0; ); - /* In parallel execution, delay position update for the events that are not part of event groups (format description, rotate, and such) until the actual event execution reaches that point. */ if (!rgi->is_parallel_exec || is_group_event(get_type_code())) - rli->stmt_done(log_pos, - (is_artificial_event() && - IF_DBUG(debug_not_change_ts_if_art_event > 0, 1) ? - 0 : when), - thd, rgi); - DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp", - if (debug_not_change_ts_if_art_event == 0) - debug_not_change_ts_if_art_event= 2; ); + rli->stmt_done(log_pos, thd, rgi); } DBUG_RETURN(0); // Cannot fail currently } @@ -2426,6 +2406,12 @@ log_event_print_value(IO_CACHE *file, const uchar *ptr, my_snprintf(typestr, typestr_length, "STRING(%d)", length); return my_b_write_quoted_with_length(file, ptr, length); + case MYSQL_TYPE_DECIMAL: + my_b_printf(file, + "!! Old DECIMAL (mysql-4.1 or earlier). " + "Not enough metadata to display the value. "); + break; + default: { char tmp[5]; @@ -4303,12 +4289,17 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, Parser_state parser_state; if (!parser_state.init(thd, thd->query(), thd->query_length())) { + DBUG_ASSERT(thd->m_digest == NULL); + thd->m_digest= & thd->m_digest_state; + DBUG_ASSERT(thd->m_statement_psi == NULL); thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state, stmt_info_rpl.m_key, thd->db, thd->db_length, thd->charset()); THD_STAGE_INFO(thd, stage_init); MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(), thd->query_length()); + if (thd->m_digest != NULL) + thd->m_digest->reset(thd->m_token_array, max_digest_length); mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); /* Finalize server status flags after executing a statement. */ @@ -4400,11 +4391,10 @@ compare_errors: !ignored_error_code(expected_error)) { rli->report(ERROR_LEVEL, 0, rgi->gtid_info(), - "\ -Query caused different errors on master and slave. \ -Error on master: message (format)='%s' error code=%d ; \ -Error on slave: actual message='%s', error code=%d. \ -Default database: '%s'. Query: '%s'", + "Query caused different errors on master and slave. " + "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, actual_error ? thd->get_stmt_da()->message() : "no error", @@ -4500,6 +4490,7 @@ end: /* Mark the statement completed. */ MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); thd->m_statement_psi= NULL; + thd->m_digest= NULL; /* As a disk space optimization, future masters will not log an event for @@ -10107,7 +10098,7 @@ Rows_log_event::do_update_pos(rpl_group_info *rgi) Step the group log position if we are not in a transaction, otherwise increase the event log position. */ - rli->stmt_done(log_pos, when, thd, rgi); + rli->stmt_done(log_pos, thd, rgi); /* Clear any errors in thd->net.last_err*. It is not known if this is needed or not. It is believed that any errors that may exist in diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 181d950bf59..e6c05aeb849 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -1830,7 +1830,7 @@ Old_rows_log_event::do_update_pos(rpl_group_info *rgi) Step the group log position if we are not in a transaction, otherwise increase the event log position. */ - rli->stmt_done(log_pos, when, thd, rgi); + rli->stmt_done(log_pos, thd, rgi); /* Clear any errors in thd->net.last_err*. It is not known if this is needed or not. It is believed that any errors that may exist in diff --git a/sql/message.rc b/sql/message.rc index 116522b7d48..0885a897e6f 100644 --- a/sql/message.rc +++ b/sql/message.rc @@ -1,2 +1,2 @@ -LANGUAGE 0x9,0x1
-1 11 MSG00001.bin
+LANGUAGE 0x9,0x1 +1 11 MSG00001.bin diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7a8c8f3388d..c9682e15eae 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. - Copyright (c) 2008, 2014, SkySQL Ab. +/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2008, 2015, MariaDB 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 @@ -515,6 +515,7 @@ ulong binlog_cache_use= 0, binlog_cache_disk_use= 0; ulong binlog_stmt_cache_use= 0, binlog_stmt_cache_disk_use= 0; ulong max_connections, max_connect_errors; ulong extra_max_connections; +ulong max_digest_length= 0; ulong slave_retried_transactions; ulong feature_files_opened_with_delayed_keys; ulonglong denied_connections; @@ -2251,7 +2252,8 @@ static struct passwd *check_user(const char *user) { if (!opt_bootstrap && !opt_help) { - sql_print_error("Fatal error: Please read \"Security\" section of the manual to find out how to run mysqld as root!\n"); + sql_print_error("Fatal error: Please consult the Knowledge Base " + "to find out how to run mysqld as root!\n"); unireg_abort(1); } return NULL; @@ -2421,10 +2423,11 @@ static MYSQL_SOCKET activate_tcp_port(uint port) if (mysql_socket_getfd(ip_sock) == INVALID_SOCKET) { - sql_print_error("Failed to create a socket for %s '%s': errno: %d.", - (a->ai_family == AF_INET) ? "IPv4" : "IPv6", - (const char *) ip_addr, - (int) socket_errno); + sql_print_message_func func= real_bind_addr_str ? sql_print_error + : sql_print_warning; + func("Failed to create a socket for %s '%s': errno: %d.", + (a->ai_family == AF_INET) ? "IPv4" : "IPv6", + (const char *) ip_addr, (int) socket_errno); } else { @@ -4068,6 +4071,10 @@ static int init_common_variables() return 1; set_server_version(); + if (!opt_help) + sql_print_information("%s (mysqld %s) starting as process %lu ...", + my_progname, server_version, (ulong) getpid()); + #ifndef EMBEDDED_LIBRARY if (opt_abort && !opt_verbose) unireg_abort(0); @@ -4338,11 +4345,12 @@ static int init_common_variables() if (lower_case_table_names_used) { if (global_system_variables.log_warnings) - sql_print_warning("\ -You have forced lower_case_table_names to 0 through a command-line \ -option, even though your file system '%s' is case insensitive. This means \ -that you can corrupt a MyISAM table by accessing it with different cases. \ -You should consider changing lower_case_table_names to 1 or 2", + sql_print_warning("You have forced lower_case_table_names to 0 through " + "a command-line option, even though your file system " + "'%s' is case insensitive. This means that you can " + "corrupt a MyISAM table by accessing it with " + "different cases. You should consider changing " + "lower_case_table_names to 1 or 2", mysql_real_data_home); } else @@ -4556,7 +4564,6 @@ static void init_ssl() opt_ssl_cipher, &error, opt_ssl_crl, opt_ssl_crlpath); DBUG_PRINT("info",("ssl_acceptor_fd: 0x%lx", (long) ssl_acceptor_fd)); - ERR_remove_state(0); if (!ssl_acceptor_fd) { sql_print_warning("Failed to setup SSL"); @@ -4564,6 +4571,14 @@ static void init_ssl() opt_use_ssl = 0; have_ssl= SHOW_OPTION_DISABLED; } + if (global_system_variables.log_warnings > 0) + { + ulong err; + while ((err= ERR_get_error())) + sql_print_warning("SSL error: %s", ERR_error_string(err, NULL)); + } + else + ERR_remove_state(0); } else { @@ -4738,15 +4753,16 @@ static int init_server_components() { if (opt_bin_log) { - sql_print_error("using --replicate-same-server-id in conjunction with \ ---log-slave-updates is impossible, it would lead to infinite loops in this \ -server."); + sql_print_error("using --replicate-same-server-id in conjunction with " + "--log-slave-updates is impossible, it would lead to " + "infinite loops in this server."); unireg_abort(1); } else - sql_print_warning("using --replicate-same-server-id in conjunction with \ ---log-slave-updates would lead to infinite loops in this server. However this \ -will be ignored as the --log-bin option is not defined."); + sql_print_warning("using --replicate-same-server-id in conjunction with " + "--log-slave-updates would lead to infinite loops in " + "this server. However this will be ignored as the " + "--log-bin option is not defined."); } #endif @@ -4759,8 +4775,8 @@ will be ignored as the --log-bin option is not defined."); if (opt_bin_logname[0] && opt_bin_logname[strlen(opt_bin_logname) - 1] == FN_LIBCHAR) { - sql_print_error("Path '%s' is a directory name, please specify \ -a file name for --log-bin option", opt_bin_logname); + sql_print_error("Path '%s' is a directory name, please specify " + "a file name for --log-bin option", opt_bin_logname); unireg_abort(1); } @@ -4770,8 +4786,9 @@ a file name for --log-bin option", opt_bin_logname); opt_binlog_index_name[strlen(opt_binlog_index_name) - 1] == FN_LIBCHAR) { - sql_print_error("Path '%s' is a directory name, please specify \ -a file name for --log-bin-index option", opt_binlog_index_name); + sql_print_error("Path '%s' is a directory name, please specify " + "a file name for --log-bin-index option", + opt_binlog_index_name); unireg_abort(1); } @@ -5010,6 +5027,7 @@ a file name for --log-bin-index option", opt_binlog_index_name); init_global_client_stats(); if (!opt_bootstrap) servers_init(0); + init_status_vars(); DBUG_RETURN(0); } @@ -5258,6 +5276,8 @@ int mysqld_main(int argc, char **argv) pfs_param.m_hints.m_table_open_cache= tc_size; pfs_param.m_hints.m_max_connections= max_connections; pfs_param.m_hints.m_open_files_limit= open_files_limit; + /* the performance schema digest size is the same as the SQL layer */ + pfs_param.m_max_digest_length= max_digest_length; PSI_hook= initialize_performance_schema(&pfs_param); if (PSI_hook == NULL) { @@ -5458,7 +5478,6 @@ int mysqld_main(int argc, char **argv) #endif } - init_status_vars(); if (opt_bootstrap) /* If running with bootstrap, do not start replication. */ opt_skip_slave_start= 1; @@ -5538,6 +5557,8 @@ int mysqld_main(int argc, char **argv) mysql_cond_signal(&COND_server_started); mysql_mutex_unlock(&LOCK_server_started); + MYSQL_SET_STAGE(0 ,__FILE__, __LINE__); + #if defined(_WIN32) || defined(HAVE_SMEM) handle_connections_methods(); #else @@ -8080,16 +8101,15 @@ static void usage(void) else { #ifdef __WIN__ - puts("NT and Win32 specific options:\n\ - --install Install the default service (NT).\n\ - --install-manual Install the default service started manually (NT).\n\ - --install service_name Install an optional service (NT).\n\ - --install-manual service_name Install an optional service started manually (NT).\n\ - --remove Remove the default service from the service list (NT).\n\ - --remove service_name Remove the service_name from the service list (NT).\n\ - --enable-named-pipe Only to be used for the default server (NT).\n\ - --standalone Dummy option to start as a standalone server (NT).\ -"); + puts("NT and Win32 specific options:\n" + " --install Install the default service (NT).\n" + " --install-manual Install the default service started manually (NT).\n" + " --install service_name Install an optional service (NT).\n" + " --install-manual service_name Install an optional service started manually (NT).\n" + " --remove Remove the default service from the service list (NT).\n" + " --remove service_name Remove the service_name from the service list (NT).\n" + " --enable-named-pipe Only to be used for the default server (NT).\n" + " --standalone Dummy option to start as a standalone server (NT)."); puts(""); #endif print_defaults(MYSQL_CONFIG_NAME,load_default_groups); @@ -8101,14 +8121,12 @@ static void usage(void) if (! plugins_are_initialized) { - puts("\n\ -Plugins have parameters that are not reflected in this list\n\ -because execution stopped before plugins were initialized."); + puts("\nPlugins have parameters that are not reflected in this list" + "\nbecause execution stopped before plugins were initialized."); } - puts("\n\ -To see what values a running MySQL server is using, type\n\ -'mysqladmin variables' instead of 'mysqld --verbose --help'."); + puts("\nTo see what values a running MySQL server is using, type" + "\n'mysqladmin variables' instead of 'mysqld --verbose --help'."); } DBUG_VOID_RETURN; } diff --git a/sql/mysqld.h b/sql/mysqld.h index d508023a22b..156e7f99bb5 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -167,6 +167,7 @@ extern ulong query_cache_limit; extern ulong query_cache_min_res_unit; extern ulong slow_launch_threads, slow_launch_time; extern MYSQL_PLUGIN_IMPORT ulong max_connections; +extern ulong max_digest_length; extern ulong max_connect_errors, connect_timeout; extern my_bool slave_allow_batching; extern my_bool allow_slave_start; diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 29b8417c698..0ce0fa93f99 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -917,7 +917,7 @@ my_real_read(NET *net, size_t *complen, my_progname,vio_errno(net->vio)); } #ifndef MYSQL_SERVER - if (vio_errno(net->vio) == SOCKET_EINTR) + if (length != 0 && vio_errno(net->vio) == SOCKET_EINTR) { DBUG_PRINT("warning",("Interrupted read. Retrying...")); continue; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 2122349f324..0ad90e2ef3d 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2010, 2012, Monty Program Ab + Copyright (c) 2010, 2015, MariaDB 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 @@ -1611,9 +1611,20 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) sj_nest->sj_on_expr= and_items(sj_nest->sj_on_expr, item_eq); } } - /* Fix the created equality and AND */ - if (!sj_nest->sj_on_expr->fixed) - sj_nest->sj_on_expr->fix_fields(parent_join->thd, &sj_nest->sj_on_expr); + /* + Fix the created equality and AND + + Note that fix_fields() can actually fail in a meaningful way here. One + example is when the IN-equality is not valid, because it compares columns + with incompatible collations. (One can argue it would be more appropriate + to check for this at name resolution stage, but as a legacy of IN->EXISTS + we have in here). + */ + if (!sj_nest->sj_on_expr->fixed && + sj_nest->sj_on_expr->fix_fields(parent_join->thd, &sj_nest->sj_on_expr)) + { + DBUG_RETURN(TRUE); + } /* Walk through sj nest's WHERE and ON expressions and call @@ -1632,12 +1643,15 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) /* Inject sj_on_expr into the parent's WHERE or ON */ if (emb_tbl_nest) { - emb_tbl_nest->on_expr= and_items(emb_tbl_nest->on_expr, + emb_tbl_nest->on_expr= and_items(emb_tbl_nest->on_expr, sj_nest->sj_on_expr); emb_tbl_nest->on_expr->top_level_item(); - if (!emb_tbl_nest->on_expr->fixed) - emb_tbl_nest->on_expr->fix_fields(parent_join->thd, - &emb_tbl_nest->on_expr); + if (!emb_tbl_nest->on_expr->fixed && + emb_tbl_nest->on_expr->fix_fields(parent_join->thd, + &emb_tbl_nest->on_expr)) + { + DBUG_RETURN(TRUE); + } } else { @@ -1650,8 +1664,12 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) */ save_lex= thd->lex->current_select; thd->lex->current_select=parent_join->select_lex; - if (!parent_join->conds->fixed) - parent_join->conds->fix_fields(parent_join->thd, &parent_join->conds); + if (!parent_join->conds->fixed && + parent_join->conds->fix_fields(parent_join->thd, + &parent_join->conds)) + { + DBUG_RETURN(1); + } thd->lex->current_select=save_lex; parent_join->select_lex->where= parent_join->conds; } @@ -2508,10 +2526,16 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, LooseScan detector in best_access_path) */ remaining_tables &= ~new_join_tab->table->map; - pos->prefix_dups_producing_tables= join->cur_dups_producing_tables; + table_map dups_producing_tables; + + if (idx == join->const_tables) + dups_producing_tables= 0; + else + dups_producing_tables= pos[-1].dups_producing_tables; + TABLE_LIST *emb_sj_nest; if ((emb_sj_nest= new_join_tab->emb_sj_nest)) - join->cur_dups_producing_tables |= emb_sj_nest->sj_inner_tables; + dups_producing_tables |= emb_sj_nest->sj_inner_tables; Semi_join_strategy_picker **strategy; if (idx == join->const_tables) @@ -2564,7 +2588,7 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, fanout from semijoin X. 3. We have no clue what to do about fanount of semi-join Y. */ - if ((join->cur_dups_producing_tables & handled_fanout) || + if ((dups_producing_tables & handled_fanout) || (read_time < *current_read_time && !(handled_fanout & pos->inner_tables_handled_with_other_sjs))) { @@ -2577,7 +2601,7 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, join->sjm_lookup_tables &= ~handled_fanout; *current_read_time= read_time; *current_record_count= rec_count; - join->cur_dups_producing_tables &= ~handled_fanout; + dups_producing_tables &= ~handled_fanout; //TODO: update bitmap of semi-joins that were handled together with // others. if (is_multiple_semi_joins(join, join->positions, idx, handled_fanout)) @@ -2604,6 +2628,7 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, pos->prefix_cost.convert_from_cost(*current_read_time); pos->prefix_record_count= *current_record_count; + pos->dups_producing_tables= dups_producing_tables; } @@ -3115,8 +3140,6 @@ void restore_prev_sj_state(const table_map remaining_tables, tab->join->cur_sj_inner_tables &= ~emb_sj_nest->sj_inner_tables; } } - POSITION *pos= tab->join->positions + idx; - tab->join->cur_dups_producing_tables= pos->prefix_dups_producing_tables; } diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h index acfbebed6b3..3da94d05521 100644 --- a/sql/opt_subselect.h +++ b/sql/opt_subselect.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2010, 2012, Monty Program Ab + Copyright (c) 2010, 2015, MariaDB 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 @@ -299,7 +299,7 @@ public: }; -extern void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, +void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, double *current_record_count, double *current_read_time, POSITION *loose_scan_pos); void restore_prev_sj_state(const table_map remaining_tables, diff --git a/sql/parse_file.cc b/sql/parse_file.cc index ee031c1bbc2..197f7c97fda 100644 --- a/sql/parse_file.cc +++ b/sql/parse_file.cc @@ -282,7 +282,7 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name, path[path_end+1]= '\0'; if ((handler= mysql_file_create(key_file_fileparser, path, CREATE_MODE, O_RDWR | O_TRUNC, - MYF(MY_WME))) <= 0) + MYF(MY_WME))) < 0) { DBUG_RETURN(TRUE); } diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 50cd44df824..47490648a43 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -36,9 +36,9 @@ Master_info::Master_info(LEX_STRING *connection_name_arg, rli(is_slave_recovery), port(MYSQL_PORT), checksum_alg_before_fd(BINLOG_CHECKSUM_ALG_UNDEF), connect_retry(DEFAULT_CONNECT_RETRY), inited(0), abort_slave(0), - slave_running(0), slave_run_id(0), sync_counter(0), - heartbeat_period(0), received_heartbeats(0), master_id(0), - prev_master_id(0), + slave_running(0), slave_run_id(0), clock_diff_with_master(0), + sync_counter(0), heartbeat_period(0), received_heartbeats(0), + master_id(0), prev_master_id(0), using_gtid(USE_GTID_NO), events_queued_since_last_gtid(0), gtid_reconnect_event_skip_count(0), gtid_event_seen(false) { @@ -966,7 +966,7 @@ bool Master_info_index::init_all_master_info() { /* Master_info is not in HASH; Add it */ if (master_info_index->add_master_info(mi, FALSE)) - return 1; + DBUG_RETURN(1); succ_num++; unlock_slave_threads(mi); } @@ -999,7 +999,7 @@ bool Master_info_index::init_all_master_info() /* Master_info was not registered; add it */ if (master_info_index->add_master_info(mi, FALSE)) - return 1; + DBUG_RETURN(1); succ_num++; unlock_slave_threads(mi); @@ -1096,7 +1096,7 @@ Master_info_index::get_master_info(LEX_STRING *connection_name, mysql_mutex_assert_owner(&LOCK_active_mi); if (!this) // master_info_index is set to NULL on server shutdown - return NULL; + DBUG_RETURN(NULL); /* Make name lower case for comparison */ res= strmake(buff, connection_name->str, connection_name->length); @@ -1251,7 +1251,7 @@ bool Master_info_index::give_error_if_slave_running() DBUG_ENTER("give_error_if_slave_running"); mysql_mutex_assert_owner(&LOCK_active_mi); if (!this) // master_info_index is set to NULL on server shutdown - return TRUE; + DBUG_RETURN(TRUE); for (uint i= 0; i< master_info_hash.records; ++i) { @@ -1282,7 +1282,7 @@ bool Master_info_index::any_slave_sql_running() { DBUG_ENTER("any_slave_sql_running"); if (!this) // master_info_index is set to NULL on server shutdown - return TRUE; + DBUG_RETURN(TRUE); for (uint i= 0; i< master_info_hash.records; ++i) { diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 9ed388265be..3207c858b20 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1290,13 +1290,9 @@ bool Relay_log_info::is_until_satisfied(THD *thd, Log_event *ev) } -void Relay_log_info::stmt_done(my_off_t event_master_log_pos, - time_t event_creation_time, THD *thd, +void Relay_log_info::stmt_done(my_off_t event_master_log_pos, THD *thd, rpl_group_info *rgi) { -#ifndef DBUG_OFF - extern uint debug_not_change_ts_if_art_event; -#endif DBUG_ENTER("Relay_log_info::stmt_done"); DBUG_ASSERT(rgi->rli == this); @@ -1350,22 +1346,6 @@ void Relay_log_info::stmt_done(my_off_t event_master_log_pos, if (mi->using_gtid == Master_info::USE_GTID_NO) flush_relay_log_info(this); DBUG_EXECUTE_IF("inject_crash_after_flush_rli", DBUG_SUICIDE();); - /* - Note that Rotate_log_event::do_apply_event() does not call this - function, so there is no chance that a fake rotate event resets - last_master_timestamp. Note that we update without mutex - (probably ok - except in some very rare cases, only consequence - is that value may take some time to display in - Seconds_Behind_Master - not critical). - - In parallel replication, we take care to not set last_master_timestamp - backwards, in case of out-of-order calls here. - */ - if (!(event_creation_time == 0 && - IF_DBUG(debug_not_change_ts_if_art_event > 0, 1)) && - !(rgi->is_parallel_exec && event_creation_time <= last_master_timestamp) - ) - last_master_timestamp= event_creation_time; } DBUG_VOID_RETURN; } diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 84a4aa93cd3..2d92f384ef3 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -415,15 +415,8 @@ public: Master log position of the event. The position is recorded in the relay log info and used to produce information for <code>SHOW SLAVE STATUS</code>. - - @param event_creation_time - Timestamp for the creation of the event on the master side. The - time stamp is recorded in the relay log info and used to compute - the <code>Seconds_behind_master</code> field. */ - void stmt_done(my_off_t event_log_pos, - time_t event_creation_time, THD *thd, - rpl_group_info *rgi); + void stmt_done(my_off_t event_log_pos, THD *thd, rpl_group_info *rgi); int alloc_inuse_relaylog(const char *name); void free_inuse_relaylog(inuse_relaylog *ir); void reset_inuse_relaylog(); diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index 9067f1e4253..146bf3b0c0e 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -452,7 +452,7 @@ void show_sql_type(enum_field_types type, uint16 metadata, String *str, CHARSET_ CHARSET_INFO *cs= str->charset(); uint32 length= cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), - "decimal(%d,?)", metadata); + "decimal(%d,?)/*old*/", metadata); str->length(length); } break; diff --git a/sql/slave.cc b/sql/slave.cc index cd5543c89c8..4129c4cbc98 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2008, 2014, SkySQL Ab. +/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2008, 2015, MariaDB 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 @@ -148,26 +148,18 @@ static int process_io_create_file(Master_info* mi, Create_file_log_event* cev); static bool wait_for_relay_log_space(Relay_log_info* rli); static bool io_slave_killed(Master_info* mi); static bool sql_slave_killed(rpl_group_info *rgi); -static int init_slave_thread(THD* thd, Master_info *mi, - SLAVE_THD_TYPE thd_type); +static int init_slave_thread(THD*, Master_info *, SLAVE_THD_TYPE); static void print_slave_skip_errors(void); static int safe_connect(THD* thd, MYSQL* mysql, Master_info* mi); -static int safe_reconnect(THD* thd, MYSQL* mysql, Master_info* mi, - bool suppress_warnings); -static int connect_to_master(THD* thd, MYSQL* mysql, Master_info* mi, - bool reconnect, bool suppress_warnings); +static int safe_reconnect(THD*, MYSQL*, Master_info*, bool); +static int connect_to_master(THD*, MYSQL*, Master_info*, bool, bool); static Log_event* next_event(rpl_group_info* rgi, ulonglong *event_size); static int queue_event(Master_info* mi,const char* buf,ulong event_len); -static int terminate_slave_thread(THD *thd, - mysql_mutex_t *term_lock, - mysql_cond_t *term_cond, - volatile uint *slave_running, - bool skip_lock); +static int terminate_slave_thread(THD *, mysql_mutex_t *, mysql_cond_t *, + volatile uint *, bool); static bool check_io_slave_killed(Master_info *mi, const char *info); -static bool send_show_master_info_header(THD *thd, bool full, - size_t gtid_pos_length); -static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full, - String *gtid_pos); +static bool send_show_master_info_header(THD *, bool, size_t); +static bool send_show_master_info_data(THD *, Master_info *, bool, String *); /* Function to set the slave's max_allowed_packet based on the value of slave_max_allowed_packet. @@ -3501,6 +3493,21 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli, Log_event_type typ= ev->get_type_code(); /* + Even if we don't execute this event, we keep the master timestamp, + so that seconds behind master shows correct delta (there are events + that are not replayed, so we keep falling behind). + + If it is an artificial event, or a relay log event (IO thread generated + event) or ev->when is set to 0, we don't update the + last_master_timestamp. + */ + if (!(ev->is_artificial_event() || ev->is_relay_log_event() || (ev->when == 0))) + { + rli->last_master_timestamp= ev->when + (time_t) ev->exec_time; + DBUG_ASSERT(rli->last_master_timestamp >= 0); + } + + /* This tests if the position of the beginning of the current event hits the UNTIL barrier. */ @@ -6067,7 +6074,23 @@ static int connect_to_master(THD* thd, MYSQL* mysql, Master_info* mi, } #endif - mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset_info->csname); + /* + If server's default charset is not supported (like utf16, utf32) as client + charset, then set client charset to 'latin1' (default client charset). + */ + if (is_supported_parser_charset(default_charset_info)) + mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset_info->csname); + else + { + sql_print_information("'%s' can not be used as client character set. " + "'%s' will be used as default client character set " + "while connecting to master.", + default_charset_info->csname, + default_client_charset_info->csname); + mysql_options(mysql, MYSQL_SET_CHARSET_NAME, + default_client_charset_info->csname); + } + /* This one is not strictly needed but we have it here for completeness */ mysql_options(mysql, MYSQL_SET_CHARSET_DIR, (char *) charsets_dir); diff --git a/sql/sp.cc b/sql/sp.cc index 35155cf031a..334b5e12ba3 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1,5 +1,6 @@ /* - Copyright (c) 2002, 2011, Oracle and/or its affiliates. + Copyright (c) 2002, 2015, Oracle and/or its affiliates. + Copyright (c) 2009, 2015, MariaDB 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 @@ -1476,6 +1477,9 @@ bool lock_db_routines(THD *thd, char *db) { char *sp_name= get_field(thd->mem_root, table->field[MYSQL_PROC_FIELD_NAME]); + if (sp_name == NULL) // skip invalid sp names (hand-edited mysql.proc?) + continue; + longlong sp_type= table->field[MYSQL_PROC_MYSQL_TYPE]->val_int(); MDL_request *mdl_request= new (thd->mem_root) MDL_request; mdl_request->init(sp_type == TYPE_ENUM_FUNCTION ? diff --git a/sql/sp_head.cc b/sql/sp_head.cc index d59e0aec541..e181e14611b 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1365,8 +1365,13 @@ sp_head::execute(THD *thd, bool merge_da_on_success) if (thd->locked_tables_mode <= LTM_LOCK_TABLES) thd->user_var_events_alloc= thd->mem_root; + sql_digest_state *parent_digest= thd->m_digest; + thd->m_digest= NULL; + err_status= i->execute(thd, &ip); + thd->m_digest= parent_digest; + if (i->free_list) cleanup_items(i->free_list); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index e4975acfb55..9cc9efae6f8 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -863,32 +863,30 @@ static char *fix_plugin_ptr(char *name) } /** - Fix ACL::plugin pointer to point to a hard-coded string, if appropriate + Fix a LEX_STRING *plugin pointer to point to a hard-coded string, + if appropriate Make sure that if ACL_USER's plugin is a built-in, then it points to a hard coded string, not to an allocated copy. Run-time, for authentication, we want to be able to detect built-ins by comparing pointers, not strings. - Additionally - update the salt if the plugin is built-in. - @retval 0 the pointers were fixed @retval 1 this ACL_USER uses a not built-in plugin */ -static bool fix_user_plugin_ptr(ACL_USER *user) +static bool fix_user_plugin_ptr(LEX_STRING *plugin_ptr) { - if (my_strcasecmp(system_charset_info, user->plugin.str, + DBUG_ASSERT(plugin_ptr); + if (my_strcasecmp(system_charset_info, plugin_ptr->str, native_password_plugin_name.str) == 0) - user->plugin= native_password_plugin_name; + *plugin_ptr= native_password_plugin_name; else - if (my_strcasecmp(system_charset_info, user->plugin.str, + if (my_strcasecmp(system_charset_info, plugin_ptr->str, old_password_plugin_name.str) == 0) - user->plugin= old_password_plugin_name; + *plugin_ptr= old_password_plugin_name; else return true; - if (user->auth_string.length) - set_user_salt(user, user->auth_string.str, user->auth_string.length); return false; } @@ -967,6 +965,23 @@ my_bool acl_init(bool dont_read_acl_tables) } /** + Check if the password length provided matches supported native formats. +*/ +static bool password_length_valid(int password_length) +{ + switch (password_length) + { + case 0: /* no password */ + case SCRAMBLED_PASSWORD_CHAR_LENGTH: + return TRUE; + case SCRAMBLED_PASSWORD_CHAR_LENGTH_323: + return TRUE; + default: + return FALSE; + } +} + +/** Choose from either native or old password plugins when assigning a password */ @@ -1257,22 +1272,43 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) char *tmpstr= get_field(&acl_memroot, table->field[next_field++]); if (tmpstr) { + LEX_STRING auth; + auth.str = safe_str(get_field(&acl_memroot, table->field[next_field++])); + auth.length = strlen(auth.str); user.plugin.str= tmpstr; user.plugin.length= strlen(user.plugin.str); - user.auth_string.str= - safe_str(get_field(&acl_memroot, table->field[next_field++])); - user.auth_string.length= strlen(user.auth_string.str); - - if (user.auth_string.length && password_len) + if (fix_user_plugin_ptr(&user.plugin)) // Non native plugin. { - sql_print_warning("'user' entry '%s@%s' has both a password " - "and an authentication plugin specified. The " - "password will be ignored.", - safe_str(user.user.str), - safe_str(user.host.hostname)); + user.auth_string= auth; + if (password_len) + { + sql_print_warning("'user' entry '%s@%s' has both a password " + "and an authentication plugin specified. The " + "password will be ignored.", + safe_str(user.user.str), + safe_str(user.host.hostname)); + } + } + else // Native plugin. + { + /* + Password field, if not empty, has precedence over + authentication_string field, only for native plugins. + See MDEV-6253 and MDEV-7985 for reasoning. + */ + if (!password_len) + { + user.auth_string = auth; + if (!password_length_valid(auth.length)) + { + sql_print_warning("Found invalid password for user: '%s@%s';" + " Ignoring user", safe_str(user.user.str), + safe_str(user.host.hostname)); + continue; + } + set_user_salt(&user, auth.str, auth.length); + } } - - fix_user_plugin_ptr(&user); } } } @@ -1971,8 +2007,13 @@ static void acl_update_user(const char *user, const char *host, acl_user->auth_string.str= auth->str ? strmake_root(&acl_memroot, auth->str, auth->length) : const_cast<char*>(""); acl_user->auth_string.length= auth->length; - if (fix_user_plugin_ptr(acl_user)) + if (acl_user->plugin.str != native_password_plugin_name.str && + acl_user->plugin.str != old_password_plugin_name.str) acl_user->plugin.str= strmake_root(&acl_memroot, plugin->str, plugin->length); + else + set_user_salt(acl_user, acl_user->auth_string.str, + acl_user->auth_string.length); + } else if (password[0]) @@ -2047,8 +2088,12 @@ static void acl_insert_user(const char *user, const char *host, acl_user.auth_string.str= auth->str ? strmake_root(&acl_memroot, auth->str, auth->length) : const_cast<char*>(""); acl_user.auth_string.length= auth->length; - if (fix_user_plugin_ptr(&acl_user)) + if (acl_user.plugin.str != native_password_plugin_name.str && + acl_user.plugin.str != old_password_plugin_name.str) acl_user.plugin.str= strmake_root(&acl_memroot, plugin->str, plugin->length); + else + set_user_salt(&acl_user, acl_user.auth_string.str, + acl_user.auth_string.length); } else { @@ -3014,17 +3059,20 @@ static int replace_user_table(THD *thd, TABLE *table, LEX_USER &combo, mysql_mutex_assert_owner(&acl_cache->lock); + size_t length_to_check = 0; + combo.password = combo.password.str ? combo.password : empty_lex_str; if (combo.password.str && combo.password.str[0]) + length_to_check = combo.password.length; + else if (!fix_user_plugin_ptr(&combo.plugin)) + { + length_to_check = combo.auth.length; + } + + if (!password_length_valid(length_to_check)) { - if (combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH && - combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323) - { my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH); DBUG_RETURN(-1); - } } - else - combo.password= empty_lex_str; /* if the user table is not up to date, we can't handle role updates */ if (table->s->fields <= ROLE_ASSIGN_COLUMN_IDX && handle_as_role) @@ -8802,10 +8850,30 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop, if (struct_no == ROLES_MAPPINGS_HASH) { const char* role= role_grant_pair->r_uname? role_grant_pair->r_uname: ""; - if (user_from->is_role() ? strcmp(user_from->user.str, role) : - (strcmp(user_from->user.str, user) || - my_strcasecmp(system_charset_info, user_from->host.str, host))) - continue; + if (user_from->is_role()) + { + /* When searching for roles within the ROLES_MAPPINGS_HASH, we have + to check both the user field as well as the role field for a match. + + It is possible to have a role granted to a role. If we are going + to modify the mapping entry, it needs to be done on either on the + "user" end (here represented by a role) or the "role" end. At least + one part must match. + + If the "user" end has a not-empty host string, it can never match + as we are searching for a role here. A role always has an empty host + string. + */ + if ((*host || strcmp(user_from->user.str, user)) && + strcmp(user_from->user.str, role)) + continue; + } + else + { + if (strcmp(user_from->user.str, user) || + my_strcasecmp(system_charset_info, user_from->host.str, host)) + continue; + } } else { diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index ce8302af0b3..a6b97ce31fa 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2010, 2014, Oracle and/or its affiliates. - Copyright (c) 2012, 2014, Monty Program Ab. + Copyright (c) 2012, 2015, MariaDB 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 @@ -309,7 +309,8 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT *), int (handler::*operator_func)(THD *, HA_CHECK_OPT *), - int (view_operator_func)(THD *, TABLE_LIST*)) + int (view_operator_func)(THD *, TABLE_LIST*, + HA_CHECK_OPT *)) { TABLE_LIST *table; SELECT_LEX *select= &thd->lex->select_lex; @@ -393,7 +394,18 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, lex->query_tables_own_last= 0; if (view_operator_func == NULL) + { table->required_type=FRMTYPE_TABLE; + DBUG_ASSERT(!lex->only_view); + } + else if (lex->only_view) + { + table->required_type= FRMTYPE_VIEW; + } + else if (!lex->only_view && lex->sql_command == SQLCOM_REPAIR) + { + table->required_type= FRMTYPE_TABLE; + } if (lex->sql_command == SQLCOM_CHECK || lex->sql_command == SQLCOM_REPAIR || @@ -521,9 +533,9 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, } /* - CHECK TABLE command is only command where VIEW allowed here and this - command use only temporary teble method for VIEWs resolving => there - can't be VIEW tree substitition of join view => if opening table + CHECK/REPAIR TABLE command is only command where VIEW allowed here and + this command use only temporary table method for VIEWs resolving => + there can't be VIEW tree substitition of join view => if opening table succeed then table->table will have real TABLE pointer as value (in case of join view substitution table->table can be 0, but here it is impossible) @@ -536,7 +548,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, ER_CHECK_NO_SUCH_TABLE, ER(ER_CHECK_NO_SUCH_TABLE)); /* if it was a view will check md5 sum */ if (table->view && - view_checksum(thd, table) == HA_ADMIN_WRONG_CHECKSUM) + view_check(thd, table, check_opt) == HA_ADMIN_WRONG_CHECKSUM) push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_VIEW_CHECKSUM, ER(ER_VIEW_CHECKSUM)); if (thd->get_stmt_da()->is_error() && @@ -551,7 +563,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, if (table->view) { DBUG_PRINT("admin", ("calling view_operator_func")); - result_code= (*view_operator_func)(thd, table); + result_code= (*view_operator_func)(thd, table, check_opt); goto send_result; } @@ -968,7 +980,16 @@ send_result_message: size_t length; protocol->store(STRING_WITH_LEN("error"), system_charset_info); - if (table->table->file->ha_table_flags() & HA_CAN_REPAIR) +#if MYSQL_VERSION_ID > 100104 +#error fix the error message to take TABLE or VIEW as an argument +#else + if (table->view) + length= my_snprintf(buf, sizeof(buf), + "Upgrade required. Please do \"REPAIR VIEW %`s\" or dump/reload to fix it!", + table->table_name); + else +#endif + if (table->table->file->ha_table_flags() & HA_CAN_REPAIR || table->view) length= my_snprintf(buf, sizeof(buf), ER(ER_TABLE_NEEDS_UPGRADE), table->table_name); else @@ -991,7 +1012,7 @@ send_result_message: break; } } - if (table->table) + if (table->table && !table->view) { if (table->table->s->tmp_table) { @@ -1189,7 +1210,7 @@ bool Sql_cmd_check_table::execute(THD *thd) res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "check", lock_type, 0, 0, HA_OPEN_FOR_REPAIR, 0, - &handler::ha_check, &view_checksum); + &handler::ha_check, &view_check); m_lex->select_lex.table_list.first= first_table; m_lex->query_tables= first_table; @@ -1246,7 +1267,7 @@ bool Sql_cmd_repair_table::execute(THD *thd) TL_WRITE, 1, MY_TEST(m_lex->check_opt.sql_flags & TT_USEFRM), HA_OPEN_FOR_REPAIR, &prepare_for_repair, - &handler::ha_repair, 0); + &handler::ha_repair, &view_repair); /* ! we write after unlocking the table */ if (!res && !m_lex->no_write_to_binlog) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 2d03e3d30cd..13b8625ebe6 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2010, 2013 Monty Program Ab +/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2010, 2015, MariaDB 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 @@ -3456,7 +3456,7 @@ request_backoff_action(enum_open_table_action action_arg, if (action_arg != OT_REOPEN_TABLES && m_has_locks) { my_error(ER_LOCK_DEADLOCK, MYF(0)); - mark_transaction_to_rollback(m_thd, true); + m_thd->mark_transaction_to_rollback(true); return TRUE; } /* @@ -6985,7 +6985,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter, Item_field for tables. */ Item_ident *item_ref= (Item_ident *) item; - if (item_ref->name && item_ref->table_name && + if (field_name && item_ref->name && item_ref->table_name && !my_strcasecmp(system_charset_info, item_ref->name, field_name) && !my_strcasecmp(table_alias_charset, item_ref->table_name, table_name) && @@ -8015,9 +8015,10 @@ bool setup_tables(THD *thd, Name_resolution_context *context, if (select_lex->first_cond_optimization) { leaves.empty(); - if (!select_lex->is_prep_leaf_list_saved) + if (select_lex->prep_leaf_list_state != SELECT_LEX::SAVED) { make_leaves_list(leaves, tables, full_table_list, first_select_table); + select_lex->prep_leaf_list_state= SELECT_LEX::READY; select_lex->leaf_tables_exec.empty(); } else diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ad096dc60f9..cf0c4a1b84f 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1,6 +1,6 @@ /* - Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2008, 2014, SkySQL Ab. + Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2008, 2015, MariaDB 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 @@ -874,6 +874,7 @@ THD::THD() stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE), m_examined_row_count(0), accessed_rows_and_keys(0), + m_digest(NULL), m_statement_psi(NULL), m_idle_psi(NULL), thread_id(0), @@ -881,7 +882,7 @@ THD::THD() failed_com_change_user(0), is_fatal_error(0), transaction_rollback_request(0), - is_fatal_sub_stmt_error(0), + is_fatal_sub_stmt_error(false), rand_used(0), time_zone_used(0), in_lock_tables(0), @@ -1044,6 +1045,13 @@ THD::THD() substitute_null_with_insert_id = FALSE; thr_lock_info_init(&lock_info); /* safety: will be reset after start */ + m_token_array= NULL; + if (max_digest_length > 0) + { + m_token_array= (unsigned char*) my_malloc(max_digest_length, + MYF(MY_WME|MY_THREAD_SPECIFIC)); + } + m_internal_handler= NULL; m_binlog_invoker= INVOKER_NONE; arena_for_cached_items= 0; @@ -1520,6 +1528,7 @@ void THD::cleanup(void) mysql_ha_cleanup(this); locked_tables_list.unlock_locked_tables(this); + delete_dynamic(&user_var_events); close_temporary_tables(this); transaction.xid_state.xa_state= XA_NOTR; @@ -1551,7 +1560,6 @@ void THD::cleanup(void) debug_sync_end_thread(this); #endif /* defined(ENABLED_DEBUG_SYNC) */ - delete_dynamic(&user_var_events); my_hash_free(&user_vars); sp_cache_clear(&sp_proc_cache); sp_cache_clear(&sp_func_cache); @@ -1625,6 +1633,7 @@ THD::~THD() #endif free_root(&main_mem_root, MYF(0)); + my_free(m_token_array); main_da.free_memory(); if (status_var.memory_used != 0) { @@ -4450,7 +4459,8 @@ extern "C" int thd_binlog_format(const MYSQL_THD thd) extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all) { - mark_transaction_to_rollback(thd, all); + DBUG_ASSERT(thd); + thd->mark_transaction_to_rollback(all); } extern "C" bool thd_binlog_filter_ok(const MYSQL_THD thd) @@ -4691,9 +4701,12 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) If we've left sub-statement mode, reset the fatal error flag. Otherwise keep the current value, to propagate it up the sub-statement stack. + + NOTE: is_fatal_sub_stmt_error can be set only if we've been in the + sub-statement mode. */ if (!in_sub_stmt) - is_fatal_sub_stmt_error= FALSE; + is_fatal_sub_stmt_error= false; if ((variables.option_bits & OPTION_BIN_LOG) && is_update_query(lex->sql_command) && !is_current_stmt_binlog_format_row()) @@ -4935,17 +4948,18 @@ void THD::get_definer(LEX_USER *definer, bool role) /** Mark transaction to rollback and mark error as fatal to a sub-statement. - @param thd Thread handle @param all TRUE <=> rollback main transaction. */ -void mark_transaction_to_rollback(THD *thd, bool all) +void THD::mark_transaction_to_rollback(bool all) { - if (thd) - { - thd->is_fatal_sub_stmt_error= TRUE; - thd->transaction_rollback_request= all; - } + /* + There is no point in setting is_fatal_sub_stmt_error unless + we are actually in_sub_stmt. + */ + if (in_sub_stmt) + is_fatal_sub_stmt_error= true; + transaction_rollback_request= all; } /*************************************************************************** Handling of XA id cacheing diff --git a/sql/sql_class.h b/sql/sql_class.h index 38e3a383208..a8d8444571e 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1,5 +1,6 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2009, 2013, Monty Program Ab. +/* + Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2009, 2015, MariaDB 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 @@ -37,6 +38,8 @@ #include "violite.h" /* vio_is_connected */ #include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA, THR_LOCK_INFO */ +#include "sql_digest_stream.h" // sql_digest_state + #include <mysql/psi/mysql_stage.h> #include <mysql/psi/mysql_statement.h> #include <mysql/psi/mysql_idle.h> @@ -772,9 +775,6 @@ void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var); void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var, STATUS_VAR *dec_var); -void mark_transaction_to_rollback(THD *thd, bool all); - - /** Get collation by name, send error to client on failure. @param name Collation name @@ -802,7 +802,6 @@ mysqld_collation_get_by_name(const char *name, return cs; } - #ifdef MYSQL_SERVER void free_tmp_table(THD *thd, TABLE *entry); @@ -2508,6 +2507,13 @@ public: PROFILING profiling; #endif + /** Current statement digest. */ + sql_digest_state *m_digest; + /** Current statement digest token array. */ + unsigned char *m_token_array; + /** Top level statement digest. */ + sql_digest_state m_digest_state; + /** Current statement instrumentation. */ PSI_statement_locker *m_statement_psi; #ifdef HAVE_PSI_STATEMENT_INTERFACE @@ -3113,6 +3119,8 @@ public: if (get_stmt_da()->is_error()) get_stmt_da()->reset_diagnostics_area(); is_slave_error= 0; + if (killed == KILL_BAD_DATA) + killed= NOT_KILLED; // KILL_BAD_DATA can be reset w/o a mutex DBUG_VOID_RETURN; } #ifndef EMBEDDED_LIBRARY @@ -3704,6 +3712,7 @@ public: wait_for_commit_ptr= suspended; } + void mark_transaction_to_rollback(bool all); private: /** The current internal error handler for this thread, or NULL. */ @@ -4885,8 +4894,6 @@ public: */ #define CF_SKIP_QUESTIONS (1U << 1) -void mark_transaction_to_rollback(THD *thd, bool all); - /* Inline functions */ inline bool add_item_to_list(THD *thd, Item *item) diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 807b028a4b1..0202b4493ac 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1122,7 +1122,7 @@ bool setup_connection_thread_globals(THD *thd) bool login_connection(THD *thd) { NET *net= &thd->net; - int error; + int error= 0; DBUG_ENTER("login_connection"); DBUG_PRINT("info", ("login_connection called by thread %lu", thd->thread_id)); @@ -1141,7 +1141,8 @@ bool login_connection(THD *thd) my_sleep(1000); /* must wait after eof() */ #endif statistic_increment(aborted_connects,&LOCK_status); - DBUG_RETURN(1); + error=1; + goto exit; } /* Connect completed, set read/write timeouts back to default */ my_net_set_read_timeout(net, thd->variables.net_read_timeout); @@ -1151,10 +1152,13 @@ bool login_connection(THD *thd) if (increment_connection_count(thd, TRUE)) { my_error(ER_OUTOFMEMORY, MYF(0), 2*sizeof(USER_STATS)); - DBUG_RETURN(1); + error= 1; + goto exit; } - DBUG_RETURN(0); +exit: + mysql_audit_notify_connection_connect(thd); + DBUG_RETURN(error); } @@ -1295,7 +1299,6 @@ bool thd_prepare_connection(THD *thd) bool rc; lex_start(thd); rc= login_connection(thd); - mysql_audit_notify_connection_connect(thd); if (rc) return rc; diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index 99b7b1e58d0..c09f3269d7a 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -98,6 +98,7 @@ public: int mysql_open_cursor(THD *thd, select_result *result, Server_side_cursor **pcursor) { + sql_digest_state *parent_digest; PSI_statement_locker *parent_locker; select_result *save_result; Select_materialize *result_materialize; @@ -117,11 +118,14 @@ int mysql_open_cursor(THD *thd, select_result *result, &thd->security_ctx->priv_user[0], (char *) thd->security_ctx->host_or_ip, 2); + parent_digest= thd->m_digest; parent_locker= thd->m_statement_psi; + thd->m_digest= NULL; thd->m_statement_psi= NULL; /* Mark that we can't use query cache with cursors */ thd->query_cache_is_applicable= 0; rc= mysql_execute_command(thd); + thd->m_digest= parent_digest; thd->m_statement_psi= parent_locker; MYSQL_QUERY_EXEC_DONE(rc); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 99b44e6008c..5292b964576 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -1,5 +1,6 @@ /* Copyright (c) 2000, 2010, Oracle and/or its affiliates. + Copyright (c) 2010, 2015, MariaDB 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 +851,7 @@ int mysql_multi_delete_prepare(THD *thd) */ lex->select_lex.exclude_from_table_unique_test= FALSE; - if (lex->select_lex.save_prep_leaf_tables(thd)) + if (lex->save_prep_leaf_tables()) DBUG_RETURN(TRUE); DBUG_RETURN(FALSE); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index c68e7f490cc..fdc615d0fae 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -1,5 +1,6 @@ /* Copyright (c) 2002, 2011, Oracle and/or its affiliates. + Copyright (c) 2010, 2015, MariaDB 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 @@ -169,7 +170,9 @@ mysql_handle_single_derived(LEX *lex, TABLE_LIST *derived, uint phases) uint8 allowed_phases= (derived->is_merged_derived() ? DT_PHASES_MERGE : DT_PHASES_MATERIALIZE); DBUG_ENTER("mysql_handle_single_derived"); - DBUG_PRINT("enter", ("phases: 0x%x allowed: 0x%x", phases, allowed_phases)); + DBUG_PRINT("enter", ("phases: 0x%x allowed: 0x%x alias: '%s'", + phases, allowed_phases, + (derived->alias ? derived->alias : "<NULL>"))); if (!lex->derived_tables) DBUG_RETURN(FALSE); diff --git a/sql/sql_digest.cc b/sql/sql_digest.cc new file mode 100644 index 00000000000..324f2fbd428 --- /dev/null +++ b/sql/sql_digest.cc @@ -0,0 +1,683 @@ +/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + + 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/* + This code needs extra visibility in the lexer structures +*/ + +#include "my_global.h" +#include "my_md5.h" +#include "mysqld_error.h" + +#include "sql_string.h" +#include "sql_class.h" +#include "sql_lex.h" +#include "sql_digest.h" +#include "sql_digest_stream.h" + +#include "sql_get_diagnostics.h" + +#ifdef NEVER +#include "my_sys.h" +#include "sql_signal.h" +#endif + +/* Generated code */ +#include "sql_yacc.h" +#define LEX_TOKEN_WITH_DEFINITION +#include "lex_token.h" + +/* Name pollution from sql/sql_lex.h */ +#ifdef LEX_YYSTYPE +#undef LEX_YYSTYPE +#endif + +#define LEX_YYSTYPE YYSTYPE* + +#define SIZE_OF_A_TOKEN 2 + +/** + Read a single token from token array. +*/ +inline uint read_token(const sql_digest_storage *digest_storage, + uint index, uint *tok) +{ + uint safe_byte_count= digest_storage->m_byte_count; + + if (index + SIZE_OF_A_TOKEN <= safe_byte_count && + safe_byte_count <= digest_storage->m_token_array_length) + { + const unsigned char *src= & digest_storage->m_token_array[index]; + *tok= src[0] | (src[1] << 8); + return index + SIZE_OF_A_TOKEN; + } + + /* The input byte stream is exhausted. */ + *tok= 0; + return MAX_DIGEST_STORAGE_SIZE + 1; +} + +/** + Store a single token in token array. +*/ +inline void store_token(sql_digest_storage* digest_storage, uint token) +{ + DBUG_ASSERT(digest_storage->m_byte_count <= digest_storage->m_token_array_length); + + if (digest_storage->m_byte_count + SIZE_OF_A_TOKEN <= digest_storage->m_token_array_length) + { + unsigned char* dest= & digest_storage->m_token_array[digest_storage->m_byte_count]; + dest[0]= token & 0xff; + dest[1]= (token >> 8) & 0xff; + digest_storage->m_byte_count+= SIZE_OF_A_TOKEN; + } + else + { + digest_storage->m_full= true; + } +} + +/** + Read an identifier from token array. +*/ +inline uint read_identifier(const sql_digest_storage* digest_storage, + uint index, char ** id_string, int *id_length) +{ + uint new_index; + uint safe_byte_count= digest_storage->m_byte_count; + + DBUG_ASSERT(index <= safe_byte_count); + DBUG_ASSERT(safe_byte_count <= digest_storage->m_token_array_length); + + /* + token + length + string are written in an atomic way, + so we do always expect a length + string here + */ + + uint bytes_needed= SIZE_OF_A_TOKEN; + /* If we can read token and identifier length */ + if ((index + bytes_needed) <= safe_byte_count) + { + const unsigned char *src= & digest_storage->m_token_array[index]; + /* Read the length of identifier */ + uint length= src[0] | (src[1] << 8); + bytes_needed+= length; + /* If we can read entire identifier from token array */ + if ((index + bytes_needed) <= safe_byte_count) + { + *id_string= (char *) (src + 2); + *id_length= length; + + new_index= index + bytes_needed; + DBUG_ASSERT(new_index <= safe_byte_count); + return new_index; + } + } + + /* The input byte stream is exhausted. */ + return MAX_DIGEST_STORAGE_SIZE + 1; +} + +/** + Store an identifier in token array. +*/ +inline void store_token_identifier(sql_digest_storage* digest_storage, + uint token, + size_t id_length, const char *id_name) +{ + DBUG_ASSERT(digest_storage->m_byte_count <= digest_storage->m_token_array_length); + + size_t bytes_needed= 2 * SIZE_OF_A_TOKEN + id_length; + if (digest_storage->m_byte_count + bytes_needed <= (unsigned int)digest_storage->m_token_array_length) + { + unsigned char* dest= & digest_storage->m_token_array[digest_storage->m_byte_count]; + /* Write the token */ + dest[0]= token & 0xff; + dest[1]= (token >> 8) & 0xff; + /* Write the string length */ + dest[2]= id_length & 0xff; + dest[3]= (id_length >> 8) & 0xff; + /* Write the string data */ + if (id_length > 0) + memcpy((char *)(dest + 4), id_name, id_length); + digest_storage->m_byte_count+= bytes_needed; + } + else + { + digest_storage->m_full= true; + } +} + +void compute_digest_md5(const sql_digest_storage *digest_storage, unsigned char *md5) +{ + compute_md5_hash((char *) md5, + (const char *) digest_storage->m_token_array, + digest_storage->m_byte_count); +} + +/* + Iterate token array and updates digest_text. +*/ +void compute_digest_text(const sql_digest_storage* digest_storage, + String *digest_text) +{ + DBUG_ASSERT(digest_storage != NULL); + uint byte_count= digest_storage->m_byte_count; + String *digest_output= digest_text; + uint tok= 0; + uint current_byte= 0; + lex_token_string *tok_data; + + /* Reset existing data */ + digest_output->length(0); + + if (byte_count > digest_storage->m_token_array_length) + { + digest_output->append("\0", 1); + return; + } + + /* Convert text to utf8 */ + const CHARSET_INFO *from_cs= get_charset(digest_storage->m_charset_number, MYF(0)); + const CHARSET_INFO *to_cs= &my_charset_utf8_bin; + + if (from_cs == NULL) + { + /* + Can happen, as we do dirty reads on digest_storage, + which can be written to in another thread. + */ + digest_output->append("\0", 1); + return; + } + + char id_buffer[NAME_LEN + 1]= {'\0'}; + char *id_string; + size_t id_length; + bool convert_text= !my_charset_same(from_cs, to_cs); + + while (current_byte < byte_count) + { + current_byte= read_token(digest_storage, current_byte, &tok); + + if (tok <= 0 || tok >= array_elements(lex_token_array) + || current_byte > max_digest_length) + return; + + tok_data= &lex_token_array[tok]; + + switch (tok) + { + /* All identifiers are printed with their name. */ + case IDENT: + case IDENT_QUOTED: + { + char *id_ptr= NULL; + int id_len= 0; + uint err_cs= 0; + + /* Get the next identifier from the storage buffer. */ + current_byte= read_identifier(digest_storage, current_byte, + &id_ptr, &id_len); + if (current_byte > max_digest_length) + return; + + if (convert_text) + { + /* Verify that the converted text will fit. */ + if (to_cs->mbmaxlen*id_len > NAME_LEN) + { + digest_output->append("...", 3); + break; + } + /* Convert identifier string into the storage character set. */ + id_length= my_convert(id_buffer, NAME_LEN, to_cs, + id_ptr, id_len, from_cs, &err_cs); + id_string= id_buffer; + } + else + { + id_string= id_ptr; + id_length= id_len; + } + + if (id_length == 0 || err_cs != 0) + { + break; + } + /* Copy the converted identifier into the digest string. */ + if (tok == IDENT_QUOTED) + digest_output->append("`", 1); + if (id_length > 0) + digest_output->append(id_string, id_length); + if (tok == IDENT_QUOTED) + digest_output->append("`", 1); + digest_output->append(" ", 1); + } + break; + + /* Everything else is printed as is. */ + default: + /* + Make sure not to overflow digest_text buffer. + +1 is to make sure extra space for ' '. + */ + int tok_length= tok_data->m_token_length; + + digest_output->append(tok_data->m_token_string, tok_length); + if (tok_data->m_append_space) + digest_output->append(" ", 1); + break; + } + } +} + +static inline uint peek_token(const sql_digest_storage *digest, uint index) +{ + uint token; + DBUG_ASSERT(index + SIZE_OF_A_TOKEN <= digest->m_byte_count); + DBUG_ASSERT(digest->m_byte_count <= digest->m_token_array_length); + + token= ((digest->m_token_array[index + 1])<<8) | digest->m_token_array[index]; + return token; +} + +/** + Function to read last two tokens from token array. If an identifier + is found, do not look for token before that. +*/ +static inline void peek_last_two_tokens(const sql_digest_storage* digest_storage, + uint last_id_index, uint *t1, uint *t2) +{ + uint byte_count= digest_storage->m_byte_count; + uint peek_index= byte_count; + + if (last_id_index + SIZE_OF_A_TOKEN <= peek_index) + { + /* Take last token. */ + peek_index-= SIZE_OF_A_TOKEN; + *t1= peek_token(digest_storage, peek_index); + + if (last_id_index + SIZE_OF_A_TOKEN <= peek_index) + { + /* Take 2nd token from last. */ + peek_index-= SIZE_OF_A_TOKEN; + *t2= peek_token(digest_storage, peek_index); + } + else + { + *t2= TOK_UNUSED; + } + } + else + { + *t1= TOK_UNUSED; + *t2= TOK_UNUSED; + } +} + +/** + Function to read last three tokens from token array. If an identifier + is found, do not look for token before that. +*/ +static inline void peek_last_three_tokens(const sql_digest_storage* digest_storage, + uint last_id_index, uint *t1, uint *t2, uint *t3) +{ + uint byte_count= digest_storage->m_byte_count; + uint peek_index= byte_count; + + if (last_id_index + SIZE_OF_A_TOKEN <= peek_index) + { + /* Take last token. */ + peek_index-= SIZE_OF_A_TOKEN; + *t1= peek_token(digest_storage, peek_index); + + if (last_id_index + SIZE_OF_A_TOKEN <= peek_index) + { + /* Take 2nd token from last. */ + peek_index-= SIZE_OF_A_TOKEN; + *t2= peek_token(digest_storage, peek_index); + + if (last_id_index + SIZE_OF_A_TOKEN <= peek_index) + { + /* Take 3rd token from last. */ + peek_index-= SIZE_OF_A_TOKEN; + *t3= peek_token(digest_storage, peek_index); + } + else + { + *t3= TOK_UNUSED; + } + } + else + { + *t2= TOK_UNUSED; + *t3= TOK_UNUSED; + } + } + else + { + *t1= TOK_UNUSED; + *t2= TOK_UNUSED; + *t3= TOK_UNUSED; + } +} + +sql_digest_state* digest_add_token(sql_digest_state *state, + uint token, + LEX_YYSTYPE yylval) +{ + sql_digest_storage *digest_storage= NULL; + + digest_storage= &state->m_digest_storage; + + /* + Stop collecting further tokens if digest storage is full or + if END token is received. + */ + if (digest_storage->m_full || token == END_OF_INPUT) + return NULL; + + /* + Take last_token 2 tokens collected till now. These tokens will be used + in reduce for normalisation. Make sure not to consider ID tokens in reduce. + */ + uint last_token; + uint last_token2; + + switch (token) + { + case NUM: + case LONG_NUM: + case ULONGLONG_NUM: + case DECIMAL_NUM: + case FLOAT_NUM: + case BIN_NUM: + case HEX_NUM: + { + bool found_unary; + do + { + found_unary= false; + peek_last_two_tokens(digest_storage, state->m_last_id_index, + &last_token, &last_token2); + + if ((last_token == '-') || (last_token == '+')) + { + /* + We need to differentiate: + - a <unary minus> operator + - a <unary plus> operator + from + - a <binary minus> operator + - a <binary plus> operator + to only reduce "a = -1" to "a = ?", and not change "b - 1" to "b ?" + + Binary operators are found inside an expression, + while unary operators are found at the beginning of an expression, or after operators. + + To achieve this, every token that is followed by an <expr> expression + in the SQL grammar is flagged. + See sql/sql_yacc.yy + See sql/gen_lex_token.cc + + For example, + "(-1)" is parsed as "(", "-", NUM, ")", and lex_token_array["("].m_start_expr is true, + so reduction of the "-" NUM is done, the result is "(?)". + "(a-1)" is parsed as "(", ID, "-", NUM, ")", and lex_token_array[ID].m_start_expr is false, + so the operator is binary, no reduction is done, and the result is "(a-?)". + */ + if (lex_token_array[last_token2].m_start_expr) + { + /* + REDUCE: + TOK_GENERIC_VALUE := (UNARY_PLUS | UNARY_MINUS) (NUM | LOG_NUM | ... | FLOAT_NUM) + + REDUCE: + TOK_GENERIC_VALUE := (UNARY_PLUS | UNARY_MINUS) TOK_GENERIC_VALUE + */ + token= TOK_GENERIC_VALUE; + digest_storage->m_byte_count-= SIZE_OF_A_TOKEN; + found_unary= true; + } + } + } while (found_unary); + } + /* fall through, for case NULL_SYM below */ + case LEX_HOSTNAME: + case TEXT_STRING: + case NCHAR_STRING: + case PARAM_MARKER: + { + /* + REDUCE: + TOK_GENERIC_VALUE := BIN_NUM | DECIMAL_NUM | ... | ULONGLONG_NUM + */ + token= TOK_GENERIC_VALUE; + + peek_last_two_tokens(digest_storage, state->m_last_id_index, + &last_token, &last_token2); + + if ((last_token2 == TOK_GENERIC_VALUE || + last_token2 == TOK_GENERIC_VALUE_LIST) && + (last_token == ',')) + { + /* + REDUCE: + TOK_GENERIC_VALUE_LIST := + TOK_GENERIC_VALUE ',' TOK_GENERIC_VALUE + + REDUCE: + TOK_GENERIC_VALUE_LIST := + TOK_GENERIC_VALUE_LIST ',' TOK_GENERIC_VALUE + */ + digest_storage->m_byte_count-= 2*SIZE_OF_A_TOKEN; + token= TOK_GENERIC_VALUE_LIST; + } + /* + Add this token or the resulting reduce to digest storage. + */ + store_token(digest_storage, token); + break; + } + case ')': + { + peek_last_two_tokens(digest_storage, state->m_last_id_index, + &last_token, &last_token2); + + if (last_token == TOK_GENERIC_VALUE && + last_token2 == '(') + { + /* + REDUCE: + TOK_ROW_SINGLE_VALUE := + '(' TOK_GENERIC_VALUE ')' + */ + digest_storage->m_byte_count-= 2*SIZE_OF_A_TOKEN; + token= TOK_ROW_SINGLE_VALUE; + + /* Read last two tokens again */ + peek_last_two_tokens(digest_storage, state->m_last_id_index, + &last_token, &last_token2); + + if ((last_token2 == TOK_ROW_SINGLE_VALUE || + last_token2 == TOK_ROW_SINGLE_VALUE_LIST) && + (last_token == ',')) + { + /* + REDUCE: + TOK_ROW_SINGLE_VALUE_LIST := + TOK_ROW_SINGLE_VALUE ',' TOK_ROW_SINGLE_VALUE + + REDUCE: + TOK_ROW_SINGLE_VALUE_LIST := + TOK_ROW_SINGLE_VALUE_LIST ',' TOK_ROW_SINGLE_VALUE + */ + digest_storage->m_byte_count-= 2*SIZE_OF_A_TOKEN; + token= TOK_ROW_SINGLE_VALUE_LIST; + } + } + else if (last_token == TOK_GENERIC_VALUE_LIST && + last_token2 == '(') + { + /* + REDUCE: + TOK_ROW_MULTIPLE_VALUE := + '(' TOK_GENERIC_VALUE_LIST ')' + */ + digest_storage->m_byte_count-= 2*SIZE_OF_A_TOKEN; + token= TOK_ROW_MULTIPLE_VALUE; + + /* Read last two tokens again */ + peek_last_two_tokens(digest_storage, state->m_last_id_index, + &last_token, &last_token2); + + if ((last_token2 == TOK_ROW_MULTIPLE_VALUE || + last_token2 == TOK_ROW_MULTIPLE_VALUE_LIST) && + (last_token == ',')) + { + /* + REDUCE: + TOK_ROW_MULTIPLE_VALUE_LIST := + TOK_ROW_MULTIPLE_VALUE ',' TOK_ROW_MULTIPLE_VALUE + + REDUCE: + TOK_ROW_MULTIPLE_VALUE_LIST := + TOK_ROW_MULTIPLE_VALUE_LIST ',' TOK_ROW_MULTIPLE_VALUE + */ + digest_storage->m_byte_count-= 2*SIZE_OF_A_TOKEN; + token= TOK_ROW_MULTIPLE_VALUE_LIST; + } + } + /* + Add this token or the resulting reduce to digest storage. + */ + store_token(digest_storage, token); + break; + } + case IDENT: + case IDENT_QUOTED: + { + YYSTYPE *lex_token= yylval; + char *yytext= lex_token->lex_str.str; + size_t yylen= lex_token->lex_str.length; + + /* Add this token and identifier string to digest storage. */ + store_token_identifier(digest_storage, token, yylen, yytext); + + /* Update the index of last identifier found. */ + state->m_last_id_index= digest_storage->m_byte_count; + break; + } + default: + { + /* Add this token to digest storage. */ + store_token(digest_storage, token); + break; + } + } + + return state; +} + +sql_digest_state* digest_reduce_token(sql_digest_state *state, + uint token_left, uint token_right) +{ + sql_digest_storage *digest_storage= NULL; + + digest_storage= &state->m_digest_storage; + + /* + Stop collecting further tokens if digest storage is full. + */ + if (digest_storage->m_full) + return NULL; + + uint last_token; + uint last_token2; + uint last_token3; + uint token_to_push= TOK_UNUSED; + + peek_last_two_tokens(digest_storage, state->m_last_id_index, + &last_token, &last_token2); + + /* + There is only one caller of digest_reduce_token(), + see sql/sql_yacc.yy, rule literal := NULL_SYM. + REDUCE: + token_left := token_right + Used for: + TOK_GENERIC_VALUE := NULL_SYM + */ + + if (last_token == token_right) + { + /* + Current stream is like: + TOKEN_X TOKEN_RIGHT . + REDUCE to + TOKEN_X TOKEN_LEFT . + */ + digest_storage->m_byte_count-= SIZE_OF_A_TOKEN; + store_token(digest_storage, token_left); + } + else + { + /* + Current stream is like: + TOKEN_X TOKEN_RIGHT TOKEN_Y . + Pop TOKEN_Y + TOKEN_X TOKEN_RIGHT . TOKEN_Y + REDUCE to + TOKEN_X TOKEN_LEFT . TOKEN_Y + */ + DBUG_ASSERT(last_token2 == token_right); + digest_storage->m_byte_count-= 2 * SIZE_OF_A_TOKEN; + store_token(digest_storage, token_left); + token_to_push= last_token; + } + + peek_last_three_tokens(digest_storage, state->m_last_id_index, + &last_token, &last_token2, &last_token3); + + if ((last_token3 == TOK_GENERIC_VALUE || + last_token3 == TOK_GENERIC_VALUE_LIST) && + (last_token2 == ',') && + (last_token == TOK_GENERIC_VALUE)) + { + /* + REDUCE: + TOK_GENERIC_VALUE_LIST := + TOK_GENERIC_VALUE ',' TOK_GENERIC_VALUE + + REDUCE: + TOK_GENERIC_VALUE_LIST := + TOK_GENERIC_VALUE_LIST ',' TOK_GENERIC_VALUE + */ + digest_storage->m_byte_count-= 3*SIZE_OF_A_TOKEN; + store_token(digest_storage, TOK_GENERIC_VALUE_LIST); + } + + if (token_to_push != TOK_UNUSED) + { + /* + Push TOKEN_Y + */ + store_token(digest_storage, token_to_push); + } + + return state; +} + diff --git a/sql/sql_digest.h b/sql/sql_digest.h new file mode 100644 index 00000000000..ce159283d4d --- /dev/null +++ b/sql/sql_digest.h @@ -0,0 +1,130 @@ +/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + + 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef SQL_DIGEST_H +#define SQL_DIGEST_H + +#include <string.h> +class String; +#include "my_md5.h" + +#define MAX_DIGEST_STORAGE_SIZE (1024*1024) + +/** + Structure to store token count/array for a statement + on which digest is to be calculated. +*/ +struct sql_digest_storage +{ + bool m_full; + uint m_byte_count; + unsigned char m_md5[MD5_HASH_SIZE]; + /** Character set number. */ + uint m_charset_number; + /** + Token array. + Token array is an array of bytes to store tokens received during parsing. + Following is the way token array is formed. + ... <non-id-token> <non-id-token> <id-token> <id_len> <id_text> ... + For Example: + SELECT * FROM T1; + <SELECT_TOKEN> <*> <FROM_TOKEN> <ID_TOKEN> <2> <T1> + */ + unsigned char *m_token_array; + /* Length of the token array to be considered for DIGEST_TEXT calculation. */ + uint m_token_array_length; + + sql_digest_storage() + { + reset(NULL, 0); + } + + inline void reset(unsigned char *token_array, uint length) + { + m_token_array= token_array; + m_token_array_length= length; + reset(); + } + + inline void reset() + { + m_full= false; + m_byte_count= 0; + m_charset_number= 0; + if (m_token_array_length > 0) + { + memset(m_token_array, 0, m_token_array_length); + } + memset(m_md5, 0, MD5_HASH_SIZE); + } + + inline bool is_empty() + { + return (m_byte_count == 0); + } + + inline void copy(const sql_digest_storage *from) + { + /* + Keep in mind this is a dirty copy of something that may change, + as the thread producing the digest is executing concurrently, + without any lock enforced. + */ + uint byte_count_copy= m_token_array_length < from->m_byte_count ? + m_token_array_length : from->m_byte_count; + + if (byte_count_copy > 0) + { + m_full= from->m_full; + m_byte_count= byte_count_copy; + m_charset_number= from->m_charset_number; + memcpy(m_token_array, from->m_token_array, m_byte_count); + memcpy(m_md5, from->m_md5, MD5_HASH_SIZE); + } + else + { + m_full= false; + m_byte_count= 0; + m_charset_number= 0; + } + } +}; +typedef struct sql_digest_storage sql_digest_storage; + +/** + Compute a digest hash. + @param digest_storage The digest + @param [out] md5 The computed digest hash. This parameter is a buffer of size @c MD5_HASH_SIZE. +*/ +void compute_digest_md5(const sql_digest_storage *digest_storage, unsigned char *md5); + +/** + Compute a digest text. + A 'digest text' is a textual representation of a query, + where: + - comments are removed, + - non significant spaces are removed, + - literal values are replaced with a special '?' marker, + - lists of values are collapsed using a shorter notation + @param digest_storage The digest + @param [out] digest_text + @param digest_text_length Size of @c digest_text. + @param [out] truncated true if the text representation was truncated +*/ +void compute_digest_text(const sql_digest_storage *digest_storage, + String *digest_text); + +#endif + diff --git a/sql/sql_digest_stream.h b/sql/sql_digest_stream.h new file mode 100644 index 00000000000..55f7e2293c6 --- /dev/null +++ b/sql/sql_digest_stream.h @@ -0,0 +1,51 @@ +/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + + 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef SQL_DIGEST_STREAM_H +#define SQL_DIGEST_STREAM_H + +#include "sql_digest.h" + +/** + State data storage for @c digest_start, @c digest_add_token. + This structure extends the @c sql_digest_storage structure + with temporary state used only during parsing. +*/ +struct sql_digest_state +{ + /** + Index, in the digest token array, of the last identifier seen. + Reduce rules used in the digest computation can not + apply to tokens seen before an identifier. + @sa digest_add_token + */ + int m_last_id_index; + sql_digest_storage m_digest_storage; + + inline void reset(unsigned char *token_array, uint length) + { + m_last_id_index= 0; + m_digest_storage.reset(token_array, length); + } + + inline bool is_empty() + { + return m_digest_storage.is_empty(); + } +}; +typedef struct sql_digest_state sql_digest_state; + +#endif + diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 697988a6bf8..2026d5f5059 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2014, Oracle and/or its affiliates. - Copyright (c) 2009, 2014, Monty Program Ab. + Copyright (c) 2009, 2015, MariaDB 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 @@ -436,6 +436,21 @@ void Lex_input_stream::body_utf8_append_literal(THD *thd, m_cpp_utf8_processed_ptr= end_ptr; } +void Lex_input_stream::add_digest_token(uint token, LEX_YYSTYPE yylval) +{ + if (m_digest != NULL) + { + m_digest= digest_add_token(m_digest, token, yylval); + } +} + +void Lex_input_stream::reduce_digest_token(uint token_left, uint token_right) +{ + if (m_digest != NULL) + { + m_digest= digest_reduce_token(m_digest, token_left, token_right); + } +} /* This is called before every query that is to be parsed. @@ -541,6 +556,7 @@ void lex_start(THD *thd) lex->is_lex_started= TRUE; lex->used_tables= 0; + lex->only_view= FALSE; lex->reset_slave_info.all= false; lex->limit_rows_examined= 0; lex->limit_rows_examined_cnt= ULONGLONG_MAX; @@ -982,7 +998,7 @@ int MYSQLlex(YYSTYPE *yylval, THD *thd) lip->lookahead_token= -1; *yylval= *(lip->lookahead_yylval); lip->lookahead_yylval= NULL; - lip->m_digest_psi= MYSQL_ADD_TOKEN(lip->m_digest_psi, token, yylval); + lip->add_digest_token(token, yylval); return token; } @@ -1000,12 +1016,10 @@ int MYSQLlex(YYSTYPE *yylval, THD *thd) token= lex_one_token(yylval, thd); switch(token) { case CUBE_SYM: - lip->m_digest_psi= MYSQL_ADD_TOKEN(lip->m_digest_psi, WITH_CUBE_SYM, - yylval); + lip->add_digest_token(WITH_CUBE_SYM, yylval); return WITH_CUBE_SYM; case ROLLUP_SYM: - lip->m_digest_psi= MYSQL_ADD_TOKEN(lip->m_digest_psi, WITH_ROLLUP_SYM, - yylval); + lip->add_digest_token(WITH_ROLLUP_SYM, yylval); return WITH_ROLLUP_SYM; default: /* @@ -1014,7 +1028,7 @@ int MYSQLlex(YYSTYPE *yylval, THD *thd) lip->lookahead_yylval= lip->yylval; lip->yylval= NULL; lip->lookahead_token= token; - lip->m_digest_psi= MYSQL_ADD_TOKEN(lip->m_digest_psi, WITH, yylval); + lip->add_digest_token(WITH, yylval); return WITH; } break; @@ -1022,7 +1036,7 @@ int MYSQLlex(YYSTYPE *yylval, THD *thd) break; } - lip->m_digest_psi= MYSQL_ADD_TOKEN(lip->m_digest_psi, token, yylval); + lip->add_digest_token(token, yylval); return token; } @@ -1860,7 +1874,7 @@ void st_select_lex::init_query() exclude_from_table_unique_test= no_wrap_view_item= FALSE; nest_level= 0; link_next= 0; - is_prep_leaf_list_saved= FALSE; + prep_leaf_list_state= UNINIT; have_merged_subqueries= FALSE; bzero((char*) expr_cache_may_be_used, sizeof(expr_cache_may_be_used)); m_non_agg_field_used= false; @@ -4113,27 +4127,58 @@ bool st_select_lex::save_leaf_tables(THD *thd) } -bool st_select_lex::save_prep_leaf_tables(THD *thd) +bool LEX::save_prep_leaf_tables() { if (!thd->save_prep_leaf_list) - return 0; + return FALSE; Query_arena *arena= thd->stmt_arena, backup; arena= thd->activate_stmt_arena_if_needed(&backup); + //It is used for DETETE/UPDATE so top level has only one SELECT + DBUG_ASSERT(select_lex.next_select() == NULL); + bool res= select_lex.save_prep_leaf_tables(thd); + + if (arena) + thd->restore_active_arena(arena, &backup); + + if (res) + return TRUE; + + thd->save_prep_leaf_list= FALSE; + return FALSE; +} + +bool st_select_lex::save_prep_leaf_tables(THD *thd) +{ List_iterator_fast<TABLE_LIST> li(leaf_tables); TABLE_LIST *table; + + /* + Check that the SELECT_LEX was really prepared and so tables are setup. + + It can be subquery in SET clause of UPDATE which was not prepared yet, so + its tables are not yet setup and ready for storing. + */ + if (prep_leaf_list_state != READY) + return FALSE; + while ((table= li++)) { if (leaf_tables_prep.push_back(table)) - return 1; + return TRUE; + } + prep_leaf_list_state= SAVED; + for (SELECT_LEX_UNIT *u= first_inner_unit(); u; u= u->next_unit()) + { + for (SELECT_LEX *sl= u->first_select(); sl; sl= sl->next_select()) + { + if (sl->save_prep_leaf_tables(thd)) + return TRUE; + } } - thd->lex->select_lex.is_prep_leaf_list_saved= TRUE; - thd->save_prep_leaf_list= FALSE; - if (arena) - thd->restore_active_arena(arena, &backup); - return 0; + return FALSE; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 88491743d39..dcd8ddfce91 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2014, Oracle and/or its affiliates. - Copyright (c) 2010, 2014, Monty Program Ab. + Copyright (c) 2010, 2015, MariaDB 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 @@ -47,6 +47,7 @@ class sys_var; class Item_func_match; class File_parser; class Key_part_spec; +struct sql_digest_state; #ifdef MYSQL_SERVER /* @@ -732,7 +733,8 @@ public: List<TABLE_LIST> leaf_tables; List<TABLE_LIST> leaf_tables_exec; List<TABLE_LIST> leaf_tables_prep; - bool is_prep_leaf_list_saved; + enum leaf_list_state {UNINIT, READY, SAVED}; + enum leaf_list_state prep_leaf_list_state; uint insert_tables; st_select_lex *merged_into; /* select which this select is merged into */ /* (not 0 only for views/derived tables) */ @@ -2048,6 +2050,10 @@ public: /** LALR(2) resolution, value of the look ahead token.*/ LEX_YYSTYPE lookahead_yylval; + void add_digest_token(uint token, LEX_YYSTYPE yylval); + + void reduce_digest_token(uint token_left, uint token_right); + private: /** Pointer to the current position in the raw input stream. */ char *m_ptr; @@ -2167,7 +2173,7 @@ public: /** Current statement digest instrumentation. */ - PSI_digest_locker* m_digest_psi; + sql_digest_state* m_digest; }; /** @@ -2743,6 +2749,8 @@ struct LEX: public Query_tables_list return FALSE; } + bool save_prep_leaf_tables(); + int print_explain(select_result_sink *output, uint8 explain_flags, bool *printed_anything); }; @@ -2861,6 +2869,18 @@ public: }; /** + Input parameters to the parser. +*/ +struct Parser_input +{ + bool m_compute_digest; + + Parser_input() + : m_compute_digest(false) + {} +}; + +/** Internal state of the parser. The complete state consist of: - state data used during lexical parsing, @@ -2887,9 +2907,15 @@ public: ~Parser_state() {} + Parser_input m_input; Lex_input_stream m_lip; Yacc_state m_yacc; + /** + Current performance digest instrumentation. + */ + PSI_digest_locker* m_digest_psi; + void reset(char *found_semicolon, unsigned int length) { m_lip.reset(found_semicolon, length); @@ -2897,6 +2923,11 @@ public: } }; +extern sql_digest_state * +digest_add_token(sql_digest_state *state, uint token, LEX_YYSTYPE yylval); + +extern sql_digest_state * +digest_reduce_token(sql_digest_state *state, uint token_left, uint token_right); struct st_lex_local: public LEX { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 9ecf168c60e..5635e9ad4b7 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -83,6 +83,8 @@ #include "rpl_handler.h" #include "rpl_mi.h" +#include "sql_digest.h" + #include "sp_head.h" #include "sp.h" #include "sp_cache.h" @@ -949,6 +951,7 @@ bool do_command(THD *thd) /* Mark the statement completed. */ MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); thd->m_statement_psi= NULL; + thd->m_digest= NULL; if (net->error != 3) { @@ -998,6 +1001,7 @@ bool do_command(THD *thd) out: /* The statement instrumentation must be closed in all cases. */ + DBUG_ASSERT(thd->m_digest == NULL); DBUG_ASSERT(thd->m_statement_psi == NULL); DBUG_RETURN(return_value); } @@ -1278,6 +1282,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } case COM_QUERY: { + DBUG_ASSERT(thd->m_digest == NULL); + thd->m_digest= & thd->m_digest_state; + thd->m_digest->reset(thd->m_token_array, max_digest_length); + if (alloc_query(thd, packet, packet_length)) break; // fatal error is set MYSQL_QUERY_START(thd->query(), thd->thread_id, @@ -1337,6 +1345,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* PSI end */ MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); thd->m_statement_psi= NULL; + thd->m_digest= NULL; /* DTRACE end */ if (MYSQL_QUERY_DONE_ENABLED()) @@ -1357,6 +1366,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, (char *) thd->security_ctx->host_or_ip); /* PSI begin */ + thd->m_digest= & thd->m_digest_state; + thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state, com_statement_info[command].m_key, thd->db, thd->db_length, @@ -1741,6 +1752,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* Performance Schema Interface instrumentation, end */ MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); thd->m_statement_psi= NULL; + thd->m_digest= NULL; thd->set_time(); dec_thread_running(); @@ -8551,11 +8563,27 @@ bool parse_sql(THD *thd, Parser_state *parser_state, thd->m_parser_state= parser_state; -#ifdef HAVE_PSI_STATEMENT_DIGEST_INTERFACE - /* Start Digest */ - thd->m_parser_state->m_lip.m_digest_psi= - MYSQL_DIGEST_START(do_pfs_digest ? thd->m_statement_psi : NULL); -#endif + parser_state->m_digest_psi= NULL; + parser_state->m_lip.m_digest= NULL; + + if (do_pfs_digest) + { + /* Start Digest */ + parser_state->m_digest_psi= MYSQL_DIGEST_START(thd->m_statement_psi); + + if (parser_state->m_input.m_compute_digest || + (parser_state->m_digest_psi != NULL)) + { + /* + If either: + - the caller wants to compute a digest + - the performance schema wants to compute a digest + set the digest listener in the lexer. + */ + parser_state->m_lip.m_digest= thd->m_digest; + parser_state->m_lip.m_digest->m_digest_storage.m_charset_number= thd->charset()->number; + } + } /* Parse the query. */ @@ -8588,6 +8616,18 @@ bool parse_sql(THD *thd, Parser_state *parser_state, /* That's it. */ ret_value= mysql_parse_status || thd->is_fatal_error; + + if ((ret_value == 0) && (parser_state->m_digest_psi != NULL)) + { + /* + On parsing success, record the digest in the performance schema. + */ + DBUG_ASSERT(do_pfs_digest); + DBUG_ASSERT(thd->m_digest != NULL); + MYSQL_DIGEST_END(parser_state->m_digest_psi, + & thd->m_digest->m_digest_storage); + } + MYSQL_QUERY_PARSE_DONE(ret_value); DBUG_RETURN(ret_value); } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 239d793c633..f0fde223984 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -57,7 +57,6 @@ #include "lock.h" // mysql_lock_remove #include "sql_show.h" // append_identifier #include <m_ctype.h> -#include "my_md5.h" #include "transaction.h" #include "debug_sync.h" diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc index 8c59febeb77..87803c220ea 100644 --- a/sql/sql_partition_admin.cc +++ b/sql/sql_partition_admin.cc @@ -824,9 +824,16 @@ bool Sql_cmd_alter_table_truncate_partition::execute(THD *thd) log. The exception is a unimplemented truncate method or failure before any call to handler::truncate() is done. Also, it is logged in statement format, regardless of the binlog format. + + Since we've changed data within the table, we also have to invalidate + the query cache for it. */ - if (error != HA_ERR_WRONG_COMMAND && binlog_stmt) - error|= write_bin_log(thd, !error, thd->query(), thd->query_length()); + if (error != HA_ERR_WRONG_COMMAND) + { + query_cache_invalidate3(thd, first_table, FALSE); + if (binlog_stmt) + error|= write_bin_log(thd, !error, thd->query(), thd->query_length()); + } /* A locked table ticket was upgraded to a exclusive lock. After the diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 4227641859d..dc408703da4 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -264,13 +264,14 @@ public: { TRASH(ptr_arg, size); } sys_var_pluginvar(sys_var_chain *chain, const char *name_arg, - struct st_mysql_sys_var *plugin_var_arg) + struct st_mysql_sys_var *plugin_var_arg, + struct st_plugin_int *plugin_arg) :sys_var(chain, name_arg, plugin_var_arg->comment, (plugin_var_arg->flags & PLUGIN_VAR_THDLOCAL ? SESSION : GLOBAL) | (plugin_var_arg->flags & PLUGIN_VAR_READONLY ? READONLY : 0), 0, -1, NO_ARG, pluginvar_show_type(plugin_var_arg), 0, 0, VARIABLE_NOT_IN_BINLOG, NULL, NULL, NULL), - plugin_var(plugin_var_arg) + plugin(plugin_arg), plugin_var(plugin_var_arg) { plugin_var->name= name_arg; } sys_var_pluginvar *cast_pluginvar() { return this; } bool check_update_type(Item_result type); @@ -1413,22 +1414,6 @@ static int plugin_initialize(MEM_ROOT *tmp_root, struct st_plugin_int *plugin, goto err; } - /* - set the plugin attribute of plugin's sys vars so they are pointing - to the active plugin - */ - if (plugin->system_vars) - { - sys_var_pluginvar *var= plugin->system_vars->cast_pluginvar(); - for (;;) - { - var->plugin= plugin; - if (!var->next) - break; - var= var->next->cast_pluginvar(); - } - } - ret= 0; err: @@ -2085,14 +2070,8 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, char **argv=orig_argv; DBUG_ENTER("mysql_install_plugin"); - if (opt_noacl) - { - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables"); - DBUG_RETURN(TRUE); - } - tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE); - if (check_table_access(thd, INSERT_ACL, &tables, FALSE, 1, FALSE)) + if (!opt_noacl && check_table_access(thd, INSERT_ACL, &tables, FALSE, 1, FALSE)) DBUG_RETURN(TRUE); /* need to open before acquiring LOCK_plugin or it will deadlock */ @@ -2227,15 +2206,9 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name, bool error= false; DBUG_ENTER("mysql_uninstall_plugin"); - if (opt_noacl) - { - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables"); - DBUG_RETURN(TRUE); - } - tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE); - if (check_table_access(thd, DELETE_ACL, &tables, FALSE, 1, FALSE)) + if (!opt_noacl && check_table_access(thd, DELETE_ACL, &tables, FALSE, 1, FALSE)) DBUG_RETURN(TRUE); /* need to open before acquiring LOCK_plugin or it will deadlock */ @@ -3973,7 +3946,7 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, continue; tmp_backup[tmp->nbackups++].save(&o->name); if ((var= find_bookmark(plugin_name.str, o->name, o->flags))) - v= new (mem_root) sys_var_pluginvar(&chain, var->key + 1, o); + v= new (mem_root) sys_var_pluginvar(&chain, var->key + 1, o, tmp); else { len= plugin_name.length + strlen(o->name) + 2; @@ -3981,7 +3954,7 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, strxmov(varname, plugin_name.str, "-", o->name, NullS); my_casedn_str(&my_charset_latin1, varname); convert_dash_to_underscore(varname, len-1); - v= new (mem_root) sys_var_pluginvar(&chain, varname, o); + v= new (mem_root) sys_var_pluginvar(&chain, varname, o, tmp); } DBUG_ASSERT(v); /* check that an object was actually constructed */ } /* end for */ diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 2c17898f07c..6496e1895fb 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -238,7 +238,6 @@ do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name, { int rc= 1; handlerton *hton; - bool new_exists, old_exists; const char *new_alias, *old_alias; DBUG_ENTER("do_rename"); @@ -254,17 +253,13 @@ do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name, } DBUG_ASSERT(new_alias); - new_exists= ha_table_exists(thd, new_db, new_alias); - - if (new_exists) + if (ha_table_exists(thd, new_db, new_alias)) { my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias); DBUG_RETURN(1); // This can't be skipped } - old_exists= ha_table_exists(thd, ren_table->db, old_alias, &hton); - - if (old_exists) + if (ha_table_exists(thd, ren_table->db, old_alias, &hton) && hton) { DBUG_ASSERT(!thd->locked_tables_mode); tdc_remove_table(thd, TDC_RT_REMOVE_ALL, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index eb222b2f95a..e0f560f0b3a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2014 Oracle and/or its affiliates. +/* Copyright (c) 2000, 2015 Oracle and/or its affiliates. Copyright (c) 2009, 2015 MariaDB This program is free software; you can redistribute it and/or modify @@ -709,9 +709,7 @@ JOIN::prepare(Item ***rref_pointer_array, if (!(select_options & OPTION_SETUP_TABLES_DONE) && setup_tables_and_check_access(thd, &select_lex->context, join_list, tables_list, select_lex->leaf_tables, - FALSE, SELECT_ACL, SELECT_ACL, - (thd->lex->sql_command == - SQLCOM_UPDATE_MULTI))) + FALSE, SELECT_ACL, SELECT_ACL, FALSE)) DBUG_RETURN(-1); /* @@ -6466,7 +6464,6 @@ choose_plan(JOIN *join, table_map join_tables) DBUG_ENTER("choose_plan"); join->cur_embedding_map= 0; - join->cur_dups_producing_tables= 0; reset_nj_counters(join, join->join_list); qsort2_cmp jtab_sort_func; @@ -9739,10 +9736,24 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) if (!sel->quick_keys.is_subset(tab->checked_keys) || !sel->needed_reg.is_subset(tab->checked_keys)) { + /* + "Range checked for each record" is a "last resort" access method + that should only be used when the other option is a cross-product + join. + + We use the following condition (it's approximate): + 1. There are potential keys for (sel->needed_reg) + 2. There were no possible ways to construct a quick select, or + the quick select would be more expensive than the full table + scan. + */ tab->use_quick= (!sel->needed_reg.is_clear_all() && (sel->quick_keys.is_clear_all() || - (sel->quick && - (sel->quick->records >= 100L)))) ? + (sel->quick && + sel->quick->read_time > + tab->table->file->scan_time() + + tab->table->file->stats.records/TIME_FOR_COMPARE + ))) ? 2 : 1; sel->read_tables= used_tables & ~current_map; sel->quick_keys.clear_all(); @@ -21149,18 +21160,33 @@ SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length, for (;order;order=order->next,pos++) { - Item *item= order->item[0]->real_item(); + Item *const item= order->item[0], *const real_item= item->real_item(); pos->field= 0; pos->item= 0; - if (item->type() == Item::FIELD_ITEM) - pos->field= ((Item_field*) item)->field; - else if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item()) - pos->field= ((Item_sum*) item)->get_tmp_table_field(); - else if (item->type() == Item::COPY_STR_ITEM) - { // Blob patch - pos->item= ((Item_copy*) item)->get_item(); + if (real_item->type() == Item::FIELD_ITEM) + { + // Could be a field, or Item_direct_view_ref wrapping a field + DBUG_ASSERT(item->type() == Item::FIELD_ITEM || + (item->type() == Item::REF_ITEM && + static_cast<Item_ref*>(item)->ref_type() == + Item_ref::VIEW_REF)); + pos->field= static_cast<Item_field*>(real_item)->field; + } + else if (real_item->type() == Item::SUM_FUNC_ITEM && + !real_item->const_item()) + { + // Aggregate, or Item_aggregate_ref + DBUG_ASSERT(item->type() == Item::SUM_FUNC_ITEM || + (item->type() == Item::REF_ITEM && + static_cast<Item_ref*>(item)->ref_type() == + Item_ref::AGGREGATE_REF)); + pos->field= item->get_tmp_table_field(); + } + else if (real_item->type() == Item::COPY_STR_ITEM) + { // Blob patch + pos->item= static_cast<Item_copy*>(real_item)->get_item(); } else - pos->item= *order->item; + pos->item= item; pos->reverse=! order->asc; DBUG_ASSERT(pos->field != NULL || pos->item != NULL); } @@ -21404,6 +21430,17 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, uint el= all_fields.elements; all_fields.push_front(order_item); /* Add new field to field list. */ ref_pointer_array[el]= order_item; + /* + If the order_item is a SUM_FUNC_ITEM, when fix_fields is called + ref_by is set to order->item which is the address of order_item. + But this needs to be address of order_item in the all_fields list. + As a result, when it gets replaced with Item_aggregate_ref + object in Item::split_sum_func2, we will be able to retrieve the + newly created object. + */ + if (order_item->type() == Item::SUM_FUNC_ITEM) + ((Item_sum *)order_item)->ref_by= all_fields.head_ref(); + order->item= ref_pointer_array + el; return FALSE; } diff --git a/sql/sql_select.h b/sql/sql_select.h index 45041def28f..5aa29715dc3 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -2,7 +2,7 @@ #define SQL_SELECT_INCLUDED /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2008, 2013, Monty Program Ab. + Copyright (c) 2008, 2015, MariaDB 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 @@ -825,7 +825,12 @@ typedef struct st_position :public Sql_alloc */ uint n_sj_tables; - table_map prefix_dups_producing_tables; + /* + Bitmap of semi-join inner tables that are in the join prefix and for + which there's no provision for how to eliminate semi-join duplicates + they produce. + */ + table_map dups_producing_tables; table_map inner_tables_handled_with_other_sjs; @@ -1046,13 +1051,6 @@ public: */ table_map cur_sj_inner_tables; - /* - Bitmap of semi-join inner tables that are in the join prefix and for - which there's no provision for how to eliminate semi-join duplicates - they produce. - */ - table_map cur_dups_producing_tables; - /* We also maintain a stack of join optimization states in * join->positions[] */ /******* Join optimization state members end *******/ diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index 2b0576ffba9..8d5bb2b596d 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -326,7 +326,8 @@ get_server_from_table_to_cache(TABLE *table) table->use_all_columns(); /* get each field into the server struct ptr */ - server->server_name= get_field(&mem, table->field[0]); + ptr= get_field(&mem, table->field[0]); + server->server_name= ptr ? ptr : blank; server->server_name_length= (uint) strlen(server->server_name); ptr= get_field(&mem, table->field[1]); server->host= ptr ? ptr : blank; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 6dabd349214..2413cb5ba53 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. - Copyright (c) 2009, 2014, SkySQL Ab. +/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2009, 2015, MariaDB 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 @@ -2301,7 +2301,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) Security_context *tmp_sctx= tmp->security_ctx; struct st_my_thread_var *mysys_var; if ((tmp->vio_ok() || tmp->system_thread) && - (!user || (tmp_sctx->user && !strcmp(tmp_sctx->user, user)))) + (!user || (!tmp->system_thread && + tmp_sctx->user && !strcmp(tmp_sctx->user, user)))) { thread_info *thd_info= new thread_info; @@ -2679,7 +2680,8 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) ulonglong max_counter; if ((!tmp->vio_ok() && !tmp->system_thread) || - (user && (!tmp_sctx->user || strcmp(tmp_sctx->user, user)))) + (user && (tmp->system_thread || !tmp_sctx->user || + strcmp(tmp_sctx->user, user)))) continue; restore_record(table, s->default_values); @@ -2895,7 +2897,7 @@ void reset_status_vars() catch-all cleanup function, cleans up everything no matter what DESCRIPTION - This function is not strictly required if all add_to_status/ + This function is not strictly required if all add_status_vars/ remove_status_vars are properly paired, but it's a safety measure that deletes everything from the all_status_vars[] even if some remove_status_vars were forgotten @@ -8099,15 +8101,20 @@ bool get_schema_tables_result(JOIN *join, TABLE_LIST *table_list= tab->table->pos_in_table_list; if (table_list->schema_table && thd->fill_information_schema_tables()) { +#if MYSQL_VERSION_ID > 100105 +#error I_S tables only need to be re-populated if make_cond_for_info_schema() will preserve outer fields bool is_subselect= (&lex->unit != lex->current_select->master_unit() && lex->current_select->master_unit()->item); +#else +#define is_subselect false +#endif /* A value of 0 indicates a dummy implementation */ if (table_list->schema_table->fill_table == 0) continue; /* skip I_S optimizations specific to get_all_tables */ - if (thd->lex->describe && + if (lex->describe && (table_list->schema_table->fill_table != get_all_tables)) continue; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 46591e8b5c1..20cfccaa3d9 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1,6 +1,6 @@ /* - Copyright (c) 2000, 2014, Oracle and/or its affiliates. - Copyright (c) 2010, 2014, SkySQL Ab. + Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2010, 2015, MariaDB 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 @@ -28,7 +28,6 @@ #include "sql_base.h" // open_table_uncached, lock_table_names #include "lock.h" // mysql_unlock_tables #include "strfunc.h" // find_type2, find_set -#include "sql_view.h" // view_checksum #include "sql_truncate.h" // regenerate_locked_table #include "sql_partition.h" // mem_alloc_error, // generate_partition_syntax, @@ -1673,6 +1672,7 @@ void execute_ddl_log_recovery() (void) mysql_file_delete(key_file_global_ddl_log, file_name, MYF(0)); global_ddl_log.recovery_phase= FALSE; mysql_mutex_unlock(&LOCK_gdl); + thd->reset_query(); delete thd; /* Remember that we don't have a THD */ set_current_thd(0); @@ -2201,15 +2201,13 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, char path[FN_REFLEN + 1], wrong_tables_buff[160], *alias= NULL; String wrong_tables(wrong_tables_buff, sizeof(wrong_tables_buff)-1, system_charset_info); - uint path_length= 0; + uint path_length= 0, errors= 0; int error= 0; int non_temp_tables_count= 0; - bool foreign_key_error=0; bool non_tmp_error= 0; bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0; bool non_tmp_table_deleted= 0; bool is_drop_tmp_if_exists_added= 0; - bool one_table= tables->next_local == 0; bool was_view= 0; String built_query; String built_trans_tmp_query, built_non_trans_tmp_query; @@ -2495,12 +2493,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, error= ha_delete_table(thd, table_type, path, db, table->table_name, !dont_log_query); - if (error == HA_ERR_ROW_IS_REFERENCED) - { - /* the table is referenced by a foreign key constraint */ - foreign_key_error= 1; - } - if (!error || error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) + if (!error) { int frm_delete_error, trigger_drop_error= 0; /* Delete the table definition file */ @@ -2518,11 +2511,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, if (trigger_drop_error || (frm_delete_error && frm_delete_error != ENOENT)) error= 1; - else if (!frm_delete_error || !error || if_exists) - { - error= 0; + else if (frm_delete_error && if_exists) thd->clear_error(); - } } non_tmp_error= error ? TRUE : non_tmp_error; } @@ -2533,6 +2523,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, wrong_tables.append(db); wrong_tables.append('.'); wrong_tables.append(table->table_name); + errors++; } else { @@ -2556,14 +2547,13 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, err: if (wrong_tables.length()) { - if (one_table && was_view) + DBUG_ASSERT(errors); + if (errors == 1 && was_view) my_printf_error(ER_IT_IS_A_VIEW, ER(ER_IT_IS_A_VIEW), MYF(0), wrong_tables.c_ptr_safe()); - else if (!foreign_key_error) + else if (errors > 1 || !thd->is_error()) my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0), wrong_tables.c_ptr_safe()); - else - my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0)); error= 1; } @@ -2614,8 +2604,8 @@ err: /* Chop of the last comma */ built_query.chop(); built_query.append(" /* generated by server */"); - int error_code = (non_tmp_error ? - (foreign_key_error ? ER_ROW_IS_REFERENCED : ER_BAD_TABLE_ERROR) : 0); + int error_code = non_tmp_error ? thd->get_stmt_da()->sql_errno() + : 0; error |= thd->binlog_query(THD::STMT_QUERY_TYPE, built_query.ptr(), built_query.length(), @@ -5150,6 +5140,7 @@ mysql_rename_table(handlerton *base, const char *old_db, ulonglong save_bits= thd->variables.option_bits; int length; DBUG_ENTER("mysql_rename_table"); + DBUG_ASSERT(base); DBUG_PRINT("enter", ("old: '%s'.'%s' new: '%s'.'%s'", old_db, old_name, new_db, new_name)); @@ -5157,8 +5148,7 @@ mysql_rename_table(handlerton *base, const char *old_db, if (flags & NO_FK_CHECKS) thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS; - file= (base == NULL ? 0 : - get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base)); + file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base); build_table_filename(from, sizeof(from) - 1, old_db, old_name, "", flags & FN_FROM_IS_TMP); @@ -5479,7 +5469,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, if (!table->view) { int result __attribute__((unused))= - show_create_table(thd, table, &query, create_info, WITHOUT_DB_NAME); + show_create_table(thd, table, &query, create_info, WITH_DB_NAME); DBUG_ASSERT(result == 0); // show_create_table() always return 0 do_logging= FALSE; @@ -5860,12 +5850,17 @@ drop_create_field: /* let us check the name of the first key part. */ if ((keyname= key->name.str) == NULL) { - List_iterator<Key_part_spec> part_it(key->columns); - Key_part_spec *kp; - if ((kp= part_it++)) - keyname= kp->field_name.str; - if (keyname == NULL) - continue; + if (key->type == Key::PRIMARY) + keyname= primary_key_name; + else + { + List_iterator<Key_part_spec> part_it(key->columns); + Key_part_spec *kp; + if ((kp= part_it++)) + keyname= kp->field_name.str; + if (keyname == NULL) + continue; + } } if (key->type != Key::FOREIGN_KEY) { @@ -8429,6 +8424,23 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, mysql_audit_alter_table(thd, table_list); THD_STAGE_INFO(thd, stage_setup); + + handle_if_exists_options(thd, table, alter_info); + + /* + Look if we have to do anything at all. + ALTER can become NOOP after handling + the IF (NOT) EXISTS options. + */ + if (alter_info->flags == 0) + { + my_snprintf(alter_ctx.tmp_name, sizeof(alter_ctx.tmp_name), + ER(ER_INSERT_INFO), 0L, 0L, + thd->get_stmt_da()->current_statement_warn_count()); + my_ok(thd, 0L, 0L, alter_ctx.tmp_name); + DBUG_RETURN(false); + } + if (!(alter_info->flags & ~(Alter_info::ALTER_RENAME | Alter_info::ALTER_KEYS_ONOFF)) && alter_info->requested_algorithm != @@ -8449,22 +8461,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, DBUG_RETURN(res); } - handle_if_exists_options(thd, table, alter_info); - - /* - Look if we have to do anything at all. - Normally ALTER can become NOOP only after handling - the IF (NOT) EXISTS options. - */ - if (alter_info->flags == 0) - { - my_snprintf(alter_ctx.tmp_name, sizeof(alter_ctx.tmp_name), - ER(ER_INSERT_INFO), 0L, 0L, - thd->get_stmt_da()->current_statement_warn_count()); - my_ok(thd, 0L, 0L, alter_ctx.tmp_name); - DBUG_RETURN(false); - } - /* We have to do full alter table. */ #ifdef WITH_PARTITION_STORAGE_ENGINE diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index fe2ea02a8e2..05869b70c8f 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2010, 2014, Oracle and/or its affiliates. - Copyright (c) 2013, 2014, SkySQL Ab. +/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. + Copyright (c) 2013, 2015, MariaDB 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 @@ -283,6 +283,12 @@ static bool recreate_temporary_table(THD *thd, TABLE *table) table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK); + /* + If LOCK TABLES list is not empty and contains this table + then unlock the table and remove it from this list. + */ + mysql_lock_remove(thd, thd->lock, table); + /* Don't free share. */ close_temporary_table(thd, table, FALSE, FALSE); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 6c4d864e75a..f616549097b 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2011, 2013, Monty Program Ab. + Copyright (c) 2011, 2015, MariaDB 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 @@ -1520,7 +1520,7 @@ int mysql_multi_update_prepare(THD *thd) */ lex->select_lex.exclude_from_table_unique_test= FALSE; - if (lex->select_lex.save_prep_leaf_tables(thd)) + if (lex->save_prep_leaf_tables()) DBUG_RETURN(TRUE); DBUG_RETURN (FALSE); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index be31a7df3f6..a63d8a51a86 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2004, 2013, Oracle and/or its affiliates. - Copyright (c) 2011, 2014, SkySQL Ab. + Copyright (c) 2011, 2015, MariaDB 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 @@ -225,7 +225,7 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view) view->definer.user= decoy.definer.user; lex->definer= &view->definer; } - if (lex->create_view_algorithm == DTYPE_ALGORITHM_UNDEFINED) + if (lex->create_view_algorithm == VIEW_ALGORITHM_INHERIT) lex->create_view_algorithm= (uint8) decoy.algorithm; if (lex->create_view_suid == VIEW_SUID_DEFAULT) lex->create_view_suid= decoy.view_suid ? @@ -685,6 +685,26 @@ err: } +static void make_view_filename(LEX_STRING *dir, char *dir_buff, + size_t dir_buff_len, + LEX_STRING *path, char *path_buff, + size_t path_buff_len, + LEX_STRING *file, + TABLE_LIST *view) +{ + /* print file name */ + dir->length= build_table_filename(dir_buff, dir_buff_len - 1, + view->db, "", "", 0); + dir->str= dir_buff; + + path->length= build_table_filename(path_buff, path_buff_len - 1, + view->db, view->table_name, reg_ext, 0); + path->str= path_buff; + + file->str= path->str + dir->length; + file->length= path->length - dir->length; +} + /* number of required parameters for making view */ static const int required_view_parameters= 15; @@ -747,6 +767,67 @@ static File_option view_parameters[]= static LEX_STRING view_file_type[]= {{(char*) STRING_WITH_LEN("VIEW") }}; +int mariadb_fix_view(THD *thd, TABLE_LIST *view, bool wrong_checksum, + bool swap_alg) +{ + char dir_buff[FN_REFLEN + 1], path_buff[FN_REFLEN + 1]; + LEX_STRING dir, file, path; + DBUG_ENTER("mariadb_fix_view"); + + if (!wrong_checksum && view->mariadb_version) + DBUG_RETURN(HA_ADMIN_OK); + + make_view_filename(&dir, dir_buff, sizeof(dir_buff), + &path, path_buff, sizeof(path_buff), + &file, view); + /* init timestamp */ + if (!view->timestamp.str) + view->timestamp.str= view->timestamp_buffer; + + if (swap_alg && view->algorithm != VIEW_ALGORITHM_UNDEFINED) + { + DBUG_ASSERT(view->algorithm == VIEW_ALGORITHM_MERGE || + view->algorithm == VIEW_ALGORITHM_TMPTABLE); + if (view->algorithm == VIEW_ALGORITHM_MERGE) + view->algorithm= VIEW_ALGORITHM_TMPTABLE; + else + view->algorithm= VIEW_ALGORITHM_MERGE; + } + else + swap_alg= 0; + if (wrong_checksum) + { + if (view->md5.length != 32) + { + if ((view->md5.str= (char *)thd->alloc(32 + 1)) == NULL) + DBUG_RETURN(HA_ADMIN_FAILED); + } + view->calc_md5(view->md5.str); + view->md5.length= 32; + } + view->mariadb_version= MYSQL_VERSION_ID; + + if (sql_create_definition_file(&dir, &file, view_file_type, + (uchar*)view, view_parameters)) + { + sql_print_error("View '%-.192s'.'%-.192s': algorithm swap error.", + view->db, view->table_name); + DBUG_RETURN(HA_ADMIN_INTERNAL_ERROR); + } + sql_print_information("View %`s.%`s: the version is set to %llu%s%s", + view->db, view->table_name, view->mariadb_version, + (wrong_checksum ? ", checksum corrected" : ""), + (swap_alg ? + ((view->algorithm == VIEW_ALGORITHM_MERGE) ? + ", algorithm restored to be MERGE" + : ", algorithm restored to be TEMPTABLE") + : "")); + + + DBUG_RETURN(HA_ADMIN_OK); +} + + /* Register VIEW (write .frm & process .frm's history backups) @@ -887,17 +968,9 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, } loop_out: /* print file name */ - dir.length= build_table_filename(dir_buff, sizeof(dir_buff) - 1, - view->db, "", "", 0); - dir.str= dir_buff; - - path.length= build_table_filename(path_buff, sizeof(path_buff) - 1, - view->db, view->table_name, reg_ext, 0); - path.str= path_buff; - - file.str= path.str + dir.length; - file.length= path.length - dir.length; - + make_view_filename(&dir, dir_buff, sizeof(dir_buff), + &path, path_buff, sizeof(path_buff), + &file, view); /* init timestamp */ if (!view->timestamp.str) view->timestamp.str= view->timestamp_buffer; @@ -1023,7 +1096,7 @@ err: SYNOPSIS mysql_make_view() - thd Thread handler + thd Thread handle parser parser object table TABLE_LIST structure for filling flags flags @@ -1609,7 +1682,7 @@ err: SYNOPSIS mysql_drop_view() - thd - thread handler + thd - thread handle views - views to delete drop_mode - cascade/check @@ -1726,7 +1799,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) SYNOPSIS check_key_in_view() - thd thread handler + thd thread handle view view for check with opened table DESCRIPTION @@ -1912,6 +1985,58 @@ int view_checksum(THD *thd, TABLE_LIST *view) HA_ADMIN_OK); } +/** + Check view + + @param thd thread handle + @param view view for check + @param check_opt check options + + @retval HA_ADMIN_OK OK + @retval HA_ADMIN_NOT_IMPLEMENTED it is not VIEW + @retval HA_ADMIN_WRONG_CHECKSUM check sum is wrong +*/ +int view_check(THD *thd, TABLE_LIST *view, HA_CHECK_OPT *check_opt) +{ + DBUG_ENTER("view_check"); + + int res= view_checksum(thd, view); + if (res != HA_ADMIN_OK) + DBUG_RETURN(res); + + if (((check_opt->sql_flags & TT_FOR_UPGRADE) && !view->mariadb_version)) + DBUG_RETURN(HA_ADMIN_NEEDS_UPGRADE); + + DBUG_RETURN(HA_ADMIN_OK); +} + + +/** + Repair view + + @param thd thread handle + @param view view for check + @param check_opt check options + + @retval HA_ADMIN_OK OK + @retval HA_ADMIN_NOT_IMPLEMENTED it is not VIEW + @retval HA_ADMIN_WRONG_CHECKSUM check sum is wrong +*/ + +int view_repair(THD *thd, TABLE_LIST *view, HA_CHECK_OPT *check_opt) +{ + DBUG_ENTER("view_repair"); + bool swap_alg= (check_opt->sql_flags & TT_FROM_MYSQL); + bool wrong_checksum= view_checksum(thd, view) != HA_ADMIN_OK; + int ret; + if (wrong_checksum || swap_alg || (!view->mariadb_version)) + { + ret= mariadb_fix_view(thd, view, wrong_checksum, swap_alg); + DBUG_RETURN(ret); + } + DBUG_RETURN(HA_ADMIN_OK); +} + /* rename view diff --git a/sql/sql_view.h b/sql/sql_view.h index abe95c63e6e..8d733a1867c 100644 --- a/sql/sql_view.h +++ b/sql/sql_view.h @@ -2,7 +2,8 @@ #define SQL_VIEW_INCLUDED /* -*- C++ -*- */ -/* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2004, 2010, Oracle and/or its affiliates. + Copyright (c) 2015, MariaDB 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 @@ -45,6 +46,8 @@ bool check_key_in_view(THD *thd, TABLE_LIST * view); bool insert_view_fields(THD *thd, List<Item> *list, TABLE_LIST *view); int view_checksum(THD *thd, TABLE_LIST *view); +int view_check(THD *thd, TABLE_LIST *view, HA_CHECK_OPT *check_opt); +int view_repair(THD *thd, TABLE_LIST *view, HA_CHECK_OPT *check_opt); extern TYPELIB updatable_views_with_limit_typelib; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a23a88b7559..d980de7e1a5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1,6 +1,6 @@ /* - Copyright (c) 2000, 2014, Oracle and/or its affiliates. - Copyright (c) 2010, 2014, Monty Program Ab. + Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2010, 2015, MariaDB 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 @@ -63,6 +63,7 @@ #include "keycaches.h" #include "set_var.h" #include "rpl_mi.h" +#include "lex_token.h" /* this is to get the bison compilation windows warnings out */ #ifdef _MSC_VER @@ -1331,6 +1332,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token MULTIPOINT %token MULTIPOLYGON %token MUTEX_SYM +%token MYSQL_SYM %token MYSQL_ERRNO_SYM %token NAMES_SYM /* SQL-2003-N */ %token NAME_SYM /* SQL-2003-N */ @@ -7018,6 +7020,7 @@ alter: { Lex->name.str= 0; Lex->name.length= 0; + Lex->only_view= FALSE; Lex->sql_command= SQLCOM_ALTER_TABLE; Lex->duplicates= DUP_ERROR; Lex->col_list.empty(); @@ -7139,7 +7142,7 @@ alter: my_error(ER_SP_BADSTATEMENT, MYF(0), "ALTER VIEW"); MYSQL_YYABORT; } - lex->create_view_algorithm= DTYPE_ALGORITHM_UNDEFINED; + lex->create_view_algorithm= VIEW_ALGORITHM_INHERIT; lex->create_view_mode= VIEW_ALTER; } view_tail @@ -7909,8 +7912,13 @@ opt_checksum_type: | EXTENDED_SYM { Lex->check_opt.flags= T_EXTEND; } ; +repair_table_or_view: + table_or_tables table_list opt_mi_repair_type + | VIEW_SYM { Lex->only_view= TRUE; } table_list opt_view_repair_type + ; + repair: - REPAIR opt_no_write_to_binlog table_or_tables + REPAIR opt_no_write_to_binlog { LEX *lex=Lex; lex->sql_command = SQLCOM_REPAIR; @@ -7920,7 +7928,7 @@ repair: /* Will be overriden during execution. */ YYPS->m_lock_type= TL_UNLOCK; } - table_list opt_mi_repair_type + repair_table_or_view { LEX* lex= thd->lex; DBUG_ASSERT(!lex->m_sql_cmd); @@ -7946,6 +7954,11 @@ mi_repair_type: | USE_FRM { Lex->check_opt.sql_flags|= TT_USEFRM; } ; +opt_view_repair_type: + /* empty */ { } + | FROM MYSQL_SYM { Lex->check_opt.sql_flags|= TT_FROM_MYSQL; } + ; + analyze: ANALYZE_SYM opt_no_write_to_binlog table_or_tables { @@ -8062,25 +8075,29 @@ binlog_base64_event: } ; -check: - CHECK_SYM table_or_tables +check_view_or_table: + table_or_tables table_list opt_mi_check_type + | VIEW_SYM { Lex->only_view= TRUE; } table_list opt_view_check_type + ; + +check: CHECK_SYM { LEX *lex=Lex; - if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "CHECK"); - MYSQL_YYABORT; - } lex->sql_command = SQLCOM_CHECK; lex->check_opt.init(); lex->alter_info.reset(); /* Will be overriden during execution. */ YYPS->m_lock_type= TL_UNLOCK; } - table_list opt_mi_check_type + check_view_or_table { LEX* lex= thd->lex; + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "CHECK"); + MYSQL_YYABORT; + } DBUG_ASSERT(!lex->m_sql_cmd); lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_check_table(); if (lex->m_sql_cmd == NULL) @@ -8107,6 +8124,11 @@ mi_check_type: | FOR_SYM UPGRADE_SYM { Lex->check_opt.sql_flags|= TT_FOR_UPGRADE; } ; +opt_view_check_type: + /* empty */ { } + | FOR_SYM UPGRADE_SYM { Lex->check_opt.sql_flags|= TT_FOR_UPGRADE; } + ; + optimize: OPTIMIZE opt_no_write_to_binlog table_or_tables { @@ -10093,7 +10115,8 @@ udf_expr: parse it out. If we hijack the input stream with remember_name we may get quoted or escaped names. */ - else if ($2->type() != Item::FIELD_ITEM) + else if ($2->type() != Item::FIELD_ITEM && + $2->type() != Item::REF_ITEM /* For HAVING */ ) $2->set_name($1, (uint) ($3 - $1), thd->charset()); $$= $2; } @@ -12517,7 +12540,6 @@ show_param: lex->sql_command = SQLCOM_SHOW_CREATE; if (!lex->select_lex.add_table_to_list(thd, $3, NULL,0)) MYSQL_YYABORT; - lex->only_view= 0; lex->create_info.storage_media= HA_SM_DEFAULT; } | CREATE VIEW_SYM table_ident @@ -13348,6 +13370,13 @@ literal: | temporal_literal { $$= $1; } | NULL_SYM { + /* + For the digest computation, in this context only, + NULL is considered a literal, hence reduced to '?' + REDUCE: + TOK_GENERIC_VALUE := NULL_SYM + */ + YYLIP->reduce_digest_token(TOK_GENERIC_VALUE, NULL_SYM); $$ = new (thd->mem_root) Item_null(); if ($$ == NULL) MYSQL_YYABORT; @@ -14199,6 +14228,7 @@ keyword_sp: | MULTIPOINT {} | MULTIPOLYGON {} | MUTEX_SYM {} + | MYSQL_SYM {} | MYSQL_ERRNO_SYM {} | NAME_SYM {} | NAMES_SYM {} @@ -14827,8 +14857,8 @@ lock: ; table_or_tables: - TABLE_SYM {} - | TABLES {} + TABLE_SYM { } + | TABLES { } ; table_lock_list: @@ -15732,6 +15762,13 @@ subselect_end: */ lex->current_select->select_n_where_fields+= child->select_n_where_fields; + + /* + Aggregate functions in having clause may add fields to an outer + select. Count them also. + */ + lex->current_select->select_n_having_items+= + child->select_n_having_items; } ; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 31bd712ee67..94466db5fd9 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2002, 2014, Oracle and/or its affiliates. - Copyright (c) 2012, 2014, SkySQL Ab. +/* Copyright (c) 2002, 2015, Oracle and/or its affiliates. + Copyright (c) 2012, 2015, MariaDB 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 @@ -1313,6 +1313,12 @@ static Sys_var_ulong Sys_max_connect_errors( VALID_RANGE(1, UINT_MAX), DEFAULT(MAX_CONNECT_ERRORS), BLOCK_SIZE(1)); +static Sys_var_long Sys_max_digest_length( + "max_digest_length", "Maximum length considered for digest text.", + PARSED_EARLY READ_ONLY GLOBAL_VAR(max_digest_length), + CMD_LINE(REQUIRED_ARG), + VALID_RANGE(0, 1024 * 1024), DEFAULT(1024), BLOCK_SIZE(1)); + static bool check_max_delayed_threads(sys_var *self, THD *thd, set_var *var) { return var->type != OPT_GLOBAL && @@ -2524,7 +2530,7 @@ static Sys_var_ulong Sys_trans_alloc_block_size( "transaction_alloc_block_size", "Allocation block size for transactions to be stored in binary log", SESSION_VAR(trans_alloc_block_size), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(1024, UINT_MAX), DEFAULT(QUERY_ALLOC_BLOCK_SIZE), + VALID_RANGE(1024, 128 * 1024 * 1024), DEFAULT(QUERY_ALLOC_BLOCK_SIZE), BLOCK_SIZE(1024), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(fix_trans_mem_root)); @@ -2532,7 +2538,7 @@ static Sys_var_ulong Sys_trans_prealloc_size( "transaction_prealloc_size", "Persistent buffer for transactions to be stored in binary log", SESSION_VAR(trans_prealloc_size), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(1024, UINT_MAX), DEFAULT(TRANS_ALLOC_PREALLOC_SIZE), + VALID_RANGE(1024, 128 * 1024 * 1024), DEFAULT(TRANS_ALLOC_PREALLOC_SIZE), BLOCK_SIZE(1024), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(fix_trans_mem_root)); diff --git a/sql/table.cc b/sql/table.cc index a9b525bd25f..053269ab435 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5111,7 +5111,8 @@ TABLE *TABLE_LIST::get_real_join_table() TABLE_LIST *tbl= this; while (tbl->table == NULL || tbl->table->reginfo.join_tab == NULL) { - if (tbl->view == NULL && tbl->derived == NULL) + if ((tbl->view == NULL && tbl->derived == NULL) || + tbl->is_materialized_derived()) break; /* we do not support merging of union yet */ DBUG_ASSERT(tbl->view == NULL || @@ -5120,28 +5121,25 @@ TABLE *TABLE_LIST::get_real_join_table() tbl->derived->first_select()->next_select() == NULL); { - List_iterator_fast<TABLE_LIST> ti; + List_iterator_fast<TABLE_LIST> + ti(tbl->view != NULL ? + tbl->view->select_lex.top_join_list : + tbl->derived->first_select()->top_join_list); + for (;;) { - List_iterator_fast<TABLE_LIST> - ti(tbl->view != NULL ? - tbl->view->select_lex.top_join_list : - tbl->derived->first_select()->top_join_list); - for (;;) - { - tbl= NULL; - /* - Find left table in outer join on this level - (the list is reverted). - */ - for (TABLE_LIST *t= ti++; t; t= ti++) - tbl= t; - if (!tbl) - return NULL; // view/derived with no tables - if (!tbl->nested_join) - break; - /* go deeper if we've found nested join */ - ti= tbl->nested_join->join_list; - } + tbl= NULL; + /* + Find left table in outer join on this level + (the list is reverted). + */ + for (TABLE_LIST *t= ti++; t; t= ti++) + tbl= t; + if (!tbl) + return NULL; // view/derived with no tables + if (!tbl->nested_join) + break; + /* go deeper if we've found nested join */ + ti= tbl->nested_join->join_list; } } } diff --git a/sql/table.h b/sql/table.h index c63f648f9d0..39faa8b9765 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1374,6 +1374,10 @@ public: } bool update_const_key_parts(COND *conds); + + my_ptrdiff_t default_values_offset() const + { return (my_ptrdiff_t) (s->default_values - record[0]); } + uint actual_n_key_parts(KEY *keyinfo); ulong actual_key_flags(KEY *keyinfo); int update_default_fields(); @@ -1537,6 +1541,8 @@ typedef struct st_schema_table #define DT_PHASES_MATERIALIZE (DT_COMMON | DT_MATERIALIZE) #define VIEW_ALGORITHM_UNDEFINED 0 +/* Special value for ALTER VIEW: inherit original algorithm. */ +#define VIEW_ALGORITHM_INHERIT DTYPE_VIEW #define VIEW_ALGORITHM_MERGE (DTYPE_VIEW | DTYPE_MERGE) #define VIEW_ALGORITHM_TMPTABLE (DTYPE_VIEW | DTYPE_MATERIALIZE) diff --git a/sql/tztime.cc b/sql/tztime.cc index d3b4fec6335..6486e9b2018 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -2523,7 +2523,8 @@ scan_tz_dir(char * name_end, uint symlink_recursion_level, uint verbose) for (i= 0; i < cur_dir->number_of_files; i++) { - if (cur_dir->dir_entry[i].name[0] != '.') + if (cur_dir->dir_entry[i].name[0] != '.' && + strcmp(cur_dir->dir_entry[i].name, "Factory")) { name_end_tmp= strmake(name_end, cur_dir->dir_entry[i].name, FN_REFLEN - (name_end - fullname)); diff --git a/sql/uniques.cc b/sql/uniques.cc index 912a38f8927..c755293035b 100644 --- a/sql/uniques.cc +++ b/sql/uniques.cc @@ -1,4 +1,5 @@ -/* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2001, 2010, Oracle and/or its affiliates. + Copyright (c) 2010, 2015, MariaDB 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 @@ -100,7 +101,7 @@ Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg, max_elements= (ulong) (max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+size)); (void) open_cached_file(&file, mysql_tmpdir,TEMP_PREFIX, DISK_BUFFER_SIZE, - MYF(MY_WME)); + MYF(MY_WME)); } @@ -641,8 +642,8 @@ bool Unique::walk(TABLE *table, tree_walk_action action, void *walk_action_arg) return 1; if (flush_io_cache(&file) || reinit_io_cache(&file, READ_CACHE, 0L, 0, 0)) return 1; - ulong buff_sz= (max_in_memory_size / full_size + 1) * full_size; - if (!(merge_buffer= (uchar *) my_malloc(buff_sz, MYF(MY_THREAD_SPECIFIC)))) + size_t buff_sz= (max_in_memory_size / full_size + 1) * full_size; + if (!(merge_buffer = (uchar *)my_malloc(buff_sz, MYF(MY_THREAD_SPECIFIC|MY_WME)))) return 1; if (buff_sz < full_size * (file_ptrs.elements + 1UL)) res= merge(table, merge_buffer, buff_sz >= full_size * MERGEBUFF2) ; @@ -773,9 +774,8 @@ bool Unique::get(TABLE *table) /* Not enough memory; Save the result to file && free memory used by tree */ if (flush()) return 1; - - ulong buff_sz= (max_in_memory_size / full_size + 1) * full_size; - if (!(sort_buffer= (uchar*) my_malloc(buff_sz, MYF(MY_THREAD_SPECIFIC)))) + size_t buff_sz= (max_in_memory_size / full_size + 1) * full_size; + if (!(sort_buffer= (uchar*) my_malloc(buff_sz, MYF(MY_THREAD_SPECIFIC|MY_WME)))) return 1; if (merge(table, sort_buffer, FALSE)) diff --git a/sql/winservice.h b/sql/winservice.h index fca7b129de5..c3e2bfe1b20 100644 --- a/sql/winservice.h +++ b/sql/winservice.h @@ -1,40 +1,40 @@ -/*
- Copyright (c) 2011, 2012, 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
- the Free Software Foundation; version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- Extract properties of a windows service binary path
-*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <windows.h>
-typedef struct mysqld_service_properties_st
-{
- char mysqld_exe[MAX_PATH];
- char inifile[MAX_PATH];
- char datadir[MAX_PATH];
- int version_major;
- int version_minor;
- int version_patch;
-} mysqld_service_properties;
-
-extern int get_mysql_service_properties(const wchar_t *bin_path,
- mysqld_service_properties *props);
-
-#ifdef __cplusplus
-}
-#endif
+/* + Copyright (c) 2011, 2012, 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + Extract properties of a windows service binary path +*/ +#ifdef __cplusplus +extern "C" { +#endif + +#include <windows.h> +typedef struct mysqld_service_properties_st +{ + char mysqld_exe[MAX_PATH]; + char inifile[MAX_PATH]; + char datadir[MAX_PATH]; + int version_major; + int version_minor; + int version_patch; +} mysqld_service_properties; + +extern int get_mysql_service_properties(const wchar_t *bin_path, + mysqld_service_properties *props); + +#ifdef __cplusplus +} +#endif |