summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2018-11-10 14:52:57 -0800
committerIgor Babaev <igor@askmonty.org>2018-11-10 14:52:57 -0800
commit5f46670bd09babbee75a24ac82eb4ade0706da66 (patch)
tree85e2759b75650b8165c3e01638e9458eb4d1274c /sql
parent8d5a11122c32f4d9eb87536886c6e893377bdd07 (diff)
parent3ea7de9a78a1410a9b79362774247e9e44b201b3 (diff)
downloadmariadb-git-5f46670bd09babbee75a24ac82eb4ade0706da66.tar.gz
Merge branch '10.4' into 10.4-mdev16188
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt37
-rw-r--r--sql/compat56.cc3
-rw-r--r--sql/contributors.h4
-rw-r--r--sql/event_data_objects.cc12
-rw-r--r--sql/event_parse_data.cc8
-rw-r--r--sql/events.cc22
-rw-r--r--sql/field.cc329
-rw-r--r--sql/field.h111
-rw-r--r--sql/field_conv.cc4
-rw-r--r--sql/filesort.cc6
-rw-r--r--sql/gcalc_slicescan.cc11
-rw-r--r--sql/gcalc_slicescan.h7
-rw-r--r--sql/gcalc_tools.cc11
-rw-r--r--sql/gcalc_tools.h1
-rw-r--r--sql/ha_partition.cc157
-rw-r--r--sql/ha_partition.h11
-rw-r--r--sql/handle_connections_win.cc555
-rw-r--r--sql/handle_connections_win.h20
-rw-r--r--sql/handler.cc51
-rw-r--r--sql/handler.h64
-rw-r--r--sql/init.h2
-rw-r--r--sql/item.cc422
-rw-r--r--sql/item.h317
-rw-r--r--sql/item_cmpfunc.cc121
-rw-r--r--sql/item_cmpfunc.h51
-rw-r--r--sql/item_create.cc21
-rw-r--r--sql/item_func.cc79
-rw-r--r--sql/item_func.h130
-rw-r--r--sql/item_jsonfunc.cc47
-rw-r--r--sql/item_jsonfunc.h2
-rw-r--r--sql/item_row.h2
-rw-r--r--sql/item_strfunc.cc136
-rw-r--r--sql/item_strfunc.h12
-rw-r--r--sql/item_subselect.cc9
-rw-r--r--sql/item_subselect.h6
-rw-r--r--sql/item_sum.cc28
-rw-r--r--sql/item_sum.h20
-rw-r--r--sql/item_timefunc.cc427
-rw-r--r--sql/item_timefunc.h283
-rw-r--r--sql/item_vers.cc7
-rw-r--r--sql/item_vers.h2
-rw-r--r--sql/item_windowfunc.cc21
-rw-r--r--sql/item_windowfunc.h9
-rw-r--r--sql/key.cc3
-rw-r--r--sql/lock.cc16
-rw-r--r--sql/lock.h1
-rw-r--r--sql/log.cc21
-rw-r--r--sql/log_event.cc60
-rw-r--r--sql/multi_range_read.cc13
-rw-r--r--sql/my_decimal.h4
-rw-r--r--sql/mysql_install_db.cc88
-rw-r--r--sql/mysqld.cc901
-rw-r--r--sql/mysqld.h10
-rw-r--r--sql/net_serv.cc2
-rw-r--r--sql/opt_range.cc66
-rw-r--r--sql/opt_range.h5
-rw-r--r--sql/opt_range_mrr.cc54
-rw-r--r--sql/opt_split.cc12
-rw-r--r--sql/opt_subselect.cc119
-rw-r--r--sql/partition_info.h5
-rw-r--r--sql/procedure.h4
-rw-r--r--sql/protocol.cc8
-rw-r--r--sql/rpl_gtid.cc72
-rw-r--r--sql/rpl_gtid.h2
-rw-r--r--sql/rpl_parallel.cc32
-rw-r--r--sql/rpl_rli.cc79
-rw-r--r--sql/rpl_rli.h11
-rw-r--r--sql/rpl_utility.cc34
-rw-r--r--sql/semisync_master_ack_receiver.cc3
-rw-r--r--sql/semisync_slave.cc3
-rw-r--r--sql/share/CMakeLists.txt12
-rw-r--r--sql/share/errmsg-utf8.txt4
-rw-r--r--sql/slave.cc13
-rw-r--r--sql/sql_acl.cc1452
-rw-r--r--sql/sql_admin.cc9
-rw-r--r--sql/sql_alter.cc19
-rw-r--r--sql/sql_alter.h2
-rw-r--r--sql/sql_base.cc203
-rw-r--r--sql/sql_base.h6
-rw-r--r--sql/sql_basic_types.h83
-rw-r--r--sql/sql_class.cc15
-rw-r--r--sql/sql_class.h42
-rw-r--r--sql/sql_const.h2
-rw-r--r--sql/sql_cte.cc36
-rw-r--r--sql/sql_cte.h19
-rw-r--r--sql/sql_delete.cc17
-rw-r--r--sql/sql_derived.cc5
-rw-r--r--sql/sql_error.h73
-rw-r--r--sql/sql_get_diagnostics.cc2
-rw-r--r--sql/sql_get_diagnostics.h2
-rw-r--r--sql/sql_insert.cc3
-rw-r--r--sql/sql_lex.cc26
-rw-r--r--sql/sql_lex.h11
-rw-r--r--sql/sql_list.h5
-rw-r--r--sql/sql_parse.cc47
-rw-r--r--sql/sql_partition.cc20
-rw-r--r--sql/sql_partition.h4
-rw-r--r--sql/sql_partition_admin.cc4
-rw-r--r--sql/sql_plist.h7
-rw-r--r--sql/sql_plugin.cc74
-rw-r--r--sql/sql_plugin_services.ic3
-rw-r--r--sql/sql_prepare.cc29
-rw-r--r--sql/sql_reload.cc14
-rw-r--r--sql/sql_select.cc296
-rw-r--r--sql/sql_select.h8
-rw-r--r--sql/sql_sequence.cc5
-rw-r--r--sql/sql_show.cc56
-rw-r--r--sql/sql_statistics.cc38
-rw-r--r--sql/sql_statistics.h34
-rw-r--r--sql/sql_string.cc23
-rw-r--r--sql/sql_string.h1
-rw-r--r--sql/sql_table.cc132
-rw-r--r--sql/sql_time.cc222
-rw-r--r--sql/sql_time.h50
-rw-r--r--sql/sql_trigger.cc26
-rw-r--r--sql/sql_truncate.cc7
-rw-r--r--sql/sql_tvc.cc19
-rw-r--r--sql/sql_tvc.h2
-rw-r--r--sql/sql_type.cc756
-rw-r--r--sql/sql_type.h954
-rw-r--r--sql/sql_type_int.h82
-rw-r--r--sql/sql_union.cc36
-rw-r--r--sql/sql_update.cc4
-rw-r--r--sql/sql_view.cc12
-rw-r--r--sql/sql_window.cc36
-rw-r--r--sql/sql_window.h6
-rw-r--r--sql/sql_yacc.yy153
-rw-r--r--sql/sql_yacc_ora.yy130
-rw-r--r--sql/structs.h7
-rw-r--r--sql/sys_vars.cc27
-rw-r--r--sql/sys_vars.ic4
-rw-r--r--sql/table.cc73
-rw-r--r--sql/table.h28
-rw-r--r--sql/table_cache.cc19
-rw-r--r--sql/temporary_tables.cc30
-rw-r--r--sql/threadpool_win.cc94
-rw-r--r--sql/tztime.cc2
-rw-r--r--sql/wsrep_applier.cc1
-rw-r--r--sql/wsrep_binlog.cc52
-rw-r--r--sql/wsrep_dummy.cc3
-rw-r--r--sql/wsrep_hton.cc9
-rw-r--r--sql/wsrep_mysqld.cc326
-rw-r--r--sql/wsrep_mysqld.h4
-rw-r--r--sql/wsrep_sst.cc121
-rw-r--r--sql/wsrep_sst.h1
-rw-r--r--sql/wsrep_var.cc11
-rw-r--r--sql/wsrep_xid.cc5
147 files changed, 6870 insertions, 4504 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 13a116a71d4..b37962d0fc9 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -153,6 +153,7 @@ IF (CMAKE_SYSTEM_NAME MATCHES "Linux" OR
ADD_DEFINITIONS(-DHAVE_POOL_OF_THREADS)
IF(WIN32)
SET(SQL_SOURCE ${SQL_SOURCE} threadpool_win.cc)
+ SET(SQL_SOURCE ${SQL_SOURCE} handle_connections_win.cc)
ENDIF()
SET(SQL_SOURCE ${SQL_SOURCE} threadpool_generic.cc)
@@ -204,9 +205,7 @@ IF(MSVC AND NOT WITHOUT_DYNAMIC_PLUGINS)
SET(MYSQLD_LIB ${CMAKE_CURRENT_BINARY_DIR}/mysqld_lib.lib)
SET(MYSQLD_CORELIBS sql mysys dbug strings)
FOREACH (CORELIB ${MYSQLD_CORELIBS})
- GET_TARGET_PROPERTY(LOC ${CORELIB} LOCATION)
- FILE(TO_NATIVE_PATH ${LOC} LOC)
- SET (LIB_LOCATIONS ${LIB_LOCATIONS} ${LOC})
+ SET (LIB_LOCATIONS ${LIB_LOCATIONS} $<TARGET_FILE:${CORELIB}>)
ENDFOREACH (CORELIB)
SET(_PLATFORM x86)
@@ -282,7 +281,7 @@ IF(APPLE)
# Add CoreServices framework since some dloadable plugins may need it
FIND_LIBRARY(CORESERVICES NAMES CoreServices)
IF(CORESERVICES)
- TARGET_LINK_LIBRARIES(mysqld ${CORESERVICES})
+ TARGET_LINK_LIBRARIES(mysqld LINK_PRIVATE ${CORESERVICES})
ENDIF()
ENDIF()
@@ -303,13 +302,12 @@ IF(NOT WITHOUT_DYNAMIC_PLUGINS)
ENDIF()
ENDIF(NOT WITHOUT_DYNAMIC_PLUGINS)
-TARGET_LINK_LIBRARIES(mysqld sql)
+TARGET_LINK_LIBRARIES(mysqld LINK_PRIVATE sql)
# Provide plugins with minimal set of libraries
SET(INTERFACE_LIBS ${LIBRT})
IF(INTERFACE_LIBS)
- SET_TARGET_PROPERTIES(mysqld PROPERTIES LINK_INTERFACE_LIBRARIES
- "${INTERFACE_LIBS}")
+ TARGET_LINK_LIBRARIES(mysqld LINK_PUBLIC ${INTERFACE_LIBS})
ENDIF()
# On Solaris, some extra effort is required in order to get dtrace probes
@@ -321,7 +319,7 @@ DTRACE_INSTRUMENT_STATIC_LIBS(mysqld
SET(WITH_MYSQLD_LDFLAGS "" CACHE STRING "Additional linker flags for mysqld")
MARK_AS_ADVANCED(WITH_MYSQLD_LDFLAGS)
IF(WITH_MYSQLD_LDFLAGS)
- GET_TARGET_PROPERTY(mysqld LINK_FLAGS MYSQLD_LINK_FLAGS)
+ GET_TARGET_PROPERTY(MYSQLD_LINK_FLAGS mysqld LINK_FLAGS)
IF(NOT MYSQLD_LINK_FLAGS)
SET(MYSQLD_LINK_FLAGS)
ENDIF()
@@ -422,23 +420,20 @@ SET(DBOPT_FILE ${CMAKE_SOURCE_DIR}/support-files/db.opt )
INSTALL(FILES ${DBOPT_FILE} DESTINATION data/test COMPONENT DataFiles)
# Install initial database on windows
-IF(NOT CMAKE_CROSSCOMPILING)
- GET_TARGET_PROPERTY(MYSQLD_EXECUTABLE mysqld LOCATION)
-ENDIF()
-IF(WIN32 AND MYSQLD_EXECUTABLE)
- CONFIGURE_FILE(
- ${CMAKE_SOURCE_DIR}/cmake/create_initial_db.cmake.in
- ${CMAKE_CURRENT_BINARY_DIR}/create_initial_db.cmake
- @ONLY
- )
-
+IF(WIN32 AND TARGET mysqld AND NOT CMAKE_CROSSCOMPILING)
+
IF(MSVC_IDE OR CMAKE_GENERATOR MATCHES "Xcode")
SET (CONFIG_PARAM -DCONFIG=${CMAKE_CFG_INTDIR})
ENDIF()
MAKE_DIRECTORY(${CMAKE_CURRENT_BINARY_DIR}/data)
ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/initdb.dep
- COMMAND ${CMAKE_COMMAND} ${CONFIG_PARAM} -P ${CMAKE_CURRENT_BINARY_DIR}/create_initial_db.cmake
+ COMMAND ${CMAKE_COMMAND} ${CONFIG_PARAM}
+ -DTOP_SRCDIR="${CMAKE_SOURCE_DIR}"
+ -DBINDIR="${CMAKE_CURRENT_BINARY_DIR}"
+ -DMYSQLD_EXECUTABLE="$<TARGET_FILE:mysqld>"
+ -DCMAKE_CFG_INTDIR="${CMAKE_CFG_INTDIR}"
+ -P ${CMAKE_SOURCE_DIR}/cmake/create_initial_db.cmake
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/initdb.dep
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/data
DEPENDS mysqld
@@ -456,7 +451,7 @@ IF(WIN32 AND MYSQLD_EXECUTABLE)
ELSE()
# Not windows or cross compiling, just install an empty directory
INSTALL(FILES ${DUMMY_FILE} DESTINATION data/mysql COMPONENT DataFiles)
-ENDIF(WIN32 AND MYSQLD_EXECUTABLE)
+ENDIF(WIN32 AND TARGET mysqld AND NOT CMAKE_CROSSCOMPILING)
ENDIF(INSTALL_LAYOUT STREQUAL "STANDALONE")
IF(WIN32)
@@ -492,7 +487,7 @@ IF(WIN32)
COMPONENT Server
)
SET_TARGET_PROPERTIES(mysql_install_db PROPERTIES COMPILE_FLAGS -DINSTALL_PLUGINDIR=${INSTALL_PLUGINDIR})
- TARGET_LINK_LIBRARIES(mysql_install_db mysys)
+ TARGET_LINK_LIBRARIES(mysql_install_db mysys shlwapi)
ADD_LIBRARY(winservice STATIC winservice.c)
TARGET_LINK_LIBRARIES(winservice shell32)
diff --git a/sql/compat56.cc b/sql/compat56.cc
index 16c25924d6e..d1cb8b0042c 100644
--- a/sql/compat56.cc
+++ b/sql/compat56.cc
@@ -254,6 +254,9 @@ void TIME_from_longlong_datetime_packed(MYSQL_TIME *ltime, longlong tmp)
{
longlong ymd, hms;
longlong ymdhms, ym;
+
+ DBUG_ASSERT(tmp != LONGLONG_MIN);
+
if ((ltime->neg= (tmp < 0)))
tmp= -tmp;
diff --git a/sql/contributors.h b/sql/contributors.h
index a0d05af3fa6..69f8fa6bd4c 100644
--- a/sql/contributors.h
+++ b/sql/contributors.h
@@ -45,12 +45,14 @@ struct show_table_contributors_st show_table_contributors[]= {
{"Visma", "https://visma.com", "Gold Sponsor of the MariaDB Foundation"},
{"DBS", "https://dbs.com", "Gold Sponsor of the MariaDB Foundation"},
{"IBM", "https://www.ibm.com", "Gold Sponsor of the MariaDB Foundation"},
+ {"Tencent Games", "http://game.qq.com/", "Gold Sponsor of the MariaDB Foundation"},
{"Nexedi", "https://www.nexedi.com", "Silver Sponsor of the MariaDB Foundation"},
- {"Acronis", "http://www.acronis.com", "Silver Sponsor of the MariaDB Foundation"},
+ {"Acronis", "https://www.acronis.com", "Silver Sponsor of the MariaDB Foundation"},
{"Verkkokauppa.com", "https://www.verkkokauppa.com", "Bronze Sponsor of the MariaDB Foundation"},
{"Virtuozzo", "https://virtuozzo.com", "Bronze Sponsor of the MariaDB Foundation"},
{"Tencent Game DBA", "http://tencentdba.com/about", "Bronze Sponsor of the MariaDB Foundation"},
{"Tencent TDSQL", "http://tdsql.org", "Bronze Sponsor of the MariaDB Foundation"},
+ {"Percona", "https://www.percona.com/", "Bronze Sponsor of the MariaDB Foundation"},
/* Sponsors of important features */
{"Google", "USA", "Sponsoring encryption, parallel replication and GTID"},
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index 19cb4865ee6..a6803982171 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -654,7 +654,7 @@ my_time_t
add_interval(MYSQL_TIME *ltime, const Time_zone *time_zone,
interval_type scale, INTERVAL interval)
{
- if (date_add_interval(ltime, scale, interval))
+ if (date_add_interval(current_thd, ltime, scale, interval))
return 0;
uint not_used;
@@ -1284,7 +1284,11 @@ Event_job_data::construct_sp_sql(THD *thd, String *sp_sql)
*/
sp_sql->append(STRING_WITH_LEN("() SQL SECURITY INVOKER "));
+ if (thd->variables.sql_mode & MODE_ORACLE)
+ sp_sql->append(STRING_WITH_LEN(" AS BEGIN "));
sp_sql->append(&body);
+ if (thd->variables.sql_mode & MODE_ORACLE)
+ sp_sql->append(STRING_WITH_LEN("; END"));
DBUG_RETURN(thd->is_fatal_error);
}
@@ -1387,9 +1391,6 @@ Event_job_data::execute(THD *thd, bool drop)
goto end;
}
- if (construct_sp_sql(thd, &sp_sql))
- goto end;
-
/*
Set up global thread attributes to reflect the properties of
this Event. We can simply reset these instead of usual
@@ -1401,6 +1402,9 @@ Event_job_data::execute(THD *thd, bool drop)
thd->variables.sql_mode= sql_mode;
thd->variables.time_zone= time_zone;
+ if (construct_sp_sql(thd, &sp_sql))
+ goto end;
+
thd->set_query(sp_sql.c_ptr_safe(), sp_sql.length());
{
diff --git a/sql/event_parse_data.cc b/sql/event_parse_data.cc
index d20d322d864..bfda8438885 100644
--- a/sql/event_parse_data.cc
+++ b/sql/event_parse_data.cc
@@ -216,7 +216,7 @@ Event_parse_data::init_execute_at(THD *thd)
(starts_null && ends_null)));
DBUG_ASSERT(starts_null && ends_null);
- if (item_execute_at->get_date(&ltime, TIME_NO_ZERO_DATE))
+ if (item_execute_at->get_date(thd, &ltime, TIME_NO_ZERO_DATE))
goto wrong_value;
ltime_utc= TIME_to_timestamp(thd,&ltime,&not_used);
@@ -275,7 +275,7 @@ Event_parse_data::init_interval(THD *thd)
if (item_expression->fix_fields(thd, &item_expression))
goto wrong_value;
- if (get_interval_value(item_expression, interval, &interval_tmp))
+ if (get_interval_value(thd, item_expression, interval, &interval_tmp))
goto wrong_value;
expression= 0;
@@ -378,7 +378,7 @@ Event_parse_data::init_starts(THD *thd)
if (item_starts->fix_fields(thd, &item_starts))
goto wrong_value;
- if (item_starts->get_date(&ltime, TIME_NO_ZERO_DATE))
+ if (item_starts->get_date(thd, &ltime, TIME_NO_ZERO_DATE))
goto wrong_value;
ltime_utc= TIME_to_timestamp(thd, &ltime, &not_used);
@@ -433,7 +433,7 @@ Event_parse_data::init_ends(THD *thd)
goto error_bad_params;
DBUG_PRINT("info", ("convert to TIME"));
- if (item_ends->get_date(&ltime, TIME_NO_ZERO_DATE))
+ if (item_ends->get_date(thd, &ltime, TIME_NO_ZERO_DATE))
goto error_bad_params;
ltime_utc= TIME_to_timestamp(thd, &ltime, &not_used);
diff --git a/sql/events.cc b/sql/events.cc
index af020d5240e..196c8df591d 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -336,7 +336,7 @@ Events::create_event(THD *thd, Event_parse_data *parse_data)
if (check_access(thd, EVENT_ACL, parse_data->dbname.str, NULL, NULL, 0, 0))
DBUG_RETURN(TRUE);
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
if (lock_object_name(thd, MDL_key::EVENT,
parse_data->dbname.str, parse_data->name.str))
@@ -420,9 +420,9 @@ Events::create_event(THD *thd, Event_parse_data *parse_data)
DBUG_RETURN(ret);
#ifdef WITH_WSREP
- error:
- DBUG_RETURN(TRUE);
-#endif /* WITH_WSREP */
+wsrep_error_label:
+ DBUG_RETURN(true);
+#endif
}
@@ -463,6 +463,7 @@ Events::update_event(THD *thd, Event_parse_data *parse_data,
if (check_access(thd, EVENT_ACL, parse_data->dbname.str, NULL, NULL, 0, 0))
DBUG_RETURN(TRUE);
+
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
if (lock_object_name(thd, MDL_key::EVENT,
@@ -550,9 +551,9 @@ Events::update_event(THD *thd, Event_parse_data *parse_data,
thd->restore_stmt_binlog_format(save_binlog_format);
DBUG_RETURN(ret);
#ifdef WITH_WSREP
-error:
- DBUG_RETURN(TRUE);
-#endif /* WITH_WSREP */
+wsrep_error_label:
+ DBUG_RETURN(true);
+#endif
}
@@ -593,6 +594,7 @@ Events::drop_event(THD *thd, const LEX_CSTRING *dbname,
if (check_access(thd, EVENT_ACL, dbname->str, NULL, NULL, 0, 0))
DBUG_RETURN(TRUE);
+
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
/*
@@ -617,9 +619,9 @@ Events::drop_event(THD *thd, const LEX_CSTRING *dbname,
thd->restore_stmt_binlog_format(save_binlog_format);
DBUG_RETURN(ret);
#ifdef WITH_WSREP
-error:
- DBUG_RETURN(TRUE);
-#endif /* WITH_WSREP */
+wsrep_error_label:
+ DBUG_RETURN(true);
+#endif
}
diff --git a/sql/field.cc b/sql/field.cc
index e014b62788a..7e27ed1bfc3 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1832,7 +1832,7 @@ int Field::store_timestamp(my_time_t ts, ulong sec_part)
{
MYSQL_TIME ltime;
THD *thd= get_thd();
- thd->timestamp_to_TIME(&ltime, ts, sec_part, 0);
+ thd->timestamp_to_TIME(&ltime, ts, sec_part, date_mode_t(0));
return store_time_dec(&ltime, decimals());
}
@@ -2064,17 +2064,16 @@ my_decimal* Field_int::val_decimal(my_decimal *decimal_value)
}
-bool Field_int::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Field_int::get_date(MYSQL_TIME *ltime,date_mode_t fuzzydate)
{
ASSERT_COLUMN_MARKED_FOR_READ;
- longlong nr= val_int();
- bool neg= !(flags & UNSIGNED_FLAG) && nr < 0;
- return int_to_datetime_with_warn(neg, neg ? -nr : nr, ltime, fuzzydate,
- field_name.str);
+ Longlong_hybrid nr(val_int(), (flags & UNSIGNED_FLAG));
+ return int_to_datetime_with_warn(get_thd(), nr, ltime,
+ fuzzydate, field_name.str);
}
-bool Field_vers_trx_id::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate, ulonglong trx_id)
+bool Field_vers_trx_id::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate, ulonglong trx_id)
{
ASSERT_COLUMN_MARKED_FOR_READ;
DBUG_ASSERT(ltime);
@@ -2254,15 +2253,13 @@ uint Field::fill_cache_field(CACHE_FIELD *copy)
}
-bool Field::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Field::get_date(MYSQL_TIME *to, date_mode_t mode)
{
- char buff[40];
- String tmp(buff,sizeof(buff),&my_charset_bin),*res;
- if (!(res=val_str(&tmp)) ||
- str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(),
- ltime, fuzzydate))
- return 1;
- return 0;
+ StringBuffer<40> tmp;
+ Temporal::Warn_push warn(get_thd(), NullS, to, mode);
+ Temporal_hybrid *t= new(to) Temporal_hybrid(get_thd(), &warn,
+ val_str(&tmp), mode);
+ return !t->is_valid_temporal();
}
/**
@@ -3106,6 +3103,12 @@ Field *Field_decimal::make_new_field(MEM_ROOT *root, TABLE *new_table,
** Field_new_decimal
****************************************************************************/
+static uint get_decimal_precision(uint len, uint8 dec, bool unsigned_val)
+{
+ uint precision= my_decimal_length_to_precision(len, dec, unsigned_val);
+ return MY_MIN(precision, DECIMAL_MAX_PRECISION);
+}
+
Field_new_decimal::Field_new_decimal(uchar *ptr_arg,
uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
@@ -3116,8 +3119,7 @@ Field_new_decimal::Field_new_decimal(uchar *ptr_arg,
:Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, dec_arg, zero_arg, unsigned_arg)
{
- precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
- set_if_smaller(precision, DECIMAL_MAX_PRECISION);
+ precision= get_decimal_precision(len_arg, dec_arg, unsigned_arg);
DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION) &&
(dec <= DECIMAL_MAX_SCALE));
bin_size= my_decimal_get_binary_size(precision, dec);
@@ -4507,7 +4509,7 @@ longlong Field_float::val_int(void)
{
float j;
float4get(j,ptr);
- return (longlong) rint(j);
+ return Converter_double_to_longlong(j, false).result();
}
@@ -4825,11 +4827,12 @@ my_decimal *Field_real::val_decimal(my_decimal *decimal_value)
}
-bool Field_real::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Field_real::get_date(MYSQL_TIME *ltime,date_mode_t fuzzydate)
{
ASSERT_COLUMN_MARKED_FOR_READ;
double nr= val_real();
- return double_to_datetime_with_warn(nr, ltime, fuzzydate, field_name.str);
+ return double_to_datetime_with_warn(get_thd(), nr, ltime, fuzzydate,
+ field_name.str);
}
@@ -5058,8 +5061,9 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, const Datetime *dt,
return 1; // date was fine but pointed to a DST gap
}
- // Adjust and store the value
- store_TIMEVAL(Timeval(timestamp, l_time->second_part).trunc(decimals()));
+ // Store the value
+ DBUG_ASSERT(!dt->fraction_remainder(decimals()));
+ store_TIMEVAL(Timeval(timestamp, l_time->second_part));
// Calculate return value and send warnings if needed
if (unlikely(conversion_error)) // e.g. DATETIME in the DST gap
@@ -5072,10 +5076,10 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, const Datetime *dt,
}
-sql_mode_t Field_timestamp::sql_mode_for_timestamp(THD *thd) const
+date_mode_t Field_timestamp::sql_mode_for_timestamp(THD *thd) const
{
// We don't want to store invalid or fuzzy datetime values in TIMESTAMP
- return (thd->variables.sql_mode & MODE_NO_ZERO_DATE) | MODE_NO_ZERO_IN_DATE;
+ return date_mode_t((thd->variables.sql_mode & MODE_NO_ZERO_DATE) | MODE_NO_ZERO_IN_DATE);
}
@@ -5084,7 +5088,7 @@ int Field_timestamp::store_time_dec(const MYSQL_TIME *ltime, uint dec)
int warn;
ErrConvTime str(ltime);
THD *thd= get_thd();
- Datetime dt(thd, &warn, ltime, sql_mode_for_timestamp(thd));
+ Datetime dt(thd, &warn, ltime, sql_mode_for_timestamp(thd), decimals());
return store_TIME_with_warning(thd, &dt, &str, warn);
}
@@ -5093,9 +5097,9 @@ int Field_timestamp::store(const char *from,size_t len,CHARSET_INFO *cs)
{
ErrConvString str(from, len, cs);
THD *thd= get_thd();
- int error;
- Datetime dt(&error, from, len, cs, sql_mode_for_timestamp(thd));
- return store_TIME_with_warning(thd, &dt, &str, error);
+ MYSQL_TIME_STATUS st;
+ Datetime dt(&st, from, len, cs, sql_mode_for_timestamp(thd), decimals());
+ return store_TIME_with_warning(thd, &dt, &str, st.warnings);
}
@@ -5104,7 +5108,7 @@ int Field_timestamp::store(double nr)
int error;
ErrConvDouble str(nr);
THD *thd= get_thd();
- Datetime dt(&error, nr, sql_mode_for_timestamp(thd));
+ Datetime dt(&error, Sec6(nr), sql_mode_for_timestamp(thd), decimals());
return store_TIME_with_warning(thd, &dt, &str, error);
}
@@ -5112,9 +5116,9 @@ int Field_timestamp::store(double nr)
int Field_timestamp::store(longlong nr, bool unsigned_val)
{
int error;
- ErrConvInteger str(nr, unsigned_val);
+ ErrConvInteger str(Longlong_hybrid(nr, unsigned_val));
THD *thd= get_thd();
- Datetime dt(&error, nr, unsigned_val, sql_mode_for_timestamp(thd));
+ Datetime dt(&error, Sec6(nr, unsigned_val), sql_mode_for_timestamp(thd));
return store_TIME_with_warning(thd, &dt, &str, error);
}
@@ -5123,7 +5127,7 @@ int Field_timestamp::store_timestamp(my_time_t ts, ulong sec_part)
{
store_TIME(ts, sec_part);
if (ts == 0 && sec_part == 0 &&
- get_thd()->variables.sql_mode & TIME_NO_ZERO_DATE)
+ get_thd()->variables.sql_mode & (ulonglong) TIME_NO_ZERO_DATE)
{
ErrConvString s(
STRING_WITH_LEN("0000-00-00 00:00:00.000000") - (decimals() ? 6 - decimals() : 7),
@@ -5232,11 +5236,11 @@ Field_timestamp::validate_value_in_record(THD *thd, const uchar *record) const
DBUG_ASSERT(!is_null_in_record(record));
ulong sec_part;
return !get_timestamp(ptr_in_record(record), &sec_part) && !sec_part &&
- (sql_mode_for_dates(thd) & TIME_NO_ZERO_DATE) != 0;
+ bool(sql_mode_for_dates(thd) & TIME_NO_ZERO_DATE) != false;
}
-bool Field_timestamp::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Field_timestamp::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
ulong sec_part;
my_time_t ts= get_timestamp(&sec_part);
@@ -5247,7 +5251,7 @@ bool Field_timestamp::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
bool Field_timestamp::send_binary(Protocol *protocol)
{
MYSQL_TIME ltime;
- Field_timestamp::get_date(&ltime, 0);
+ Field_timestamp::get_date(&ltime, date_mode_t(0));
return protocol->store(&ltime, 0);
}
@@ -5405,7 +5409,7 @@ double Field_timestamp_with_dec::val_real(void)
my_decimal *Field_timestamp_with_dec::val_decimal(my_decimal *d)
{
MYSQL_TIME ltime;
- get_date(&ltime, 0);
+ get_date(&ltime, date_mode_t(0));
return TIME_to_my_decimal(&ltime, d);
}
@@ -5414,7 +5418,7 @@ int Field_timestamp::store_decimal(const my_decimal *d)
int error;
THD *thd= get_thd();
ErrConvDecimal str(d);
- Datetime dt(&error, d, sql_mode_for_timestamp(thd));
+ Datetime dt(&error, Sec6(d), sql_mode_for_timestamp(thd), decimals());
return store_TIME_with_warning(thd, &dt, &str, error);
}
@@ -5430,7 +5434,7 @@ int Field_timestamp_with_dec::set_time()
bool Field_timestamp_with_dec::send_binary(Protocol *protocol)
{
MYSQL_TIME ltime;
- Field_timestamp::get_date(&ltime, 0);
+ Field_timestamp::get_date(&ltime, date_mode_t(0));
return protocol->store(&ltime, dec);
}
@@ -5535,81 +5539,66 @@ void Field_temporal::set_warnings(Sql_condition::enum_warning_level trunc_level,
3 Datetime value that was cut (warning level NOTE)
This is used by opt_range.cc:get_mm_leaf().
*/
-int Field_temporal_with_date::store_TIME_with_warning(const Datetime *dt,
- const ErrConv *str,
- int was_cut)
+int Field_datetime::store_TIME_with_warning(const Datetime *dt,
+ const ErrConv *str,
+ int was_cut)
{
- Sql_condition::enum_warning_level trunc_level= Sql_condition::WARN_LEVEL_WARN;
- timestamp_type ts_type= type_handler()->mysql_timestamp_type();
-
ASSERT_COLUMN_MARKED_FOR_WRITE;
// Handle totally bad values
if (!dt->is_valid_datetime())
- {
- static const Datetime zero;
- store_TIME(zero.get_mysql_time());
- if (was_cut == 0) // special case: zero date
- {
- set_warnings(trunc_level, str, MYSQL_TIME_WARN_OUT_OF_RANGE, ts_type);
- return 2;
- }
- set_warnings(trunc_level, str, MYSQL_TIME_WARN_TRUNCATED, ts_type);
- return 1;
- }
- // Adjust and store the value
- if (ts_type == MYSQL_TIMESTAMP_DATE)
- {
- if (!dt->hhmmssff_is_zero())
- was_cut|= MYSQL_TIME_NOTE_TRUNCATED;
- store_TIME(dt->get_mysql_time());
- }
- else if (dt->fraction_remainder(decimals()))
- {
- Datetime truncated(dt->trunc(decimals()));
- store_TIME(truncated.get_mysql_time());
- }
- else
- store_TIME(dt->get_mysql_time());
+ return store_invalid_with_warning(str, was_cut, MYSQL_TIMESTAMP_DATETIME);
+ // Store the value
+ DBUG_ASSERT(!dt->fraction_remainder(decimals()));
+ store_TIME(dt->get_mysql_time());
// Caclulate return value and send warnings if needed
- return store_TIME_return_code_with_warnings(was_cut, str, ts_type);
+ return store_TIME_return_code_with_warnings(was_cut, str,
+ MYSQL_TIMESTAMP_DATETIME);
}
-int Field_temporal_with_date::store(const char *from, size_t len, CHARSET_INFO *cs)
+int Field_datetime::store(const char *from, size_t len, CHARSET_INFO *cs)
{
- int error;
+ MYSQL_TIME_STATUS st;
ErrConvString str(from, len, cs);
- Datetime dt(&error, from, len, cs, sql_mode_for_dates(get_thd()));
- return store_TIME_with_warning(&dt, &str, error);
+ Datetime dt(&st, from, len, cs, sql_mode_for_dates(get_thd()), decimals());
+ return store_TIME_with_warning(&dt, &str, st.warnings);
}
-int Field_temporal_with_date::store(double nr)
+int Field_datetime::store(double nr)
{
int error;
ErrConvDouble str(nr);
- Datetime dt(&error, nr, sql_mode_for_dates(get_thd()));
+ Datetime dt(&error, Sec6(nr), sql_mode_for_dates(get_thd()), decimals());
return store_TIME_with_warning(&dt, &str, error);
}
-int Field_temporal_with_date::store(longlong nr, bool unsigned_val)
+int Field_datetime::store(longlong nr, bool unsigned_val)
{
int error;
- ErrConvInteger str(nr, unsigned_val);
- Datetime dt(&error, nr, unsigned_val, sql_mode_for_dates(get_thd()));
+ ErrConvInteger str(Longlong_hybrid(nr, unsigned_val));
+ Datetime dt(&error, Sec6(nr, unsigned_val), sql_mode_for_dates(get_thd()));
return store_TIME_with_warning(&dt, &str, error);
}
-int Field_temporal_with_date::store_time_dec(const MYSQL_TIME *ltime, uint dec)
+int Field_datetime::store_time_dec(const MYSQL_TIME *ltime, uint dec)
{
int error;
ErrConvTime str(ltime);
THD *thd= get_thd();
- Datetime dt(thd, &error, ltime, sql_mode_for_dates(thd));
+ Datetime dt(thd, &error, ltime, sql_mode_for_dates(thd), decimals());
return store_TIME_with_warning(&dt, &str, error);
}
+int Field_datetime::store_decimal(const my_decimal *d)
+{
+ int error;
+ ErrConvDecimal str(d);
+ Datetime tm(&error, Sec6(d), sql_mode_for_dates(get_thd()), decimals());
+ return store_TIME_with_warning(&tm, &str, error);
+}
+
bool
Field_temporal_with_date::validate_value_in_record(THD *thd,
const uchar *record) const
@@ -5623,7 +5612,7 @@ Field_temporal_with_date::validate_value_in_record(THD *thd,
my_decimal *Field_temporal::val_decimal(my_decimal *d)
{
MYSQL_TIME ltime;
- if (get_date(&ltime, 0))
+ if (get_date(&ltime, date_mode_t(0)))
{
bzero(&ltime, sizeof(ltime));
ltime.time_type= type_handler()->mysql_timestamp_type();
@@ -5656,7 +5645,7 @@ Item *Field_temporal::get_equal_const_item_datetime(THD *thd,
const_item->field_type() != MYSQL_TYPE_TIMESTAMP) ||
const_item->decimals != decimals())
{
- Datetime dt(thd, const_item, 0);
+ Datetime dt(thd, const_item, date_mode_t(0));
if (!dt.is_valid_datetime())
return NULL;
/*
@@ -5698,20 +5687,10 @@ int Field_time::store_TIME_with_warning(const Time *t,
ASSERT_COLUMN_MARKED_FOR_WRITE;
// Handle totally bad values
if (!t->is_valid_time())
- {
- static const Datetime zero;
- store_TIME(zero.get_mysql_time());
- set_warnings(Sql_condition::WARN_LEVEL_WARN, str, MYSQL_TIME_WARN_TRUNCATED);
- return 1;
- }
- // Adjust and store the value
- if (t->fraction_remainder(decimals()))
- {
- Time truncated(t->trunc(decimals()));
- store_TIME(truncated.get_mysql_time());
- }
- else
- store_TIME(t->get_mysql_time());
+ return store_invalid_with_warning(str, warn, MYSQL_TIMESTAMP_TIME);
+ // Store the value
+ DBUG_ASSERT(!t->fraction_remainder(decimals()));
+ store_TIME(t->get_mysql_time());
// Calculate return value and send warnings if needed
return store_TIME_return_code_with_warnings(warn, str, MYSQL_TIMESTAMP_TIME);
}
@@ -5731,9 +5710,10 @@ void Field_time::store_TIME(const MYSQL_TIME *ltime)
int Field_time::store(const char *from,size_t len,CHARSET_INFO *cs)
{
ErrConvString str(from, len, cs);
- int error;
- Time tm(&error, from, len, cs, sql_mode_for_dates(get_thd()));
- return store_TIME_with_warning(&tm, &str, error);
+ MYSQL_TIME_STATUS st;
+ THD *thd= get_thd();
+ Time tm(thd, &st, from, len, cs, sql_mode_for_dates(thd), decimals());
+ return store_TIME_with_warning(&tm, &str, st.warnings);
}
@@ -5741,7 +5721,7 @@ int Field_time::store_time_dec(const MYSQL_TIME *ltime, uint dec)
{
ErrConvTime str(ltime);
int warn;
- Time tm(&warn, ltime, curdays);
+ Time tm(&warn, ltime, curdays, decimals());
return store_TIME_with_warning(&tm, &str, warn);
}
@@ -5750,16 +5730,17 @@ int Field_time::store(double nr)
{
ErrConvDouble str(nr);
int was_cut;
- Time tm(&was_cut, nr);
+ Time tm(get_thd(), &was_cut, Sec6(nr), decimals());
return store_TIME_with_warning(&tm, &str, was_cut);
}
int Field_time::store(longlong nr, bool unsigned_val)
{
- ErrConvInteger str(nr, unsigned_val);
+ ErrConvInteger str(Longlong_hybrid(nr, unsigned_val));
int was_cut;
- Time tm(&was_cut, nr, unsigned_val);
+ // Need fractional digit truncation if nr overflows to '838:59:59.999999'
+ Time tm(get_thd(), &was_cut, Sec6(nr, unsigned_val), decimals());
return store_TIME_with_warning(&tm, &str, was_cut);
}
@@ -5819,7 +5800,7 @@ String *Field_time::val_str(String *str,
}
-bool Field_time::check_zero_in_date_with_warn(ulonglong fuzzydate)
+bool Field_time::check_zero_in_date_with_warn(date_mode_t fuzzydate)
{
if (!(fuzzydate & TIME_TIME_ONLY) && (fuzzydate & TIME_NO_ZERO_IN_DATE))
{
@@ -5841,7 +5822,7 @@ bool Field_time::check_zero_in_date_with_warn(ulonglong fuzzydate)
DATE_FORMAT(time, "%l.%i %p")
*/
-bool Field_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Field_time::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
if (check_zero_in_date_with_warn(fuzzydate))
return true;
@@ -5917,7 +5898,7 @@ int Field_time::store_decimal(const my_decimal *d)
{
ErrConvDecimal str(d);
int was_cut;
- Time tm(&was_cut, d);
+ Time tm(get_thd(), &was_cut, Sec6(d), decimals());
return store_TIME_with_warning(&tm, &str, was_cut);
}
@@ -5977,7 +5958,7 @@ Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx,
if (const_item->field_type() != MYSQL_TYPE_TIME)
{
// Get the value of const_item with conversion from DATETIME to TIME
- Time tm(const_item,
+ Time tm(get_thd(), const_item,
Time::Options(Time::comparison_flags_for_get_date(), mode));
if (!tm.is_valid_time())
return NULL;
@@ -6002,7 +5983,8 @@ Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx,
if (const_item->field_type() != MYSQL_TYPE_TIME ||
const_item->decimals != decimals())
{
- Time tm(const_item, Time::Options(TIME_TIME_ONLY, mode));
+ Time tm(get_thd(), const_item,
+ Time::Options(TIME_TIME_ONLY, mode));
if (!tm.is_valid_time())
return NULL;
/*
@@ -6045,7 +6027,7 @@ double Field_time_with_dec::val_real(void)
return TIME_to_double(&ltime);
}
-bool Field_time_hires::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Field_time_hires::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
if (check_zero_in_date_with_warn(fuzzydate))
return true;
@@ -6097,7 +6079,7 @@ void Field_timef::store_TIME(const MYSQL_TIME *ltime)
my_time_packed_to_binary(tmp, ptr, dec);
}
-bool Field_timef::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Field_timef::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
if (check_zero_in_date_with_warn(fuzzydate))
return true;
@@ -6231,12 +6213,13 @@ String *Field_year::val_str(String *val_buffer,
}
-bool Field_year::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Field_year::get_date(MYSQL_TIME *ltime,date_mode_t fuzzydate)
{
int tmp= (int) ptr[0];
if (tmp || field_length != 4)
tmp+= 1900;
- return int_to_datetime_with_warn(false, tmp * 10000,
+ return int_to_datetime_with_warn(get_thd(),
+ Longlong_hybrid(tmp * 10000, true),
ltime, fuzzydate, field_name.str);
}
@@ -6249,6 +6232,67 @@ void Field_year::sql_type(String &res) const
}
+/*****************************************************************************/
+
+int Field_date_common::store_TIME_with_warning(const Datetime *dt,
+ const ErrConv *str,
+ int was_cut)
+{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
+ // Handle totally bad values
+ if (!dt->is_valid_datetime())
+ return store_invalid_with_warning(str, was_cut, MYSQL_TIMESTAMP_DATE);
+ // Store the value
+ if (!dt->hhmmssff_is_zero())
+ was_cut|= MYSQL_TIME_NOTE_TRUNCATED;
+ store_TIME(dt->get_mysql_time());
+ // Caclulate return value and send warnings if needed
+ return store_TIME_return_code_with_warnings(was_cut, str,
+ MYSQL_TIMESTAMP_DATE);
+}
+
+int Field_date_common::store(const char *from, size_t len, CHARSET_INFO *cs)
+{
+ MYSQL_TIME_STATUS st;
+ ErrConvString str(from, len, cs);
+ Datetime dt(&st, from, len, cs, sql_mode_for_dates(get_thd()));
+ return store_TIME_with_warning(&dt, &str, st.warnings);
+}
+
+int Field_date_common::store(double nr)
+{
+ int error;
+ ErrConvDouble str(nr);
+ Datetime dt(&error, Sec6(nr), sql_mode_for_dates(get_thd()));
+ return store_TIME_with_warning(&dt, &str, error);
+}
+
+int Field_date_common::store(longlong nr, bool unsigned_val)
+{
+ int error;
+ ErrConvInteger str(Longlong_hybrid(nr, unsigned_val));
+ Datetime dt(&error, Sec6(nr, unsigned_val), sql_mode_for_dates(get_thd()));
+ return store_TIME_with_warning(&dt, &str, error);
+}
+
+int Field_date_common::store_time_dec(const MYSQL_TIME *ltime, uint dec)
+{
+ int error;
+ ErrConvTime str(ltime);
+ THD *thd= get_thd();
+ Datetime dt(thd, &error, ltime, sql_mode_for_dates(thd));
+ return store_TIME_with_warning(&dt, &str, error);
+}
+
+int Field_date_common::store_decimal(const my_decimal *d)
+{
+ int error;
+ ErrConvDecimal str(d);
+ Datetime tm(&error, Sec6(d), sql_mode_for_dates(get_thd()));
+ return store_TIME_with_warning(&tm, &str, error);
+}
+
+
/****************************************************************************
** date type
** In string context: YYYY-MM-DD
@@ -6292,7 +6336,7 @@ longlong Field_date::val_int(void)
bool Field_date::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
ASSERT_COLUMN_MARKED_FOR_READ;
int32 tmp= sint4korr(pos);
@@ -6309,7 +6353,7 @@ String *Field_date::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
MYSQL_TIME ltime;
- get_TIME(&ltime, ptr, 0);
+ get_TIME(&ltime, ptr, date_mode_t(0));
val_buffer->alloc(MAX_DATE_STRING_REP_LENGTH);
uint length= (uint) my_date_to_str(&ltime,
const_cast<char*>(val_buffer->ptr()));
@@ -6359,7 +6403,7 @@ void Field_newdate::store_TIME(const MYSQL_TIME *ltime)
bool Field_newdate::send_binary(Protocol *protocol)
{
MYSQL_TIME tm;
- Field_newdate::get_date(&tm,0);
+ Field_newdate::get_date(&tm, date_mode_t(0));
return protocol->store_date(&tm);
}
@@ -6411,7 +6455,7 @@ String *Field_newdate::val_str(String *val_buffer,
bool Field_newdate::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
ASSERT_COLUMN_MARKED_FOR_READ;
uint32 tmp=(uint32) uint3korr(pos);
@@ -6482,7 +6526,7 @@ Item *Field_newdate::get_equal_const_item(THD *thd, const Context &ctx,
case IDENTITY_SUBST:
if (const_item->field_type() != MYSQL_TYPE_DATE)
{
- Date d(thd, const_item, 0);
+ Date d(thd, const_item, date_mode_t(0));
if (!d.is_valid_date())
return NULL;
return new (thd->mem_root) Item_date_literal(thd, d.get_mysql_time());
@@ -6509,7 +6553,7 @@ void Field_datetime::store_TIME(const MYSQL_TIME *ltime)
bool Field_datetime::send_binary(Protocol *protocol)
{
MYSQL_TIME tm;
- Field_datetime::get_date(&tm, 0);
+ Field_datetime::get_date(&tm, date_mode_t(0));
return protocol->store(&tm, 0);
}
@@ -6575,7 +6619,7 @@ String *Field_datetime::val_str(String *val_buffer,
}
bool Field_datetime::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
ASSERT_COLUMN_MARKED_FOR_READ;
longlong tmp= sint8korr(pos);
@@ -6651,18 +6695,10 @@ void Field_datetime_hires::store_TIME(const MYSQL_TIME *ltime)
store_bigendian(packed, ptr, Field_datetime_hires::pack_length());
}
-int Field_temporal_with_date::store_decimal(const my_decimal *d)
-{
- int error;
- ErrConvDecimal str(d);
- Datetime tm(&error, d, sql_mode_for_dates(get_thd()));
- return store_TIME_with_warning(&tm, &str, error);
-}
-
bool Field_datetime_with_dec::send_binary(Protocol *protocol)
{
MYSQL_TIME ltime;
- get_date(&ltime, 0);
+ get_date(&ltime, date_mode_t(0));
return protocol->store(&ltime, dec);
}
@@ -6670,14 +6706,14 @@ bool Field_datetime_with_dec::send_binary(Protocol *protocol)
double Field_datetime_with_dec::val_real(void)
{
MYSQL_TIME ltime;
- get_date(&ltime, 0);
+ get_date(&ltime, date_mode_t(0));
return TIME_to_double(&ltime);
}
longlong Field_datetime_with_dec::val_int(void)
{
MYSQL_TIME ltime;
- get_date(&ltime, 0);
+ get_date(&ltime, date_mode_t(0));
return TIME_to_ulonglong_datetime(&ltime);
}
@@ -6686,7 +6722,7 @@ String *Field_datetime_with_dec::val_str(String *str,
String *unused __attribute__((unused)))
{
MYSQL_TIME ltime;
- get_date(&ltime, 0);
+ get_date(&ltime, date_mode_t(0));
str->alloc(field_length+1);
str->length(field_length);
my_datetime_to_str(&ltime, (char*) str->ptr(), dec);
@@ -6696,7 +6732,7 @@ String *Field_datetime_with_dec::val_str(String *str,
bool Field_datetime_hires::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
ASSERT_COLUMN_MARKED_FOR_READ;
ulonglong packed= read_bigendian(pos, Field_datetime_hires::pack_length());
@@ -6736,7 +6772,7 @@ void Field_datetimef::store_TIME(const MYSQL_TIME *ltime)
}
bool Field_datetimef::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
ASSERT_COLUMN_MARKED_FOR_READ;
longlong tmp= my_datetime_packed_from_binary(pos, dec);
@@ -7120,7 +7156,9 @@ int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr)
void Field_string::sort_string(uchar *to,uint length)
{
- IF_DBUG(size_t tmp= ,)
+#ifdef DBUG_ASSERT_EXISTS
+ size_t tmp=
+#endif
field_charset->coll->strnxfrm(field_charset,
to, length,
char_length() *
@@ -7526,7 +7564,7 @@ void Field_varstring::sort_string(uchar *to,uint length)
length-= length_bytes;
}
-#ifndef DBUG_OFF
+#ifdef DBUG_ASSERT_EXISTS
size_t rc=
#endif
field_charset->coll->strnxfrm(field_charset, to, length,
@@ -8064,7 +8102,13 @@ int Field_blob::store(const char *from,size_t length,CHARSET_INFO *cs)
return 0;
}
- if (table->blob_storage) // GROUP_CONCAT with ORDER BY | DISTINCT
+ /*
+ For min/max fields of statistical data 'table' is set to NULL.
+ It could not be otherwise as this data is shared by many instances
+ of the same base table.
+ */
+
+ if (table && table->blob_storage) // GROUP_CONCAT with ORDER BY | DISTINCT
{
DBUG_ASSERT(!f_is_hex_escape(flags));
DBUG_ASSERT(field_charset == cs);
@@ -8388,7 +8432,7 @@ void Field_blob::sort_string(uchar *to,uint length)
store_bigendian(buf.length(), to + length, packlength);
}
-#ifndef DBUG_OFF
+#ifdef DBUG_ASSERT_EXISTS
size_t rc=
#endif
field_charset->coll->strnxfrm(field_charset, to, length, length,
@@ -10128,12 +10172,9 @@ void Column_definition::create_length_to_internal_length_bit()
void Column_definition::create_length_to_internal_length_newdecimal()
{
- key_length= pack_length=
- my_decimal_get_binary_size(my_decimal_length_to_precision((uint) length,
- decimals,
- flags &
- UNSIGNED_FLAG),
- decimals);
+ DBUG_ASSERT(length < UINT_MAX32);
+ uint prec= get_decimal_precision((uint)length, decimals, flags & UNSIGNED_FLAG);
+ key_length= pack_length= my_decimal_get_binary_size(prec, decimals);
}
diff --git a/sql/field.h b/sql/field.h
index 8b080a0d06f..eb39b6bcec9 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1342,7 +1342,7 @@ public:
}
void copy_from_tmp(int offset);
uint fill_cache_field(struct st_cache_field *copy);
- virtual bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ virtual bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool get_time(MYSQL_TIME *ltime) { return get_date(ltime, TIME_TIME_ONLY); }
virtual TYPELIB *get_typelib() const { return NULL; }
virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; }
@@ -1958,7 +1958,7 @@ public:
}
int store_decimal(const my_decimal *dec) { return store(dec->to_double()); }
int store_time_dec(const MYSQL_TIME *ltime, uint dec);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
my_decimal *val_decimal(my_decimal *);
bool val_bool() { return val_real() != 0e0; }
uint32 max_display_length() const { return field_length; }
@@ -2075,10 +2075,11 @@ public:
return my_decimal(ptr, precision, dec).
to_string(val_buffer, fixed_precision, dec, '0');
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return my_decimal(ptr, precision, dec).
- to_datetime_with_warn(ltime, fuzzydate, field_name.str);
+ my_decimal nr(ptr, precision, dec);
+ return decimal_to_datetime_with_warn(get_thd(), &nr, ltime,
+ fuzzydate, field_name.str);
}
bool val_bool()
{
@@ -2127,7 +2128,7 @@ public:
return nr < 0 && !unsigned_flag ? 0 : (ulonglong) nr;
}
int store_time_dec(const MYSQL_TIME *ltime, uint dec);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
virtual const Type_limits_int *type_limits_int() const= 0;
uint32 max_display_length() const
{
@@ -2390,7 +2391,6 @@ public:
{
return unpack_int64(to, from, from_end);
}
-
void set_max();
bool is_max();
};
@@ -2411,8 +2411,8 @@ public:
{}
const Type_handler *type_handler() const { return &type_handler_vers_trx_id; }
uint size_of() const { return sizeof(*this); }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate, ulonglong trx_id);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate, ulonglong trx_id);
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
return get_date(ltime, fuzzydate, (ulonglong) val_int());
}
@@ -2595,6 +2595,8 @@ class Field_temporal: public Field {
protected:
Item *get_equal_const_item_datetime(THD *thd, const Context &ctx,
Item *const_item);
+ void set_warnings(Sql_condition::enum_warning_level trunc_level,
+ const ErrConv *str, int was_cut, timestamp_type ts_type);
int store_TIME_return_code_with_warnings(int warn, const ErrConv *str,
timestamp_type ts_type)
{
@@ -2608,7 +2610,21 @@ protected:
set_warnings(Sql_condition::WARN_LEVEL_WARN, str, warn, ts_type);
return warn ? 2 : 0;
}
-
+ int store_invalid_with_warning(const ErrConv *str, int was_cut,
+ timestamp_type ts_type)
+ {
+ DBUG_ASSERT(was_cut);
+ reset();
+ Sql_condition::enum_warning_level level= Sql_condition::WARN_LEVEL_WARN;
+ if (was_cut & MYSQL_TIME_WARN_ZERO_DATE)
+ {
+ DBUG_ASSERT(ts_type != MYSQL_TIMESTAMP_TIME);
+ set_warnings(level, str, MYSQL_TIME_WARN_OUT_OF_RANGE, ts_type);
+ return 2;
+ }
+ set_warnings(level, str, MYSQL_TIME_WARN_TRUNCATED, ts_type);
+ return 1;
+ }
public:
Field_temporal(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
@@ -2624,7 +2640,7 @@ public:
int save_in_field(Field *to)
{
MYSQL_TIME ltime;
- if (get_date(&ltime, 0))
+ if (get_date(&ltime, date_mode_t(0)))
return to->reset();
return to->store_time_dec(&ltime, decimals());
}
@@ -2643,8 +2659,6 @@ public:
return (Field::eq_def(field) && decimals() == field->decimals());
}
my_decimal *val_decimal(my_decimal*);
- void set_warnings(Sql_condition::enum_warning_level trunc_level,
- const ErrConv *str, int was_cut, timestamp_type ts_type);
double pos_in_interval(Field *min, Field *max)
{
return pos_in_interval_val_real(min, max);
@@ -2674,19 +2688,16 @@ public:
*/
class Field_temporal_with_date: public Field_temporal {
protected:
- int store_TIME_with_warning(const Datetime *ltime, const ErrConv *str,
- int was_cut);
- void store_TIME_with_trunc(const Time *);
virtual void store_TIME(const MYSQL_TIME *ltime) = 0;
virtual bool get_TIME(MYSQL_TIME *ltime, const uchar *pos,
- ulonglong fuzzydate) const = 0;
+ date_mode_t fuzzydate) const = 0;
bool validate_MMDD(bool not_zero_date, uint month, uint day,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
if (!not_zero_date)
- return fuzzydate & TIME_NO_ZERO_DATE;
+ return bool(fuzzydate & TIME_NO_ZERO_DATE);
if (!month || !day)
- return fuzzydate & TIME_NO_ZERO_IN_DATE;
+ return bool(fuzzydate & TIME_NO_ZERO_IN_DATE);
return false;
}
public:
@@ -2697,18 +2708,13 @@ public:
:Field_temporal(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg)
{}
- int store(const char *to, size_t length, CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- int store_time_dec(const MYSQL_TIME *ltime, uint dec);
- int store_decimal(const my_decimal *);
bool validate_value_in_record(THD *thd, const uchar *record) const;
};
class Field_timestamp :public Field_temporal {
protected:
- sql_mode_t sql_mode_for_timestamp(THD *thd) const;
+ date_mode_t sql_mode_for_timestamp(THD *thd) const;
int store_TIME_with_warning(THD *, const Datetime *,
const ErrConv *, int warn);
virtual void store_TIMEVAL(const timeval &tv)
@@ -2758,7 +2764,7 @@ public:
{
store_TIMEVAL(Timeval(timestamp, sec_part).trunc(decimals()));
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
uchar *pack(uchar *to, const uchar *from,
uint max_length __attribute__((unused)))
{
@@ -2938,7 +2944,7 @@ public:
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool send_binary(Protocol *protocol);
Information_schema_numeric_attributes
information_schema_numeric_attributes() const
@@ -2952,6 +2958,9 @@ public:
class Field_date_common: public Field_temporal_with_date
{
+protected:
+ int store_TIME_with_warning(const Datetime *ltime, const ErrConv *str,
+ int was_cut);
public:
Field_date_common(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg,
@@ -2963,13 +2972,18 @@ public:
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
const Item_bool_func *cond,
scalar_comparison_op op, Item *value);
+ int store(const char *to, size_t length, CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr, bool unsigned_val);
+ int store_time_dec(const MYSQL_TIME *ltime, uint dec);
+ int store_decimal(const my_decimal *);
};
class Field_date :public Field_date_common
{
void store_TIME(const MYSQL_TIME *ltime);
- bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const;
+ bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate) const;
public:
Field_date(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg)
@@ -2978,7 +2992,7 @@ public:
const Type_handler *type_handler() const { return &type_handler_date; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{ return Field_date::get_TIME(ltime, ptr, fuzzydate); }
double val_real(void);
longlong val_int(void);
@@ -3005,7 +3019,7 @@ public:
class Field_newdate :public Field_date_common
{
void store_TIME(const MYSQL_TIME *ltime);
- bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const;
+ bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate) const;
public:
Field_newdate(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg)
@@ -3023,7 +3037,7 @@ public:
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 3; }
void sql_type(String &str) const;
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{ return Field_newdate::get_TIME(ltime, ptr, fuzzydate); }
uint size_of() const { return sizeof(*this); }
Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item);
@@ -3040,12 +3054,7 @@ class Field_time :public Field_temporal {
protected:
virtual void store_TIME(const MYSQL_TIME *ltime);
int store_TIME_with_warning(const Time *ltime, const ErrConv *str, int warn);
- void set_warnings(Sql_condition::enum_warning_level level,
- const ErrConv *str, int was_cut)
- {
- Field_temporal::set_warnings(level, str, was_cut, MYSQL_TIMESTAMP_TIME);
- }
- bool check_zero_in_date_with_warn(ulonglong fuzzydate);
+ bool check_zero_in_date_with_warn(date_mode_t fuzzydate);
static void do_field_time(Copy_field *copy);
public:
Field_time(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg,
@@ -3079,7 +3088,7 @@ public:
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool send_binary(Protocol *protocol);
int cmp(const uchar *,const uchar *);
void sort_string(uchar *buff,uint length);
@@ -3140,7 +3149,7 @@ public:
((TIME_MAX_VALUE_SECONDS+1LL)*TIME_SECOND_PART_FACTOR), dec);
}
int reset(void);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
int cmp(const uchar *,const uchar *);
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return Type_handler_time::hires_bytes(dec); }
@@ -3191,14 +3200,17 @@ public:
return memcmp(a_ptr, b_ptr, pack_length());
}
int reset();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
uint size_of() const { return sizeof(*this); }
};
class Field_datetime :public Field_temporal_with_date {
void store_TIME(const MYSQL_TIME *ltime);
- bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const;
+ bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate) const;
+protected:
+ int store_TIME_with_warning(const Datetime *ltime, const ErrConv *str,
+ int was_cut);
public:
Field_datetime(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg,
uchar null_bit_arg, enum utype unireg_check_arg,
@@ -3212,6 +3224,11 @@ public:
}
const Type_handler *type_handler() const { return &type_handler_datetime; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; }
+ int store(const char *to, size_t length, CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr, bool unsigned_val);
+ int store_time_dec(const MYSQL_TIME *ltime, uint dec);
+ int store_decimal(const my_decimal *);
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
@@ -3220,7 +3237,7 @@ public:
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 8; }
void sql_type(String &str) const;
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{ return Field_datetime::get_TIME(ltime, ptr, fuzzydate); }
int set_time();
int evaluate_update_default_function()
@@ -3291,7 +3308,7 @@ public:
*/
class Field_datetime_hires :public Field_datetime_with_dec {
void store_TIME(const MYSQL_TIME *ltime);
- bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const;
+ bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate) const;
public:
Field_datetime_hires(uchar *ptr_arg, uchar *null_ptr_arg,
uchar null_bit_arg, enum utype unireg_check_arg,
@@ -3303,7 +3320,7 @@ public:
}
int cmp(const uchar *,const uchar *);
uint32 pack_length() const { return Type_handler_datetime::hires_bytes(dec); }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{ return Field_datetime_hires::get_TIME(ltime, ptr, fuzzydate); }
uint size_of() const { return sizeof(*this); }
};
@@ -3314,7 +3331,7 @@ public:
*/
class Field_datetimef :public Field_datetime_with_dec {
void store_TIME(const MYSQL_TIME *ltime);
- bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const;
+ bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate) const;
int save_field_metadata(uchar *metadata_ptr)
{
*metadata_ptr= (uchar) decimals();
@@ -3345,7 +3362,7 @@ public:
return memcmp(a_ptr, b_ptr, pack_length());
}
int reset();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{ return Field_datetimef::get_TIME(ltime, ptr, fuzzydate); }
uint size_of() const { return sizeof(*this); }
};
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index f413dec82be..8b3d9c04656 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2010, 2016, MariaDB
+ Copyright (c) 2010, 2018, MariaDB Corporation
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
@@ -429,7 +429,7 @@ void Field::do_field_temporal(Copy_field *copy)
{
MYSQL_TIME ltime;
// TODO: we now need to check result
- if (copy->from_field->get_date(&ltime, 0))
+ if (copy->from_field->get_date(&ltime, date_mode_t(0)))
copy->to_field->reset();
else
copy->to_field->store_time_dec(&ltime, copy->from_field->decimals());
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 1855430b944..6f2a6096aa2 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -1004,7 +1004,9 @@ Type_handler_string_result::make_sort_key(uchar *to, Item *item,
if (use_strnxfrm(cs))
{
- IF_DBUG(size_t tmp_length= ,)
+#ifdef DBUG_ASSERT_EXISTS
+ size_t tmp_length=
+#endif
cs->coll->strnxfrm(cs, to, sort_field->length,
item->max_char_length() *
cs->strxfrm_multiply,
@@ -1055,7 +1057,7 @@ Type_handler_temporal_result::make_sort_key(uchar *to, Item *item,
Sort_param *param) const
{
MYSQL_TIME buf;
- if (item->get_date_result(&buf, TIME_INVALID_DATES))
+ if (item->get_date_result(current_thd, &buf, TIME_INVALID_DATES))
{
DBUG_ASSERT(item->maybe_null);
DBUG_ASSERT(item->null_value);
diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc
index ce1f4394ebd..9127bb95aeb 100644
--- a/sql/gcalc_slicescan.cc
+++ b/sql/gcalc_slicescan.cc
@@ -177,6 +177,17 @@ Gcalc_dyn_list::Gcalc_dyn_list(size_t blk_size, size_t sizeof_item):
{}
+Gcalc_dyn_list::Gcalc_dyn_list(const Gcalc_dyn_list &dl)
+{
+ m_blk_size= dl.m_blk_size;
+ m_sizeof_item= dl.m_sizeof_item;
+ m_points_per_blk= dl.m_points_per_blk;
+ m_blk_hook= &m_first_blk;
+ m_free= NULL;
+ m_keep= NULL;
+}
+
+
void Gcalc_dyn_list::format_blk(void* block)
{
Item *pi_end, *cur_pi, *first_pi;
diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h
index b9516fc8d8c..ebf173c1a57 100644
--- a/sql/gcalc_slicescan.h
+++ b/sql/gcalc_slicescan.h
@@ -63,6 +63,7 @@ public:
};
Gcalc_dyn_list(size_t blk_size, size_t sizeof_item);
+ Gcalc_dyn_list(const Gcalc_dyn_list &dl);
~Gcalc_dyn_list();
Item *new_item()
{
@@ -229,6 +230,12 @@ public:
Gcalc_dyn_list(blk_size, sizeof(Info)),
m_hook(&m_first), m_n_points(0)
{}
+
+ Gcalc_heap(const Gcalc_heap &gh) :
+ Gcalc_dyn_list(gh),
+ m_hook(&m_first), m_n_points(0)
+ {}
+
void set_extent(double xmin, double xmax, double ymin, double ymax);
Info *new_point_info(double x, double y, gcalc_shape_info shape);
void free_point_info(Info *i, Gcalc_dyn_list::Item **i_hook);
diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc
index 2aeaafc1a76..832a52db522 100644
--- a/sql/gcalc_tools.cc
+++ b/sql/gcalc_tools.cc
@@ -663,6 +663,17 @@ Gcalc_operation_reducer::Gcalc_operation_reducer(size_t blk_size) :
{}
+Gcalc_operation_reducer::Gcalc_operation_reducer(
+ const Gcalc_operation_reducer &gor) :
+ Gcalc_dyn_list(gor),
+#ifndef GCALC_DBUG_OFF
+ n_res_points(0),
+#endif /*GCALC_DBUG_OFF*/
+ m_res_hook((Gcalc_dyn_list::Item **)&m_result),
+ m_first_active_thread(NULL)
+{}
+
+
void Gcalc_operation_reducer::init(Gcalc_function *fn, modes mode)
{
m_fn= fn;
diff --git a/sql/gcalc_tools.h b/sql/gcalc_tools.h
index 8bda3c144a6..4d5aec0d443 100644
--- a/sql/gcalc_tools.h
+++ b/sql/gcalc_tools.h
@@ -224,6 +224,7 @@ public:
};
Gcalc_operation_reducer(size_t blk_size=8192);
+ Gcalc_operation_reducer(const Gcalc_operation_reducer &gor);
void init(Gcalc_function *fn, modes mode= default_mode);
Gcalc_operation_reducer(Gcalc_function *fn, modes mode= default_mode,
size_t blk_size=8192);
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 262e791ec7a..37a3decdbca 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -419,7 +419,7 @@ const char *ha_partition::table_type() const
ha_partition::~ha_partition()
{
- DBUG_ENTER("ha_partition::~ha_partition()");
+ DBUG_ENTER("ha_partition::~ha_partition");
if (m_new_partitions_share_refs.elements)
m_new_partitions_share_refs.delete_elements();
if (m_file != NULL)
@@ -634,7 +634,7 @@ int ha_partition::create_partitioning_metadata(const char *path,
const char *old_path,
int action_flag)
{
- DBUG_ENTER("ha_partition::create_partitioning_metadata()");
+ DBUG_ENTER("ha_partition::create_partitioning_metadata");
/*
We need to update total number of parts since we might write the handler
@@ -4034,9 +4034,14 @@ THR_LOCK_DATA **ha_partition::store_lock(THD *thd,
}
else
{
- for (i= bitmap_get_first_set(&(m_part_info->lock_partitions));
+ MY_BITMAP *used_partitions= lock_type == TL_UNLOCK ||
+ lock_type == TL_IGNORE ?
+ &m_locked_partitions :
+ &m_part_info->lock_partitions;
+
+ for (i= bitmap_get_first_set(used_partitions);
i < m_tot_parts;
- i= bitmap_get_next_set(&m_part_info->lock_partitions, i))
+ i= bitmap_get_next_set(used_partitions, i))
{
DBUG_PRINT("info", ("store lock %u iteration", i));
to= m_file[i]->store_lock(thd, to, lock_type);
@@ -8471,6 +8476,24 @@ err_handler:
}
+static int extra_cb(handler *h, void *operation)
+{
+ return h->extra(*(enum ha_extra_function*)operation);
+}
+
+
+static int start_keyread_cb(handler* h, void *p)
+{
+ return h->ha_start_keyread(*(uint*)p);
+}
+
+
+static int end_keyread_cb(handler* h, void *unused)
+{
+ return h->ha_end_keyread();
+}
+
+
/**
General function to prepare handler for certain behavior.
@@ -8799,11 +8822,12 @@ int ha_partition::extra(enum ha_extra_function operation)
switch (operation) {
/* Category 1), used by most handlers */
- case HA_EXTRA_KEYREAD:
case HA_EXTRA_NO_KEYREAD:
+ DBUG_RETURN(loop_partitions(end_keyread_cb, NULL));
+ case HA_EXTRA_KEYREAD:
case HA_EXTRA_FLUSH:
case HA_EXTRA_PREPARE_FOR_FORCED_CLOSE:
- DBUG_RETURN(loop_extra(operation));
+ DBUG_RETURN(loop_partitions(extra_cb, &operation));
case HA_EXTRA_PREPARE_FOR_RENAME:
case HA_EXTRA_FORCE_REOPEN:
DBUG_RETURN(loop_extra_alter(operation));
@@ -8815,7 +8839,7 @@ int ha_partition::extra(enum ha_extra_function operation)
case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
{
if (!m_myisam)
- DBUG_RETURN(loop_extra(operation));
+ DBUG_RETURN(loop_partitions(extra_cb, &operation));
}
break;
@@ -8842,7 +8866,7 @@ int ha_partition::extra(enum ha_extra_function operation)
case HA_EXTRA_REMEMBER_POS:
case HA_EXTRA_RESTORE_POS:
{
- DBUG_RETURN(loop_extra(operation));
+ DBUG_RETURN(loop_partitions(extra_cb, &operation));
}
case HA_EXTRA_NO_READCHECK:
{
@@ -8874,7 +8898,7 @@ int ha_partition::extra(enum ha_extra_function operation)
m_extra_cache_size= 0;
m_extra_prepare_for_update= FALSE;
m_extra_cache_part_id= NO_CURRENT_PART_ID;
- DBUG_RETURN(loop_extra(operation));
+ DBUG_RETURN(loop_partitions(extra_cb, &operation));
}
case HA_EXTRA_IGNORE_NO_KEY:
case HA_EXTRA_NO_IGNORE_NO_KEY:
@@ -8895,11 +8919,11 @@ int ha_partition::extra(enum ha_extra_function operation)
At this time, this is safe by limitation of ha_partition
*/
- DBUG_RETURN(loop_extra(operation));
+ DBUG_RETURN(loop_partitions(extra_cb, &operation));
}
/* Category 7), used by federated handlers */
case HA_EXTRA_INSERT_WITH_UPDATE:
- DBUG_RETURN(loop_extra(operation));
+ DBUG_RETURN(loop_partitions(extra_cb, &operation));
/* Category 8) Operations only used by NDB */
case HA_EXTRA_DELETE_CANNOT_BATCH:
case HA_EXTRA_UPDATE_CANNOT_BATCH:
@@ -8909,13 +8933,13 @@ int ha_partition::extra(enum ha_extra_function operation)
}
/* Category 9) Operations only used by MERGE */
case HA_EXTRA_ADD_CHILDREN_LIST:
- DBUG_RETURN(loop_extra(operation));
+ DBUG_RETURN(loop_partitions(extra_cb, &operation));
case HA_EXTRA_ATTACH_CHILDREN:
{
int result;
uint num_locks;
handler **file;
- if ((result= loop_extra(operation)))
+ if ((result= loop_partitions(extra_cb, &operation)))
DBUG_RETURN(result);
/* Recalculate lock count as each child may have different set of locks */
@@ -8930,9 +8954,9 @@ int ha_partition::extra(enum ha_extra_function operation)
break;
}
case HA_EXTRA_IS_ATTACHED_CHILDREN:
- DBUG_RETURN(loop_extra(operation));
+ DBUG_RETURN(loop_partitions(extra_cb, &operation));
case HA_EXTRA_DETACH_CHILDREN:
- DBUG_RETURN(loop_extra(operation));
+ DBUG_RETURN(loop_partitions(extra_cb, &operation));
case HA_EXTRA_MARK_AS_LOG_TABLE:
/*
http://dev.mysql.com/doc/refman/5.1/en/partitioning-limitations.html
@@ -8944,7 +8968,7 @@ int ha_partition::extra(enum ha_extra_function operation)
case HA_EXTRA_BEGIN_ALTER_COPY:
case HA_EXTRA_END_ALTER_COPY:
case HA_EXTRA_FAKE_START_STMT:
- DBUG_RETURN(loop_extra(operation));
+ DBUG_RETURN(loop_partitions(extra_cb, &operation));
default:
{
/* Temporary crash to discover what is wrong */
@@ -8952,7 +8976,7 @@ int ha_partition::extra(enum ha_extra_function operation)
break;
}
}
- DBUG_RETURN(0);
+ DBUG_RETURN(1);
}
@@ -8989,26 +9013,42 @@ int ha_partition::reset(void)
DBUG_RETURN(result);
}
-/*
- Special extra method for HA_EXTRA_CACHE with cachesize as extra parameter
+/**
+ Special extra method with additional parameter
+ See @ref ha_partition::extra
- SYNOPSIS
- extra_opt()
- operation Must be HA_EXTRA_CACHE
- cachesize Size of cache in full table scan
+ @param[in] operation operation to execute
+ @param[in] arg extra argument
- RETURN VALUE
- >0 Error code
- 0 Success
+ @return status
+ @retval 0 success
+ @retval >0 error code
+
+ @detail
+ Operations supported by extra_opt:
+ HA_EXTRA_KEYREAD:
+ arg is interpreted as key index
+ HA_EXTRA_CACHE:
+ arg is interpreted as size of cache in full table scan
+
+ For detailed description refer to @ref ha_partition::extra
*/
-int ha_partition::extra_opt(enum ha_extra_function operation, ulong cachesize)
+int ha_partition::extra_opt(enum ha_extra_function operation, ulong arg)
{
- DBUG_ENTER("ha_partition::extra_opt()");
+ DBUG_ENTER("ha_partition::extra_opt");
- DBUG_ASSERT(HA_EXTRA_CACHE == operation);
- prepare_extra_cache(cachesize);
- DBUG_RETURN(0);
+ switch (operation)
+ {
+ case HA_EXTRA_KEYREAD:
+ DBUG_RETURN(loop_partitions(start_keyread_cb, &arg));
+ case HA_EXTRA_CACHE:
+ prepare_extra_cache(arg);
+ DBUG_RETURN(0);
+ default:
+ DBUG_ASSERT(0);
+ }
+ DBUG_RETURN(1);
}
@@ -9025,7 +9065,7 @@ int ha_partition::extra_opt(enum ha_extra_function operation, ulong cachesize)
void ha_partition::prepare_extra_cache(uint cachesize)
{
- DBUG_ENTER("ha_partition::prepare_extra_cache()");
+ DBUG_ENTER("ha_partition::prepare_extra_cache");
DBUG_PRINT("enter", ("cachesize %u", cachesize));
m_extra_cache= TRUE;
@@ -9055,7 +9095,7 @@ int ha_partition::loop_extra_alter(enum ha_extra_function operation)
{
int result= 0, tmp;
handler **file;
- DBUG_ENTER("ha_partition::loop_extra_alter()");
+ DBUG_ENTER("ha_partition::loop_extra_alter");
DBUG_ASSERT(operation == HA_EXTRA_PREPARE_FOR_RENAME ||
operation == HA_EXTRA_FORCE_REOPEN);
@@ -9071,28 +9111,28 @@ int ha_partition::loop_extra_alter(enum ha_extra_function operation)
if ((tmp= (*file)->extra(operation)))
result= tmp;
}
- if ((tmp= loop_extra(operation)))
+ if ((tmp= loop_partitions(extra_cb, &operation)))
result= tmp;
DBUG_RETURN(result);
}
-/*
- Call extra on all partitions
- SYNOPSIS
- loop_extra()
- operation extra operation type
+/**
+ Call callback(part, param) on all partitions
- RETURN VALUE
- >0 Error code
- 0 Success
+ @param callback a callback to call for each partition
+ @param param a void*-parameter passed to callback
+
+ @return Operation status
+ @retval >0 Error code
+ @retval 0 Success
*/
-int ha_partition::loop_extra(enum ha_extra_function operation)
+int ha_partition::loop_partitions(handler_callback callback, void *param)
{
int result= 0, tmp;
uint i;
- DBUG_ENTER("ha_partition::loop_extra()");
+ DBUG_ENTER("ha_partition::loop_partitions");
for (i= bitmap_get_first_set(&m_part_info->lock_partitions);
i < m_tot_parts;
@@ -9103,7 +9143,7 @@ int ha_partition::loop_extra(enum ha_extra_function operation)
In this case calling 'extra' can crash.
*/
if (bitmap_is_set(&m_opened_partitions, i) &&
- (tmp= m_file[i]->extra(operation)))
+ (tmp= callback(m_file[i], param)))
result= tmp;
}
/* Add all used partitions to be called in reset(). */
@@ -10856,11 +10896,9 @@ int ha_partition::check_for_upgrade(HA_CHECK_OPT *check_opt)
}
m_part_info->key_algorithm= partition_info::KEY_ALGORITHM_51;
if (skip_generation ||
- !(part_buf= generate_partition_syntax(thd, m_part_info,
- &part_buf_len,
- true,
- NULL,
- NULL)) ||
+ !(part_buf= generate_partition_syntax_for_frm(thd, m_part_info,
+ &part_buf_len,
+ NULL, NULL)) ||
print_admin_msg(thd, SQL_ADMIN_MSG_TEXT_SIZE + 1, "error",
table_share->db.str,
table->alias,
@@ -10908,6 +10946,18 @@ TABLE_LIST *ha_partition::get_next_global_for_child()
}
+/**
+ Push an engine condition to the condition stack of the storage engine
+ for each partition.
+
+ @param cond Pointer to the engine condition to be pushed.
+
+ @return NULL Underlying engine will not return rows that
+ do not match the passed condition.
+ <> NULL 'Remainder' condition that the caller must use
+ to filter out records.
+*/
+
const COND *ha_partition::cond_push(const COND *cond)
{
handler **file= m_file;
@@ -10944,10 +10994,15 @@ const COND *ha_partition::cond_push(const COND *cond)
}
+/**
+ Pop the top condition from the condition stack of the storage engine
+ for each partition.
+*/
+
void ha_partition::cond_pop()
{
handler **file= m_file;
- DBUG_ENTER("ha_partition::cond_push");
+ DBUG_ENTER("ha_partition::cond_pop");
do
{
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 8a251016703..202f27840dc 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -349,7 +349,6 @@ private:
/*
Variables for lock structures.
*/
- THR_LOCK_DATA lock; /* MySQL lock */
bool auto_increment_lock; /**< lock reading/updating auto_inc */
/**
@@ -844,7 +843,7 @@ public:
int change_partitions_to_open(List<String> *partition_names);
int open_read_partitions(char *name_buff, size_t name_buff_size);
virtual int extra(enum ha_extra_function operation);
- virtual int extra_opt(enum ha_extra_function operation, ulong cachesize);
+ virtual int extra_opt(enum ha_extra_function operation, ulong arg);
virtual int reset(void);
virtual uint count_query_cache_dependant_tables(uint8 *tables_type);
virtual my_bool
@@ -854,6 +853,8 @@ public:
uint *n);
private:
+ typedef int handler_callback(handler *, void *);
+
my_bool reg_query_cache_dependant_table(THD *thd,
char *engine_key,
uint engine_key_len,
@@ -864,7 +865,7 @@ private:
**block_table,
handler *file, uint *n);
static const uint NO_CURRENT_PART_ID= NOT_A_PARTITION_ID;
- int loop_extra(enum ha_extra_function operation);
+ int loop_partitions(handler_callback callback, void *param);
int loop_extra_alter(enum ha_extra_function operations);
void late_extra_cache(uint partition_id);
void late_extra_no_cache(uint partition_id);
@@ -1039,6 +1040,10 @@ public:
with hidden primary key)
(No handler has this limitation currently)
+ HA_WANTS_PRIMARY_KEY:
+ Can't define a table without primary key except sequences
+ (Only InnoDB has this when using innodb_force_primary_key == ON)
+
HA_STATS_RECORDS_IS_EXACT:
Does the counter of records after the info call specify an exact
value or not. If it does this flag is set.
diff --git a/sql/handle_connections_win.cc b/sql/handle_connections_win.cc
new file mode 100644
index 00000000000..b37b4dedad1
--- /dev/null
+++ b/sql/handle_connections_win.cc
@@ -0,0 +1,555 @@
+/* Copyright (c) 2018 MariaDB Corporation.
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
+
+/* Accepting connections on Windows */
+
+#include <my_global.h>
+#include <sql_class.h>
+#include <sql_connect.h>
+#include <mysqld.h>
+#include <mswsock.h>
+#include <mysql/psi/mysql_socket.h>
+#include <sddl.h>
+
+#include <handle_connections_win.h>
+
+/* From mysqld.cc */
+extern HANDLE hEventShutdown;
+extern MYSQL_SOCKET base_ip_sock, extra_ip_sock;
+extern PTP_CALLBACK_ENVIRON get_threadpool_win_callback_environ();
+extern void tp_win_callback_prolog();
+static SECURITY_ATTRIBUTES pipe_security;
+
+/**
+ Abstract base class for accepting new connection,
+ asynchronously (i.e the accept() operation can be posted,
+ and result is retrieved later) , and creating a new connection.
+*/
+
+struct Listener
+{
+ /** Windows handle of the Listener.
+ Subclasses would use SOCKET or named pipe handle
+ */
+ HANDLE m_handle;
+ /** Required for all async IO*/
+ OVERLAPPED m_overlapped;
+
+ /** Create new listener
+ @param handle - @see m_handle
+ @param wait_handle - usually, event handle or INVALID_HANDLE_VALUE
+ @see wait_handle
+ */
+ Listener(HANDLE handle, HANDLE wait_handle):
+ m_handle(handle), m_overlapped()
+ {
+ m_overlapped.hEvent= wait_handle;
+ }
+
+ /**
+ if not NULL, this handle can be be used in WaitForSingle/MultipleObject(s).
+ This handle will be closed when object is destroyed.
+
+ If NULL, the completion notification happens in threadpool.
+ */
+ HANDLE wait_handle()
+ {
+ return m_overlapped.hEvent;
+ }
+
+ /* Start waiting for new client connection. */
+ virtual void begin_accept()= 0;
+
+ /**
+ Completion callback,called whenever IO posted by begin_accept is finisjed
+ Listener needs to create a new THD then (or, call scheduler so it creates one)
+
+ @param success - whether IO completed successfull
+ */
+ virtual void completion_callback(bool success)= 0;
+
+ /**
+ Completion callback for Listener, that uses events for waiting
+ to IO. Not suitable for threadpool etc. Retrieves the status of
+ completed IO from the OVERLAPPED structure
+ */
+ void completion_callback()
+ {
+ DBUG_ASSERT(wait_handle() && (wait_handle() != INVALID_HANDLE_VALUE));
+ DWORD bytes;
+ return completion_callback(
+ GetOverlappedResult(wait_handle(), &m_overlapped, &bytes, FALSE));
+ }
+
+ /** Cancel an in-progress IO. Useful for threadpool-bound IO */
+ void cancel()
+ {
+ CancelIoEx(m_handle, &m_overlapped);
+ }
+
+ /* Destructor. Closes wait handle, if it was passed in constructor */
+ virtual ~Listener()
+ {
+ if (m_overlapped.hEvent)
+ CloseHandle(m_overlapped.hEvent);
+ };
+};
+
+/* Winsock extension finctions. */
+static LPFN_ACCEPTEX my_AcceptEx;
+static LPFN_GETACCEPTEXSOCKADDRS my_GetAcceptExSockaddrs;
+
+/**
+ Listener that handles socket connections.
+ Can be threadpool-bound (i.e the completion is executed in threadpool thread),
+ or use events for waits.
+
+ Threadpool-bound listener should be used with theradpool scheduler, for better
+ performance.
+*/
+struct Socket_Listener: public Listener
+{
+ /** Client socket passed to AcceptEx() call.*/
+ SOCKET m_client_socket;
+
+ /** Buffer for sockaddrs passed to AcceptEx()/GetAcceptExSockaddrs() */
+ char m_buffer[2 * sizeof(sockaddr_storage) + 32];
+
+ /* Threadpool IO struct.*/
+ PTP_IO m_tp_io;
+
+ /**
+ Callback for Windows threadpool's StartThreadpoolIo() function.
+ */
+ static void CALLBACK tp_accept_completion_callback(
+ PTP_CALLBACK_INSTANCE, PVOID context, PVOID , ULONG io_result,
+ ULONG_PTR, PTP_IO io)
+ {
+ tp_win_callback_prolog();
+ Listener *listener= (Listener *)context;
+
+ if (io_result == ERROR_OPERATION_ABORTED)
+ {
+ /* ERROR_OPERATION_ABORTED caused by CancelIoEx()*/
+ CloseThreadpoolIo(io);
+ delete listener;
+ return;
+ }
+ listener->completion_callback(io_result == 0);
+ }
+
+ /**
+ Constructor
+ @param listen_socket - listening socket
+ @PTP_CALLBACK_ENVIRON callback_environ - threadpool environment, or NULL
+ if threadpool is not used for completion callbacks.
+ */
+ Socket_Listener(MYSQL_SOCKET listen_socket, PTP_CALLBACK_ENVIRON callback_environ) :
+ Listener((HANDLE)listen_socket.fd,0),
+ m_client_socket(INVALID_SOCKET)
+ {
+ if (callback_environ)
+ {
+ /* Accept executed in threadpool. */
+ m_tp_io= CreateThreadpoolIo(m_handle,
+ tp_accept_completion_callback, this, callback_environ);
+ }
+ else
+ {
+ /* Completion signaled via event. */
+ m_tp_io= 0;
+ m_overlapped.hEvent= CreateEvent(0, FALSE , FALSE, 0);
+ }
+ }
+
+ /*
+ Use AcceptEx to asynchronously wait for new connection;
+ */
+ void begin_accept()
+ {
+retry :
+ m_client_socket= socket(server_socket_ai_family, SOCK_STREAM, IPPROTO_TCP);
+ if (m_client_socket == INVALID_SOCKET)
+ {
+ sql_perror("socket() call failed.");
+ unireg_abort(1);
+ }
+
+ DWORD bytes_received;
+ if (m_tp_io)
+ StartThreadpoolIo(m_tp_io);
+
+ BOOL ret= my_AcceptEx(
+ (SOCKET)m_handle,
+ m_client_socket,
+ m_buffer,
+ 0,
+ sizeof(sockaddr_storage) + 16,
+ sizeof(sockaddr_storage) + 16,
+ &bytes_received,
+ &m_overlapped);
+
+ DWORD last_error= ret? 0: WSAGetLastError();
+ if (last_error == WSAECONNRESET)
+ {
+ if (m_tp_io)
+ CancelThreadpoolIo(m_tp_io);
+ goto retry;
+ }
+
+ if (ret || last_error == ERROR_IO_PENDING || abort_loop)
+ return;
+
+ sql_print_error("my_AcceptEx failed, last error %u", last_error);
+ abort();
+ }
+
+ /* Create new socket connection.*/
+ void completion_callback(bool success)
+ {
+ if (!success)
+ {
+ /* my_AcceptEx() returned error */
+ closesocket(m_client_socket);
+ begin_accept();
+ return;
+ }
+
+ MYSQL_SOCKET s_client{m_client_socket};
+ MYSQL_SOCKET s_listen{(SOCKET)m_handle};
+
+#ifdef HAVE_PSI_SOCKET_INTERFACE
+ /* Parse socket addresses buffer filled by AcceptEx(),
+ only needed for PSI instrumentation. */
+ sockaddr *local_addr, *remote_addr;
+ int local_addr_len, remote_addr_len;
+
+ my_GetAcceptExSockaddrs(m_buffer,
+ 0, sizeof(sockaddr_storage) + 16, sizeof(sockaddr_storage) + 16,
+ &local_addr, &local_addr_len, &remote_addr, &remote_addr_len);
+
+ s_client.m_psi= PSI_SOCKET_CALL(init_socket)
+ (key_socket_client_connection, (const my_socket*)&s_listen.fd, remote_addr, remote_addr_len);
+#endif
+
+ /* Start accepting new connection. After this point, do not use
+ any member data, they could be used by a different (threadpool) thread. */
+ begin_accept();
+
+ /* Some chores post-AcceptEx() that we need to create a normal socket.*/
+ if (setsockopt(s_client.fd, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
+ (char *)&s_listen.fd, sizeof(s_listen.fd)))
+ {
+ if (!abort_loop)
+ {
+ sql_perror("setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed.");
+ abort();
+ }
+ }
+
+ /* Create a new connection.*/
+ handle_accepted_socket(s_client, s_listen);
+ }
+
+ ~Socket_Listener()
+ {
+ if (m_client_socket != INVALID_SOCKET)
+ closesocket(m_client_socket);
+ }
+
+ /*
+ Retrieve the pointer to the Winsock extension functions
+ AcceptEx and GetAcceptExSockaddrs.
+ */
+ static void init_winsock_extensions()
+ {
+ SOCKET s= mysql_socket_getfd(base_ip_sock);
+ if (s == INVALID_SOCKET)
+ s= mysql_socket_getfd(extra_ip_sock);
+ if (s == INVALID_SOCKET)
+ {
+ /* --skip-networking was used*/
+ return;
+ }
+ GUID guid_AcceptEx= WSAID_ACCEPTEX;
+ GUID guid_GetAcceptExSockaddrs= WSAID_GETACCEPTEXSOCKADDRS;
+
+ GUID *guids[]= { &guid_AcceptEx, &guid_GetAcceptExSockaddrs };
+ void *funcs[]= { &my_AcceptEx, &my_GetAcceptExSockaddrs };
+ DWORD bytes;
+ for (int i= 0; i < array_elements(guids); i++)
+ {
+ if (WSAIoctl(s,
+ SIO_GET_EXTENSION_FUNCTION_POINTER,
+ guids[i], sizeof(GUID),
+ funcs[i], sizeof(void *),
+ &bytes, 0, 0) == -1)
+ {
+ sql_print_error("WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER) failed");
+ unireg_abort(1);
+ }
+ }
+ }
+};
+
+
+/**
+ Pipe Listener.
+ Only event notification mode is implemented, no threadpool
+*/
+struct Pipe_Listener : public Listener
+{
+ PTP_CALLBACK_ENVIRON m_tp_env;
+ Pipe_Listener():
+ Listener(INVALID_HANDLE_VALUE, CreateEvent(0, FALSE, FALSE, 0)),
+ m_tp_env(get_threadpool_win_callback_environ())
+ {
+ }
+
+ /*
+ Creates local named pipe instance \\.\pipe\$socket for named pipe connection.
+ */
+ static HANDLE create_named_pipe()
+ {
+ static bool first_instance= true;
+ static char pipe_name[512];
+ DWORD open_mode= PIPE_ACCESS_DUPLEX |
+ FILE_FLAG_OVERLAPPED;
+
+ if (first_instance)
+ {
+ snprintf(pipe_name, sizeof(pipe_name), "\\\\.\\pipe\\%s", mysqld_unix_port);
+ open_mode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
+ if (!ConvertStringSecurityDescriptorToSecurityDescriptorA(
+ "S:(ML;; NW;;; LW) D:(A;; FRFW;;; WD)",
+ 1, &pipe_security.lpSecurityDescriptor, NULL))
+ {
+ sql_perror("Can't start server : Initialize security descriptor");
+ unireg_abort(1);
+ }
+ pipe_security.nLength= sizeof(SECURITY_ATTRIBUTES);
+ pipe_security.bInheritHandle= FALSE;
+ }
+ HANDLE pipe_handle= CreateNamedPipe(pipe_name,
+ open_mode,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES,
+ (int)global_system_variables.net_buffer_length,
+ (int)global_system_variables.net_buffer_length,
+ NMPWAIT_USE_DEFAULT_WAIT,
+ &pipe_security);
+ if (pipe_handle == INVALID_HANDLE_VALUE)
+ {
+ sql_perror("Create named pipe failed");
+ sql_print_error("Aborting\n");
+ exit(1);
+ }
+ first_instance= false;
+ return pipe_handle;
+ }
+
+ static void create_pipe_connection(HANDLE pipe)
+ {
+ CONNECT *connect;
+ if (!(connect= new CONNECT) || !(connect->vio= vio_new_win32pipe(pipe)))
+ {
+ CloseHandle(pipe);
+ delete connect;
+ statistic_increment(aborted_connects, &LOCK_status);
+ statistic_increment(connection_errors_internal, &LOCK_status);
+ return;
+ }
+ connect->host= my_localhost;
+ create_new_thread(connect);
+ }
+
+ /* Threadpool callback.*/
+ static void CALLBACK tp_create_pipe_connection(
+ PTP_CALLBACK_INSTANCE,void *Context)
+ {
+ tp_win_callback_prolog();
+ create_pipe_connection(Context);
+ }
+
+ void begin_accept()
+ {
+ m_handle= create_named_pipe();
+ BOOL connected= ConnectNamedPipe(m_handle, &m_overlapped);
+ if (connected)
+ {
+ /* Overlapped ConnectNamedPipe should return zero. */
+ sql_perror("Overlapped ConnectNamedPipe() already connected.");
+ abort();
+ }
+ DWORD last_error= GetLastError();
+ switch (last_error)
+ {
+ case ERROR_PIPE_CONNECTED:
+ /* Client is already connected, so signal an event.*/
+ {
+ /*
+ Cleanup overlapped (so that subsequent GetOverlappedResult()
+ does not show results of previous IO
+ */
+ HANDLE e= m_overlapped.hEvent;
+ memset(&m_overlapped, 0, sizeof(m_overlapped));
+ m_overlapped.hEvent = e;
+ }
+ if (!SetEvent(m_overlapped.hEvent))
+ {
+ sql_perror("SetEvent() failed for connected pipe.");
+ abort();
+ }
+ break;
+ case ERROR_IO_PENDING:
+ break;
+ default:
+ sql_perror("ConnectNamedPipe() failed.");
+ abort();
+ break;
+ }
+ }
+
+ void completion_callback(bool success)
+ {
+ if (!success)
+ {
+#ifdef DBUG_OFF
+ sql_print_warning("ConnectNamedPipe completed with %u", GetLastError());
+#endif
+ CloseHandle(m_handle);
+ m_handle= INVALID_HANDLE_VALUE;
+ begin_accept();
+ return;
+ }
+ HANDLE pipe= m_handle;
+ begin_accept();
+ // If threadpool is on, create connection in threadpool thread
+ if (!m_tp_env || !TrySubmitThreadpoolCallback(tp_create_pipe_connection, pipe, m_tp_env))
+ create_pipe_connection(pipe);
+ }
+
+ ~Pipe_Listener()
+ {
+ if (m_handle != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(m_handle);
+ }
+ }
+
+ static void cleanup()
+ {
+ LocalFree(pipe_security.lpSecurityDescriptor);
+ }
+};
+
+/**
+ Accept new client connections on Windows.
+
+ Since we deal with pipe and sockets, they cannot be put into a select/loop.
+ But we can use asynchronous IO, and WaitForMultipleObject() loop.
+
+ In addition, for slightly better performance, if we're using threadpool,
+ socket connections are accepted directly in the threadpool.
+
+ The mode of operation is therefore
+
+ 1. There is WaitForMultipleObject() loop that waits for shutdown notification
+ (hEventShutdown),and possibly pipes and sockets(e.g if threadpool is not used)
+ This loop ends when shutdown notification is detected.
+
+ 2. If threadpool is used, new socket connections are accepted there.
+*/
+
+
+#define MAX_WAIT_HANDLES 32
+#define NUM_PIPE_LISTENERS 24
+#define SHUTDOWN_IDX 0
+#define LISTENER_START_IDX 1
+
+void handle_connections_win()
+{
+ Listener* all_listeners[MAX_WAIT_HANDLES]= {};
+ HANDLE wait_events[MAX_WAIT_HANDLES]= {};
+ int n_listeners= 0;
+ int n_waits= 0;
+
+ Socket_Listener::init_winsock_extensions();
+
+ /* Listen for TCP connections on "extra-port" (no threadpool).*/
+ if (extra_ip_sock.fd != INVALID_SOCKET)
+ all_listeners[n_listeners++]= new Socket_Listener(extra_ip_sock, 0);
+
+ /* Listen for named pipe connections */
+ if (mysqld_unix_port[0] && !opt_bootstrap && opt_enable_named_pipe)
+ {
+ /*
+ Use several listeners for pipe, to reduce ERROR_PIPE_BUSY on client side.
+ */
+ for (int i= 0; i < NUM_PIPE_LISTENERS; i++)
+ all_listeners[n_listeners++]= new Pipe_Listener();
+ }
+
+ if (base_ip_sock.fd != INVALID_SOCKET)
+ {
+ /* Wait for TCP connections.*/
+ SetFileCompletionNotificationModes((HANDLE)base_ip_sock.fd, FILE_SKIP_SET_EVENT_ON_HANDLE);
+ all_listeners[n_listeners++]= new Socket_Listener(base_ip_sock, get_threadpool_win_callback_environ());
+ }
+
+ if (!n_listeners && !opt_bootstrap)
+ {
+ sql_print_error("Either TCP connections or named pipe connections must be enabled.");
+ unireg_abort(1);
+ }
+
+ wait_events[SHUTDOWN_IDX]= hEventShutdown;
+ n_waits = 1;
+
+ for (int i= 0; i < n_listeners; i++)
+ {
+ HANDLE wait_handle= all_listeners[i]->wait_handle();
+ if(wait_handle)
+ {
+ DBUG_ASSERT((i == 0) || (all_listeners[i-1]->wait_handle() != 0));
+ wait_events[n_waits++]= wait_handle;
+ }
+ all_listeners[i]->begin_accept();
+ }
+
+ for (;;)
+ {
+ DWORD idx = WaitForMultipleObjects(n_waits ,wait_events, FALSE, INFINITE);
+ DBUG_ASSERT((int)idx >= 0 && (int)idx < n_waits);
+
+ if (idx == SHUTDOWN_IDX)
+ break;
+
+ all_listeners[idx - LISTENER_START_IDX]->completion_callback();
+ }
+
+ /* Cleanup */
+ for (int i= 0; i < n_listeners; i++)
+ {
+ Listener *listener= all_listeners[i];
+ if (listener->wait_handle())
+ delete listener;
+ else
+ // Threadpool-bound listener will be deleted in threadpool
+ // Do not call destructor, because callback maybe running.
+ listener->cancel();
+ }
+ Pipe_Listener::cleanup();
+} \ No newline at end of file
diff --git a/sql/handle_connections_win.h b/sql/handle_connections_win.h
new file mode 100644
index 00000000000..a81f4346fb2
--- /dev/null
+++ b/sql/handle_connections_win.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2018 MariaDB Corporation.
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
+
+/**
+ Handles incoming socket and pipe connections, on Windows.
+ Creates new (THD) connections..
+*/
+extern void handle_connections_win();
diff --git a/sql/handler.cc b/sql/handler.cc
index d48a4660d52..e5081accb30 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -21,6 +21,7 @@
*/
#include "mariadb.h"
+#include <inttypes.h>
#include "sql_priv.h"
#include "unireg.h"
#include "rpl_rli.h"
@@ -74,7 +75,7 @@ KEY_CREATE_INFO default_key_create_info=
ulong total_ha= 0;
/* number of storage engines (from handlertons[]) that support 2pc */
ulong total_ha_2pc= 0;
-#ifndef DBUG_OFF
+#ifdef DBUG_ASSERT_EXISTS
/*
Number of non-mandatory 2pc handlertons whose initialization failed
to estimate total_ha_2pc value under supposition of the failures
@@ -661,7 +662,7 @@ err_deinit:
(void) plugin->plugin->deinit(NULL);
err:
-#ifndef DBUG_OFF
+#ifdef DBUG_ASSERT_EXISTS
if (hton->prepare && hton->state == SHOW_OPTION_YES)
failed_ha_2pc++;
#endif
@@ -3086,6 +3087,45 @@ void handler::adjust_next_insert_id_after_explicit_value(ulonglong nr)
}
+/** @brief
+ Computes the largest number X:
+ - smaller than or equal to "nr"
+ - of the form: auto_increment_offset + N * auto_increment_increment
+ where N>=0.
+
+ SYNOPSIS
+ prev_insert_id
+ nr Number to "round down"
+ variables variables struct containing auto_increment_increment and
+ auto_increment_offset
+
+ RETURN
+ The number X if it exists, "nr" otherwise.
+*/
+inline ulonglong
+prev_insert_id(ulonglong nr, struct system_variables *variables)
+{
+ if (unlikely(nr < variables->auto_increment_offset))
+ {
+ /*
+ There's nothing good we can do here. That is a pathological case, where
+ the offset is larger than the column's max possible value, i.e. not even
+ the first sequence value may be inserted. User will receive warning.
+ */
+ DBUG_PRINT("info",("auto_increment: nr: %lu cannot honour "
+ "auto_increment_offset: %lu",
+ (ulong) nr, variables->auto_increment_offset));
+ return nr;
+ }
+ if (variables->auto_increment_increment == 1)
+ return nr; // optimization of the formula below
+ nr= (((nr - variables->auto_increment_offset)) /
+ (ulonglong) variables->auto_increment_increment);
+ return (nr * (ulonglong) variables->auto_increment_increment +
+ variables->auto_increment_offset);
+}
+
+
/**
Update the auto_increment field if necessary.
@@ -4593,6 +4633,7 @@ handler::ha_create_partitioning_metadata(const char *name,
(!old_name && strcmp(name, table_share->path.str)));
+ mark_trx_read_write();
return create_partitioning_metadata(name, old_name, action_flag);
}
@@ -6521,7 +6562,7 @@ void ha_fake_trx_id(THD *thd)
if (thd->wsrep_ws_handle.trx_id != WSREP_UNDEFINED_TRX_ID)
{
- WSREP_DEBUG("fake trx id skipped: %lu", thd->wsrep_ws_handle.trx_id);
+ WSREP_DEBUG("fake trx id skipped: %" PRIu64, thd->wsrep_ws_handle.trx_id);
DBUG_VOID_RETURN;
}
@@ -6786,7 +6827,7 @@ int del_global_index_stats_for_table(THD *thd, uchar* cache_key, size_t cache_ke
/* Remove a table from global table statistics */
-int del_global_table_stat(THD *thd, LEX_CSTRING *db, LEX_CSTRING *table)
+int del_global_table_stat(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *table)
{
TABLE_STATS *table_stats;
int res = 0;
@@ -6927,7 +6968,7 @@ bool Vers_parse_info::fix_implicit(THD *thd, Alter_info *alter_info)
return false;
}
-bool Table_scope_and_contents_source_st::vers_native(THD *thd) const
+bool Table_scope_and_contents_source_pod_st::vers_native(THD *thd) const
{
if (ha_check_storage_engine_flag(db_type, HTON_NATIVE_SYS_VERSIONING))
return true;
diff --git a/sql/handler.h b/sql/handler.h
index bfc8bd774b3..e5a6deb6659 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -2,7 +2,7 @@
#define HANDLER_INCLUDED
/*
Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2009, 2017, MariaDB Corporation.
+ Copyright (c) 2009, 2018, MariaDB
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -151,7 +151,6 @@ enum enum_alter_inplace_result {
#define HA_HAS_OLD_CHECKSUM (1ULL << 24)
/* Table data are stored in separate files (for lower_case_table_names) */
#define HA_FILE_BASED (1ULL << 26)
-#define HA_NO_VARCHAR (1ULL << 27) /* unused */
#define HA_CAN_BIT_FIELD (1ULL << 28) /* supports bit fields */
#define HA_NEED_READ_RANGE_BUFFER (1ULL << 29) /* for read_multi_range */
#define HA_ANY_INDEX_MAY_BE_UNIQUE (1ULL << 30)
@@ -302,6 +301,9 @@ enum enum_alter_inplace_result {
/* calling cmp_ref() on the engine is expensive */
#define HA_CMP_REF_IS_EXPENSIVE (1ULL << 54)
+/* Engine wants primary keys for everything except sequences */
+#define HA_WANTS_PRIMARY_KEY (1ULL << 55)
+
/* bits in index_flags(index_number) for what you can do with index */
#define HA_READ_NEXT 1 /* TODO really use this flag */
#define HA_READ_PREV 2 /* supports ::index_prev */
@@ -818,7 +820,7 @@ struct xid_t {
bqual_length= b;
memcpy(data, d, g+b);
}
- bool is_null() { return formatID == -1; }
+ bool is_null() const { return formatID == -1; }
void null() { formatID= -1; }
my_xid quick_get_my_xid()
{
@@ -950,6 +952,7 @@ enum enum_schema_tables
SCH_ALL_PLUGINS,
SCH_APPLICABLE_ROLES,
SCH_CHARSETS,
+ SCH_CHECK_CONSTRAINTS,
SCH_COLLATIONS,
SCH_COLLATION_CHARACTER_SET_APPLICABILITY,
SCH_COLUMNS,
@@ -1905,6 +1908,8 @@ enum vers_sys_type_t
VERS_TRX_ID
};
+extern const LEX_CSTRING null_clex_str;
+
struct Vers_parse_info
{
Vers_parse_info() :
@@ -1913,6 +1918,15 @@ struct Vers_parse_info
unversioned_fields(false)
{}
+ void init() // Deep initialization
+ {
+ system_time= start_end_t(null_clex_str, null_clex_str);
+ as_row= start_end_t(null_clex_str, null_clex_str);
+ check_unit= VERS_UNDEFINED;
+ versioned_fields= false;
+ unversioned_fields= false;
+ }
+
struct start_end_t
{
start_end_t()
@@ -1992,7 +2006,7 @@ public:
- [AS] SELECT ... // Copy structure from a subquery
*/
-struct Table_scope_and_contents_source_st
+struct Table_scope_and_contents_source_pod_st // For trivial members
{
CHARSET_INFO *table_charset;
LEX_CUSTRING tabledef_version;
@@ -2018,7 +2032,6 @@ struct Table_scope_and_contents_source_st
uint options; /* OR of HA_CREATE_ options */
uint merge_insert_method;
uint extra_size; /* length of extra data segment */
- SQL_I_List<TABLE_LIST> merge_list;
handlerton *db_type;
/**
Row type of the table definition.
@@ -2052,15 +2065,6 @@ struct Table_scope_and_contents_source_st
bool table_was_deleted;
sequence_definition *seq_create_info;
- Vers_parse_info vers_info;
-
- bool vers_fix_system_fields(THD *thd, Alter_info *alter_info,
- const TABLE_LIST &create_table,
- bool create_select= false);
-
- bool vers_check_system_fields(THD *thd, Alter_info *alter_info,
- const TABLE_LIST &create_table);
-
bool vers_native(THD *thd) const;
void init()
@@ -2081,6 +2085,30 @@ struct Table_scope_and_contents_source_st
};
+struct Table_scope_and_contents_source_st:
+ public Table_scope_and_contents_source_pod_st
+{
+ SQL_I_List<TABLE_LIST> merge_list;
+
+ Vers_parse_info vers_info;
+
+ void init()
+ {
+ Table_scope_and_contents_source_pod_st::init();
+ merge_list.empty();
+ vers_info.init();
+ }
+
+ bool vers_fix_system_fields(THD *thd, Alter_info *alter_info,
+ const TABLE_LIST &create_table,
+ bool create_select= false);
+
+ bool vers_check_system_fields(THD *thd, Alter_info *alter_info,
+ const TABLE_LIST &create_table);
+
+};
+
+
/**
This struct is passed to handler table routines, e.g. ha_create().
It does not include the "OR REPLACE" and "IF NOT EXISTS" parts, as these
@@ -3096,7 +3124,7 @@ public:
bool keyread_enabled() { return keyread < MAX_KEY; }
int ha_start_keyread(uint idx)
{
- int res= keyread_enabled() ? 0 : extra(HA_EXTRA_KEYREAD);
+ int res= keyread_enabled() ? 0 : extra_opt(HA_EXTRA_KEYREAD, idx);
keyread= idx;
return res;
}
@@ -3227,7 +3255,7 @@ public:
/*
True if changes to the table is persistent (no rollback)
- This is manly used to decide how to log changes to the table in
+ This is mainly used to decide how to log changes to the table in
the binary log.
*/
bool has_transactions()
@@ -3610,7 +3638,7 @@ public:
{ return 0; }
virtual int extra(enum ha_extra_function operation)
{ return 0; }
- virtual int extra_opt(enum ha_extra_function operation, ulong cache_size)
+ virtual int extra_opt(enum ha_extra_function operation, ulong arg)
{ return extra(operation); }
/**
@@ -4831,5 +4859,5 @@ void print_keydup_error(TABLE *table, KEY *key, const char *msg, myf errflag);
void print_keydup_error(TABLE *table, KEY *key, myf errflag);
int del_global_index_stat(THD *thd, TABLE* table, KEY* key_info);
-int del_global_table_stat(THD *thd, LEX_CSTRING *db, LEX_CSTRING *table);
+int del_global_table_stat(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *table);
#endif /* HANDLER_INCLUDED */
diff --git a/sql/init.h b/sql/init.h
index e8dec0c1e2e..e96bb478cee 100644
--- a/sql/init.h
+++ b/sql/init.h
@@ -17,6 +17,6 @@
#define INIT_INCLUDED
void unireg_init(ulong options);
-ATTRIBUTE_NORETURN void unireg_end(void);
+void unireg_end(void);
#endif /* INIT_INCLUDED */
diff --git a/sql/item.cc b/sql/item.cc
index 8782efc88e3..d4cfa790986 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2000, 2016, Oracle and/or its affiliates.
+ Copyright (c) 2000, 2018, Oracle and/or its affiliates.
Copyright (c) 2010, 2018, MariaDB Corporation
This program is free software; you can redistribute it and/or modify
@@ -115,14 +115,15 @@ void Item::push_note_converted_to_positive_complement(THD *thd)
}
-longlong Item::val_datetime_packed_result()
+longlong Item::val_datetime_packed_result(THD *thd)
{
MYSQL_TIME ltime, tmp;
- if (get_date_result(&ltime, Datetime::comparison_flags_for_get_date()))
+ if (get_date_result(thd, &ltime, Datetime::comparison_flags_for_get_date()))
return 0;
if (ltime.time_type != MYSQL_TIMESTAMP_TIME)
return pack_time(&ltime);
- if ((null_value= time_to_datetime_with_warn(current_thd, &ltime, &tmp, 0)))
+ if ((null_value= time_to_datetime_with_warn(thd, &ltime,
+ &tmp, date_mode_t(0))))
return 0;
return pack_time(&tmp);
}
@@ -293,7 +294,7 @@ my_decimal *Item::val_decimal_from_string(my_decimal *decimal_value)
int Item::save_time_in_field(Field *field, bool no_conversions)
{
MYSQL_TIME ltime;
- if (get_time(&ltime))
+ if (get_time(field->table->in_use, &ltime))
return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
return field->store_time_dec(&ltime, decimals);
@@ -303,7 +304,8 @@ int Item::save_time_in_field(Field *field, bool no_conversions)
int Item::save_date_in_field(Field *field, bool no_conversions)
{
MYSQL_TIME ltime;
- if (get_date(&ltime, sql_mode_for_dates(field->table->in_use)))
+ THD *thd= field->table->in_use;
+ if (get_date(thd, &ltime, sql_mode_for_dates(thd)))
return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
return field->store_time_dec(&ltime, decimals);
@@ -1272,64 +1274,30 @@ Item *Item_param::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
As a extra convenience the time structure is reset on error or NULL values!
*/
-bool Item::get_date_from_int(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item::get_date_from_int(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- longlong value= val_int();
- bool neg= !unsigned_flag && value < 0;
- if (null_value || int_to_datetime_with_warn(neg, neg ? -value : value,
- ltime, fuzzydate,
- field_name_or_null()))
- return null_value|= make_zero_date(ltime, fuzzydate);
- return null_value= false;
+ Longlong_hybrid value(val_int(), unsigned_flag);
+ return null_value || int_to_datetime_with_warn(thd, value,
+ ltime, fuzzydate,
+ field_name_or_null());
}
-bool Item::get_date_from_real(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item::get_date_from_real(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
double value= val_real();
- if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate,
- field_name_or_null()))
- return null_value|= make_zero_date(ltime, fuzzydate);
- return null_value= false;
-}
-
-
-bool Item::get_date_from_string(MYSQL_TIME *ltime, ulonglong fuzzydate)
-{
- char buff[40];
- String tmp(buff,sizeof(buff), &my_charset_bin),*res;
- if (!(res=val_str(&tmp)) ||
- str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(),
- ltime, fuzzydate))
- return null_value|= make_zero_date(ltime, fuzzydate);
- return null_value= false;
+ return null_value || double_to_datetime_with_warn(thd, value,
+ ltime, fuzzydate,
+ field_name_or_null());
}
-bool Item::make_zero_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item::get_date_from_string(THD *thd, MYSQL_TIME *to, date_mode_t mode)
{
- /*
- if the item was not null and convertion failed, we return a zero date
- if allowed, otherwise - null.
- */
- bzero((char*) ltime,sizeof(*ltime));
- if (fuzzydate & TIME_TIME_ONLY)
- {
- /*
- In the following scenario:
- - The caller expected to get a TIME value
- - Item returned a not NULL string or numeric value
- - But then conversion from string or number to TIME failed
- we need to change the default time_type from MYSQL_TIMESTAMP_DATE
- (which was set in bzero) to MYSQL_TIMESTAMP_TIME and therefore
- return TIME'00:00:00' rather than DATE'0000-00-00'.
- If we don't do this, methods like Item::get_time_with_conversion()
- will erroneously subtract CURRENT_DATE from '0000-00-00 00:00:00'
- and return TIME'-838:59:59' instead of TIME'00:00:00' as a result.
- */
- ltime->time_type= MYSQL_TIMESTAMP_TIME;
- }
- return !(fuzzydate & TIME_FUZZY_DATES);
+ StringBuffer<40> tmp;
+ Temporal::Warn_push warn(thd, field_name_or_null(), to, mode);
+ Temporal_hybrid *t= new(to) Temporal_hybrid(thd, &warn, val_str(&tmp), mode);
+ return !t->is_valid_temporal();
}
@@ -1429,7 +1397,14 @@ Query_fragment::Query_fragment(THD *thd, sp_head *sphead,
const char *start, const char *end)
{
DBUG_ASSERT(start <= end);
- if (sphead)
+ if (thd->lex->clone_spec_offset)
+ {
+ Lex_input_stream *lip= (& thd->m_parser_state->m_lip);
+ DBUG_ASSERT(lip->get_buf() <= start);
+ DBUG_ASSERT(end <= lip->get_end_of_query());
+ set(start - lip->get_buf(), end - start);
+ }
+ else if (sphead)
{
if (sphead->m_tmp_query)
{
@@ -1561,11 +1536,11 @@ my_decimal *Item_sp_variable::val_decimal(my_decimal *decimal_value)
}
-bool Item_sp_variable::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_sp_variable::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed);
Item *it= this_item();
- bool val= it->get_date(ltime, fuzzydate);
+ bool val= it->get_date(thd, ltime, fuzzydate);
null_value= it->null_value;
return val;
}
@@ -1942,10 +1917,10 @@ my_decimal *Item_name_const::val_decimal(my_decimal *decimal_value)
return val;
}
-bool Item_name_const::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_name_const::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed);
- bool rc= value_item->get_date(ltime, fuzzydate);
+ bool rc= value_item->get_date(thd, ltime, fuzzydate);
null_value= value_item->null_value;
return rc;
}
@@ -1960,25 +1935,6 @@ Item_name_const::Item_name_const(THD *thd, Item *name_arg, Item *val):
Item_fixed_hybrid(thd), value_item(val), name_item(name_arg)
{
Item::maybe_null= TRUE;
- if (!name_item->basic_const_item())
- goto err;
-
- if (value_item->basic_const_item())
- return; // ok
-
- if (value_item->type() == FUNC_ITEM)
- {
- Item_func *value_func= (Item_func *) value_item;
- if (value_func->functype() != Item_func::COLLATE_FUNC &&
- value_func->functype() != Item_func::NEG_FUNC)
- goto err;
-
- if (value_func->key_item()->basic_const_item())
- return; // ok
- }
-
-err:
- my_error(ER_WRONG_ARGUMENTS, MYF(0), "NAME_CONST");
}
@@ -3201,7 +3157,7 @@ String *Item_field::str_result(String *str)
return result_field->val_str(str,&str_value);
}
-bool Item_field::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Item_field::get_date(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate)
{
if ((null_value=field->is_null()) || field->get_date(ltime,fuzzydate))
{
@@ -3211,7 +3167,7 @@ bool Item_field::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
return 0;
}
-bool Item_field::get_date_result(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_field::get_date_result(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
if (result_field->is_null() || result_field->get_date(ltime,fuzzydate))
{
@@ -3744,9 +3700,9 @@ my_decimal *Item_null::val_decimal(my_decimal *decimal_value)
}
-bool Item_null::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_null::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- make_zero_date(ltime, fuzzydate);
+ set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
return (null_value= true);
}
@@ -3805,7 +3761,8 @@ Item_param::Item_param(THD *thd, const LEX_CSTRING *name_arg,
For dynamic SQL, settability depends on the type of Item passed
as an actual parameter. See Item_param::set_from_item().
*/
- m_is_settable_routine_parameter(true)
+ m_is_settable_routine_parameter(true),
+ m_clones(thd->mem_root)
{
name= *name_arg;
/*
@@ -3817,6 +3774,59 @@ Item_param::Item_param(THD *thd, const LEX_CSTRING *name_arg,
}
+/* Add reference to Item_param used in a copy of CTE to its master as a clone */
+
+bool Item_param::add_as_clone(THD *thd)
+{
+ LEX *lex= thd->lex;
+ my_ptrdiff_t master_pos= pos_in_query + lex->clone_spec_offset;
+ List_iterator_fast<Item_param> it(lex->param_list);
+ Item_param *master_param;
+ while ((master_param = it++))
+ {
+ if (master_pos == master_param->pos_in_query)
+ return master_param->register_clone(this);
+ }
+ DBUG_ASSERT(false);
+ return false;
+}
+
+
+/* Update all clones of Item_param to sync their values with the item's value */
+
+void Item_param::sync_clones()
+{
+ Item_param **c_ptr= m_clones.begin();
+ Item_param **end= m_clones.end();
+ for ( ; c_ptr < end; c_ptr++)
+ {
+ Item_param *c= *c_ptr;
+ /* Scalar-type members: */
+ c->maybe_null= maybe_null;
+ c->null_value= null_value;
+ c->Type_std_attributes::operator=(*this);
+ c->Type_handler_hybrid_field_type::operator=(*this);
+ c->Type_geometry_attributes::operator=(*this);
+
+ c->state= state;
+ c->m_empty_string_is_null= m_empty_string_is_null;
+
+ c->value.PValue_simple::operator=(value);
+ c->value.Type_handler_hybrid_field_type::operator=(value);
+ type_handler()->Item_param_setup_conversion(current_thd, c);
+
+ /* Class-type members: */
+ c->value.m_decimal= value.m_decimal;
+ /*
+ Note that String's assignment op properly sets m_is_alloced to 'false',
+ which is correct here: c->str_value doesn't own anything.
+ */
+ c->value.m_string= value.m_string;
+ c->value.m_string_ptr= value.m_string_ptr;
+ }
+}
+
+
void Item_param::set_null()
{
DBUG_ENTER("Item_param::set_null");
@@ -4101,7 +4111,7 @@ bool Item_param::set_from_item(THD *thd, Item *item)
}
}
struct st_value tmp;
- if (!item->save_in_value(&tmp))
+ if (!item->save_in_value(thd, &tmp))
{
const Type_handler *h= item->type_handler();
set_handler(h);
@@ -4204,7 +4214,7 @@ void Item_param::invalid_default_param() const
}
-bool Item_param::get_date(MYSQL_TIME *res, ulonglong fuzzydate)
+bool Item_param::get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate)
{
/*
LIMIT clause parameter should not call get_date()
@@ -4218,7 +4228,7 @@ bool Item_param::get_date(MYSQL_TIME *res, ulonglong fuzzydate)
*res= value.time;
return 0;
}
- return type_handler()->Item_get_date(this, res, fuzzydate);
+ return type_handler()->Item_get_date_with_warn(thd, this, res, fuzzydate);
}
@@ -4251,7 +4261,7 @@ longlong Item_param::PValue::val_int(const Type_std_attributes *attr) const
{
switch (type_handler()->cmp_type()) {
case REAL_RESULT:
- return (longlong) rint(real);
+ return Converter_double_to_longlong(real, attr->unsigned_flag).result();
case INT_RESULT:
return integer;
case DECIMAL_RESULT:
@@ -4634,7 +4644,7 @@ Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it)
correctly fetches the value from the client-server protocol,
using set_param_func().
*/
- if (arg->save_in_value(&tmp) ||
+ if (arg->save_in_value(thd, &tmp) ||
set_value(thd, arg, &tmp, arg->type_handler()))
{
set_null();
@@ -4719,32 +4729,6 @@ bool Item_param::append_for_log(THD *thd, String *str)
return str->append(*val);
}
-/****************************************************************************
- Item_copy
-****************************************************************************/
-
-Item_copy *Item_copy::create(THD *thd, Item *item)
-{
- MEM_ROOT *mem_root= thd->mem_root;
- switch (item->result_type())
- {
- case STRING_RESULT:
- return new (mem_root) Item_copy_string(thd, item);
- case REAL_RESULT:
- return new (mem_root) Item_copy_float(thd, item);
- case INT_RESULT:
- return item->unsigned_flag ?
- new (mem_root) Item_copy_uint(thd, item) :
- new (mem_root) Item_copy_int(thd, item);
- case DECIMAL_RESULT:
- return new (mem_root) Item_copy_decimal(thd, item);
- case TIME_RESULT:
- case ROW_RESULT:
- DBUG_ASSERT (0);
- }
- /* should not happen */
- return NULL;
-}
/****************************************************************************
Item_copy_string
@@ -4802,138 +4786,6 @@ my_decimal *Item_copy_string::val_decimal(my_decimal *decimal_value)
}
-/****************************************************************************
- Item_copy_int
-****************************************************************************/
-
-void Item_copy_int::copy()
-{
- cached_value= item->val_int();
- null_value=item->null_value;
-}
-
-static int save_int_value_in_field (Field *, longlong, bool, bool);
-
-int Item_copy_int::save_in_field(Field *field, bool no_conversions)
-{
- return save_int_value_in_field(field, cached_value,
- null_value, unsigned_flag);
-}
-
-
-String *Item_copy_int::val_str(String *str)
-{
- if (null_value)
- return (String *) 0;
-
- str->set(cached_value, &my_charset_bin);
- return str;
-}
-
-
-my_decimal *Item_copy_int::val_decimal(my_decimal *decimal_value)
-{
- if (null_value)
- return (my_decimal *) 0;
-
- int2my_decimal(E_DEC_FATAL_ERROR, cached_value, unsigned_flag, decimal_value);
- return decimal_value;
-}
-
-
-/****************************************************************************
- Item_copy_uint
-****************************************************************************/
-
-String *Item_copy_uint::val_str(String *str)
-{
- if (null_value)
- return (String *) 0;
-
- str->set((ulonglong) cached_value, &my_charset_bin);
- return str;
-}
-
-
-/****************************************************************************
- Item_copy_float
-****************************************************************************/
-
-String *Item_copy_float::val_str(String *str)
-{
- if (null_value)
- return (String *) 0;
- else
- {
- double nr= val_real();
- str->set_real(nr,decimals, &my_charset_bin);
- return str;
- }
-}
-
-
-my_decimal *Item_copy_float::val_decimal(my_decimal *decimal_value)
-{
- if (null_value)
- return (my_decimal *) 0;
- else
- {
- double nr= val_real();
- double2my_decimal(E_DEC_FATAL_ERROR, nr, decimal_value);
- return decimal_value;
- }
-}
-
-
-int Item_copy_float::save_in_field(Field *field, bool no_conversions)
-{
- if (null_value)
- return set_field_to_null(field);
- field->set_notnull();
- return field->store(cached_value);
-}
-
-
-/****************************************************************************
- Item_copy_decimal
-****************************************************************************/
-
-int Item_copy_decimal::save_in_field(Field *field, bool no_conversions)
-{
- if (null_value)
- return set_field_to_null(field);
- field->set_notnull();
- return field->store_decimal(&cached_value);
-}
-
-
-String *Item_copy_decimal::val_str(String *result)
-{
- return null_value ? NULL : cached_value.to_string(result);
-}
-
-
-double Item_copy_decimal::val_real()
-{
- return null_value ? 0.0 : cached_value.to_double();
-}
-
-
-longlong Item_copy_decimal::val_int()
-{
- return null_value ? 0 : cached_value.to_longlong(unsigned_flag);
-}
-
-
-void Item_copy_decimal::copy()
-{
- my_decimal *nr= item->val_decimal(&cached_value);
- if (nr && nr != &cached_value)
- my_decimal2decimal (nr, &cached_value);
- null_value= item->null_value;
-}
-
-
/*
Functions to convert item to field (for send_result_set_metadata)
*/
@@ -4991,9 +4843,9 @@ String* Item_ref_null_helper::val_str(String* s)
}
-bool Item_ref_null_helper::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_ref_null_helper::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return (owner->was_null|= null_value= (*ref)->get_date_result(ltime, fuzzydate));
+ return (owner->was_null|= null_value= (*ref)->get_date_result(thd, ltime, fuzzydate));
}
@@ -7032,11 +6884,11 @@ Item *Item_date_literal::clone_item(THD *thd)
}
-bool Item_date_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_date_literal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- fuzzy_date |= sql_mode_for_dates(current_thd);
+ fuzzydate |= sql_mode_for_dates(thd);
*ltime= cached_time;
- return (null_value= check_date_with_warn(ltime, fuzzy_date,
+ return (null_value= check_date_with_warn(thd, ltime, fuzzydate,
MYSQL_TIMESTAMP_ERROR));
}
@@ -7057,11 +6909,11 @@ Item *Item_datetime_literal::clone_item(THD *thd)
}
-bool Item_datetime_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_datetime_literal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- fuzzy_date |= sql_mode_for_dates(current_thd);
+ fuzzydate |= sql_mode_for_dates(thd);
*ltime= cached_time;
- return (null_value= check_date_with_warn(ltime, fuzzy_date,
+ return (null_value= check_date_with_warn(thd, ltime, fuzzydate,
MYSQL_TIMESTAMP_ERROR));
}
@@ -7082,12 +6934,12 @@ Item *Item_time_literal::clone_item(THD *thd)
}
-bool Item_time_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_time_literal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
*ltime= cached_time;
- if (fuzzy_date & TIME_TIME_ONLY)
+ if (fuzzydate & TIME_TIME_ONLY)
return (null_value= false);
- return (null_value= check_date_with_warn(ltime, fuzzy_date,
+ return (null_value= check_date_with_warn(thd, ltime, fuzzydate,
MYSQL_TIMESTAMP_ERROR));
}
@@ -7594,7 +7446,7 @@ Item *Item_direct_view_ref::derived_field_transformer_for_where(THD *thd,
DBUG_ASSERT (producing_item != NULL);
return producing_item->build_clone(thd);
}
- return this;
+ return (*ref);
}
static
@@ -7656,7 +7508,7 @@ Item_direct_view_ref::grouping_field_transformer_for_where(THD *thd,
void Item_field::print(String *str, enum_query_type query_type)
{
if (field && field->table->const_table &&
- !(query_type & QT_NO_DATA_EXPANSION))
+ !(query_type & (QT_NO_DATA_EXPANSION | QT_VIEW_INTERNAL)))
{
print_value(str);
return;
@@ -8313,9 +8165,9 @@ bool Item_ref::is_null()
}
-bool Item_ref::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Item_ref::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return (null_value=(*ref)->get_date_result(ltime,fuzzydate));
+ return (null_value=(*ref)->get_date_result(thd, ltime, fuzzydate));
}
@@ -8450,9 +8302,9 @@ bool Item_direct_ref::is_null()
}
-bool Item_direct_ref::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Item_direct_ref::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return (null_value=(*ref)->get_date(ltime,fuzzydate));
+ return (null_value=(*ref)->get_date(thd, ltime, fuzzydate));
}
@@ -8829,18 +8681,18 @@ bool Item_cache_wrapper::is_null()
Get the date value of the possibly cached item
*/
-bool Item_cache_wrapper::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_cache_wrapper::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
Item *cached_value;
DBUG_ENTER("Item_cache_wrapper::get_date");
if (!expr_cache)
- DBUG_RETURN((null_value= orig_item->get_date(ltime, fuzzydate)));
+ DBUG_RETURN((null_value= orig_item->get_date(thd, ltime, fuzzydate)));
if ((cached_value= check_cache()))
- DBUG_RETURN((null_value= cached_value->get_date(ltime, fuzzydate)));
+ DBUG_RETURN((null_value= cached_value->get_date(thd, ltime, fuzzydate)));
cache();
- DBUG_RETURN((null_value= expr_value->get_date(ltime, fuzzydate)));
+ DBUG_RETURN((null_value= expr_value->get_date(thd, ltime, fuzzydate)));
}
@@ -9257,10 +9109,10 @@ my_decimal *Item_default_value::val_decimal(my_decimal *decimal_value)
return Item_field::val_decimal(decimal_value);
}
-bool Item_default_value::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Item_default_value::get_date(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate)
{
calculate();
- return Item_field::get_date(ltime, fuzzydate);
+ return Item_field::get_date(thd, ltime, fuzzydate);
}
bool Item_default_value::send(Protocol *protocol, st_value *buffer)
@@ -9363,7 +9215,7 @@ my_decimal *Item_ignore_value::val_decimal(my_decimal *decimal_value)
return 0;
}
-bool Item_ignore_value::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_ignore_value::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(0); // never should be called
null_value= 1;
@@ -9605,13 +9457,11 @@ void Item_trigger_field::cleanup()
Item_result item_cmp_type(Item_result a,Item_result b)
{
- if (a == STRING_RESULT && b == STRING_RESULT)
- return STRING_RESULT;
- if (a == INT_RESULT && b == INT_RESULT)
- return INT_RESULT;
- else if (a == ROW_RESULT || b == ROW_RESULT)
+ if (a == b)
+ return a;
+ if (a == ROW_RESULT || b == ROW_RESULT)
return ROW_RESULT;
- else if (a == TIME_RESULT || b == TIME_RESULT)
+ if (a == TIME_RESULT || b == TIME_RESULT)
return TIME_RESULT;
if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
(b == INT_RESULT || b == DECIMAL_RESULT))
@@ -9798,7 +9648,7 @@ bool Item_cache_temporal::cache_value()
if (!example)
return false;
value_cached= true;
- value= example->val_datetime_packed_result();
+ value= example->val_datetime_packed_result(current_thd);
null_value= example->null_value;
return true;
}
@@ -9809,16 +9659,14 @@ bool Item_cache_time::cache_value()
if (!example)
return false;
value_cached= true;
- value= example->val_time_packed_result();
+ value= example->val_time_packed_result(current_thd);
null_value= example->null_value;
return true;
}
-bool Item_cache_temporal::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_cache_temporal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- ErrConvInteger str(value);
-
if (!has_value())
{
bzero((char*) ltime,sizeof(*ltime));
@@ -9833,7 +9681,7 @@ bool Item_cache_temporal::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
int Item_cache_temporal::save_in_field(Field *field, bool no_conversions)
{
MYSQL_TIME ltime;
- if (get_date(&ltime, 0))
+ if (get_date(field->get_thd(), &ltime, date_mode_t(0)))
return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
int error= field->store_time_dec(&ltime, decimals);
@@ -9876,21 +9724,21 @@ Item *Item_cache_temporal::convert_to_basic_const_item(THD *thd)
Item *Item_cache_datetime::make_literal(THD *thd)
{
MYSQL_TIME ltime;
- unpack_time(val_datetime_packed(), &ltime, MYSQL_TIMESTAMP_DATETIME);
+ unpack_time(val_datetime_packed(thd), &ltime, MYSQL_TIMESTAMP_DATETIME);
return new (thd->mem_root) Item_datetime_literal(thd, &ltime, decimals);
}
Item *Item_cache_date::make_literal(THD *thd)
{
MYSQL_TIME ltime;
- unpack_time(val_datetime_packed(), &ltime, MYSQL_TIMESTAMP_DATE);
+ unpack_time(val_datetime_packed(thd), &ltime, MYSQL_TIMESTAMP_DATE);
return new (thd->mem_root) Item_date_literal(thd, &ltime);
}
Item *Item_cache_time::make_literal(THD *thd)
{
MYSQL_TIME ltime;
- unpack_time(val_time_packed(), &ltime, MYSQL_TIMESTAMP_TIME);
+ unpack_time(val_time_packed(thd), &ltime, MYSQL_TIMESTAMP_TIME);
return new (thd->mem_root) Item_time_literal(thd, &ltime, decimals);
}
@@ -9916,7 +9764,7 @@ longlong Item_cache_real::val_int()
{
if (!has_value())
return 0;
- return (longlong) rint(value);
+ return Converter_double_to_longlong(value, unsigned_flag).result();
}
@@ -10238,7 +10086,7 @@ String *Item_type_holder::val_str(String*)
return 0;
}
-bool Item_type_holder::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_type_holder::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(0); // should never be called
return true;
diff --git a/sql/item.h b/sql/item.h
index 727d1f33f5f..c2666c35c67 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -28,6 +28,7 @@
#include "field.h" /* Derivation */
#include "sql_type.h"
#include "sql_time.h"
+#include "mem_root_array.h"
C_MODE_START
#include <ma_dyncol.h>
@@ -861,19 +862,14 @@ protected:
value= NULL;
return value;
}
- bool get_date_from_item(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date_from_item(THD *thd, Item *item,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- bool rc= item->get_date(ltime, fuzzydate);
+ bool rc= item->get_date(thd, ltime, fuzzydate);
null_value= MY_TEST(rc || item->null_value);
return rc;
}
public:
- /*
- This method is used if the item was not null but convertion to
- TIME/DATE/DATETIME failed. We return a zero date if allowed,
- otherwise - null.
- */
- bool make_zero_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
/*
Cache val_str() into the own buffer, e.g. to evaluate constant
@@ -994,9 +990,9 @@ public:
DBUG_ASSERT(0);
}
- bool save_in_value(struct st_value *value)
+ bool save_in_value(THD *thd, struct st_value *value)
{
- return type_handler()->Item_save_in_value(this, value);
+ return type_handler()->Item_save_in_value(thd, this, value);
}
/* Function returns 1 on overflow and -1 on fatal errors */
@@ -1170,6 +1166,12 @@ public:
If value is not null null_value flag will be reset to FALSE.
*/
virtual double val_real()=0;
+ Double_null to_double_null()
+ {
+ // val_real() must be caleed on a separate line. See to_longlong_null()
+ double nr= val_real();
+ return Double_null(nr, null_value);
+ }
/*
Return integer representation of item.
@@ -1181,6 +1183,20 @@ public:
If value is not null null_value flag will be reset to FALSE.
*/
virtual longlong val_int()=0;
+ Longlong_null to_longlong_null()
+ {
+ longlong nr= val_int();
+ /*
+ C++ does not guarantee the order of parameter evaluation,
+ so to make sure "null_value" is passed to the constructor
+ after the val_int() call, val_int() is caled on a separate line.
+ */
+ return Longlong_null(nr, null_value);
+ }
+ Longlong_hybrid_null to_longlong_hybrid_null()
+ {
+ return Longlong_hybrid_null(to_longlong_null(), unsigned_flag);
+ }
/**
Get a value for CAST(x AS SIGNED).
Too large positive unsigned integer values are converted
@@ -1505,14 +1521,14 @@ public:
/**
TIME or DATETIME precision of the item: 0..6
*/
- uint time_precision()
+ uint time_precision(THD *thd)
{
- return const_item() ? type_handler()->Item_time_precision(this) :
+ return const_item() ? type_handler()->Item_time_precision(thd, this) :
MY_MIN(decimals, TIME_SECOND_PART_DIGITS);
}
- uint datetime_precision()
+ uint datetime_precision(THD *thd)
{
- return const_item() ? type_handler()->Item_datetime_precision(this) :
+ return const_item() ? type_handler()->Item_datetime_precision(thd, this) :
MY_MIN(decimals, TIME_SECOND_PART_DIGITS);
}
virtual longlong val_int_min() const
@@ -1610,33 +1626,33 @@ public:
void split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &fields,
Item **ref, uint flags);
- virtual bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)= 0;
- bool get_date_from_int(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool get_date_from_real(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool get_date_from_string(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool get_time(MYSQL_TIME *ltime)
- { return get_date(ltime, Time::flags_for_get_date()); }
+ virtual bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)= 0;
+ bool get_date_from_int(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool get_date_from_real(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool get_date_from_string(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool get_time(THD *thd, MYSQL_TIME *ltime)
+ { return get_date(thd, ltime, Time::flags_for_get_date()); }
// Get a DATE or DATETIME value in numeric packed format for comparison
- virtual longlong val_datetime_packed()
+ virtual longlong val_datetime_packed(THD *thd)
{
- ulonglong fuzzydate= Datetime::comparison_flags_for_get_date();
+ date_mode_t fuzzydate= Datetime::comparison_flags_for_get_date();
return Datetime(current_thd, this, fuzzydate).to_packed();
}
// Get a TIME value in numeric packed format for comparison
- virtual longlong val_time_packed()
+ virtual longlong val_time_packed(THD *thd)
{
- return Time(this, Time::comparison_flags_for_get_date()).to_packed();
+ return Time(thd, this, Time::comparison_flags_for_get_date()).to_packed();
}
- longlong val_datetime_packed_result();
- longlong val_time_packed_result()
+ longlong val_datetime_packed_result(THD *thd);
+ longlong val_time_packed_result(THD *thd)
{
MYSQL_TIME ltime;
- ulonglong fuzzydate= Time::comparison_flags_for_get_date();
- return get_date_result(&ltime, fuzzydate) ? 0 : pack_time(&ltime);
+ date_mode_t fuzzydate= Time::comparison_flags_for_get_date();
+ return get_date_result(thd, &ltime, fuzzydate) ? 0 : pack_time(&ltime);
}
- virtual bool get_date_result(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date(ltime,fuzzydate); }
+ virtual bool get_date_result(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date(thd, ltime,fuzzydate); }
/*
The method allows to determine nullness of a complex expression
without fully evaluating it, instead of calling val/result*() then
@@ -1765,6 +1781,11 @@ public:
virtual bool limit_index_condition_pushdown_processor(void *arg) { return 0; }
virtual bool exists2in_processor(void *arg) { return 0; }
virtual bool find_selective_predicates_list_processor(void *arg) { return 0; }
+ bool cleanup_is_expensive_cache_processor(void *arg)
+ {
+ is_expensive_cache= (int8)(-1);
+ return 0;
+ }
/*
TRUE if the expression depends only on the table indicated by tab_map
@@ -2388,6 +2409,15 @@ protected:
}
return true;
}
+ bool eq(const Item_args *other, bool binary_cmp) const
+ {
+ for (uint i= 0; i < arg_count ; i++)
+ {
+ if (!args[i]->eq(other->args[i], binary_cmp))
+ return false;
+ }
+ return true;
+ }
bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred)
{
for (uint i= 0; i < arg_count; i++)
@@ -2653,7 +2683,7 @@ public:
longlong val_int();
String *val_str(String *sp);
my_decimal *val_decimal(my_decimal *decimal_value);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool is_null();
public:
@@ -2943,7 +2973,7 @@ public:
longlong val_int();
String *val_str(String *sp);
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool is_null();
virtual void print(String *str, enum_query_type query_type);
@@ -3003,9 +3033,9 @@ class Item_num: public Item_literal
public:
Item_num(THD *thd): Item_literal(thd) { collation.set_numeric(); }
Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate);
}
};
@@ -3136,7 +3166,7 @@ public:
longlong val_int() { return field->val_int(); }
String *val_str(String *str) { return field->val_str(str); }
my_decimal *val_decimal(my_decimal *dec) { return field->val_decimal(dec); }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
return field->get_date(ltime, fuzzydate);
}
@@ -3254,8 +3284,8 @@ public:
return MONOTONIC_STRICT_INCREASING;
}
longlong val_int_endpoint(bool left_endp, bool *incl_endp);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool get_date_result(MYSQL_TIME *ltime,ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool get_date_result(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate);
bool is_null() { return field->is_null(); }
void update_null_value();
void update_table_bitmaps()
@@ -3460,7 +3490,7 @@ public:
longlong val_int();
String *val_str(String *str);
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
int save_in_field(Field *field, bool no_conversions);
int save_safe_in_field(Field *field);
bool send(Protocol *protocol, st_value *buffer);
@@ -3779,7 +3809,7 @@ public:
{
return can_return_value() ? value.val_str(str, this) : NULL;
}
- bool get_date(MYSQL_TIME *tm, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *tm, date_mode_t fuzzydate);
int save_in_field(Field *field, bool no_conversions);
void set_default();
@@ -3904,6 +3934,10 @@ public:
bool check_vcol_func_processor(void *int_arg) {return FALSE;}
Item *get_copy(THD *thd) { return 0; }
+ bool add_as_clone(THD *thd);
+ void sync_clones();
+ bool register_clone(Item_param *i) { return m_clones.push_back(i); }
+
private:
void invalid_default_param() const;
@@ -3921,6 +3955,12 @@ public:
private:
Send_field *m_out_param_info;
bool m_is_settable_routine_parameter;
+ /*
+ Array of all references of this parameter marker used in a CTE to its clones
+ created for copies of this marker used the CTE's copies. It's used to
+ synchronize the actual value of the parameter with the values of the clones.
+ */
+ Mem_root_array<Item_param *, true> m_clones;
};
@@ -4027,7 +4067,7 @@ public:
longlong val_int();
double val_real() { return (double)val_int(); }
void set(longlong packed, enum_mysql_timestamp_type ts_type);
- bool get_date(MYSQL_TIME *to, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate)
{
*to= ltime;
return false;
@@ -4226,9 +4266,9 @@ public:
return (String*) &str_value;
}
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return get_date_from_string(ltime, fuzzydate);
+ return get_date_from_string(thd, ltime, fuzzydate);
}
int save_in_field(Field *field, bool no_conversions);
const Type_handler *type_handler() const { return &type_handler_varchar; }
@@ -4478,9 +4518,9 @@ public:
}
const String *const_ptr_string() const { return &str_value; }
String *val_str(String*) { return &str_value; }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate);
}
};
@@ -4625,7 +4665,7 @@ public:
double val_real() { return Date(this).to_double(); }
String *val_str(String *to) { return Date(this).to_string(to); }
my_decimal *val_decimal(my_decimal *to) { return Date(this).to_decimal(to); }
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_date_literal>(thd, this); }
};
@@ -4649,7 +4689,7 @@ public:
double val_real() { return Time(this).to_double(); }
String *val_str(String *to) { return Time(this).to_string(to, decimals); }
my_decimal *val_decimal(my_decimal *to) { return Time(this).to_decimal(to); }
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_time_literal>(thd, this); }
};
@@ -4681,7 +4721,7 @@ public:
{
return Datetime(this).to_decimal(to);
}
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_datetime_literal>(thd, this); }
};
@@ -4718,7 +4758,7 @@ class Item_date_literal_for_invalid_dates: public Item_date_literal
public:
Item_date_literal_for_invalid_dates(THD *thd, const MYSQL_TIME *ltime)
:Item_date_literal(thd, ltime) { }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
*ltime= cached_time;
return (null_value= false);
@@ -4736,7 +4776,7 @@ public:
Item_datetime_literal_for_invalid_dates(THD *thd,
const MYSQL_TIME *ltime, uint dec_arg)
:Item_datetime_literal(thd, ltime, dec_arg) { }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
*ltime= cached_time;
return (null_value= false);
@@ -5018,7 +5058,7 @@ public:
bool val_bool();
String *val_str(String* tmp);
bool is_null();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
double val_result();
longlong val_int_result();
String *str_result(String* tmp);
@@ -5229,7 +5269,7 @@ public:
my_decimal *val_decimal(my_decimal *);
bool val_bool();
bool is_null();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
virtual Ref_Type ref_type() { return DIRECT_REF; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_direct_ref>(thd, this); }
@@ -5325,7 +5365,7 @@ public:
my_decimal *val_decimal(my_decimal *);
bool val_bool();
bool is_null();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool send(Protocol *protocol, st_value *buffer);
void save_org_in_field(Field *field,
fast_field_copier data __attribute__ ((__unused__)))
@@ -5539,14 +5579,14 @@ public:
else
return Item_direct_ref::is_null();
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
if (check_null_ref())
{
bzero((char*) ltime,sizeof(*ltime));
return 1;
}
- return Item_direct_ref::get_date(ltime, fuzzydate);
+ return Item_direct_ref::get_date(thd, ltime, fuzzydate);
}
bool send(Protocol *protocol, st_value *buffer);
void save_org_in_field(Field *field,
@@ -5662,7 +5702,7 @@ public:
String* val_str(String* s);
my_decimal *val_decimal(my_decimal *);
bool val_bool();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
virtual void print(String *str, enum_query_type query_type);
table_map used_tables() const;
Item *get_copy(THD *thd)
@@ -5716,7 +5756,7 @@ public:
Base class to implement typed value caching Item classes
Item_copy_ classes are very similar to the corresponding Item_
- classes (e.g. Item_copy_int is similar to Item_int) but they add
+ classes (e.g. Item_copy_string is similar to Item_string) but they add
the following additional functionality to Item_ :
1. Nullability
2. Possibility to store the value not only on instantiation time,
@@ -5763,13 +5803,6 @@ protected:
}
public:
- /**
- Factory method to create the appropriate subclass dependent on the type of
- the original item.
-
- @param item the original item.
- */
- static Item_copy *create(THD *thd, Item *item);
/**
Update the cache with the value of the original item
@@ -5834,8 +5867,8 @@ public:
my_decimal *val_decimal(my_decimal *);
double val_real();
longlong val_int();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_string(ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_string(thd, ltime, fuzzydate); }
void copy();
int save_in_field(Field *field, bool no_conversions);
Item *get_copy(THD *thd)
@@ -5843,107 +5876,6 @@ public:
};
-class Item_copy_int : public Item_copy
-{
-protected:
- longlong cached_value;
-public:
- Item_copy_int(THD *thd, Item *i): Item_copy(thd, i) {}
- int save_in_field(Field *field, bool no_conversions);
-
- virtual String *val_str(String*);
- virtual my_decimal *val_decimal(my_decimal *);
- virtual double val_real()
- {
- return null_value ? 0.0 : (double) cached_value;
- }
- virtual longlong val_int()
- {
- return null_value ? 0 : cached_value;
- }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_int(ltime, fuzzydate); }
- virtual void copy();
- Item *get_copy(THD *thd)
- { return get_item_copy<Item_copy_int>(thd, this); }
-};
-
-
-class Item_copy_uint : public Item_copy_int
-{
-public:
- Item_copy_uint(THD *thd, Item *item_arg): Item_copy_int(thd, item_arg)
- {
- unsigned_flag= 1;
- }
-
- String *val_str(String*);
- double val_real()
- {
- return null_value ? 0.0 : (double) (ulonglong) cached_value;
- }
- Item *get_copy(THD *thd)
- { return get_item_copy<Item_copy_uint>(thd, this); }
-};
-
-
-class Item_copy_float : public Item_copy
-{
-protected:
- double cached_value;
-public:
- Item_copy_float(THD *thd, Item *i): Item_copy(thd, i) {}
- int save_in_field(Field *field, bool no_conversions);
-
- String *val_str(String*);
- my_decimal *val_decimal(my_decimal *);
- double val_real()
- {
- return null_value ? 0.0 : cached_value;
- }
- longlong val_int()
- {
- return (longlong) rint(val_real());
- }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- {
- return get_date_from_real(ltime, fuzzydate);
- }
- void copy()
- {
- cached_value= item->val_real();
- null_value= item->null_value;
- }
- Item *get_copy(THD *thd)
- { return get_item_copy<Item_copy_float>(thd, this); }
-};
-
-
-class Item_copy_decimal : public Item_copy
-{
-protected:
- my_decimal cached_value;
-public:
- Item_copy_decimal(THD *thd, Item *i): Item_copy(thd, i) {}
- int save_in_field(Field *field, bool no_conversions);
-
- String *val_str(String*);
- my_decimal *val_decimal(my_decimal *)
- {
- return null_value ? NULL: &cached_value;
- }
- double val_real();
- longlong val_int();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- {
- return VDec(this).to_datetime_with_warn(ltime, fuzzydate, this);
- }
- void copy();
- Item *get_copy(THD *thd)
- { return get_item_copy<Item_copy_decimal>(thd, this); }
-};
-
-
/*
Cached_item_XXX objects are not exactly caches. They do the following:
@@ -6077,7 +6009,7 @@ public:
double val_real();
longlong val_int();
my_decimal *val_decimal(my_decimal *decimal_value);
- bool get_date(MYSQL_TIME *ltime,ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate);
bool send(Protocol *protocol, st_value *buffer);
int save_in_field(Field *field_arg, bool no_conversions);
bool save_in_param(THD *thd, Item_param *param)
@@ -6129,7 +6061,7 @@ public:
double val_real();
longlong val_int();
my_decimal *val_decimal(my_decimal *decimal_value);
- bool get_date(MYSQL_TIME *ltime,ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate);
bool send(Protocol *protocol, st_value *buffer);
};
@@ -6446,8 +6378,8 @@ public:
longlong val_int();
String* val_str(String *str);
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_int(ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_int(thd, ltime, fuzzydate); }
bool cache_value();
int save_in_field(Field *field, bool no_conversions);
Item *convert_to_basic_const_item(THD *thd);
@@ -6461,10 +6393,9 @@ class Item_cache_year: public Item_cache_int
public:
Item_cache_year(THD *thd, const Type_handler *handler)
:Item_cache_int(thd, handler) { }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t mode)
{
- return null_value=
- VYear(this).to_mysql_time_with_warn(ltime, fuzzydate, NULL);
+ return type_handler_year.Item_get_date_with_warn(thd, this, to, mode);
}
};
@@ -6475,7 +6406,7 @@ protected:
Item_cache_temporal(THD *thd, const Type_handler *handler);
public:
bool cache_value();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
int save_in_field(Field *field, bool no_conversions);
void store_packed(longlong val_arg, Item *example);
/*
@@ -6498,12 +6429,12 @@ public:
Item *get_copy(THD *thd)
{ return get_item_copy<Item_cache_time>(thd, this); }
Item *make_literal(THD *);
- longlong val_datetime_packed()
+ longlong val_datetime_packed(THD *thd)
{
- ulonglong fuzzy= Datetime::comparison_flags_for_get_date();
- return has_value() ? Datetime(current_thd, this, fuzzy).to_longlong() : 0;
+ date_mode_t fuzzy= Datetime::comparison_flags_for_get_date();
+ return has_value() ? Datetime(thd, this, fuzzy).to_packed() : 0;
}
- longlong val_time_packed()
+ longlong val_time_packed(THD *thd)
{
return has_value() ? value : 0;
}
@@ -6534,13 +6465,13 @@ public:
Item *get_copy(THD *thd)
{ return get_item_copy<Item_cache_datetime>(thd, this); }
Item *make_literal(THD *);
- longlong val_datetime_packed()
+ longlong val_datetime_packed(THD *thd)
{
return has_value() ? value : 0;
}
- longlong val_time_packed()
+ longlong val_time_packed(THD *thd)
{
- return Time(this, Time::comparison_flags_for_get_date()).to_packed();
+ return Time(thd, this, Time::comparison_flags_for_get_date()).to_packed();
}
longlong val_int()
{
@@ -6569,13 +6500,13 @@ public:
Item *get_copy(THD *thd)
{ return get_item_copy<Item_cache_date>(thd, this); }
Item *make_literal(THD *);
- longlong val_datetime_packed()
+ longlong val_datetime_packed(THD *thd)
{
return has_value() ? value : 0;
}
- longlong val_time_packed()
+ longlong val_time_packed(THD *thd)
{
- return Time(this, Time::comparison_flags_for_get_date()).to_packed();
+ return Time(thd, this, Time::comparison_flags_for_get_date()).to_packed();
}
longlong val_int() { return has_value() ? Date(this).to_longlong() : 0; }
double val_real() { return has_value() ? Date(this).to_double() : 0; }
@@ -6601,8 +6532,8 @@ public:
longlong val_int();
String* val_str(String *str);
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_real(ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_real(thd, ltime, fuzzydate); }
bool cache_value();
Item *convert_to_basic_const_item(THD *thd);
Item *get_copy(THD *thd)
@@ -6621,8 +6552,10 @@ public:
longlong val_int();
String* val_str(String *str);
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return VDec(this).to_datetime_with_warn(ltime, fuzzydate, this); }
+ bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t mode)
+ {
+ return decimal_to_datetime_with_warn(thd, VDec(this).ptr(), to, mode, NULL);
+ }
bool cache_value();
Item *convert_to_basic_const_item(THD *thd);
Item *get_copy(THD *thd)
@@ -6649,8 +6582,8 @@ public:
longlong val_int();
String* val_str(String *);
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_string(ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_string(thd, ltime, fuzzydate); }
CHARSET_INFO *charset() const { return value->charset(); };
int save_in_field(Field *field, bool no_conversions);
bool cache_value();
@@ -6731,7 +6664,7 @@ public:
illegal_method_call((const char*)"val_decimal");
return 0;
};
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
illegal_method_call((const char*)"val_decimal");
return true;
@@ -6814,7 +6747,7 @@ public:
longlong val_int();
my_decimal *val_decimal(my_decimal *);
String *val_str(String*);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index b62e71d84fa..f5c49214076 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -684,10 +684,11 @@ Item** Arg_comparator::cache_converted_constant(THD *thd_arg, Item **value,
int Arg_comparator::compare_time()
{
- longlong val1= (*a)->val_time_packed();
+ THD *thd= current_thd;
+ longlong val1= (*a)->val_time_packed(thd);
if (!(*a)->null_value)
{
- longlong val2= (*b)->val_time_packed();
+ longlong val2= (*b)->val_time_packed(thd);
if (!(*b)->null_value)
return compare_not_null_values(val1, val2);
}
@@ -699,8 +700,9 @@ int Arg_comparator::compare_time()
int Arg_comparator::compare_e_time()
{
- longlong val1= (*a)->val_time_packed();
- longlong val2= (*b)->val_time_packed();
+ THD *thd= current_thd;
+ longlong val1= (*a)->val_time_packed(thd);
+ longlong val2= (*b)->val_time_packed(thd);
if ((*a)->null_value || (*b)->null_value)
return MY_TEST((*a)->null_value && (*b)->null_value);
return MY_TEST(val1 == val2);
@@ -710,10 +712,11 @@ int Arg_comparator::compare_e_time()
int Arg_comparator::compare_datetime()
{
- longlong val1= (*a)->val_datetime_packed();
+ THD *thd= current_thd;
+ longlong val1= (*a)->val_datetime_packed(thd);
if (!(*a)->null_value)
{
- longlong val2= (*b)->val_datetime_packed();
+ longlong val2= (*b)->val_datetime_packed(thd);
if (!(*b)->null_value)
return compare_not_null_values(val1, val2);
}
@@ -725,8 +728,9 @@ int Arg_comparator::compare_datetime()
int Arg_comparator::compare_e_datetime()
{
- longlong val1= (*a)->val_datetime_packed();
- longlong val2= (*b)->val_datetime_packed();
+ THD *thd= current_thd;
+ longlong val1= (*a)->val_datetime_packed(thd);
+ longlong val2= (*b)->val_datetime_packed(thd);
if ((*a)->null_value || (*b)->null_value)
return MY_TEST((*a)->null_value && (*b)->null_value);
return MY_TEST(val1 == val2);
@@ -823,7 +827,7 @@ int Arg_comparator::compare_e_real()
int Arg_comparator::compare_e_decimal()
{
VDec val1(*a), val2(*b);
- if (val1.is_null() || val1.is_null())
+ if (val1.is_null() || val2.is_null())
return MY_TEST(val1.is_null() && val2.is_null());
return MY_TEST(val1.cmp(val2) == 0);
}
@@ -1786,10 +1790,7 @@ bool Item_func_opt_neg::eq(const Item *item, bool binary_cmp) const
return 0;
if (negated != ((Item_func_opt_neg *) item_func)->negated)
return 0;
- for (uint i=0; i < arg_count ; i++)
- if (!args[i]->eq(item_func->arguments()[i], binary_cmp))
- return 0;
- return 1;
+ return Item_args::eq(item_func, binary_cmp);
}
@@ -2099,22 +2100,24 @@ bool Item_func_between::fix_length_and_dec_temporal(THD *thd)
longlong Item_func_between::val_int_cmp_datetime()
{
- longlong value= args[0]->val_datetime_packed(), a, b;
+ THD *thd= current_thd;
+ longlong value= args[0]->val_datetime_packed(thd), a, b;
if ((null_value= args[0]->null_value))
return 0;
- a= args[1]->val_datetime_packed();
- b= args[2]->val_datetime_packed();
+ a= args[1]->val_datetime_packed(thd);
+ b= args[2]->val_datetime_packed(thd);
return val_int_cmp_int_finalize(value, a, b);
}
longlong Item_func_between::val_int_cmp_time()
{
- longlong value= args[0]->val_time_packed(), a, b;
+ THD *thd= current_thd;
+ longlong value= args[0]->val_time_packed(thd), a, b;
if ((null_value= args[0]->null_value))
return 0;
- a= args[1]->val_time_packed();
- b= args[2]->val_time_packed();
+ a= args[1]->val_time_packed(thd);
+ b= args[2]->val_time_packed(thd);
return val_int_cmp_int_finalize(value, a, b);
}
@@ -2296,12 +2299,12 @@ Item_func_ifnull::str_op(String *str)
}
-bool Item_func_ifnull::date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_func_ifnull::date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
for (uint i= 0; i < 2; i++)
{
- Datetime dt(current_thd, args[i], fuzzydate & ~TIME_FUZZY_DATES);
+ Datetime dt(thd, args[i], fuzzydate & ~TIME_FUZZY_DATES);
if (!(dt.copy_to_mysql_time(ltime, mysql_timestamp_type())))
return (null_value= false);
}
@@ -2309,12 +2312,12 @@ bool Item_func_ifnull::date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
}
-bool Item_func_ifnull::time_op(MYSQL_TIME *ltime)
+bool Item_func_ifnull::time_op(THD *thd, MYSQL_TIME *ltime)
{
DBUG_ASSERT(fixed == 1);
for (uint i= 0; i < 2; i++)
{
- if (!Time(args[i]).copy_to_mysql_time(ltime))
+ if (!Time(thd, args[i]).copy_to_mysql_time(ltime))
return (null_value= false);
}
return (null_value= true);
@@ -2796,23 +2799,23 @@ Item_func_nullif::decimal_op(my_decimal * decimal_value)
bool
-Item_func_nullif::date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
+Item_func_nullif::date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
if (!compare())
return (null_value= true);
- Datetime dt(current_thd, args[2], fuzzydate);
+ Datetime dt(thd, args[2], fuzzydate);
return (null_value= dt.copy_to_mysql_time(ltime, mysql_timestamp_type()));
}
bool
-Item_func_nullif::time_op(MYSQL_TIME *ltime)
+Item_func_nullif::time_op(THD *thd, MYSQL_TIME *ltime)
{
DBUG_ASSERT(fixed == 1);
if (!compare())
return (null_value= true);
- return (null_value= Time(args[2]).copy_to_mysql_time(ltime));
+ return (null_value= Time(thd, args[2]).copy_to_mysql_time(ltime));
}
@@ -2894,7 +2897,7 @@ Item *Item_func_case_simple::find_item()
Item *Item_func_decode_oracle::find_item()
{
uint idx;
- if (!Predicant_to_list_comparator::cmp_nulls_equal(this, &idx))
+ if (!Predicant_to_list_comparator::cmp_nulls_equal(current_thd, this, &idx))
return args[idx + when_count()];
Item **pos= Item_func_decode_oracle::else_expr_addr();
return pos ? pos[0] : 0;
@@ -2970,24 +2973,24 @@ my_decimal *Item_func_case::decimal_op(my_decimal *decimal_value)
}
-bool Item_func_case::date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_func_case::date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
Item *item= find_item();
if (!item)
return (null_value= true);
- Datetime dt(current_thd, item, fuzzydate);
+ Datetime dt(thd, item, fuzzydate);
return (null_value= dt.copy_to_mysql_time(ltime, mysql_timestamp_type()));
}
-bool Item_func_case::time_op(MYSQL_TIME *ltime)
+bool Item_func_case::time_op(THD *thd, MYSQL_TIME *ltime)
{
DBUG_ASSERT(fixed == 1);
Item *item= find_item();
if (!item)
return (null_value= true);
- return (null_value= Time(item).copy_to_mysql_time(ltime));
+ return (null_value= Time(thd, item).copy_to_mysql_time(ltime));
}
@@ -3323,12 +3326,12 @@ double Item_func_coalesce::real_op()
}
-bool Item_func_coalesce::date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_func_coalesce::date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
for (uint i= 0; i < arg_count; i++)
{
- Datetime dt(current_thd, args[i], fuzzydate & ~TIME_FUZZY_DATES);
+ Datetime dt(thd, args[i], fuzzydate & ~TIME_FUZZY_DATES);
if (!dt.copy_to_mysql_time(ltime, mysql_timestamp_type()))
return (null_value= false);
}
@@ -3336,12 +3339,12 @@ bool Item_func_coalesce::date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
}
-bool Item_func_coalesce::time_op(MYSQL_TIME *ltime)
+bool Item_func_coalesce::time_op(THD *thd, MYSQL_TIME *ltime)
{
DBUG_ASSERT(fixed == 1);
for (uint i= 0; i < arg_count; i++)
{
- if (!Time(args[i]).copy_to_mysql_time(ltime))
+ if (!Time(thd, args[i]).copy_to_mysql_time(ltime))
return (null_value= false);
}
return (null_value= true);
@@ -3629,7 +3632,7 @@ void in_datetime::set(uint pos,Item *item)
{
struct packed_longlong *buff= &((packed_longlong*) base)[pos];
- buff->val= item->val_datetime_packed();
+ buff->val= item->val_datetime_packed(current_thd);
buff->unsigned_flag= 1L;
}
@@ -3637,13 +3640,13 @@ void in_time::set(uint pos,Item *item)
{
struct packed_longlong *buff= &((packed_longlong*) base)[pos];
- buff->val= item->val_time_packed();
+ buff->val= item->val_time_packed(current_thd);
buff->unsigned_flag= 1L;
}
uchar *in_datetime::get_value(Item *item)
{
- tmp.val= item->val_datetime_packed();
+ tmp.val= item->val_datetime_packed(current_thd);
if (item->null_value)
return 0;
tmp.unsigned_flag= 1L;
@@ -3652,7 +3655,7 @@ uchar *in_datetime::get_value(Item *item)
uchar *in_time::get_value(Item *item)
{
- tmp.val= item->val_time_packed();
+ tmp.val= item->val_time_packed(current_thd);
if (item->null_value)
return 0;
tmp.unsigned_flag= 1L;
@@ -3993,7 +3996,7 @@ int cmp_item_datetime::cmp_not_null(const Value *val)
int cmp_item_datetime::cmp(Item *arg)
{
- const bool rc= value != arg->val_datetime_packed();
+ const bool rc= value != arg->val_datetime_packed(current_thd);
return (m_null_value || arg->null_value) ? UNKNOWN : rc;
}
@@ -4008,7 +4011,7 @@ int cmp_item_time::cmp_not_null(const Value *val)
int cmp_item_time::cmp(Item *arg)
{
- const bool rc= value != arg->val_time_packed();
+ const bool rc= value != arg->val_time_packed(current_thd);
return (m_null_value || arg->null_value) ? UNKNOWN : rc;
}
@@ -4228,12 +4231,21 @@ bool Item_func_in::value_list_convert_const_to_int(THD *thd)
if (field_item->field_type() == MYSQL_TYPE_LONGLONG ||
field_item->field_type() == MYSQL_TYPE_YEAR)
{
- bool all_converted= TRUE;
+ bool all_converted= true;
Item **arg, **arg_end;
for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++)
{
- if (!convert_const_to_int(thd, field_item, &arg[0]))
- all_converted= FALSE;
+ /*
+ Explicit NULLs should not affect data cmp_type resolution:
+ - we ignore NULLs when calling collect_cmp_type()
+ - we ignore NULLs here
+ So this expression:
+ year_column IN (DATE'2001-01-01', NULL)
+ switches from TIME_RESULT to INT_RESULT.
+ */
+ if (arg[0]->type() != Item::NULL_ITEM &&
+ !convert_const_to_int(thd, field_item, &arg[0]))
+ all_converted= false;
}
if (all_converted)
m_comparator.set_handler(&type_handler_longlong);
@@ -4984,6 +4996,19 @@ Item *Item_cond::build_clone(THD *thd)
}
+bool Item_cond::excl_dep_on_grouping_fields(st_select_lex *sel)
+{
+ List_iterator_fast<Item> li(list);
+ Item *item;
+ while ((item= li++))
+ {
+ if (!item->excl_dep_on_grouping_fields(sel))
+ return false;
+ }
+ return true;
+}
+
+
void Item_cond_and::mark_as_condition_AND_part(TABLE_LIST *embedding)
{
List_iterator<Item> li(list);
@@ -5120,7 +5145,11 @@ longlong Item_func_isnull::val_int()
void Item_func_isnull::print(String *str, enum_query_type query_type)
{
- args[0]->print_parenthesised(str, query_type, precedence());
+ if (const_item() && !args[0]->maybe_null &&
+ !(query_type & (QT_NO_DATA_EXPANSION | QT_VIEW_INTERNAL)))
+ str->append("/*always not null*/ 1");
+ else
+ args[0]->print_parenthesised(str, query_type, precedence());
str->append(STRING_WITH_LEN(" is null"));
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 856aae54a6b..cf210a71433 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1011,8 +1011,8 @@ public:
longlong int_op();
String *str_op(String *);
my_decimal *decimal_op(my_decimal *);
- bool date_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool time_op(MYSQL_TIME *ltime);
+ bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool time_op(THD *thd, MYSQL_TIME *ltime);
bool fix_length_and_dec()
{
if (aggregate_for_result(func_name(), args, arg_count, true))
@@ -1090,8 +1090,8 @@ public:
longlong int_op();
String *str_op(String *str);
my_decimal *decimal_op(my_decimal *);
- bool date_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool time_op(MYSQL_TIME *ltime);
+ bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool time_op(THD *thd, MYSQL_TIME *ltime);
bool fix_length_and_dec()
{
if (Item_func_case_abbreviation2::fix_length_and_dec2(args))
@@ -1125,12 +1125,12 @@ public:
:Item_func_case_abbreviation2(thd, a, b, c)
{ }
- bool date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- Datetime dt(current_thd, find_item(), fuzzydate);
+ Datetime dt(thd, find_item(), fuzzydate);
return (null_value= dt.copy_to_mysql_time(ltime, mysql_timestamp_type()));
}
- bool time_op(MYSQL_TIME *ltime)
+ bool time_op(THD *thd, MYSQL_TIME *ltime)
{
return (null_value= Time(find_item()).copy_to_mysql_time(ltime));
}
@@ -1243,8 +1243,8 @@ public:
Item_func_hybrid_field_type::cleanup();
arg_count= 2; // See the comment to the constructor
}
- bool date_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool time_op(MYSQL_TIME *ltime);
+ bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool time_op(THD *thd, MYSQL_TIME *ltime);
double real_op();
longlong int_op();
String *str_op(String *str);
@@ -1641,7 +1641,7 @@ public:
{ }
void store_value(Item *item)
{
- value= item->val_datetime_packed();
+ value= item->val_datetime_packed(current_thd);
m_null_value= item->null_value;
}
int cmp_not_null(const Value *val);
@@ -1658,7 +1658,7 @@ public:
{ }
void store_value(Item *item)
{
- value= item->val_time_packed();
+ value= item->val_time_packed(current_thd);
m_null_value= item->null_value;
}
int cmp_not_null(const Value *val);
@@ -1897,7 +1897,7 @@ class Predicant_to_list_comparator
return UNKNOWN;
return in_item->cmp(args->arguments()[m_comparators[i].m_arg_index]);
}
- int cmp_args_nulls_equal(Item_args *args, uint i)
+ int cmp_args_nulls_equal(THD *thd, Item_args *args, uint i)
{
Predicant_to_value_comparator *cmp=
&m_comparators[m_comparators[i].m_handler_index];
@@ -1908,7 +1908,7 @@ class Predicant_to_list_comparator
ValueBuffer<MAX_FIELD_WIDTH> val;
if (m_comparators[i].m_handler_index == i)
in_item->store_value(predicant);
- m_comparators[i].m_handler->Item_save_in_value(arg, &val);
+ m_comparators[i].m_handler->Item_save_in_value(thd, arg, &val);
if (predicant->null_value && val.is_null())
return FALSE; // Two nulls are equal
if (predicant->null_value || val.is_null())
@@ -2089,12 +2089,12 @@ public:
/*
Same as above, but treats two NULLs as equal, e.g. as in DECODE_ORACLE().
*/
- bool cmp_nulls_equal(Item_args *args, uint *idx)
+ bool cmp_nulls_equal(THD *thd, Item_args *args, uint *idx)
{
for (uint i= 0 ; i < m_comparator_count ; i++)
{
DBUG_ASSERT(m_comparators[i].m_handler != NULL);
- if (cmp_args_nulls_equal(args, i) == FALSE)
+ if (cmp_args_nulls_equal(thd, args, i) == FALSE)
{
*idx= m_comparators[i].m_arg_index;
return false; // Found a matching value
@@ -2130,8 +2130,8 @@ public:
longlong int_op();
String *str_op(String *);
my_decimal *decimal_op(my_decimal *);
- bool date_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool time_op(MYSQL_TIME *ltime);
+ bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool time_op(THD *thd, MYSQL_TIME *ltime);
bool fix_fields(THD *thd, Item **ref);
table_map not_null_tables() const { return 0; }
const char *func_name() const { return "case"; }
@@ -2160,6 +2160,7 @@ public:
DBUG_ASSERT(arg_count >= 2);
reorder_args(0);
}
+ enum Functype functype() const { return CASE_SEARCHED_FUNC; }
void print(String *str, enum_query_type query_type);
bool fix_length_and_dec();
Item *propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
@@ -2212,6 +2213,7 @@ public:
Predicant_to_list_comparator::cleanup();
DBUG_VOID_RETURN;
}
+ enum Functype functype() const { return CASE_SIMPLE_FUNC; }
void print(String *str, enum_query_type query_type);
bool fix_length_and_dec();
Item *propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond);
@@ -2846,16 +2848,7 @@ public:
bool fix_length_and_dec();
const char *func_name() const { return "regexp"; }
enum precedence precedence() const { return CMP_PRECEDENCE; }
- Item *get_copy(THD *thd)
- { return get_item_copy<Item_func_regex>(thd, this); }
- Item *build_clone(THD *thd)
- {
- Item_func_regex *clone= (Item_func_regex*) Item_bool_func::build_clone(thd);
- if (clone)
- clone->re.reset();
- return clone;
- }
-
+ Item *get_copy(THD *) { return 0; }
void print(String *str, enum_query_type query_type)
{
print_op(str, query_type);
@@ -2895,8 +2888,7 @@ public:
bool fix_fields(THD *thd, Item **ref);
bool fix_length_and_dec();
const char *func_name() const { return "regexp_instr"; }
- Item *get_copy(THD *thd)
- { return get_item_copy<Item_func_regexp_instr>(thd, this); }
+ Item *get_copy(THD *thd) { return 0; }
};
@@ -2974,6 +2966,7 @@ public:
Item_transformer transformer, uchar *arg_t);
bool eval_not_null_tables(void *opt_arg);
Item *build_clone(THD *thd);
+ bool excl_dep_on_grouping_fields(st_select_lex *sel);
};
template <template<class> class LI, class T> class Item_equal_iterator;
diff --git a/sql/item_create.cc b/sql/item_create.cc
index d9b007d4728..87bf69f3c96 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -6103,7 +6103,26 @@ Create_func_name_const Create_func_name_const::s_singleton;
Item*
Create_func_name_const::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
- return new (thd->mem_root) Item_name_const(thd, arg1, arg2);
+ if (!arg1->basic_const_item())
+ goto err;
+
+ if (arg2->basic_const_item())
+ return new (thd->mem_root) Item_name_const(thd, arg1, arg2);
+
+ if (arg2->type() == Item::FUNC_ITEM)
+ {
+ Item_func *value_func= (Item_func *) arg2;
+ if (value_func->functype() != Item_func::COLLATE_FUNC &&
+ value_func->functype() != Item_func::NEG_FUNC)
+ goto err;
+
+ if (!value_func->key_item()->basic_const_item())
+ goto err;
+ return new (thd->mem_root) Item_name_const(thd, arg1, arg2);
+ }
+err:
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "NAME_CONST");
+ return NULL;
}
diff --git a/sql/item_func.cc b/sql/item_func.cc
index fa14bc58f2e..c176a7e43a7 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -647,10 +647,7 @@ bool Item_func::eq(const Item *item, bool binary_cmp) const
(func_type == Item_func::FUNC_SP &&
my_strcasecmp(system_charset_info, func_name(), item_func->func_name())))
return 0;
- for (uint i=0; i < arg_count ; i++)
- if (!args[i]->eq(item_func->args[i], binary_cmp))
- return 0;
- return 1;
+ return Item_args::eq(item_func, binary_cmp);
}
@@ -834,17 +831,6 @@ Item_func_hybrid_field_type::val_decimal_from_int_op(my_decimal *dec)
return dec;
}
-bool Item_func_hybrid_field_type::get_date_from_int_op(MYSQL_TIME *ltime,
- ulonglong fuzzydate)
-{
- longlong value= int_op();
- bool neg= !unsigned_flag && value < 0;
- if (null_value || int_to_datetime_with_warn(neg, neg ? -value : value,
- ltime, fuzzydate, NULL))
- return make_zero_mysql_time(ltime, fuzzydate);
- return (null_value= 0);
-}
-
String *Item_func_hybrid_field_type::val_str_from_real_op(String *str)
{
@@ -857,7 +843,7 @@ String *Item_func_hybrid_field_type::val_str_from_real_op(String *str)
longlong Item_func_hybrid_field_type::val_int_from_real_op()
{
- return (longlong) rint(real_op());
+ return Converter_double_to_longlong(real_op(), unsigned_flag).result();
}
my_decimal *
@@ -870,20 +856,11 @@ Item_func_hybrid_field_type::val_decimal_from_real_op(my_decimal *dec)
return dec;
}
-bool Item_func_hybrid_field_type::get_date_from_real_op(MYSQL_TIME *ltime,
- ulonglong fuzzydate)
-{
- double value= real_op();
- if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate, NULL))
- return make_zero_mysql_time(ltime, fuzzydate);
- return (null_value= 0);
-}
-
String *Item_func_hybrid_field_type::val_str_from_date_op(String *str)
{
MYSQL_TIME ltime;
- if (date_op_with_null_check(&ltime) ||
+ if (date_op_with_null_check(current_thd, &ltime) ||
(null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH)))
return (String *) 0;
str->length(my_TIME_to_str(&ltime, const_cast<char*>(str->ptr()), decimals));
@@ -895,7 +872,7 @@ String *Item_func_hybrid_field_type::val_str_from_date_op(String *str)
double Item_func_hybrid_field_type::val_real_from_date_op()
{
MYSQL_TIME ltime;
- if (date_op_with_null_check(&ltime))
+ if (date_op_with_null_check(current_thd, &ltime))
return 0;
return TIME_to_double(&ltime);
}
@@ -903,7 +880,7 @@ double Item_func_hybrid_field_type::val_real_from_date_op()
longlong Item_func_hybrid_field_type::val_int_from_date_op()
{
MYSQL_TIME ltime;
- if (date_op_with_null_check(&ltime))
+ if (date_op_with_null_check(current_thd, &ltime))
return 0;
return TIME_to_ulonglong(&ltime);
}
@@ -912,7 +889,7 @@ my_decimal *
Item_func_hybrid_field_type::val_decimal_from_date_op(my_decimal *dec)
{
MYSQL_TIME ltime;
- if (date_op_with_null_check(&ltime))
+ if (date_op_with_null_check(current_thd, &ltime))
{
my_decimal_set_zero(dec);
return 0;
@@ -924,7 +901,7 @@ Item_func_hybrid_field_type::val_decimal_from_date_op(my_decimal *dec)
String *Item_func_hybrid_field_type::val_str_from_time_op(String *str)
{
MYSQL_TIME ltime;
- if (time_op_with_null_check(&ltime) ||
+ if (time_op_with_null_check(current_thd, &ltime) ||
(null_value= my_TIME_to_str(&ltime, str, decimals)))
return NULL;
return str;
@@ -933,20 +910,22 @@ String *Item_func_hybrid_field_type::val_str_from_time_op(String *str)
double Item_func_hybrid_field_type::val_real_from_time_op()
{
MYSQL_TIME ltime;
- return time_op_with_null_check(&ltime) ? 0 : TIME_to_double(&ltime);
+ return time_op_with_null_check(current_thd, &ltime) ? 0 :
+ TIME_to_double(&ltime);
}
longlong Item_func_hybrid_field_type::val_int_from_time_op()
{
MYSQL_TIME ltime;
- return time_op_with_null_check(&ltime) ? 0 : TIME_to_ulonglong(&ltime);
+ return time_op_with_null_check(current_thd, &ltime) ? 0 :
+ TIME_to_ulonglong(&ltime);
}
my_decimal *
Item_func_hybrid_field_type::val_decimal_from_time_op(my_decimal *dec)
{
MYSQL_TIME ltime;
- if (time_op_with_null_check(&ltime))
+ if (time_op_with_null_check(current_thd, &ltime))
{
my_decimal_set_zero(dec);
return 0;
@@ -974,18 +953,6 @@ Item_func_hybrid_field_type::val_decimal_from_str_op(my_decimal *decimal_value)
return res ? decimal_from_string_with_check(decimal_value, res) : 0;
}
-bool Item_func_hybrid_field_type::get_date_from_str_op(MYSQL_TIME *ltime,
- ulonglong fuzzydate)
-{
- StringBuffer<40> tmp;
- String *res;
- if (!(res= str_op_with_null_check(&tmp)) ||
- str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(),
- ltime, fuzzydate))
- return make_zero_mysql_time(ltime, fuzzydate);
- return (null_value= 0);
-}
-
void Item_func_signed::print(String *str, enum_query_type query_type)
{
@@ -2611,14 +2578,15 @@ bool Item_func_min_max::fix_attributes(Item **items, uint nitems)
0 Otherwise
*/
-bool Item_func_min_max::get_date_native(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_func_min_max::get_date_native(THD *thd, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate)
{
longlong UNINIT_VAR(min_max);
DBUG_ASSERT(fixed == 1);
for (uint i=0; i < arg_count ; i++)
{
- longlong res= args[i]->val_datetime_packed();
+ longlong res= args[i]->val_datetime_packed(thd);
/* Check if we need to stop (because of error or KILL) and stop the loop */
if (unlikely(args[i]->null_value))
@@ -2629,8 +2597,8 @@ bool Item_func_min_max::get_date_native(MYSQL_TIME *ltime, ulonglong fuzzy_date)
}
unpack_time(min_max, ltime, mysql_timestamp_type());
- if (!(fuzzy_date & TIME_TIME_ONLY) &&
- unlikely((null_value= check_date_with_warn(ltime, fuzzy_date,
+ if (!(fuzzydate & TIME_TIME_ONLY) &&
+ unlikely((null_value= check_date_with_warn(thd, ltime, fuzzydate,
MYSQL_TIMESTAMP_ERROR))))
return true;
@@ -2638,17 +2606,17 @@ bool Item_func_min_max::get_date_native(MYSQL_TIME *ltime, ulonglong fuzzy_date)
}
-bool Item_func_min_max::get_time_native(MYSQL_TIME *ltime)
+bool Item_func_min_max::get_time_native(THD *thd, MYSQL_TIME *ltime)
{
DBUG_ASSERT(fixed == 1);
- Time value(args[0]);
+ Time value(thd, args[0], Time::Options(), decimals);
if (!value.is_valid_time())
return (null_value= true);
for (uint i= 1; i < arg_count ; i++)
{
- Time tmp(args[i]);
+ Time tmp(thd, args[i], Time::Options(), decimals);
if (!tmp.is_valid_time())
return (null_value= true);
@@ -5416,7 +5384,8 @@ my_decimal* Item_user_var_as_out_param::val_decimal(my_decimal *decimal_buffer)
}
-bool Item_user_var_as_out_param::get_date(MYSQL_TIME *ltime, ulonglong fuzzy)
+bool Item_user_var_as_out_param::get_date(THD *thd, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate)
{
DBUG_ASSERT(0);
return true;
@@ -6512,10 +6481,10 @@ my_decimal *Item_func_last_value::val_decimal(my_decimal *decimal_value)
}
-bool Item_func_last_value::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_func_last_value::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
evaluate_sideeffects();
- bool tmp= last_value->get_date(ltime, fuzzydate);
+ bool tmp= last_value->get_date(thd, ltime, fuzzydate);
null_value= last_value->null_value;
return tmp;
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 48b2ad2afeb..660d39f48ea 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -76,7 +76,10 @@ public:
SUSERVAR_FUNC, GUSERVAR_FUNC, COLLATE_FUNC,
EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC,
NEG_FUNC, GSYSVAR_FUNC, IN_OPTIMIZER_FUNC, DYNCOL_FUNC,
- JSON_EXTRACT_FUNC };
+ JSON_EXTRACT_FUNC,
+ CASE_SEARCHED_FUNC, // Used by ColumnStore/Spider
+ CASE_SIMPLE_FUNC // Used by ColumnStore/spider
+ };
static scalar_comparison_op functype_to_scalar_comparison_op(Functype type)
{
switch (type) {
@@ -177,12 +180,6 @@ public:
virtual void print(String *str, enum_query_type query_type);
void print_op(String *str, enum_query_type query_type);
void print_args(String *str, uint from, enum_query_type query_type);
- inline bool get_arg0_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
- {
- DBUG_ASSERT(!(fuzzy_date & TIME_TIME_ONLY));
- Datetime dt(current_thd, args[0], fuzzy_date);
- return (null_value= dt.copy_to_mysql_time(ltime));
- }
bool is_null() {
update_null_value();
return null_value;
@@ -410,9 +407,12 @@ public:
String *val_str(String*str);
my_decimal *val_decimal(my_decimal *decimal_value);
longlong val_int()
- { DBUG_ASSERT(fixed == 1); return (longlong) rint(val_real()); }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_real(ltime, fuzzydate); }
+ {
+ DBUG_ASSERT(fixed == 1);
+ return Converter_double_to_longlong(val_real(), unsigned_flag).result();
+ }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_real(thd, ltime, fuzzydate); }
const Type_handler *type_handler() const { return &type_handler_double; }
bool fix_length_and_dec()
{
@@ -464,7 +464,7 @@ public:
virtual double val_real(Item_handled_func *) const= 0;
virtual longlong val_int(Item_handled_func *) const= 0;
virtual my_decimal *val_decimal(Item_handled_func *, my_decimal *) const= 0;
- virtual bool get_date(Item_handled_func *, MYSQL_TIME *, ulonglong fuzzydate) const= 0;
+ virtual bool get_date(THD *thd, Item_handled_func *, MYSQL_TIME *, date_mode_t fuzzydate) const= 0;
virtual const Type_handler *return_type_handler() const= 0;
virtual bool fix_length_and_dec(Item_handled_func *) const= 0;
};
@@ -632,9 +632,9 @@ public:
{
return m_func_handler->val_decimal(this, to);
}
- bool get_date(MYSQL_TIME *to, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate)
{
- return m_func_handler->get_date(this, to, fuzzydate);
+ return m_func_handler->get_date(thd, this, to, fuzzydate);
}
};
@@ -661,15 +661,15 @@ class Item_func_hybrid_field_type: public Item_hybrid_func
Helper methods to make sure that the result of
decimal_op(), str_op() and date_op() is properly synched with null_value.
*/
- bool date_op_with_null_check(MYSQL_TIME *ltime)
+ bool date_op_with_null_check(THD *thd, MYSQL_TIME *ltime)
{
- bool rc= date_op(ltime, 0);
+ bool rc= date_op(thd, ltime, date_mode_t(0));
DBUG_ASSERT(!rc ^ null_value);
return rc;
}
- bool time_op_with_null_check(MYSQL_TIME *ltime)
+ bool time_op_with_null_check(THD *thd, MYSQL_TIME *ltime)
{
- bool rc= time_op(ltime);
+ bool rc= time_op(thd, ltime);
DBUG_ASSERT(!rc ^ null_value);
DBUG_ASSERT(rc || ltime->time_type == MYSQL_TIMESTAMP_TIME);
return rc;
@@ -680,11 +680,6 @@ class Item_func_hybrid_field_type: public Item_hybrid_func
DBUG_ASSERT((res != NULL) ^ null_value);
return res;
}
- bool make_zero_mysql_time(MYSQL_TIME *ltime, ulonglong fuzzydate)
- {
- bzero(ltime, sizeof(*ltime));
- return null_value|= !(fuzzydate & TIME_FUZZY_DATES);
- }
public:
// Value methods that involve no conversion
@@ -723,10 +718,6 @@ public:
double val_real_from_time_op();
double val_real_from_int_op();
- bool get_date_from_str_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool get_date_from_real_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool get_date_from_int_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
-
public:
Item_func_hybrid_field_type(THD *thd):
Item_hybrid_func(thd)
@@ -770,11 +761,11 @@ public:
DBUG_ASSERT(null_value == (res == NULL));
return res;
}
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date)
+ bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t mode)
{
DBUG_ASSERT(fixed);
return Item_func_hybrid_field_type::type_handler()->
- Item_func_hybrid_field_type_get_date(this, res, fuzzy_date);
+ Item_func_hybrid_field_type_get_date_with_warn(thd, this, to, mode);
}
/**
@@ -784,6 +775,20 @@ public:
@return The result of the operation.
*/
virtual longlong int_op()= 0;
+ Longlong_null to_longlong_null_op()
+ {
+ longlong nr= int_op();
+ /*
+ C++ does not guarantee the order of parameter evaluation,
+ so to make sure "null_value" is passed to the constructor
+ after the int_op() call, int_op() is caled on a separate line.
+ */
+ return Longlong_null(nr, null_value);
+ }
+ Longlong_hybrid_null to_longlong_hybrid_null_op()
+ {
+ return Longlong_hybrid_null(to_longlong_null_op(), unsigned_flag);
+ }
/**
@brief Performs the operation that this functions implements when the
@@ -792,6 +797,12 @@ public:
@return The result of the operation.
*/
virtual double real_op()= 0;
+ Double_null to_double_null_op()
+ {
+ // val_real() must be caleed on a separate line. See to_longlong_null()
+ double nr= real_op();
+ return Double_null(nr, null_value);
+ }
/**
@brief Performs the operation that this functions implements when the
@@ -818,14 +829,14 @@ public:
field type is DATETIME or DATE.
@return The result of the operation.
*/
- virtual bool date_op(MYSQL_TIME *res, ulonglong fuzzy_date)= 0;
+ virtual bool date_op(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate)= 0;
/**
@brief Performs the operation that this functions implements when
field type is TIME.
@return The result of the operation.
*/
- virtual bool time_op(MYSQL_TIME *res)= 0;
+ virtual bool time_op(THD *thd, MYSQL_TIME *res)= 0;
};
@@ -884,12 +895,12 @@ public:
Item_func_hybrid_field_type(thd, list)
{ }
String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
- bool date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(0);
return true;
}
- bool time_op(MYSQL_TIME *ltime)
+ bool time_op(THD *thd, MYSQL_TIME *ltime)
{
DBUG_ASSERT(0);
return true;
@@ -975,8 +986,8 @@ public:
{ collation.set_numeric(); }
double val_real();
String *val_str(String*str);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_int(ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_int(thd, ltime, fuzzydate); }
const Type_handler *type_handler() const= 0;
bool fix_length_and_dec() { return FALSE; }
};
@@ -1170,8 +1181,10 @@ public:
double val_real() { return VDec(this).to_double(); }
longlong val_int() { return VDec(this).to_longlong(unsigned_flag); }
my_decimal *val_decimal(my_decimal*);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return VDec(this).to_datetime_with_warn(ltime, fuzzydate, this); }
+ bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t mode)
+ {
+ return decimal_to_datetime_with_warn(thd, VDec(this).ptr(), to, mode, NULL);
+ }
const Type_handler *type_handler() const { return &type_handler_newdecimal; }
void fix_length_and_dec_generic() {}
bool fix_length_and_dec()
@@ -1725,8 +1738,8 @@ public:
double val_real_native();
longlong val_int_native();
my_decimal *val_decimal_native(my_decimal *);
- bool get_date_native(MYSQL_TIME *res, ulonglong fuzzydate);
- bool get_time_native(MYSQL_TIME *res);
+ bool get_date_native(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
+ bool get_time_native(THD *thd, MYSQL_TIME *res);
double val_real()
{
@@ -1752,11 +1765,11 @@ public:
return Item_func_min_max::type_handler()->
Item_func_min_max_val_decimal(this, dec);
}
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date)
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed);
return Item_func_min_max::type_handler()->
- Item_func_min_max_get_date(this, res, fuzzy_date);
+ Item_func_min_max_get_date(thd, this, res, fuzzydate);
}
void aggregate_attributes_real(Item **items, uint nitems)
{
@@ -1823,8 +1836,8 @@ public:
String *val_str(String *str) { return val_str_from_item(args[0], str); }
my_decimal *val_decimal(my_decimal *dec)
{ return val_decimal_from_item(args[0], dec); }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_item(args[0], ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_item(thd, args[0], ltime, fuzzydate); }
const char *func_name() const { return "rollup_const"; }
bool const_item() const { return 0; }
const Type_handler *type_handler() const { return args[0]->type_handler(); }
@@ -2280,9 +2293,9 @@ public:
{
return mark_unsupported_function(func_name(), "()", arg, VCOL_NON_DETERMINISTIC);
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate);
}
};
@@ -2298,7 +2311,8 @@ class Item_func_udf_float :public Item_udf_func
longlong val_int()
{
DBUG_ASSERT(fixed == 1);
- return (longlong) rint(Item_func_udf_float::val_real());
+ return Converter_double_to_longlong(Item_func_udf_float::val_real(),
+ unsigned_flag).result();
}
my_decimal *val_decimal(my_decimal *dec_buf)
{
@@ -2590,8 +2604,10 @@ public:
Field *create_field_for_create_select(TABLE *table)
{ return create_table_field_from_handler(table); }
bool check_vcol_func_processor(void *arg);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return type_handler()->Item_get_date(this, ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ {
+ return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate);
+ }
};
@@ -2772,7 +2788,7 @@ public:
double val_real();
longlong val_int();
String *val_str(String *str);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
my_decimal *val_decimal(my_decimal *decimal_buffer);
/* fix_fields() binds variable name with its entry structure */
bool fix_fields(THD *thd, Item **ref);
@@ -2819,9 +2835,9 @@ public:
String* val_str(String*);
my_decimal *val_decimal(my_decimal *dec_buf)
{ return val_decimal_from_real(dec_buf); }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate);
}
/* TODO: fix to support views */
const char *func_name() const { return "get_system_var"; }
@@ -3111,7 +3127,7 @@ public:
return sp_result_field->val_decimal(dec_buf);
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
if (execute())
return true;
@@ -3165,15 +3181,7 @@ public:
{
return TRUE;
}
- Item *get_copy(THD *thd)
- { return get_item_copy<Item_func_sp>(thd, this); }
- Item *build_clone(THD *thd)
- {
- Item_func_sp *clone= (Item_func_sp *) Item_func::build_clone(thd);
- if (clone)
- clone->sp_result_field= NULL;
- return clone;
- }
+ Item *get_copy(THD *) { return 0; }
bool eval_not_null_tables(void *opt_arg)
{
not_null_tables_cache= 0;
@@ -3273,7 +3281,7 @@ public:
longlong val_int();
String *val_str(String *);
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool fix_length_and_dec();
const char *func_name() const { return "last_value"; }
const Type_handler *type_handler() const { return last_value->type_handler(); }
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc
index 5e7f49e2a26..4ec481cf439 100644
--- a/sql/item_jsonfunc.cc
+++ b/sql/item_jsonfunc.cc
@@ -479,7 +479,7 @@ String *Item_func_json_value::val_str(String *str)
(const uchar *) js->ptr() + js->length());
str->length(0);
- str->set_charset(&my_charset_utf8mb4_bin);
+ str->set_charset(collation.collation);
path.cur_step= path.p.steps;
continue_search:
@@ -1622,13 +1622,15 @@ String *Item_func_json_array_append::val_str(String *str)
if (je.value_type == JSON_VALUE_ARRAY)
{
- if (json_skip_level(&je))
+ int n_items;
+ if (json_skip_level_and_count(&je, &n_items))
goto js_error;
ar_end= je.s.c_str - je.sav_c_len;
str_rest_len= js->length() - (ar_end - (const uchar *) js->ptr());
str->q_append(js->ptr(), ar_end-(const uchar *) js->ptr());
- str->append(", ", 2);
+ if (n_items)
+ str->append(", ", 2);
if (append_json_value(str, args[n_arg+1], &tmp_val))
goto return_null; /* Out of memory. */
@@ -2019,23 +2021,14 @@ continue_j2:
else
{
const uchar *end1, *beg1, *end2, *beg2;
- int empty_array= 0;
+ int n_items1=1, n_items2= 1;
beg1= je1->value_begin;
/* Merge as a single array. */
if (je1->value_type == JSON_VALUE_ARRAY)
{
- int cur_level= je1->stack_p;
- empty_array= 1;
- while (json_scan_next(je1) == 0)
- {
- if (je1->stack_p < cur_level)
- break;
- empty_array= 0;
- }
-
- if (unlikely(je1->s.error))
+ if (json_skip_level_and_count(je1, &n_items1))
return 1;
end1= je1->s.c_str - je1->sav_c_len;
@@ -2054,8 +2047,7 @@ continue_j2:
end1= je1->value_end;
}
- if (str->append((const char*) beg1, end1 - beg1) ||
- (!empty_array && str->append(", ", 2)))
+ if (str->append((const char*) beg1, end1 - beg1))
return 3;
if (json_value_scalar(je2))
@@ -2066,15 +2058,22 @@ continue_j2:
else
{
if (je2->value_type == JSON_VALUE_OBJECT)
+ {
beg2= je2->value_begin;
+ if (json_skip_level(je2))
+ return 2;
+ }
else
+ {
beg2= je2->s.c_str;
- if (json_skip_level(je2))
- return 2;
+ if (json_skip_level_and_count(je2, &n_items2))
+ return 2;
+ }
end2= je2->s.c_str;
}
- if (str->append((const char*) beg2, end2 - beg2))
+ if ((n_items1 && n_items2 && str->append(", ", 2)) ||
+ str->append((const char*) beg2, end2 - beg2))
return 3;
if (je2->value_type != JSON_VALUE_ARRAY &&
@@ -2387,8 +2386,9 @@ String *Item_func_json_insert::val_str(String *str)
if ((null_value= args[0]->null_value))
return 0;
- str->set_charset(js->charset());
- json_string_set_cs(&key_name, js->charset());
+ str->set_charset(collation.collation);
+ tmp_js.set_charset(collation.collation);
+ json_string_set_cs(&key_name, collation.collation);
for (n_arg=1, n_path=0; n_arg < arg_count; n_arg+=2, n_path++)
{
@@ -2602,7 +2602,6 @@ continue_point:
json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
(const uchar *) js->ptr() + js->length());
str->length(0);
- str->set_charset(js->charset());
if (json_nice(&je, str, Item_func_json_format::LOOSE))
goto js_error;
@@ -3057,7 +3056,7 @@ static int append_json_path(String *str, const json_path_t *p)
String *Item_func_json_search::val_str(String *str)
{
String *js= args[0]->val_json(&tmp_js);
- String *s_str= args[2]->val_str(&tmp_js);
+ String *s_str= args[2]->val_str(&tmp_path);
json_engine_t je;
json_path_t p, sav_path;
uint n_arg;
@@ -3306,5 +3305,3 @@ int Arg_comparator::compare_e_json_str_basic(Item *j, Item *s)
return MY_TEST(sortcmp(res1, res2, compare_collation()) == 0);
}
-
-
diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h
index af0995b9605..a4705f012f2 100644
--- a/sql/item_jsonfunc.h
+++ b/sql/item_jsonfunc.h
@@ -407,7 +407,7 @@ public:
class Item_func_json_search: public Item_json_str_multipath
{
protected:
- String tmp_js, esc_value;
+ String tmp_js, tmp_path, esc_value;
bool mode_one;
bool ooa_constant, ooa_parsed;
int escape;
diff --git a/sql/item_row.h b/sql/item_row.h
index 278dc88479d..4f60a33ab9f 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -91,7 +91,7 @@ public:
illegal_method_call((const char*)"val_decimal");
return 0;
};
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
illegal_method_call((const char*)"get_date");
return true;
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 12618d68c27..6c82c580858 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -603,7 +603,7 @@ String *Item_func_concat::val_str(String *str)
goto null;
if (res != str)
- str->copy(res->ptr(), res->length(), res->charset());
+ str->copy_or_move(res->ptr(), res->length(), res->charset());
for (uint i= 1 ; i < arg_count ; i++)
{
@@ -1568,32 +1568,18 @@ String *Item_str_conv::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
String *res;
- if (!(res=args[0]->val_str(str)))
- {
- null_value=1; /* purecov: inspected */
- return 0; /* purecov: inspected */
- }
- null_value=0;
- if (multiply == 1)
- {
- size_t len;
- res= copy_if_not_alloced(&tmp_value, res, res->length());
- len= converter(collation.collation, (char*) res->ptr(), res->length(),
- (char*) res->ptr(), res->length());
- DBUG_ASSERT(len <= res->length());
- res->length(len);
- }
- else
- {
- size_t len= res->length() * multiply;
- tmp_value.alloc(len);
- tmp_value.set_charset(collation.collation);
- len= converter(collation.collation, (char*) res->ptr(), res->length(),
- (char*) tmp_value.ptr(), len);
- tmp_value.length(len);
- res= &tmp_value;
- }
- return res;
+ size_t alloced_length, len;
+
+ if ((null_value= (!(res= args[0]->val_str(&tmp_value)) ||
+ str->alloc((alloced_length= res->length() * multiply)))))
+ return 0;
+
+ len= converter(collation.collation, (char*) res->ptr(), res->length(),
+ (char*) str->ptr(), alloced_length);
+ DBUG_ASSERT(len <= alloced_length);
+ str->set_charset(collation.collation);
+ str->length(len);
+ return str;
}
@@ -1796,7 +1782,7 @@ String *Item_func_substr_index::val_str(String *str)
DBUG_ASSERT(fixed == 1);
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff),system_charset_info);
- String *res= args[0]->val_str(str);
+ String *res= args[0]->val_str(&tmp_value);
String *delimiter= args[1]->val_str(&tmp);
int32 count= (int32) args[2]->val_int();
uint offset;
@@ -1845,20 +1831,31 @@ String *Item_func_substr_index::val_str(String *str)
if (pass == 0) /* count<0 */
{
c+=n+1;
- if (c<=0) return res; /* not found, return original string */
+ if (c<=0)
+ {
+ str->copy(res->ptr(), res->length(), collation.collation);
+ return str; // not found, return the original string
+ }
ptr=res->ptr();
}
else
{
- if (c) return res; /* Not found, return original string */
+ if (c)
+ {
+ str->copy(res->ptr(), res->length(), collation.collation);
+ return str; // not found, return the original string
+ }
if (count>0) /* return left part */
{
- tmp_value.set(*res,0,(ulong) (ptr-res->ptr()));
+ str->copy(res->ptr(), (uint32) (ptr-res->ptr()), collation.collation);
+ return str;
}
else /* return right part */
{
- ptr+= delimiter_length;
- tmp_value.set(*res,(ulong) (ptr-res->ptr()), (ulong) (strend-ptr));
+ ptr+= delimiter_length;
+ str->copy(res->ptr() + (ptr-res->ptr()), (uint32) (strend - ptr),
+ collation.collation);
+ return str;
}
}
}
@@ -1870,13 +1867,16 @@ String *Item_func_substr_index::val_str(String *str)
{ // start counting from the beginning
for (offset=0; ; offset+= delimiter_length)
{
- if ((int) (offset= res->strstr(*delimiter, offset)) < 0)
- return res; // Didn't find, return org string
- if (!--count)
- {
- tmp_value.set(*res,0,offset);
- break;
- }
+ if ((int) (offset= res->strstr(*delimiter, offset)) < 0)
+ {
+ str->copy(res->ptr(), res->length(), collation.collation);
+ return str; // not found, return the original string
+ }
+ if (!--count)
+ {
+ str->copy(res->ptr(), offset, collation.collation);
+ return str;
+ }
}
}
else
@@ -1891,30 +1891,32 @@ String *Item_func_substr_index::val_str(String *str)
address space less than where the found substring is located
in res
*/
- if ((int) (offset= res->strrstr(*delimiter, offset)) < 0)
- return res; // Didn't find, return org string
+ if ((int) (offset= res->strrstr(*delimiter, offset)) < 0)
+ {
+ str->copy(res->ptr(), res->length(), collation.collation);
+ return str; // not found, return the original string
+ }
/*
At this point, we've searched for the substring
the number of times as supplied by the index value
*/
- if (!++count)
- {
- offset+= delimiter_length;
- tmp_value.set(*res,offset,res->length()- offset);
- break;
- }
+ if (!++count)
+ {
+ offset+= delimiter_length;
+ str->copy(res->ptr() + offset, res->length() - offset,
+ collation.collation);
+ return str;
+ }
}
if (count)
- return res; // Didn't find, return org string
+ {
+ str->copy(res->ptr(), res->length(), collation.collation);
+ return str; // not found, return the original string
+ }
}
}
- /*
- We always mark tmp_value as const so that if val_str() is called again
- on this object, we don't disrupt the contents of tmp_value when it was
- derived from another String.
- */
- tmp_value.mark_as_const();
- return (&tmp_value);
+ DBUG_ASSERT(0);
+ return NULL;
}
/*
@@ -4541,11 +4543,11 @@ bool Item_func_dyncol_create::prepare_arguments(THD *thd, bool force_names_arg)
break;
case DYN_COL_DATETIME:
case DYN_COL_DATE:
- args[valpos]->get_date(&vals[i].x.time_value,
+ args[valpos]->get_date(thd, &vals[i].x.time_value,
sql_mode_for_dates(thd));
break;
case DYN_COL_TIME:
- args[valpos]->get_time(&vals[i].x.time_value);
+ args[valpos]->get_time(thd, &vals[i].x.time_value);
break;
default:
DBUG_ASSERT(0);
@@ -5111,7 +5113,7 @@ null:
}
-bool Item_dyncol_get::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_dyncol_get::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DYNAMIC_COLUMN_VALUE val;
char buff[STRING_BUFFER_USUAL_SIZE];
@@ -5132,10 +5134,8 @@ bool Item_dyncol_get::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
if (signed_value || val.x.ulong_value <= LONGLONG_MAX)
{
longlong llval = (longlong)val.x.ulong_value;
- bool neg = llval < 0;
- if (int_to_datetime_with_warn(neg, (ulonglong)(neg ? -llval :
- llval),
- ltime, fuzzy_date, 0 /* TODO */))
+ if (int_to_datetime_with_warn(thd, Longlong_hybrid(llval, !signed_value),
+ ltime, fuzzydate, 0 /* TODO */))
goto null;
return 0;
}
@@ -5143,20 +5143,20 @@ bool Item_dyncol_get::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
val.x.double_value= static_cast<double>(ULONGLONG_MAX);
/* fall through */
case DYN_COL_DOUBLE:
- if (double_to_datetime_with_warn(val.x.double_value, ltime, fuzzy_date,
+ if (double_to_datetime_with_warn(thd, val.x.double_value, ltime, fuzzydate,
0 /* TODO */))
goto null;
return 0;
case DYN_COL_DECIMAL:
- if (decimal_to_datetime_with_warn((my_decimal*)&val.x.decimal.value, ltime,
- fuzzy_date, 0 /* TODO */))
+ if (decimal_to_datetime_with_warn(thd, (my_decimal*)&val.x.decimal.value,
+ ltime, fuzzydate, 0 /* TODO */))
goto null;
return 0;
case DYN_COL_STRING:
- if (str_to_datetime_with_warn(&my_charset_numeric,
+ if (str_to_datetime_with_warn(thd, &my_charset_numeric,
val.x.string.value.str,
val.x.string.value.length,
- ltime, fuzzy_date))
+ ltime, fuzzydate))
goto null;
return 0;
case DYN_COL_DATETIME:
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 7c4ab93dc80..762a3c2559e 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -62,8 +62,8 @@ public:
longlong val_int();
double val_real();
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_string(ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_string(thd, ltime, fuzzydate); }
const Type_handler *type_handler() const { return string_type_handler(); }
void left_right_max_length();
bool fix_fields(THD *thd, Item **ref);
@@ -1465,11 +1465,11 @@ public:
return NULL;
return res;
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
if (args[0]->result_type() == STRING_RESULT)
- return Item_str_func::get_date(ltime, fuzzydate);
- bool res= args[0]->get_date(ltime, fuzzydate);
+ return Item_str_func::get_date(thd, ltime, fuzzydate);
+ bool res= args[0]->get_date(thd, ltime, fuzzydate);
if ((null_value= args[0]->null_value))
return 1;
return res;
@@ -1764,7 +1764,7 @@ public:
double val_real();
my_decimal *val_decimal(my_decimal *);
bool get_dyn_value(THD *thd, DYNAMIC_COLUMN_VALUE *val, String *tmp);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
void print(String *str, enum_query_type query_type);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_dyncol_get>(thd, this); }
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index eef6755bc98..7408dc378ef 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1388,15 +1388,15 @@ bool Item_singlerow_subselect::val_bool()
}
-bool Item_singlerow_subselect::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Item_singlerow_subselect::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
if (forced_const)
- return value->get_date(ltime, fuzzydate);
+ return value->get_date(thd, ltime, fuzzydate);
if (!exec() && !value->null_value)
{
null_value= FALSE;
- return value->get_date(ltime, fuzzydate);
+ return value->get_date(thd, ltime, fuzzydate);
}
else
{
@@ -1991,8 +1991,7 @@ bool Item_allany_subselect::transform_into_max_min(JOIN *join)
print_where(item, "rewrite with MIN/MAX", QT_ORDINARY););
save_allow_sum_func= thd->lex->allow_sum_func;
- thd->lex->allow_sum_func|=
- (nesting_map)1 << thd->lex->current_select->nest_level;
+ thd->lex->allow_sum_func.set_bit(thd->lex->current_select->nest_level);
/*
Item_sum_(max|min) can't substitute other item => we can use 0 as
reference, also Item_sum_(max|min) can't be fixed after creation, so
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 4980709b979..443354f4900 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -308,7 +308,7 @@ public:
String *val_str (String *);
my_decimal *val_decimal(my_decimal *);
bool val_bool();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
const Type_handler *type_handler() const;
bool fix_length_and_dec();
@@ -405,8 +405,8 @@ public:
String *val_str(String*);
my_decimal *val_decimal(my_decimal *);
bool val_bool();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_int(ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_int(thd, ltime, fuzzydate); }
bool fix_fields(THD *thd, Item **ref);
bool fix_length_and_dec();
void print(String *str, enum_query_type query_type);
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 98a3f6116a6..0e52b2988a3 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -72,14 +72,15 @@ size_t Item_sum::ram_limitation(THD *thd)
bool Item_sum::init_sum_func_check(THD *thd)
{
SELECT_LEX *curr_sel= thd->lex->current_select;
- if (curr_sel && !curr_sel->name_visibility_map)
+ if (curr_sel && curr_sel->name_visibility_map.is_clear_all())
{
for (SELECT_LEX *sl= curr_sel; sl; sl= sl->context.outer_select())
{
- curr_sel->name_visibility_map|= (1 << sl-> nest_level);
+ curr_sel->name_visibility_map.set_bit(sl->nest_level);
}
}
- if (!curr_sel || !(thd->lex->allow_sum_func & curr_sel->name_visibility_map))
+ if (!curr_sel ||
+ !(thd->lex->allow_sum_func.is_overlapping(curr_sel->name_visibility_map)))
{
my_message(ER_INVALID_GROUP_FUNC_USE, ER_THD(thd, ER_INVALID_GROUP_FUNC_USE),
MYF(0));
@@ -155,10 +156,11 @@ bool Item_sum::init_sum_func_check(THD *thd)
bool Item_sum::check_sum_func(THD *thd, Item **ref)
{
SELECT_LEX *curr_sel= thd->lex->current_select;
- nesting_map allow_sum_func= (thd->lex->allow_sum_func &
- curr_sel->name_visibility_map);
+ nesting_map allow_sum_func(thd->lex->allow_sum_func);
+ allow_sum_func.intersect(curr_sel->name_visibility_map);
bool invalid= FALSE;
- DBUG_ASSERT(curr_sel->name_visibility_map); // should be set already
+ // should be set already
+ DBUG_ASSERT(!curr_sel->name_visibility_map.is_clear_all());
/*
Window functions can not be used as arguments to sum functions.
@@ -189,10 +191,10 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref)
If it is there under a construct where it is not allowed
we report an error.
*/
- invalid= !(allow_sum_func & ((nesting_map)1 << max_arg_level));
+ invalid= !(allow_sum_func.is_set(max_arg_level));
}
else if (max_arg_level >= 0 ||
- !(allow_sum_func & ((nesting_map)1 << nest_level)))
+ !(allow_sum_func.is_set(nest_level)))
{
/*
The set function can be aggregated only in outer subqueries.
@@ -202,7 +204,7 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref)
if (register_sum_func(thd, ref))
return TRUE;
invalid= aggr_level < 0 &&
- !(allow_sum_func & ((nesting_map)1 << nest_level));
+ !(allow_sum_func.is_set(nest_level));
if (!invalid && thd->variables.sql_mode & MODE_ANSI)
invalid= aggr_level < 0 && max_arg_level < nest_level;
}
@@ -354,14 +356,14 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref)
sl= sl->context.outer_select())
{
if (aggr_level < 0 &&
- (allow_sum_func & ((nesting_map)1 << sl->nest_level)))
+ (allow_sum_func.is_set(sl->nest_level)))
{
/* Found the most nested subquery where the function can be aggregated */
aggr_level= sl->nest_level;
aggr_sel= sl;
}
}
- if (sl && (allow_sum_func & ((nesting_map)1 << sl->nest_level)))
+ if (sl && (allow_sum_func.is_set(sl->nest_level)))
{
/*
We reached the subquery of level max_arg_level and checked
@@ -2305,12 +2307,12 @@ void Item_sum_hybrid::clear()
bool
-Item_sum_hybrid::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+Item_sum_hybrid::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
if (null_value)
return true;
- bool retval= value->get_date(ltime, fuzzydate);
+ bool retval= value->get_date(thd, ltime, fuzzydate);
if ((null_value= value->null_value))
DBUG_ASSERT(retval == true);
return retval;
diff --git a/sql/item_sum.h b/sql/item_sum.h
index fe055673328..1a21c257221 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -742,9 +742,9 @@ public:
longlong val_int() { return val_int_from_real(); /* Real as default */ }
String *val_str(String*str);
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate);
}
void reset_field();
};
@@ -1067,7 +1067,7 @@ protected:
double val_real();
longlong val_int();
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
void reset_field();
String *val_str(String *);
const Type_handler *real_type_handler() const
@@ -1363,7 +1363,7 @@ public:
void update_field(){DBUG_ASSERT(0);}
void clear();
void cleanup();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
return execute() || sp_result_field->get_date(ltime, fuzzydate);
}
@@ -1403,9 +1403,9 @@ public:
{
return mark_unsupported_function(name.str, arg, VCOL_IMPOSSIBLE);
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate);
}
};
@@ -1565,9 +1565,9 @@ public:
void update_field() {};
void cleanup();
virtual void print(String *str, enum_query_type query_type);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate);
}
};
@@ -1874,9 +1874,9 @@ public:
{
return val_decimal_from_string(decimal_value);
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return get_date_from_string(ltime, fuzzydate);
+ return get_date_from_string(thd, ltime, fuzzydate);
}
String* val_str(String* str);
Item *copy_or_same(THD* thd);
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 84db154566a..2da92f971d1 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -41,6 +41,7 @@
#include "set_var.h"
#include "sql_locale.h" // MY_LOCALE my_locale_en_US
#include "strfunc.h" // check_word
+#include "sql_type_int.h" // Longlong_hybrid
#include "sql_time.h" // make_truncated_value_warning,
// get_date_from_daynr,
// calc_weekday, calc_week,
@@ -125,12 +126,12 @@ static DATE_TIME_FORMAT time_24hrs_format= {{0}, '\0', 0,
1 error
*/
-static bool extract_date_time(DATE_TIME_FORMAT *format,
+static bool extract_date_time(THD *thd, DATE_TIME_FORMAT *format,
const char *val, uint length, MYSQL_TIME *l_time,
timestamp_type cached_timestamp_type,
const char **sub_pattern_end,
const char *date_time_type,
- ulonglong fuzzy_date)
+ date_mode_t fuzzydate)
{
int weekday= 0, yearday= 0, daypart= 0;
int week_number= -1;
@@ -325,17 +326,17 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
We can't just set error here, as we don't want to generate two
warnings in case of errors
*/
- if (extract_date_time(&time_ampm_format, val,
+ if (extract_date_time(thd, &time_ampm_format, val,
(uint)(val_end - val), l_time,
- cached_timestamp_type, &val, "time", fuzzy_date))
+ cached_timestamp_type, &val, "time", fuzzydate))
DBUG_RETURN(1);
break;
/* Time in 24-hour notation */
case 'T':
- if (extract_date_time(&time_24hrs_format, val,
+ if (extract_date_time(thd, &time_24hrs_format, val,
(uint)(val_end - val), l_time,
- cached_timestamp_type, &val, "time", fuzzy_date))
+ cached_timestamp_type, &val, "time", fuzzydate))
DBUG_RETURN(1);
break;
@@ -441,7 +442,7 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
goto err;
int was_cut;
- if (check_date(l_time, fuzzy_date | TIME_INVALID_DATES, &was_cut))
+ if (check_date(l_time, fuzzydate | TIME_INVALID_DATES, &was_cut))
goto err;
if (val != val_end)
@@ -451,8 +452,7 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
if (!my_isspace(&my_charset_latin1,*val))
{
ErrConvString err(val_begin, length, &my_charset_bin);
- make_truncated_value_warning(current_thd,
- Sql_condition::WARN_LEVEL_WARN,
+ make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN,
&err, cached_timestamp_type, NullS);
break;
}
@@ -462,7 +462,6 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
err:
{
- THD *thd= current_thd;
char buff[128];
strmake(buff, val_begin, MY_MIN(length, sizeof(buff)-1));
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
@@ -809,10 +808,8 @@ longlong Item_func_period_diff::val_int()
longlong Item_func_to_days::val_int()
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
- return 0;
- return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day);
+ Date d(current_thd, args[0], TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE);
+ return (null_value= !d.is_valid_date()) ? 0 : d.daynr();
}
@@ -820,42 +817,26 @@ longlong Item_func_to_seconds::val_int_endpoint(bool left_endp,
bool *incl_endp)
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- longlong seconds;
- longlong days;
- int dummy; /* unused */
- if (get_arg0_date(&ltime, TIME_FUZZY_DATES))
+ Datetime dt(current_thd, args[0], TIME_FUZZY_DATES);
+ if ((null_value= !dt.is_valid_datetime()))
{
/* got NULL, leave the incl_endp intact */
return LONGLONG_MIN;
}
- seconds= ltime.hour * 3600L + ltime.minute * 60 + ltime.second;
- seconds= ltime.neg ? -seconds : seconds;
- days= (longlong) calc_daynr(ltime.year, ltime.month, ltime.day);
- seconds+= days * 24L * 3600L;
/* Set to NULL if invalid date, but keep the value */
- null_value= check_date(&ltime,
- (ltime.year || ltime.month || ltime.day),
- (TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE),
- &dummy);
+ null_value= dt.check_date(TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE);
/*
Even if the evaluation return NULL, seconds is useful for pruning
*/
- return seconds;
+ return dt.to_seconds();
}
longlong Item_func_to_seconds::val_int()
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- longlong seconds;
- longlong days;
- if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
- return 0;
- seconds= ltime.hour * 3600L + ltime.minute * 60 + ltime.second;
- seconds=ltime.neg ? -seconds : seconds;
- days= (longlong) calc_daynr(ltime.year, ltime.month, ltime.day);
- return seconds + days * 24L * 3600L;
+ THD *thd= current_thd;
+ Datetime dt(thd, args[0], TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE);
+ return (null_value= !dt.is_valid_datetime()) ? 0 : dt.to_seconds();
}
/*
@@ -899,19 +880,16 @@ enum_monotonicity_info Item_func_to_seconds::get_monotonicity_info() const
longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp)
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
+ Datetime dt(current_thd, args[0], date_mode_t(0));
longlong res;
- int dummy; /* unused */
- if (get_arg0_date(&ltime, 0))
+ if ((null_value= !dt.is_valid_datetime()))
{
/* got NULL, leave the incl_endp intact */
return LONGLONG_MIN;
}
- res=(longlong) calc_daynr(ltime.year,ltime.month,ltime.day);
+ res= (longlong) dt.daynr();
/* Set to NULL if invalid date, but keep the value */
- null_value= check_date(&ltime,
- (TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE),
- &dummy);
+ null_value= dt.check_date(TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE);
if (null_value)
{
/*
@@ -940,8 +918,8 @@ longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp)
col < '2007-09-15 12:34:56' -> TO_DAYS(col) <= TO_DAYS('2007-09-15')
*/
- if ((!left_endp && !(ltime.hour || ltime.minute || ltime.second ||
- ltime.second_part)) ||
+ const MYSQL_TIME &ltime= dt.get_mysql_time()[0];
+ if ((!left_endp && dt.hhmmssff_is_zero()) ||
(left_endp && ltime.hour == 23 && ltime.minute == 59 &&
ltime.second == 59))
/* do nothing */
@@ -955,25 +933,22 @@ longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp)
longlong Item_func_dayofyear::val_int()
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if (get_arg0_date(&ltime, TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE))
- return 0;
- return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day) -
- calc_daynr(ltime.year,1,1) + 1;
+ Date d(current_thd, args[0], TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE);
+ return (null_value= !d.is_valid_date()) ? 0 : d.dayofyear();
}
longlong Item_func_dayofmonth::val_int()
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- return get_arg0_date(&ltime, 0) ? 0 : (longlong) ltime.day;
+ Date d(current_thd, args[0], date_mode_t(0));
+ return (null_value= !d.is_valid_date()) ? 0 : d.get_mysql_time()->day;
}
longlong Item_func_month::val_int()
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- return get_arg0_date(&ltime, 0) ? 0 : (longlong) ltime.month;
+ Date d(current_thd, args[0], date_mode_t(0));
+ return (null_value= !d.is_valid_date()) ? 0 : d.get_mysql_time()->month;
}
@@ -995,12 +970,12 @@ String* Item_func_monthname::val_str(String* str)
DBUG_ASSERT(fixed == 1);
const char *month_name;
uint err;
- MYSQL_TIME ltime;
+ Date d(current_thd, args[0], date_mode_t(0));
- if ((null_value= (get_arg0_date(&ltime, 0) || !ltime.month)))
+ if ((null_value= (!d.is_valid_date() || !d.get_mysql_time()->month)))
return (String *) 0;
- month_name= locale->month_names->type_names[ltime.month - 1];
+ month_name= locale->month_names->type_names[d.get_mysql_time()->month - 1];
str->copy(month_name, (uint) strlen(month_name), &my_charset_utf8_bin,
collation.collation, &err);
return str;
@@ -1014,23 +989,21 @@ String* Item_func_monthname::val_str(String* str)
longlong Item_func_quarter::val_int()
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if (get_arg0_date(&ltime, 0))
- return 0;
- return (longlong) ((ltime.month+2)/3);
+ Date d(current_thd, args[0], date_mode_t(0));
+ return (null_value= !d.is_valid_date()) ? 0 : d.quarter();
}
longlong Item_func_hour::val_int()
{
DBUG_ASSERT(fixed == 1);
- Time tm(args[0], Time::Options_for_cast());
+ Time tm(current_thd, args[0], Time::Options_for_cast());
return (null_value= !tm.is_valid_time()) ? 0 : tm.get_mysql_time()->hour;
}
longlong Item_func_minute::val_int()
{
DBUG_ASSERT(fixed == 1);
- Time tm(args[0], Time::Options_for_cast());
+ Time tm(current_thd, args[0], Time::Options_for_cast());
return (null_value= !tm.is_valid_time()) ? 0 : tm.get_mysql_time()->minute;
}
@@ -1040,7 +1013,7 @@ longlong Item_func_minute::val_int()
longlong Item_func_second::val_int()
{
DBUG_ASSERT(fixed == 1);
- Time tm(args[0], Time::Options_for_cast());
+ Time tm(current_thd, args[0], Time::Options_for_cast());
return (null_value= !tm.is_valid_time()) ? 0 : tm.get_mysql_time()->second;
}
@@ -1087,43 +1060,34 @@ uint week_mode(uint mode)
longlong Item_func_week::val_int()
{
DBUG_ASSERT(fixed == 1);
- uint year, week_format;
- MYSQL_TIME ltime;
- if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
+ uint week_format;
+ THD *thd= current_thd;
+ Date d(thd, args[0], TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE);
+ if ((null_value= !d.is_valid_date()))
return 0;
if (arg_count > 1)
week_format= (uint)args[1]->val_int();
else
- week_format= current_thd->variables.default_week_format;
- return (longlong) calc_week(&ltime, week_mode(week_format), &year);
+ week_format= thd->variables.default_week_format;
+ return d.week(week_mode(week_format));
}
longlong Item_func_yearweek::val_int()
{
DBUG_ASSERT(fixed == 1);
- uint year,week;
- MYSQL_TIME ltime;
- if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
- return 0;
- week= calc_week(&ltime,
- (week_mode((uint) args[1]->val_int()) | WEEK_YEAR),
- &year);
- return week+year*100;
+ Date d(current_thd, args[0], TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE);
+ return (null_value= !d.is_valid_date()) ? 0 :
+ d.yearweek((week_mode((uint) args[1]->val_int()) | WEEK_YEAR));
}
longlong Item_func_weekday::val_int()
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
-
- if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
- return 0;
-
- return (longlong) calc_weekday(calc_daynr(ltime.year, ltime.month,
- ltime.day),
- odbc_type) + MY_TEST(odbc_type);
+ Date d(current_thd, args[0], TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE);
+ return ((null_value= !d.is_valid_date())) ? 0 :
+ calc_weekday(d.daynr(), odbc_type) + MY_TEST(odbc_type);
}
bool Item_func_dayname::fix_length_and_dec()
@@ -1159,8 +1123,8 @@ String* Item_func_dayname::val_str(String* str)
longlong Item_func_year::val_int()
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- return get_arg0_date(&ltime, 0) ? 0 : (longlong) ltime.year;
+ Date d(current_thd, args[0], date_mode_t(0));
+ return (null_value= !d.is_valid_date()) ? 0 : d.get_mysql_time()->year;
}
@@ -1191,8 +1155,8 @@ enum_monotonicity_info Item_func_year::get_monotonicity_info() const
longlong Item_func_year::val_int_endpoint(bool left_endp, bool *incl_endp)
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if (get_arg0_date(&ltime, 0))
+ Datetime dt(current_thd, args[0], date_mode_t(0));
+ if ((null_value= !dt.is_valid_datetime()))
{
/* got NULL, leave the incl_endp intact */
return LONGLONG_MIN;
@@ -1209,8 +1173,9 @@ longlong Item_func_year::val_int_endpoint(bool left_endp, bool *incl_endp)
col < '2007-09-15 23:00:00' -> YEAR(col) <= 2007
*/
+ const MYSQL_TIME &ltime= dt.get_mysql_time()[0];
if (!left_endp && ltime.day == 1 && ltime.month == 1 &&
- !(ltime.hour || ltime.minute || ltime.second || ltime.second_part))
+ dt.hhmmssff_is_zero())
; /* do nothing */
else
*incl_endp= TRUE;
@@ -1234,13 +1199,14 @@ bool Item_func_unix_timestamp::get_timestamp_value(my_time_t *seconds,
}
}
- MYSQL_TIME ltime;
- if (get_arg0_date(&ltime, TIME_NO_ZERO_IN_DATE))
- return 1;
+ THD *thd= current_thd;
+ Datetime dt(thd, args[0], TIME_NO_ZERO_IN_DATE);
+ if ((null_value= !dt.is_valid_datetime()))
+ return true;
uint error_code;
- *seconds= TIME_to_timestamp(current_thd, &ltime, &error_code);
- *second_part= ltime.second_part;
+ *seconds= TIME_to_timestamp(thd, dt.get_mysql_time(), &error_code);
+ *second_part= dt.get_mysql_time()->second_part;
return (null_value= (error_code == ER_WARN_DATA_OUT_OF_RANGE));
}
@@ -1298,7 +1264,7 @@ longlong Item_func_unix_timestamp::val_int_endpoint(bool left_endp, bool *incl_e
longlong Item_func_time_to_sec::int_op()
{
DBUG_ASSERT(fixed == 1);
- Time tm(args[0], Time::Options_for_cast());
+ Time tm(current_thd, args[0], Time::Options_for_cast());
return ((null_value= !tm.is_valid_time())) ? 0 : tm.to_seconds();
}
@@ -1306,7 +1272,7 @@ longlong Item_func_time_to_sec::int_op()
my_decimal *Item_func_time_to_sec::decimal_op(my_decimal* buf)
{
DBUG_ASSERT(fixed == 1);
- Time tm(args[0], Time::Options_for_cast());
+ Time tm(current_thd, args[0], Time::Options_for_cast());
if ((null_value= !tm.is_valid_time()))
return 0;
const MYSQL_TIME *ltime= tm.get_mysql_time();
@@ -1321,7 +1287,8 @@ my_decimal *Item_func_time_to_sec::decimal_op(my_decimal* buf)
To make code easy, allow interval objects without separators.
*/
-bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval)
+bool get_interval_value(THD *thd, Item *args,
+ interval_type int_type, INTERVAL *interval)
{
ulonglong array[5];
longlong UNINIT_VAR(value);
@@ -1342,7 +1309,7 @@ bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval)
if (d.sec() >= LONGLONG_MAX)
{
ErrConvDecimal err(val.ptr());
- current_thd->push_warning_truncated_wrong_value("seconds", err.ptr());
+ thd->push_warning_truncated_wrong_value("seconds", err.ptr());
return true;
}
interval->second= d.sec();
@@ -1492,11 +1459,11 @@ bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval)
}
-bool Item_func_from_days::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_func_from_days::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
longlong value=args[0]->val_int();
if ((null_value= (args[0]->null_value ||
- ((fuzzy_date & TIME_NO_ZERO_DATE) && value == 0))))
+ ((fuzzydate & TIME_NO_ZERO_DATE) && value == 0))))
return true;
bzero(ltime, sizeof(MYSQL_TIME));
if (get_date_from_daynr((long) value, &ltime->year, &ltime->month,
@@ -1533,10 +1500,9 @@ void Item_func_curdate_utc::store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)
}
-bool Item_func_curdate::get_date(MYSQL_TIME *res,
- ulonglong fuzzy_date __attribute__((unused)))
+bool Item_func_curdate::get_date(THD *thd, MYSQL_TIME *res,
+ date_mode_t fuzzydate __attribute__((unused)))
{
- THD *thd= current_thd;
query_id_t query_id= thd->query_id;
/* Cache value for this query */
if (last_query_id != query_id)
@@ -1563,10 +1529,9 @@ bool Item_func_curtime::fix_fields(THD *thd, Item **items)
return Item_timefunc::fix_fields(thd, items);
}
-bool Item_func_curtime::get_date(MYSQL_TIME *res,
- ulonglong fuzzy_date __attribute__((unused)))
+bool Item_func_curtime::get_date(THD *thd, MYSQL_TIME *res,
+ date_mode_t fuzzydate __attribute__((unused)))
{
- THD *thd= current_thd;
query_id_t query_id= thd->query_id;
/* Cache value for this query */
if (last_query_id != query_id)
@@ -1695,10 +1660,9 @@ void Item_func_now_utc::store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)
}
-bool Item_func_now::get_date(MYSQL_TIME *res,
- ulonglong fuzzy_date __attribute__((unused)))
+bool Item_func_now::get_date(THD *thd, MYSQL_TIME *res,
+ date_mode_t fuzzydate __attribute__((unused)))
{
- THD *thd= current_thd;
query_id_t query_id= thd->query_id;
/* Cache value for this query */
if (last_query_id != query_id)
@@ -1724,21 +1688,21 @@ void Item_func_sysdate_local::store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)
}
-bool Item_func_sysdate_local::get_date(MYSQL_TIME *res,
- ulonglong fuzzy_date __attribute__((unused)))
+bool Item_func_sysdate_local::get_date(THD *thd, MYSQL_TIME *res,
+ date_mode_t fuzzydate __attribute__((unused)))
{
- store_now_in_TIME(current_thd, res);
+ store_now_in_TIME(thd, res);
return 0;
}
-bool Item_func_sec_to_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_func_sec_to_time::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
- VSec6 sec(args[0], "seconds", LONGLONG_MAX);
+ VSec6 sec(thd, args[0], "seconds", LONGLONG_MAX);
if ((null_value= sec.is_null()))
return true;
if (sec.sec_to_time(ltime, decimals) && !sec.truncated())
- sec.make_truncated_warning(current_thd, "seconds");
+ sec.make_truncated_warning(thd, "seconds");
return false;
}
@@ -1895,7 +1859,9 @@ String *Item_func_date_format::val_str(String *str)
const MY_LOCALE *lc= 0;
DBUG_ASSERT(fixed == 1);
- if ((null_value= args[0]->get_date(&l_time, is_time_format ? TIME_TIME_ONLY : 0)))
+ if ((null_value= args[0]->get_date(current_thd, &l_time,
+ is_time_format ? TIME_TIME_ONLY :
+ date_mode_t(0))))
return 0;
if (!(format = args[1]->val_str(str)) || !format->length())
@@ -1946,13 +1912,13 @@ bool Item_func_from_unixtime::fix_length_and_dec()
}
-bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime,
- ulonglong fuzzy_date __attribute__((unused)))
+bool Item_func_from_unixtime::get_date(THD *thd, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate __attribute__((unused)))
{
bzero((char *)ltime, sizeof(*ltime));
ltime->time_type= MYSQL_TIMESTAMP_TIME;
- VSec6 sec(args[0], "unixtime", TIMESTAMP_MAX_VALUE);
+ VSec6 sec(thd, args[0], "unixtime", TIMESTAMP_MAX_VALUE);
DBUG_ASSERT(sec.sec() <= TIMESTAMP_MAX_VALUE);
if (sec.is_null() || sec.truncated() || sec.neg())
@@ -1965,12 +1931,11 @@ bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime,
}
-bool Item_func_convert_tz::get_date(MYSQL_TIME *ltime,
- ulonglong fuzzy_date __attribute__((unused)))
+bool Item_func_convert_tz::get_date(THD *thd, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate __attribute__((unused)))
{
my_time_t my_time_tmp;
String str;
- THD *thd= current_thd;
if (!from_tz_cached)
{
@@ -1984,9 +1949,12 @@ bool Item_func_convert_tz::get_date(MYSQL_TIME *ltime,
to_tz_cached= args[2]->const_item();
}
- if (from_tz==0 || to_tz==0 ||
- get_arg0_date(ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
- return (null_value= 1);
+ if ((null_value= (from_tz == 0 || to_tz == 0)))
+ return true;
+
+ Datetime *dt= new(ltime) Datetime(thd, args[0], TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE);
+ if ((null_value= !dt->is_valid_datetime()))
+ return true;
{
uint not_used;
@@ -2067,9 +2035,9 @@ bool Item_date_add_interval::fix_length_and_dec()
bool Func_handler_date_add_interval_datetime_arg0_time::
- get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
{
- THD *thd= current_thd;
// time_expr + INTERVAL {YEAR|QUARTER|MONTH|WEEK|YEAR_MONTH}
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_DATETIME_FUNCTION_OVERFLOW,
@@ -2130,7 +2098,7 @@ bool Item_extract::fix_length_and_dec()
case INTERVAL_QUARTER: set_date_length(2); break; // 1..4
case INTERVAL_MONTH: set_date_length(2); break; // MM
case INTERVAL_WEEK: set_date_length(2); break; // 0..52
- case INTERVAL_DAY: set_date_length(2); break; // DD
+ case INTERVAL_DAY: set_day_length(2); break; // DD
case INTERVAL_DAY_HOUR: set_time_length(4); break; // DDhh
case INTERVAL_DAY_MINUTE: set_time_length(6); break; // DDhhmm
case INTERVAL_DAY_SECOND: set_time_length(8); break; // DDhhmmss
@@ -2151,69 +2119,45 @@ bool Item_extract::fix_length_and_dec()
}
-longlong Item_extract::val_int()
+uint Extract_source::week(THD *thd) const
{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
+ DBUG_ASSERT(is_valid_extract_source());
uint year;
- ulong week_format;
- long neg;
- int is_time_flag = date_value ? 0 : TIME_TIME_ONLY;
-
- // Not using get_arg0_date to avoid automatic TIME to DATETIME conversion
- if ((null_value= args[0]->get_date(&ltime, is_time_flag)))
- return 0;
-
- neg= ltime.neg ? -1 : 1;
+ ulong week_format= current_thd->variables.default_week_format;
+ return calc_week(this, week_mode(week_format), &year);
+}
- DBUG_ASSERT(ltime.time_type != MYSQL_TIMESTAMP_TIME || ltime.day == 0);
- if (ltime.time_type == MYSQL_TIMESTAMP_TIME)
- time_to_daytime_interval(&ltime);
+longlong Item_extract::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ Extract_source dt(current_thd, args[0], m_date_mode);
+ if ((null_value= !dt.is_valid_extract_source()))
+ return 0;
switch (int_type) {
- case INTERVAL_YEAR: return ltime.year;
- case INTERVAL_YEAR_MONTH: return ltime.year*100L+ltime.month;
- case INTERVAL_QUARTER: return (ltime.month+2)/3;
- case INTERVAL_MONTH: return ltime.month;
- case INTERVAL_WEEK:
- {
- week_format= current_thd->variables.default_week_format;
- return calc_week(&ltime, week_mode(week_format), &year);
- }
- case INTERVAL_DAY: return ltime.day;
- case INTERVAL_DAY_HOUR: return (long) (ltime.day*100L+ltime.hour)*neg;
- case INTERVAL_DAY_MINUTE: return (long) (ltime.day*10000L+
- ltime.hour*100L+
- ltime.minute)*neg;
- case INTERVAL_DAY_SECOND: return ((longlong) ltime.day*1000000L+
- (longlong) (ltime.hour*10000L+
- ltime.minute*100+
- ltime.second))*neg;
- case INTERVAL_HOUR: return (long) ltime.hour*neg;
- case INTERVAL_HOUR_MINUTE: return (long) (ltime.hour*100+ltime.minute)*neg;
- case INTERVAL_HOUR_SECOND: return (long) (ltime.hour*10000+ltime.minute*100+
- ltime.second)*neg;
- case INTERVAL_MINUTE: return (long) ltime.minute*neg;
- case INTERVAL_MINUTE_SECOND: return (long) (ltime.minute*100+ltime.second)*neg;
- case INTERVAL_SECOND: return (long) ltime.second*neg;
- case INTERVAL_MICROSECOND: return (long) ltime.second_part*neg;
- case INTERVAL_DAY_MICROSECOND: return (((longlong)ltime.day*1000000L +
- (longlong)ltime.hour*10000L +
- ltime.minute*100 +
- ltime.second)*1000000L +
- ltime.second_part)*neg;
- case INTERVAL_HOUR_MICROSECOND: return (((longlong)ltime.hour*10000L +
- ltime.minute*100 +
- ltime.second)*1000000L +
- ltime.second_part)*neg;
- case INTERVAL_MINUTE_MICROSECOND: return (((longlong)(ltime.minute*100+
- ltime.second))*1000000L+
- ltime.second_part)*neg;
- case INTERVAL_SECOND_MICROSECOND: return ((longlong)ltime.second*1000000L+
- ltime.second_part)*neg;
+ case INTERVAL_YEAR: return dt.year();
+ case INTERVAL_YEAR_MONTH: return dt.year_month();
+ case INTERVAL_QUARTER: return dt.quarter();
+ case INTERVAL_MONTH: return dt.month();
+ case INTERVAL_WEEK: return dt.week(current_thd);
+ case INTERVAL_DAY: return dt.day();
+ case INTERVAL_DAY_HOUR: return dt.day_hour();
+ case INTERVAL_DAY_MINUTE: return dt.day_minute();
+ case INTERVAL_DAY_SECOND: return dt.day_second();
+ case INTERVAL_HOUR: return dt.hour();
+ case INTERVAL_HOUR_MINUTE: return dt.hour_minute();
+ case INTERVAL_HOUR_SECOND: return dt.hour_second();
+ case INTERVAL_MINUTE: return dt.minute();
+ case INTERVAL_MINUTE_SECOND: return dt.minute_second();
+ case INTERVAL_SECOND: return dt.second();
+ case INTERVAL_MICROSECOND: return dt.microsecond();
+ case INTERVAL_DAY_MICROSECOND: return dt.day_microsecond();
+ case INTERVAL_HOUR_MICROSECOND: return dt.hour_microsecond();
+ case INTERVAL_MINUTE_MICROSECOND: return dt.minute_microsecond();
+ case INTERVAL_SECOND_MICROSECOND: return dt.second_microsecond();
case INTERVAL_LAST: DBUG_ASSERT(0); break; /* purecov: deadcode */
}
- return 0; // Impossible
+ return 0; // Impossible
}
bool Item_extract::eq(const Item *item, bool binary_cmp) const
@@ -2472,45 +2416,28 @@ void Item_char_typecast::fix_length_and_dec_internal(CHARSET_INFO *from_cs)
}
-bool Item_time_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_time_typecast::get_date(THD *thd, MYSQL_TIME *to, date_mode_t mode)
{
- Time tm(args[0], Time::Options_for_cast());
- if ((null_value= !tm.is_valid_time()))
- return true;
- tm.copy_to_mysql_time(ltime);
- if (decimals < TIME_SECOND_PART_DIGITS)
- my_time_trunc(ltime, decimals);
- return (fuzzy_date & TIME_TIME_ONLY) ? 0 :
- (null_value= check_date_with_warn(ltime, fuzzy_date,
- MYSQL_TIMESTAMP_ERROR));
+ Time *tm= new(to) Time(thd, args[0], Time::Options_for_cast(mode),
+ MY_MIN(decimals, TIME_SECOND_PART_DIGITS));
+ return (null_value= !tm->is_valid_time());
}
-bool Item_date_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_date_typecast::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- fuzzy_date |= sql_mode_for_dates(current_thd);
- if (get_arg0_date(ltime, fuzzy_date & ~TIME_TIME_ONLY))
- return 1;
-
- if (make_date_with_warn(ltime, fuzzy_date, MYSQL_TIMESTAMP_DATE))
- return (null_value= 1);
-
- return 0;
+ date_mode_t tmp= (fuzzydate | sql_mode_for_dates(thd)) & ~TIME_TIME_ONLY;
+ Date *d= new(ltime) Date(thd, args[0], tmp);
+ return (null_value= !d->is_valid_date());
}
-bool Item_datetime_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_datetime_typecast::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- fuzzy_date |= sql_mode_for_dates(current_thd);
- if (get_arg0_date(ltime, fuzzy_date & ~TIME_TIME_ONLY))
- return 1;
-
- if (decimals < TIME_SECOND_PART_DIGITS)
- my_time_trunc(ltime, decimals);
-
- DBUG_ASSERT(ltime->time_type != MYSQL_TIMESTAMP_TIME);
- ltime->time_type= MYSQL_TIMESTAMP_DATETIME;
- return 0;
+ date_mode_t tmp= (fuzzydate | sql_mode_for_dates(thd)) & ~TIME_TIME_ONLY;
+ Datetime *dt= new(ltime) Datetime(thd, args[0], tmp,
+ MY_MIN(decimals, TIME_SECOND_PART_DIGITS));
+ return (null_value= !dt->is_valid_datetime());
}
@@ -2525,7 +2452,7 @@ bool Item_datetime_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
0099-12-31
*/
-bool Item_func_makedate::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_func_makedate::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
long year, days, daynr= (long) args[1]->val_int();
@@ -2603,7 +2530,7 @@ bool Item_func_add_time::fix_length_and_dec()
Result: Time value
*/
-bool Item_func_timediff::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_func_timediff::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
int l_sign= 1;
@@ -2611,22 +2538,22 @@ bool Item_func_timediff::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
ErrConvTime str(&l_time3);
/* the following may be true in, for example, date_add(timediff(...), ... */
- if (fuzzy_date & TIME_NO_ZERO_IN_DATE)
+ if (fuzzydate & TIME_NO_ZERO_IN_DATE)
return (null_value= 1);
- if (args[0]->get_time(&l_time1) ||
- args[1]->get_time(&l_time2) ||
+ if (args[0]->get_time(thd, &l_time1) ||
+ args[1]->get_time(thd, &l_time2) ||
l_time1.time_type != l_time2.time_type)
return (null_value= 1);
if (l_time1.neg != l_time2.neg)
l_sign= -l_sign;
- if (calc_time_diff(&l_time1, &l_time2, l_sign, &l_time3, fuzzy_date))
+ if (calc_time_diff(&l_time1, &l_time2, l_sign, &l_time3, fuzzydate))
return (null_value= 1);
*ltime= l_time3;
- return (null_value= adjust_time_range_with_warn(ltime, decimals));
+ return (null_value= adjust_time_range_with_warn(thd, ltime, decimals));
}
/**
@@ -2635,13 +2562,12 @@ bool Item_func_timediff::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
Result: Time value
*/
-bool Item_func_maketime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_func_maketime::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
- bool overflow= 0;
- longlong hour= args[0]->val_int();
+ Longlong_hybrid hour(args[0]->val_int(), args[0]->unsigned_flag);
longlong minute= args[1]->val_int();
- VSec6 sec(args[2], "seconds", 59);
+ VSec6 sec(thd, args[2], "seconds", 59);
DBUG_ASSERT(sec.sec() <= 59);
if (args[0]->null_value || args[1]->null_value || sec.is_null() ||
@@ -2650,36 +2576,27 @@ bool Item_func_maketime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
bzero(ltime, sizeof(*ltime));
ltime->time_type= MYSQL_TIMESTAMP_TIME;
+ ltime->neg= hour.neg();
- /* Check for integer overflows */
- if (hour < 0)
+ if (hour.abs() <= TIME_MAX_HOUR)
{
- if (args[0]->unsigned_flag)
- overflow= 1;
- else
- ltime->neg= 1;
- }
- if (-hour > TIME_MAX_HOUR || hour > TIME_MAX_HOUR)
- overflow= 1;
-
- if (!overflow)
- {
- ltime->hour= (uint) ((hour < 0 ? -hour : hour));
+ ltime->hour= (uint) hour.abs();
ltime->minute= (uint) minute;
ltime->second= (uint) sec.sec();
ltime->second_part= sec.usec();
}
else
{
- ltime->hour= TIME_MAX_HOUR;
- ltime->minute= TIME_MAX_MINUTE;
- ltime->second= TIME_MAX_SECOND;
+ // use check_time_range() to set ltime to the max value depending on dec
+ int unused;
+ ltime->hour= TIME_MAX_HOUR + 1;
+ check_time_range(ltime, decimals, &unused);
char buf[28];
- char *ptr= longlong10_to_str(hour, buf, args[0]->unsigned_flag ? 10 : -10);
+ char *ptr= longlong10_to_str(hour.value(), buf, hour.is_unsigned() ? 10 : -10);
int len = (int)(ptr - buf) + sprintf(ptr, ":%02u:%02u",
(uint) minute, (uint) sec.sec());
ErrConvString err(buf, len, &my_charset_bin);
- current_thd->push_warning_truncated_wrong_value("time", err.ptr());
+ thd->push_warning_truncated_wrong_value("time", err.ptr());
}
return (null_value= 0);
@@ -2697,7 +2614,7 @@ bool Item_func_maketime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
longlong Item_func_microsecond::val_int()
{
DBUG_ASSERT(fixed == 1);
- Time tm(args[0], Time::Options_for_cast());
+ Time tm(current_thd, args[0], Time::Options_for_cast());
return ((null_value= !tm.is_valid_time())) ?
0 : tm.get_mysql_time()->second_part;
}
@@ -2711,7 +2628,7 @@ longlong Item_func_timestamp_diff::val_int()
long months= 0;
int neg= 1;
THD *thd= current_thd;
- ulonglong fuzzydate= TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE;
+ date_mode_t fuzzydate= TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE;
null_value= 0;
@@ -3008,8 +2925,8 @@ bool Item_func_str_to_date::fix_length_and_dec()
}
-bool Item_func_str_to_date::get_date_common(MYSQL_TIME *ltime,
- ulonglong fuzzy_date,
+bool Item_func_str_to_date::get_date_common(THD *thd, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate,
timestamp_type tstype)
{
DATE_TIME_FORMAT date_time_format;
@@ -3023,19 +2940,19 @@ bool Item_func_str_to_date::get_date_common(MYSQL_TIME *ltime,
date_time_format.format.str= (char*) format->ptr();
date_time_format.format.length= format->length();
- if (extract_date_time(&date_time_format, val->ptr(), val->length(),
+ if (extract_date_time(thd, &date_time_format, val->ptr(), val->length(),
ltime, tstype, 0, "datetime",
- fuzzy_date | sql_mode_for_dates(current_thd)))
+ fuzzydate | sql_mode_for_dates(thd)))
return (null_value=1);
return (null_value= 0);
}
-bool Item_func_last_day::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_func_last_day::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- if (get_arg0_date(ltime, fuzzy_date & ~TIME_TIME_ONLY) ||
- (ltime->month == 0))
- return (null_value=1);
+ Date *d= new(ltime) Date(thd, args[0], fuzzydate & ~TIME_TIME_ONLY);
+ if ((null_value= (!d->is_valid_date() || ltime->month == 0)))
+ return true;
uint month_idx= ltime->month-1;
ltime->day= days_in_month[month_idx];
if ( month_idx == 1 && calc_days_in_year(ltime->year) == 366)
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index f9709b8f72a..d2a4e87a3d1 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -26,7 +26,8 @@
class MY_LOCALE;
-bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval);
+bool get_interval_value(THD *thd, Item *args,
+ interval_type int_type, INTERVAL *interval);
class Item_long_func_date_field: public Item_long_func
@@ -181,9 +182,9 @@ public:
str->set(nr, collation.collation);
return str;
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return get_date_from_int(ltime, fuzzydate);
+ return get_date_from_int(thd, ltime, fuzzydate);
}
const char *func_name() const { return "month"; }
const Type_handler *type_handler() const { return &type_handler_long; }
@@ -454,9 +455,9 @@ public:
{
return (odbc_type ? "dayofweek" : "weekday");
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate);
}
const Type_handler *type_handler() const { return &type_handler_long; }
bool fix_length_and_dec()
@@ -511,7 +512,7 @@ public:
}
double real_op() { DBUG_ASSERT(0); return 0; }
String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
- bool date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(0);
return true;
@@ -547,7 +548,8 @@ public:
}
bool fix_length_and_dec()
{
- fix_length_and_dec_generic(arg_count ? args[0]->datetime_precision() : 0);
+ fix_length_and_dec_generic(arg_count ?
+ args[0]->datetime_precision(current_thd) : 0);
return FALSE;
}
longlong int_op();
@@ -571,7 +573,7 @@ public:
}
bool fix_length_and_dec()
{
- fix_length_and_dec_generic(args[0]->time_precision());
+ fix_length_and_dec_generic(args[0]->time_precision(current_thd));
return FALSE;
}
longlong int_op();
@@ -643,7 +645,7 @@ public:
{ decimals= dec; }
bool fix_fields(THD *, Item **);
bool fix_length_and_dec() { fix_attributes_time(decimals); return FALSE; }
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
/*
Abstract method that defines which time zone is used for conversion.
Converts time current time in my_time_t representation to broken-down
@@ -688,7 +690,7 @@ class Item_func_curdate :public Item_datefunc
MYSQL_TIME ltime;
public:
Item_func_curdate(THD *thd): Item_datefunc(thd), last_query_id(0) {}
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
virtual void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)=0;
bool check_vcol_func_processor(void *arg)
{
@@ -731,7 +733,7 @@ public:
bool fix_fields(THD *, Item **);
bool fix_length_and_dec()
{ fix_attributes_datetime(decimals); return FALSE;}
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
virtual void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)=0;
bool check_vcol_func_processor(void *arg)
{
@@ -786,7 +788,7 @@ public:
bool const_item() const { return 0; }
const char *func_name() const { return "sysdate"; }
void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time);
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
table_map used_tables() const { return RAND_TABLE_BIT; }
bool check_vcol_func_processor(void *arg)
{
@@ -806,7 +808,7 @@ class Item_func_from_days :public Item_datefunc
public:
Item_func_from_days(THD *thd, Item *a): Item_datefunc(thd, a) {}
const char *func_name() const { return "from_days"; }
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
bool check_partition_func_processor(void *int_arg) {return FALSE;}
bool check_vcol_func_processor(void *arg) { return FALSE;}
bool check_valid_arguments_processor(void *int_arg)
@@ -871,7 +873,7 @@ class Item_func_from_unixtime :public Item_datetimefunc
Item_func_from_unixtime(THD *thd, Item *a): Item_datetimefunc(thd, a) {}
const char *func_name() const { return "from_unixtime"; }
bool fix_length_and_dec();
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_from_unixtime>(thd, this); }
};
@@ -912,11 +914,11 @@ class Item_func_convert_tz :public Item_datetimefunc
const char *func_name() const { return "convert_tz"; }
bool fix_length_and_dec()
{
- fix_attributes_datetime(args[0]->datetime_precision());
+ fix_attributes_datetime(args[0]->datetime_precision(current_thd));
maybe_null= true;
return FALSE;
}
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
void cleanup();
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_convert_tz>(thd, this); }
@@ -929,7 +931,7 @@ class Item_func_sec_to_time :public Item_timefunc
{ return args[0]->check_type_can_return_decimal(func_name()); }
public:
Item_func_sec_to_time(THD *thd, Item *item): Item_timefunc(thd, item) {}
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
bool fix_length_and_dec()
{
fix_attributes_time(args[0]->decimals);
@@ -962,9 +964,17 @@ public:
};
-class Item_extract :public Item_int_func
+class Item_extract :public Item_int_func,
+ public Type_handler_hybrid_field_type
{
- bool date_value;
+ date_mode_t m_date_mode;
+ const Type_handler_int_result *handler_by_length(uint32 length,
+ uint32 threashold)
+ {
+ if (length >= threashold)
+ return &type_handler_longlong;
+ return &type_handler_long;
+ }
void set_date_length(uint32 length)
{
/*
@@ -973,48 +983,34 @@ class Item_extract :public Item_int_func
because all around the code we assume that max_length is sign inclusive.
Another options is to set unsigned_flag to "true".
*/
- max_length= length; //QQ: see above
- date_value= true;
+ set_handler(handler_by_length(max_length= length, 10)); // QQ: see above
+ m_date_mode= date_mode_t(0);
+ }
+ void set_day_length(uint32 length)
+ {
+ /*
+ Units starting with DAY can be negative:
+ EXTRACT(DAY FROM '-24:00:00') -> -1
+ */
+ set_handler(handler_by_length(max_length= length + 1/*sign*/, 11));
+ m_date_mode= date_mode_t(0);
}
void set_time_length(uint32 length)
{
- max_length= length + 1/*sign*/;
- date_value= false;
+ set_handler(handler_by_length(max_length= length + 1/*sign*/, 11));
+ m_date_mode= TIME_TIME_ONLY;
}
public:
const interval_type int_type; // keep it public
Item_extract(THD *thd, interval_type type_arg, Item *a):
- Item_int_func(thd, a), int_type(type_arg) {}
+ Item_int_func(thd, a),
+ Type_handler_hybrid_field_type(&type_handler_longlong),
+ m_date_mode(date_mode_t(0)),
+ int_type(type_arg)
+ { }
const Type_handler *type_handler() const
{
- switch (int_type) {
- case INTERVAL_YEAR:
- case INTERVAL_YEAR_MONTH:
- case INTERVAL_QUARTER:
- case INTERVAL_MONTH:
- case INTERVAL_WEEK:
- case INTERVAL_DAY:
- case INTERVAL_DAY_HOUR:
- case INTERVAL_DAY_MINUTE:
- case INTERVAL_DAY_SECOND:
- case INTERVAL_HOUR:
- case INTERVAL_HOUR_MINUTE:
- case INTERVAL_HOUR_SECOND:
- case INTERVAL_MINUTE:
- case INTERVAL_MINUTE_SECOND:
- case INTERVAL_SECOND:
- case INTERVAL_MICROSECOND:
- case INTERVAL_SECOND_MICROSECOND:
- return &type_handler_long;
- case INTERVAL_DAY_MICROSECOND:
- case INTERVAL_HOUR_MICROSECOND:
- case INTERVAL_MINUTE_MICROSECOND:
- return &type_handler_longlong;
- case INTERVAL_LAST:
- break;
- }
- DBUG_ASSERT(0);
- return &type_handler_longlong;
+ return Type_handler_hybrid_field_type::type_handler();
}
longlong val_int();
enum Functype functype() const { return EXTRACT_FUNC; }
@@ -1119,7 +1115,7 @@ public:
{
print_cast_temporal(str, query_type);
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool fix_length_and_dec()
{
return args[0]->type_handler()->Item_date_typecast_fix_length_and_dec(this);
@@ -1139,7 +1135,7 @@ public:
{
print_cast_temporal(str, query_type);
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool fix_length_and_dec()
{
return args[0]->type_handler()->
@@ -1160,7 +1156,7 @@ public:
{
print_cast_temporal(str, query_type);
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool fix_length_and_dec()
{
return args[0]->type_handler()->
@@ -1179,7 +1175,7 @@ public:
Item_func_makedate(THD *thd, Item *a, Item *b):
Item_datefunc(thd, a, b) {}
const char *func_name() const { return "makedate"; }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_makedate>(thd, this); }
};
@@ -1199,19 +1195,23 @@ public:
const char *func_name() const { return "timestamp"; }
bool fix_length_and_dec()
{
- uint dec= MY_MAX(args[0]->datetime_precision(), args[1]->time_precision());
- fix_attributes_datetime(dec);
+ THD *thd= current_thd;
+ uint dec0= args[0]->datetime_precision(thd);
+ uint dec1= Interval_DDhhmmssff::fsp(thd, args[1]);
+ fix_attributes_datetime(MY_MAX(dec0, dec1));
maybe_null= true;
return false;
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- Datetime dt(current_thd, args[0], 0);
- MYSQL_TIME ltime2;
- return (null_value= (!dt.is_valid_datetime() ||
- args[1]->get_time(&ltime2) ||
- Sec6_add(dt.get_mysql_time(), &ltime2, 1).
- to_datetime(ltime)));
+ Datetime dt(thd, args[0], date_mode_t(0));
+ if (!dt.is_valid_datetime())
+ return null_value= true;
+ Interval_DDhhmmssff it(thd, args[1]);
+ if (!it.is_valid_interval_DDhhmmssff())
+ return null_value= true;
+ return (null_value= Sec6_add(dt.get_mysql_time(), it.get_mysql_time(), 1).
+ to_datetime(ltime));
}
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_timestamp>(thd, this); }
@@ -1251,12 +1251,14 @@ public:
const char *func_name() const { return "timediff"; }
bool fix_length_and_dec()
{
- uint dec= MY_MAX(args[0]->time_precision(), args[1]->time_precision());
+ THD *thd= current_thd;
+ uint dec= MY_MAX(args[0]->time_precision(thd),
+ args[1]->time_precision(thd));
fix_attributes_time(dec);
maybe_null= true;
return FALSE;
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_timediff>(thd, this); }
};
@@ -1279,7 +1281,7 @@ public:
return FALSE;
}
const char *func_name() const { return "maketime"; }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_maketime>(thd, this); }
};
@@ -1369,7 +1371,8 @@ public:
Item_handled_func(thd, a, b), const_item(false),
internal_charset(NULL)
{}
- bool get_date_common(MYSQL_TIME *ltime, ulonglong fuzzy_date, timestamp_type);
+ bool get_date_common(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate,
+ timestamp_type);
const char *func_name() const { return "str_to_date"; }
bool fix_length_and_dec();
Item *get_copy(THD *thd)
@@ -1384,7 +1387,7 @@ class Item_func_last_day :public Item_datefunc
public:
Item_func_last_day(THD *thd, Item *a): Item_datefunc(thd, a) {}
const char *func_name() const { return "last_day"; }
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_last_day>(thd, this); }
};
@@ -1413,14 +1416,14 @@ protected:
{
return static_cast<const Item_date_add_interval*>(item)->date_sub_interval;
}
- bool add(Item *item, interval_type type, bool sub, MYSQL_TIME *to) const
+ bool add(THD *thd, Item *item, interval_type type, bool sub, MYSQL_TIME *to) const
{
INTERVAL interval;
- if (get_interval_value(item, type, &interval))
+ if (get_interval_value(thd, item, type, &interval))
return true;
if (sub)
interval.neg = !interval.neg;
- return date_add_interval(to, type, interval);
+ return date_add_interval(thd, to, type, interval);
}
};
@@ -1432,19 +1435,20 @@ class Func_handler_date_add_interval_datetime:
public:
bool fix_length_and_dec(Item_handled_func *item) const
{
- uint dec= MY_MAX(item->arguments()[0]->datetime_precision(),
+ uint dec= MY_MAX(item->arguments()[0]->datetime_precision(current_thd),
interval_dec(item->arguments()[1], int_type(item)));
item->fix_attributes_datetime(dec);
return false;
}
- bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
{
- Datetime dt(current_thd, item->arguments()[0], 0);
+ Datetime dt(thd, item->arguments()[0], date_mode_t(0));
if (!dt.is_valid_datetime() ||
- dt.check_date_with_warn(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
+ dt.check_date_with_warn(thd, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
return (item->null_value= true);
dt.copy_to_mysql_time(to);
- return (item->null_value= add(item->arguments()[1],
+ return (item->null_value= add(thd, item->arguments()[1],
int_type(item), sub(item), to));
}
};
@@ -1454,7 +1458,8 @@ class Func_handler_date_add_interval_datetime_arg0_time:
public Func_handler_date_add_interval_datetime
{
public:
- bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const;
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const;
};
@@ -1463,14 +1468,15 @@ class Func_handler_date_add_interval_date:
public Func_handler_date_add_interval
{
public:
- bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
{
- Date d(current_thd, item->arguments()[0], 0);
+ Date d(thd, item->arguments()[0], date_mode_t(0));
if (!d.is_valid_date() ||
- d.check_date_with_warn(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
+ d.check_date_with_warn(thd, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
return (item->null_value= true);
d.copy_to_mysql_time(to);
- return (item->null_value= add(item->arguments()[1],
+ return (item->null_value= add(thd, item->arguments()[1],
int_type(item), sub(item), to));
}
};
@@ -1483,18 +1489,19 @@ class Func_handler_date_add_interval_time:
public:
bool fix_length_and_dec(Item_handled_func *item) const
{
- uint dec= MY_MAX(item->arguments()[0]->time_precision(),
+ uint dec= MY_MAX(item->arguments()[0]->time_precision(current_thd),
interval_dec(item->arguments()[1], int_type(item)));
item->fix_attributes_time(dec);
return false;
}
- bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
{
- Time t(item->arguments()[0]);
+ Time t(thd, item->arguments()[0]);
if (!t.is_valid_time())
return (item->null_value= true);
t.copy_to_mysql_time(to);
- return (item->null_value= add(item->arguments()[1],
+ return (item->null_value= add(thd, item->arguments()[1],
int_type(item), sub(item), to));
}
};
@@ -1507,21 +1514,22 @@ class Func_handler_date_add_interval_string:
public:
bool fix_length_and_dec(Item_handled_func *item) const
{
- uint dec= MY_MAX(item->arguments()[0]->datetime_precision(),
+ uint dec= MY_MAX(item->arguments()[0]->datetime_precision(current_thd),
interval_dec(item->arguments()[1], int_type(item)));
item->collation.set(item->default_charset(),
DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
item->fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec);
return false;
}
- bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
{
- if (item->arguments()[0]->get_date(to, 0) ||
+ if (item->arguments()[0]->get_date(thd, to, date_mode_t(0)) ||
(to->time_type != MYSQL_TIMESTAMP_TIME &&
- check_date_with_warn(to, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE,
+ check_date_with_warn(thd, to, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE,
MYSQL_TIMESTAMP_ERROR)))
return (item->null_value= true);
- return (item->null_value= add(item->arguments()[1],
+ return (item->null_value= add(thd, item->arguments()[1],
int_type(item), sub(item), to));
}
};
@@ -1545,19 +1553,24 @@ public:
{ }
bool fix_length_and_dec(Item_handled_func *item) const
{
- uint dec= MY_MAX(item->arguments()[0]->datetime_precision(),
- item->arguments()[1]->time_precision());
- item->fix_attributes_datetime(dec);
+ THD *thd= current_thd;
+ uint dec0= item->arguments()[0]->datetime_precision(thd);
+ uint dec1= Interval_DDhhmmssff::fsp(thd, item->arguments()[1]);
+ item->fix_attributes_datetime(MY_MAX(dec0, dec1));
return false;
}
- bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
{
DBUG_ASSERT(item->is_fixed());
- MYSQL_TIME l_time2;
- Datetime dt(current_thd, item->arguments()[0], 0);
- return (item->null_value= (!dt.is_valid_datetime() ||
- item->arguments()[1]->get_time(&l_time2) ||
- Sec6_add(dt.get_mysql_time(), &l_time2, m_sign).
+ Datetime dt(thd, item->arguments()[0], date_mode_t(0));
+ if (!dt.is_valid_datetime())
+ return item->null_value= true;
+ Interval_DDhhmmssff it(thd, item->arguments()[1]);
+ if (!it.is_valid_interval_DDhhmmssff())
+ return item->null_value= true;
+ return (item->null_value= (Sec6_add(dt.get_mysql_time(),
+ it.get_mysql_time(), m_sign).
to_datetime(to)));
}
};
@@ -1573,20 +1586,25 @@ public:
{ }
bool fix_length_and_dec(Item_handled_func *item) const
{
- uint dec= MY_MAX(item->arguments()[0]->time_precision(),
- item->arguments()[1]->time_precision());
- item->fix_attributes_time(dec);
+ THD *thd= current_thd;
+ uint dec0= item->arguments()[0]->time_precision(thd);
+ uint dec1= Interval_DDhhmmssff::fsp(thd, item->arguments()[1]);
+ item->fix_attributes_time(MY_MAX(dec0, dec1));
return false;
}
- bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
{
DBUG_ASSERT(item->is_fixed());
- MYSQL_TIME l_time2;
- Time t(item->arguments()[0]);
- return (item->null_value= (!t.is_valid_time() ||
- item->arguments()[1]->get_time(&l_time2) ||
- Sec6_add(t.get_mysql_time(), &l_time2, m_sign).
- to_time(to, item->decimals)));
+ Time t(thd, item->arguments()[0]);
+ if (!t.is_valid_time())
+ return item->null_value= true;
+ Interval_DDhhmmssff i(thd, item->arguments()[1]);
+ if (!i.is_valid_interval_DDhhmmssff())
+ return item->null_value= true;
+ return (item->null_value= (Sec6_add(t.get_mysql_time(),
+ i.get_mysql_time(), m_sign).
+ to_time(thd, to, item->decimals)));
}
};
@@ -1601,24 +1619,29 @@ public:
{ }
bool fix_length_and_dec(Item_handled_func *item) const
{
- uint dec= MY_MAX(item->arguments()[0]->decimals,
- item->arguments()[1]->decimals);
+ uint dec0= item->arguments()[0]->decimals;
+ uint dec1= Interval_DDhhmmssff::fsp(current_thd, item->arguments()[1]);
+ uint dec= MY_MAX(dec0, dec1);
item->collation.set(item->default_charset(),
DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
item->fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec);
return false;
}
- bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
{
DBUG_ASSERT(item->is_fixed());
// Detect a proper timestamp type based on the argument values
- MYSQL_TIME l_time1, l_time2;
- if (item->arguments()[0]->get_time(&l_time1) ||
- item->arguments()[1]->get_time(&l_time2))
+ Temporal_hybrid l_time1(thd, item->arguments()[0], TIME_TIME_ONLY);
+ if (!l_time1.is_valid_temporal())
+ return (item->null_value= true);
+ Interval_DDhhmmssff l_time2(thd, item->arguments()[1]);
+ if (!l_time2.is_valid_interval_DDhhmmssff())
return (item->null_value= true);
- Sec6_add add(&l_time1, &l_time2, m_sign);
- return (item->null_value= (l_time1.time_type == MYSQL_TIMESTAMP_TIME ?
- add.to_time(to, item->decimals) :
+ Sec6_add add(l_time1.get_mysql_time(), l_time2.get_mysql_time(), m_sign);
+ return (item->null_value= (l_time1.get_mysql_time()->time_type ==
+ MYSQL_TIMESTAMP_TIME ?
+ add.to_time(thd, to, item->decimals) :
add.to_datetime(to)));
}
};
@@ -1633,10 +1656,11 @@ public:
item->fix_attributes_datetime(0);
return false;
}
- bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
{
return static_cast<Item_func_str_to_date*>(item)->
- get_date_common(to, fuzzy, MYSQL_TIMESTAMP_DATETIME);
+ get_date_common(thd, to, fuzzy, MYSQL_TIMESTAMP_DATETIME);
}
};
@@ -1650,10 +1674,11 @@ public:
item->fix_attributes_datetime(TIME_SECOND_PART_DIGITS);
return false;
}
- bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
{
return static_cast<Item_func_str_to_date*>(item)->
- get_date_common(to, fuzzy, MYSQL_TIMESTAMP_DATETIME);
+ get_date_common(thd, to, fuzzy, MYSQL_TIMESTAMP_DATETIME);
}
};
@@ -1661,10 +1686,11 @@ public:
class Func_handler_str_to_date_date: public Item_handled_func::Handler_date
{
public:
- bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
{
return static_cast<Item_func_str_to_date*>(item)->
- get_date_common(to, fuzzy, MYSQL_TIMESTAMP_DATE);
+ get_date_common(thd, to, fuzzy, MYSQL_TIMESTAMP_DATE);
}
};
@@ -1672,10 +1698,11 @@ public:
class Func_handler_str_to_date_time: public Item_handled_func::Handler_time
{
public:
- bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
{
if (static_cast<Item_func_str_to_date*>(item)->
- get_date_common(to, fuzzy, MYSQL_TIMESTAMP_TIME))
+ get_date_common(thd, to, fuzzy, MYSQL_TIMESTAMP_TIME))
return true;
if (to->day)
{
diff --git a/sql/item_vers.cc b/sql/item_vers.cc
index d7361f687f9..6946ae0e1e5 100644
--- a/sql/item_vers.cc
+++ b/sql/item_vers.cc
@@ -37,9 +37,8 @@ Item_func_trt_ts::Item_func_trt_ts(THD *thd, Item* a, TR_table::field_id_t _trt_
bool
-Item_func_trt_ts::get_date(MYSQL_TIME *res, ulonglong fuzzy_date)
+Item_func_trt_ts::get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate)
{
- THD *thd= current_thd; // can it differ from constructor's?
DBUG_ASSERT(thd);
DBUG_ASSERT(args[0]);
if (args[0]->result_type() != INT_RESULT)
@@ -67,7 +66,7 @@ Item_func_trt_ts::get_date(MYSQL_TIME *res, ulonglong fuzzy_date)
return true;
}
- return trt[trt_field]->get_date(res, fuzzy_date);
+ return trt[trt_field]->get_date(res, fuzzydate);
}
@@ -143,7 +142,7 @@ Item_func_trt_id::val_int()
else
{
MYSQL_TIME commit_ts;
- if (args[0]->get_date(&commit_ts, 0))
+ if (args[0]->get_date(current_thd, &commit_ts, date_mode_t(0)))
{
null_value= true;
return 0;
diff --git a/sql/item_vers.h b/sql/item_vers.h
index 8b9c0e6056c..a42b5a033f2 100644
--- a/sql/item_vers.h
+++ b/sql/item_vers.h
@@ -35,7 +35,7 @@ public:
}
return "trt_commit_ts";
}
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_trt_ts>(thd, this); }
bool fix_length_and_dec()
diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc
index a17f9482ea0..aa2c7756ab7 100644
--- a/sql/item_windowfunc.cc
+++ b/sql/item_windowfunc.cc
@@ -439,12 +439,12 @@ Item_sum_hybrid_simple::val_str(String *str)
return retval;
}
-bool Item_sum_hybrid_simple::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_sum_hybrid_simple::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
if (null_value)
return true;
- bool retval= value->get_date(ltime, fuzzydate);
+ bool retval= value->get_date(thd, ltime, fuzzydate);
if ((null_value= value->null_value))
DBUG_ASSERT(retval == true);
return retval;
@@ -542,6 +542,11 @@ void Item_sum_hybrid_simple::update_field()
void Item_window_func::print(String *str, enum_query_type query_type)
{
+ if (only_single_element_order_list())
+ {
+ print_for_percentile_functions(str, query_type);
+ return;
+ }
window_func()->print(str, query_type);
str->append(" over ");
#ifndef DBUG_OFF
@@ -551,3 +556,15 @@ void Item_window_func::print(String *str, enum_query_type query_type)
#endif
window_spec->print(str, query_type);
}
+void Item_window_func::print_for_percentile_functions(String *str, enum_query_type query_type)
+{
+ window_func()->print(str, query_type);
+ str->append(" within group ");
+ str->append('(');
+ window_spec->print_order(str,query_type);
+ str->append(')');
+ str->append(" over ");
+ str->append('(');
+ window_spec->print_partition(str,query_type);
+ str->append(')');
+}
diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h
index 48851da7d96..4c704808fe4 100644
--- a/sql/item_windowfunc.h
+++ b/sql/item_windowfunc.h
@@ -319,7 +319,7 @@ class Item_sum_hybrid_simple : public Item_sum,
my_decimal *val_decimal(my_decimal *);
void reset_field();
String *val_str(String *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
void update_field();
@@ -1085,6 +1085,8 @@ public:
case Item_sum::DENSE_RANK_FUNC:
case Item_sum::PERCENT_RANK_FUNC:
case Item_sum::CUME_DIST_FUNC:
+ case Item_sum::LAG_FUNC:
+ case Item_sum::LEAD_FUNC:
case Item_sum::PERCENTILE_CONT_FUNC:
case Item_sum::PERCENTILE_DISC_FUNC:
return true;
@@ -1153,6 +1155,7 @@ private:
*/
bool force_return_blank;
bool read_value_from_result_field;
+ void print_for_percentile_functions(String *str, enum_query_type query_type);
public:
void set_phase_to_initial()
@@ -1270,7 +1273,7 @@ public:
return res;
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
bool res;
if (force_return_blank)
@@ -1287,7 +1290,7 @@ public:
}
else
{
- res= window_func()->get_date(ltime, fuzzydate);
+ res= window_func()->get_date(thd, ltime, fuzzydate);
null_value= window_func()->null_value;
}
return res;
diff --git a/sql/key.cc b/sql/key.cc
index 34196a973c5..9ad1103fbe8 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -146,7 +146,8 @@ void key_copy(uchar *to_key, const uchar *from_record, KEY *key_info,
{
key_length-= HA_KEY_BLOB_LENGTH;
length= MY_MIN(key_length, key_part->length);
- uint bytes= key_part->field->get_key_image(to_key, length, Field::itRAW);
+ uint bytes= key_part->field->get_key_image(to_key, length,
+ key_info->flags & HA_SPATIAL ? Field::itMBR : Field::itRAW);
if (with_zerofill && bytes < length)
bzero((char*) to_key + bytes, length - bytes);
to_key+= HA_KEY_BLOB_LENGTH;
diff --git a/sql/lock.cc b/sql/lock.cc
index 17629f17291..5420e9f42b5 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -596,22 +596,6 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table)
}
-/** Abort all other threads waiting to get lock in table. */
-
-void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock)
-{
- MYSQL_LOCK *locked;
- DBUG_ENTER("mysql_lock_abort");
-
- if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK | GET_LOCK_ON_THD)))
- {
- for (uint i=0; i < locked->lock_count; i++)
- thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
- }
- DBUG_VOID_RETURN;
-}
-
-
/**
Abort one thread / table combination.
diff --git a/sql/lock.h b/sql/lock.h
index 35cb3043d57..e9324c80d89 100644
--- a/sql/lock.h
+++ b/sql/lock.h
@@ -33,7 +33,6 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag);
void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table);
-void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock);
bool mysql_lock_abort_for_thread(THD *thd, TABLE *table);
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b);
/* Lock based on name */
diff --git a/sql/log.cc b/sql/log.cc
index 6975b58dfb7..a56117a4ac1 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1162,6 +1162,10 @@ bool LOGGER::error_log_print(enum loglevel level, const char *format,
{
bool error= FALSE;
Log_event_handler **current_handler;
+ THD *thd= current_thd;
+
+ if (likely(thd))
+ thd->error_printed_to_log= 1;
/* currently we don't need locking here as there is no error_log table */
for (current_handler= error_log_handler_list ; *current_handler ;)
@@ -1703,14 +1707,14 @@ static int binlog_close_connection(handlerton *hton, THD *thd)
uchar *buf;
size_t len=0;
wsrep_write_cache_buf(cache, &buf, &len);
- WSREP_WARN("binlog trx cache not empty (%lu bytes) @ connection close %lld",
- (ulong) len, (longlong) thd->thread_id);
+ WSREP_WARN("binlog trx cache not empty (%zu bytes) @ connection close %lld",
+ len, (longlong) thd->thread_id);
if (len > 0) wsrep_dump_rbr_buf(thd, buf, len);
cache = cache_mngr->get_binlog_cache_log(false);
wsrep_write_cache_buf(cache, &buf, &len);
- WSREP_WARN("binlog stmt cache not empty (%lu bytes) @ connection close %lld",
- (ulong) len, (longlong) thd->thread_id);
+ WSREP_WARN("binlog stmt cache not empty (%zu bytes) @ connection close %lld",
+ len, (longlong) thd->thread_id);
if (len > 0) wsrep_dump_rbr_buf(thd, buf, len);
}
#endif /* WITH_WSREP */
@@ -2746,14 +2750,14 @@ void MYSQL_LOG::close(uint exiting)
if (log_type == LOG_BIN && mysql_file_sync(log_file.file, MYF(MY_WME)) && ! write_error)
{
write_error= 1;
- sql_print_error(ER_THD_OR_DEFAULT(current_thd, ER_ERROR_ON_WRITE), name, errno);
+ sql_print_error(ER_DEFAULT(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_THD_OR_DEFAULT(current_thd, ER_ERROR_ON_WRITE), name, errno);
+ sql_print_error(ER_DEFAULT(ER_ERROR_ON_WRITE), name, errno);
}
}
@@ -2937,7 +2941,7 @@ err:
if (!write_error)
{
write_error= 1;
- sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
+ sql_print_error(ER_DEFAULT(ER_ERROR_ON_WRITE), name, errno);
}
mysql_mutex_unlock(&LOCK_log);
return TRUE;
@@ -8474,8 +8478,7 @@ void MYSQL_BIN_LOG::close(uint exiting)
! write_error)
{
write_error= 1;
- sql_print_error(ER_THD_OR_DEFAULT(current_thd, ER_ERROR_ON_WRITE),
- index_file_name, errno);
+ sql_print_error(ER_DEFAULT(ER_ERROR_ON_WRITE), index_file_name, errno);
}
}
log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 13690a8be60..651fb4ce5b1 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -264,6 +264,27 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error,
}
#endif
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+static void set_thd_db(THD *thd, Rpl_filter *rpl_filter,
+ const char *db, uint32 db_len)
+{
+ char lcase_db_buf[NAME_LEN +1];
+ LEX_CSTRING new_db;
+ new_db.length= db_len;
+ if (lower_case_table_names == 1)
+ {
+ strmov(lcase_db_buf, db);
+ my_casedn_str(system_charset_info, lcase_db_buf);
+ new_db.str= lcase_db_buf;
+ }
+ else
+ new_db.str= db;
+ /* TODO WARNING this makes rewrite_db respect lower_case_table_names values
+ * for more info look MDEV-17446 */
+ new_db.str= rpl_filter->get_rewrite_db(new_db.str, &new_db.length);
+ thd->set_db(&new_db);
+}
+#endif
/*
Cache that will automatically be written to a dedicated file on
destruction.
@@ -5374,7 +5395,6 @@ bool test_if_equal_repl_errors(int expected_error, int actual_error)
int Query_log_event::do_apply_event(rpl_group_info *rgi,
const char *query_arg, uint32 q_len_arg)
{
- LEX_CSTRING new_db;
int expected_error,actual_error= 0;
Schema_specification_st db_options;
uint64 sub_id= 0;
@@ -5406,9 +5426,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
goto end;
}
- new_db.length= db_len;
- new_db.str= (char *) rpl_filter->get_rewrite_db(db, &new_db.length);
- thd->set_db(&new_db); /* allocates a copy of 'db' */
+ set_thd_db(thd, rpl_filter, db, db_len);
/*
Setting the character set and collation of the current database thd->db.
@@ -5563,7 +5581,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
gtid= rgi->current_gtid;
if (unlikely(rpl_global_gtid_slave_state->record_gtid(thd, &gtid,
sub_id,
- true, false,
+ rgi, false,
&hton)))
{
int errcode= thd->get_stmt_da()->sql_errno();
@@ -7238,15 +7256,12 @@ void Load_log_event::set_fields(const char* affected_db,
int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi,
bool use_rli_only_for_errors)
{
- LEX_CSTRING new_db;
Relay_log_info const *rli= rgi->rli;
Rpl_filter *rpl_filter= rli->mi->rpl_filter;
DBUG_ENTER("Load_log_event::do_apply_event");
- new_db.length= db_len;
- new_db.str= rpl_filter->get_rewrite_db(db, &new_db.length);
- thd->set_db(&new_db);
DBUG_ASSERT(thd->query() == 0);
+ set_thd_db(thd, rpl_filter, db, db_len);
thd->clear_error(1);
/* see Query_log_event::do_apply_event() and BUG#13360 */
@@ -7290,6 +7305,8 @@ int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi,
TABLE_LIST tables;
LEX_CSTRING db_name= { thd->strmake(thd->db.str, thd->db.length), thd->db.length };
+ if (lower_case_table_names)
+ my_casedn_str(system_charset_info, (char *)table_name);
LEX_CSTRING tbl_name= { table_name, strlen(table_name) };
tables.init_one_table(&db_name, &tbl_name, 0, TL_WRITE);
tables.updating= 1;
@@ -8361,7 +8378,7 @@ Gtid_list_log_event::do_apply_event(rpl_group_info *rgi)
{
if ((ret= rpl_global_gtid_slave_state->record_gtid(thd, &list[i],
sub_id_list[i],
- false, false, &hton)))
+ NULL, false, &hton)))
return ret;
rpl_global_gtid_slave_state->update_state_hash(sub_id_list[i], &list[i],
hton, NULL);
@@ -8898,7 +8915,7 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi)
rgi->gtid_pending= false;
gtid= rgi->current_gtid;
- err= rpl_global_gtid_slave_state->record_gtid(thd, &gtid, sub_id, true,
+ err= rpl_global_gtid_slave_state->record_gtid(thd, &gtid, sub_id, rgi,
false, &hton);
if (unlikely(err))
{
@@ -9168,11 +9185,6 @@ User_var_log_event(const char* buf, uint event_len,
we keep the flags set to UNDEF_F.
*/
size_t bytes_read= (val + val_len) - buf_start;
- if (bytes_read > size_t(event_len))
- {
- error= true;
- goto err;
- }
if ((data_written - bytes_read) > 0)
{
flags= (uint) *(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
@@ -12578,7 +12590,7 @@ check_table_map(rpl_group_info *rgi, RPL_TABLE_LIST *table_list)
int Table_map_log_event::do_apply_event(rpl_group_info *rgi)
{
RPL_TABLE_LIST *table_list;
- char *db_mem, *tname_mem;
+ char *db_mem, *tname_mem, *ptr;
size_t dummy_len, db_mem_length, tname_mem_length;
void *memory;
Rpl_filter *filter;
@@ -12595,10 +12607,20 @@ int Table_map_log_event::do_apply_event(rpl_group_info *rgi)
NullS)))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ db_mem_length= strmov(db_mem, m_dbnam) - db_mem;
+ tname_mem_length= strmov(tname_mem, m_tblnam) - tname_mem;
+ if (lower_case_table_names)
+ {
+ my_casedn_str(files_charset_info, (char*)tname_mem);
+ my_casedn_str(files_charset_info, (char*)db_mem);
+ }
+
/* call from mysql_client_binlog_statement() will not set rli->mi */
filter= rgi->thd->slave_thread ? rli->mi->rpl_filter : global_rpl_filter;
- db_mem_length= strmov(db_mem, filter->get_rewrite_db(m_dbnam, &dummy_len))- db_mem;
- tname_mem_length= strmov(tname_mem, m_tblnam)- tname_mem;
+
+ /* rewrite rules changed the database */
+ if (((ptr= (char*) filter->get_rewrite_db(db_mem, &dummy_len)) != db_mem))
+ db_mem_length= strmov(db_mem, ptr) - db_mem;
LEX_CSTRING tmp_db_name= {db_mem, db_mem_length };
LEX_CSTRING tmp_tbl_name= {tname_mem, tname_mem_length };
diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc
index cf587ef4acd..d6952e71899 100644
--- a/sql/multi_range_read.cc
+++ b/sql/multi_range_read.cc
@@ -18,6 +18,7 @@
#include <my_bit.h>
#include "sql_select.h"
#include "key.h"
+#include "sql_statistics.h"
/****************************************************************************
* Default MRR implementation (MRR to non-MRR converter)
@@ -64,7 +65,12 @@ handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
ha_rows rows, total_rows= 0;
uint n_ranges=0;
THD *thd= table->in_use;
+ uint limit= thd->variables.eq_range_index_dive_limit;
+ bool use_statistics_for_eq_range= eq_ranges_exceeds_limit(seq,
+ seq_init_param,
+ limit);
+
/* Default MRR implementation doesn't need buffer */
*bufsz= 0;
@@ -88,8 +94,15 @@ handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
min_endp= range.start_key.length? &range.start_key : NULL;
max_endp= range.end_key.length? &range.end_key : NULL;
}
+ int keyparts_used= my_count_bits(range.start_key.keypart_map);
if ((range.range_flag & UNIQUE_RANGE) && !(range.range_flag & NULL_RANGE))
rows= 1; /* there can be at most one row */
+ else if (use_statistics_for_eq_range &&
+ !(range.range_flag & NULL_RANGE) &&
+ (range.range_flag & EQ_RANGE) &&
+ table->key_info[keyno].actual_rec_per_key(keyparts_used - 1) > 0.5)
+ rows=
+ (ha_rows) table->key_info[keyno].actual_rec_per_key(keyparts_used - 1);
else
{
if (HA_POS_ERROR == (rows= this->records_in_range(keyno, min_endp,
diff --git a/sql/my_decimal.h b/sql/my_decimal.h
index d035641cfa6..b22c686cc90 100644
--- a/sql/my_decimal.h
+++ b/sql/my_decimal.h
@@ -29,6 +29,8 @@
#ifndef my_decimal_h
#define my_decimal_h
+#include "sql_basic_types.h"
+
#if defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY)
#include "sql_string.h" /* String */
#endif
@@ -215,8 +217,6 @@ public:
{
return check_result(mask, decimal_round(this, to, (int) scale, mode));
}
- bool to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
- const char *field_name);
int to_binary(uchar *bin, int prec, int scale,
uint mask= E_DEC_FATAL_ERROR) const;
#endif
diff --git a/sql/mysql_install_db.cc b/sql/mysql_install_db.cc
index ce40b5edc2c..fc8bce08276 100644
--- a/sql/mysql_install_db.cc
+++ b/sql/mysql_install_db.cc
@@ -26,6 +26,8 @@
#include <shellapi.h>
#include <accctrl.h>
#include <aclapi.h>
+struct IUnknown;
+#include <shlwapi.h>
#define USAGETEXT \
"mysql_install_db.exe Ver 1.00 for Windows\n" \
@@ -93,9 +95,7 @@ static struct my_option my_long_options[]=
static my_bool
-get_one_option(int optid,
- const struct my_option *opt __attribute__ ((unused)),
- char *argument __attribute__ ((unused)))
+get_one_option(int optid, const struct my_option *, char *)
{
DBUG_ENTER("get_one_option");
switch (optid) {
@@ -109,7 +109,7 @@ get_one_option(int optid,
}
-static void die(const char *fmt, ...)
+ATTRIBUTE_NORETURN static void die(const char *fmt, ...)
{
va_list args;
DBUG_ENTER("die");
@@ -290,7 +290,7 @@ static int create_myini()
FILE *myini= fopen("my.ini","wt");
if (!myini)
{
- die("Cannot create my.ini in data directory");
+ die("Can't create my.ini in data directory");
}
/* Write out server settings. */
@@ -308,7 +308,7 @@ static int create_myini()
if (enable_named_pipe)
{
- fprintf(myini,"enable-named-pipe\n");
+ fprintf(myini,"named-pipe=ON\n");
}
if (opt_socket && opt_socket[0])
@@ -523,6 +523,7 @@ static int set_directory_permissions(const char *dir, const char *os_user)
}
+
/* Create database instance (including registering as service etc) .*/
static int create_db_instance()
@@ -532,19 +533,78 @@ static int create_db_instance()
DWORD cwd_len= MAX_PATH;
char cmdline[3*MAX_PATH];
FILE *in;
+ bool cleanup_datadir= true;
+ DWORD last_error;
verbose("Running bootstrap");
GetCurrentDirectory(cwd_len, cwd);
- CreateDirectory(opt_datadir, NULL); /*ignore error, it might already exist */
+
+ /* Create datadir and datadir/mysql, if they do not already exist. */
+
+ if (!CreateDirectory(opt_datadir, NULL) && (GetLastError() != ERROR_ALREADY_EXISTS))
+ {
+ last_error = GetLastError();
+ switch(last_error)
+ {
+ case ERROR_ACCESS_DENIED:
+ die("Can't create data directory '%s' (access denied)\n",
+ opt_datadir);
+ break;
+ case ERROR_PATH_NOT_FOUND:
+ die("Can't create data directory '%s' "
+ "(one or more intermediate directories do not exist)\n",
+ opt_datadir);
+ break;
+ default:
+ die("Can't create data directory '%s', last error %u\n",
+ opt_datadir, last_error);
+ break;
+ }
+ }
if (!SetCurrentDirectory(opt_datadir))
{
- die("Cannot set current directory to '%s'\n",opt_datadir);
- return -1;
+ last_error = GetLastError();
+ switch (last_error)
+ {
+ case ERROR_DIRECTORY:
+ die("Can't set current directory to '%s', the path is not a valid directory \n",
+ opt_datadir);
+ break;
+ default:
+ die("Can' set current directory to '%s', last error %u\n",
+ opt_datadir, last_error);
+ break;
+ }
}
- CreateDirectory("mysql",NULL);
+ if (PathIsDirectoryEmpty(opt_datadir))
+ {
+ cleanup_datadir= false;
+ }
+
+ if (!CreateDirectory("mysql",NULL))
+ {
+ last_error = GetLastError();
+ DWORD attributes;
+ switch(last_error)
+ {
+ case ERROR_ACCESS_DENIED:
+ die("Can't create subdirectory 'mysql' in '%s' (access denied)\n",opt_datadir);
+ break;
+ case ERROR_ALREADY_EXISTS:
+ attributes = GetFileAttributes("mysql");
+
+ if (attributes == INVALID_FILE_ATTRIBUTES)
+ die("GetFileAttributes() failed for existing file '%s\\mysql', last error %u",
+ opt_datadir, GetLastError());
+ else if (!(attributes & FILE_ATTRIBUTE_DIRECTORY))
+ die("File '%s\\mysql' exists, but it is not a directory", opt_datadir);
+
+ break;
+ }
+ }
/*
Set data directory permissions for both current user and
@@ -565,11 +625,11 @@ static int create_db_instance()
if (setvbuf(in, NULL, _IONBF, 0))
{
- verbose("WARNING: Cannot disable buffering on mysqld's stdin");
+ verbose("WARNING: Can't disable buffering on mysqld's stdin");
}
if (fwrite("use mysql;\n",11,1, in) != 1)
{
- verbose("ERROR: Cannot write to mysqld's stdin");
+ verbose("ERROR: Can't write to mysqld's stdin");
ret= 1;
goto end;
}
@@ -580,7 +640,7 @@ static int create_db_instance()
/* Write the bootstrap script to stdin. */
if (fwrite(mysql_bootstrap_sql[i], strlen(mysql_bootstrap_sql[i]), 1, in) != 1)
{
- verbose("ERROR: Cannot write to mysqld's stdin");
+ verbose("ERROR: Can't write to mysqld's stdin");
ret= 1;
goto end;
}
@@ -649,7 +709,7 @@ static int create_db_instance()
}
end:
- if (ret)
+ if (ret && cleanup_datadir)
{
SetCurrentDirectory(cwd);
clean_directory(opt_datadir);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index ce14dc678c6..9ff47dc1ff1 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -117,6 +117,10 @@
#include <poll.h>
#endif
+#ifdef _WIN32
+#include <handle_connections_win.h>
+#endif
+
#include <my_service_manager.h>
#define mysqld_charset &my_charset_latin1
@@ -319,23 +323,6 @@ MY_TIMER_INFO sys_timer_info;
/* static variables */
#ifdef HAVE_PSI_INTERFACE
-#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
-static PSI_thread_key key_thread_handle_con_namedpipes;
-static PSI_cond_key key_COND_handler_count;
-#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */
-
-#if defined(HAVE_SMEM) && !defined(EMBEDDED_LIBRARY)
-static PSI_thread_key key_thread_handle_con_sharedmem;
-#endif /* HAVE_SMEM && !EMBEDDED_LIBRARY */
-
-#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
-static PSI_thread_key key_thread_handle_con_sockets;
-#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */
-
-#ifdef __WIN__
-static PSI_thread_key key_thread_handle_shutdown;
-#endif /* __WIN__ */
-
#ifdef HAVE_OPENSSL10
static PSI_rwlock_key key_rwlock_openssl;
#endif
@@ -371,6 +358,7 @@ static char *character_set_filesystem_name;
static char *lc_messages;
static char *lc_time_names_name;
char *my_bind_addr_str;
+int server_socket_ai_family;
static char *default_collation_name;
char *default_storage_engine, *default_tmp_storage_engine;
char *enforced_storage_engine=NULL;
@@ -484,7 +472,7 @@ my_bool opt_master_verify_checksum= 0;
my_bool opt_slave_sql_verify_checksum= 1;
const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS};
volatile sig_atomic_t calling_initgroups= 0; /**< Used in SIGSEGV handler. */
-uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options;
+uint mysqld_port, select_errors, dropping_tables, ha_open_options;
uint mysqld_extra_port;
uint mysqld_port_timeout;
ulong delay_key_write_options;
@@ -512,6 +500,7 @@ ulonglong max_binlog_cache_size=0;
ulong slave_max_allowed_packet= 0;
ulonglong binlog_stmt_cache_size=0;
ulonglong max_binlog_stmt_cache_size=0;
+ulonglong test_flags;
ulonglong query_cache_size=0;
ulong query_cache_limit=0;
ulong executed_events=0;
@@ -743,7 +732,6 @@ mysql_mutex_t LOCK_thread_count;
other threads.
It also protects these variables:
- handler_count
in_bootstrap
select_thread_in_use
slave_init_thread_running
@@ -798,6 +786,7 @@ char *master_info_file;
char *relay_log_info_file, *report_user, *report_password, *report_host;
char *opt_relay_logname = 0, *opt_relaylog_index_name=0;
char *opt_logname, *opt_slow_logname, *opt_bin_logname;
+char *opt_binlog_index_name=0;
/* Static variables */
@@ -807,7 +796,6 @@ my_bool opt_expect_abort= 0, opt_bootstrap= 0;
static my_bool opt_myisam_log;
static int cleanup_done;
static ulong opt_specialflag;
-static char *opt_binlog_index_name;
char *mysql_home_ptr, *pidfile_name_ptr;
/** Initial command line arguments (count), after load_defaults().*/
static int defaults_argc;
@@ -1097,9 +1085,6 @@ PSI_cond_key key_COND_ack_receiver;
static PSI_cond_info all_server_conds[]=
{
-#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
- { &key_COND_handler_count, "COND_handler_count", PSI_FLAG_GLOBAL},
-#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */
#ifdef HAVE_MMAP
{ &key_PAGE_cond, "PAGE::cond", 0},
{ &key_COND_active, "TC_LOG_MMAP::COND_active", 0},
@@ -1160,22 +1145,6 @@ PSI_thread_key key_thread_ack_receiver;
static PSI_thread_info all_server_threads[]=
{
-#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
- { &key_thread_handle_con_namedpipes, "con_named_pipes", PSI_FLAG_GLOBAL},
-#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */
-
-#if defined(HAVE_SMEM) && !defined(EMBEDDED_LIBRARY)
- { &key_thread_handle_con_sharedmem, "con_shared_mem", PSI_FLAG_GLOBAL},
-#endif /* HAVE_SMEM && !EMBEDDED_LIBRARY */
-
-#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
- { &key_thread_handle_con_sockets, "con_sockets", PSI_FLAG_GLOBAL},
-#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */
-
-#ifdef __WIN__
- { &key_thread_handle_shutdown, "shutdown", PSI_FLAG_GLOBAL},
-#endif /* __WIN__ */
-
{ &key_thread_bootstrap, "bootstrap", PSI_FLAG_GLOBAL},
{ &key_thread_delayed_insert, "delayed_insert", 0},
{ &key_thread_handle_manager, "manager", PSI_FLAG_GLOBAL},
@@ -1418,10 +1387,10 @@ void Buffered_logs::print()
/** Logs reported before a logger is available. */
static Buffered_logs buffered_logs;
-static MYSQL_SOCKET unix_sock, base_ip_sock, extra_ip_sock;
struct my_rnd_struct sql_rand; ///< used by sql_class.cc:THD::THD()
#ifndef EMBEDDED_LIBRARY
+MYSQL_SOCKET unix_sock, base_ip_sock, extra_ip_sock;
/**
Error reporter that buffer log messages.
@param level log message level
@@ -1477,27 +1446,18 @@ static pthread_t select_thread;
#undef getpid
#include <process.h>
-static mysql_cond_t COND_handler_count;
-static uint handler_count;
static bool start_mode=0, use_opt_args;
static int opt_argc;
static char **opt_argv;
#if !defined(EMBEDDED_LIBRARY)
-static HANDLE hEventShutdown;
+HANDLE hEventShutdown;
static char shutdown_event_name[40];
#include "nt_servc.h"
static NTService Service; ///< Service object for WinNT
#endif /* EMBEDDED_LIBRARY */
#endif /* __WIN__ */
-#ifdef _WIN32
-static char pipe_name[512];
-static SECURITY_ATTRIBUTES saPipeSecurity;
-static SECURITY_DESCRIPTOR sdPipeDescriptor;
-static HANDLE hPipe = INVALID_HANDLE_VALUE;
-#endif
-
#ifndef EMBEDDED_LIBRARY
bool mysqld_embedded=0;
#else
@@ -1518,11 +1478,7 @@ int deny_severity = LOG_WARNING;
ulong query_cache_min_res_unit= QUERY_CACHE_MIN_RESULT_DATA_SIZE;
Query_cache query_cache;
#endif
-#ifdef HAVE_SMEM
-const char *shared_memory_base_name= default_shared_memory_base_name;
-my_bool opt_enable_shared_memory;
-HANDLE smem_event_connect_request= 0;
-#endif
+
my_bool opt_use_ssl = 0;
char *opt_ssl_ca= NULL, *opt_ssl_capath= NULL, *opt_ssl_cert= NULL,
@@ -1574,19 +1530,13 @@ extern "C" my_bool mysqld_get_one_option(int, const struct my_option *, char *);
static int init_thread_environment();
static char *get_relative_path(const char *path);
static int fix_paths(void);
+#ifndef _WIN32
void handle_connections_sockets();
-#ifdef _WIN32
-pthread_handler_t handle_connections_sockets_thread(void *arg);
#endif
+
pthread_handler_t kill_server_thread(void *arg);
static void bootstrap(MYSQL_FILE *file);
static bool read_init_file(char *file_name);
-#ifdef _WIN32
-pthread_handler_t handle_connections_namedpipes(void *arg);
-#endif
-#ifdef HAVE_SMEM
-pthread_handler_t handle_connections_shared_memory(void *arg);
-#endif
pthread_handler_t handle_slave(void *arg);
static void clean_up(bool print_message);
static int test_if_case_insensitive(const char *dir_name);
@@ -1621,6 +1571,7 @@ static void close_connections(void)
kill_cached_threads++;
flush_thread_cache();
+
/* kill connection thread */
#if !defined(__WIN__)
DBUG_PRINT("quit", ("waiting for select thread: %lu",
@@ -1670,30 +1621,7 @@ static void close_connections(void)
extra_ip_sock= MYSQL_INVALID_SOCKET;
}
}
-#ifdef _WIN32
- if (hPipe != INVALID_HANDLE_VALUE && opt_enable_named_pipe)
- {
- HANDLE temp;
- DBUG_PRINT("quit", ("Closing named pipes") );
-
- /* Create connection to the handle named pipe handler to break the loop */
- if ((temp = CreateFile(pipe_name,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- OPEN_EXISTING,
- 0,
- NULL )) != INVALID_HANDLE_VALUE)
- {
- WaitNamedPipe(pipe_name, 1000);
- DWORD dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
- SetNamedPipeHandleState(temp, &dwMode, NULL, NULL);
- CancelIo(temp);
- DisconnectNamedPipe(temp);
- CloseHandle(temp);
- }
- }
-#endif
+
#ifdef HAVE_SYS_UN_H
if (mysql_socket_getfd(unix_sock) != INVALID_SOCKET)
{
@@ -1806,7 +1734,14 @@ static void close_connections(void)
(ulong) tmp->thread_id,
(tmp->main_security_ctx.user ?
tmp->main_security_ctx.user : ""));
+ /*
+ close_connection() might need a valid current_thd
+ for memory allocation tracking.
+ */
+ THD* save_thd= current_thd;
+ set_current_thd(tmp);
close_connection(tmp,ER_SERVER_SHUTDOWN);
+ set_current_thd(save_thd);
}
#endif
@@ -1933,12 +1868,6 @@ void kill_mysql(THD *thd)
{
DBUG_PRINT("error",("Got error: %ld from SetEvent",GetLastError()));
}
- /*
- or:
- HANDLE hEvent=OpenEvent(0, FALSE, "MySqlShutdown");
- SetEvent(hEventShutdown);
- CloseHandle(hEvent);
- */
}
#endif
#elif defined(HAVE_PTHREAD_KILL)
@@ -1970,7 +1899,7 @@ void kill_mysql(THD *thd)
/**
Force server down. Kill all connections and threads and exit.
- @param sig_ptr Signal number that caused kill_server to be called.
+ @param sig Signal number that caused kill_server to be called.
@note
A signal number of 0 mean that the function was not called
@@ -1978,22 +1907,14 @@ void kill_mysql(THD *thd)
or stop, we just want to kill the server.
*/
-#if !defined(__WIN__)
-static void *kill_server(void *sig_ptr)
-#define RETURN_FROM_KILL_SERVER return 0
-#else
-static void __cdecl kill_server(int sig_ptr)
-#define RETURN_FROM_KILL_SERVER return
-#endif
+static void kill_server(int sig)
{
DBUG_ENTER("kill_server");
#ifndef EMBEDDED_LIBRARY
- int sig=(int) (long) sig_ptr; // This is passed a int
// if there is a signal during the kill in progress, ignore the other
if (kill_in_progress) // Safety
{
- DBUG_LEAVE;
- RETURN_FROM_KILL_SERVER;
+ DBUG_VOID_RETURN;
}
kill_in_progress=TRUE;
abort_loop=1; // This should be set
@@ -2010,21 +1931,6 @@ static void __cdecl kill_server(int sig_ptr)
else
sql_print_error(ER_DEFAULT(ER_GOT_SIGNAL),my_progname,sig); /* purecov: inspected */
-#ifdef HAVE_SMEM
- /*
- Send event to smem_event_connect_request for aborting
- */
- if (opt_enable_shared_memory)
- {
- if (!SetEvent(smem_event_connect_request))
- {
- DBUG_PRINT("error",
- ("Got error: %ld from SetEvent of smem_event_connect_request",
- GetLastError()));
- }
- }
-#endif
-
/* Stop wsrep threads in case they are running. */
if (wsrep_running_threads > 0)
{
@@ -2042,20 +1948,9 @@ static void __cdecl kill_server(int sig_ptr)
else
unireg_end();
- /* purecov: begin deadcode */
- DBUG_LEAVE; // Must match DBUG_ENTER()
- my_thread_end();
- pthread_exit(0);
- /* purecov: end */
-
- RETURN_FROM_KILL_SERVER; // Avoid compiler warnings
-
-#else /* EMBEDDED_LIBRARY*/
-
- DBUG_LEAVE;
- RETURN_FROM_KILL_SERVER;
+#endif /* EMBEDDED_LIBRARY*/
-#endif /* EMBEDDED_LIBRARY */
+ DBUG_VOID_RETURN;
}
@@ -2064,11 +1959,9 @@ pthread_handler_t kill_server_thread(void *arg __attribute__((unused)))
{
my_thread_init(); // Initialize new thread
kill_server(0);
- /* purecov: begin deadcode */
my_thread_end();
pthread_exit(0);
return 0;
- /* purecov: end */
}
#endif
@@ -2114,13 +2007,7 @@ static void clean_up_error_log_mutex()
void unireg_end(void)
{
clean_up(1);
- my_thread_end();
sd_notify(0, "STATUS=MariaDB server is down");
-#if defined(SIGNALS_DONT_BREAK_READ)
- exit(0);
-#else
- pthread_exit(0); // Exit is in main thread
-#endif
}
@@ -2615,6 +2502,7 @@ static MYSQL_SOCKET activate_tcp_port(uint port)
}
else
{
+ server_socket_ai_family= a->ai_family;
sql_print_information("Server socket created on IP: '%s'.",
(const char *) ip_addr);
break;
@@ -2741,45 +2629,6 @@ static void network_init(void)
extra_ip_sock= activate_tcp_port(mysqld_extra_port);
}
-#ifdef _WIN32
- /* create named pipe */
- if (mysqld_unix_port[0] && !opt_bootstrap &&
- opt_enable_named_pipe)
- {
-
- strxnmov(pipe_name, sizeof(pipe_name)-1, "\\\\.\\pipe\\",
- mysqld_unix_port, NullS);
- bzero((char*) &saPipeSecurity, sizeof(saPipeSecurity));
- bzero((char*) &sdPipeDescriptor, sizeof(sdPipeDescriptor));
- if (!InitializeSecurityDescriptor(&sdPipeDescriptor,
- SECURITY_DESCRIPTOR_REVISION))
- {
- sql_perror("Can't start server : Initialize security descriptor");
- unireg_abort(1);
- }
- if (!SetSecurityDescriptorDacl(&sdPipeDescriptor, TRUE, NULL, FALSE))
- {
- sql_perror("Can't start server : Set security descriptor");
- unireg_abort(1);
- }
- saPipeSecurity.nLength = sizeof(SECURITY_ATTRIBUTES);
- saPipeSecurity.lpSecurityDescriptor = &sdPipeDescriptor;
- saPipeSecurity.bInheritHandle = FALSE;
- if ((hPipe= CreateNamedPipe(pipe_name,
- PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
- PIPE_UNLIMITED_INSTANCES,
- (int) global_system_variables.net_buffer_length,
- (int) global_system_variables.net_buffer_length,
- NMPWAIT_USE_DEFAULT_WAIT,
- &saPipeSecurity)) == INVALID_HANDLE_VALUE)
- {
- sql_perror("Create named pipe failed");
- unireg_abort(1);
- }
- }
-#endif
-
#if defined(HAVE_SYS_UN_H)
/*
** Create the UNIX socket
@@ -3005,10 +2854,6 @@ static bool cache_thread(THD *thd)
_db_pop_();
#endif
- /* Clear warnings. */
- if (!thd->get_stmt_da()->is_warning_info_empty())
- thd->get_stmt_da()->clear_warning_info(thd->query_id);
-
set_timespec(abstime, THREAD_CACHE_TIMEOUT);
while (!abort_loop && ! wake_thread && ! kill_cached_threads)
{
@@ -3598,7 +3443,7 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
sql_print_error("Can't create thread to kill server (errno= %d)",
error);
#else
- kill_server((void*) sig); // MIT THREAD has a alarm thread
+ kill_server(sig); // MIT THREAD has a alarm thread
#endif
}
break;
@@ -3714,23 +3559,6 @@ void *my_str_malloc_mysqld(size_t size)
}
-#ifdef __WIN__
-
-pthread_handler_t handle_shutdown(void *arg)
-{
- MSG msg;
- my_thread_init();
-
- /* this call should create the message queue for this thread */
- PeekMessage(&msg, NULL, 1, 65534,PM_NOREMOVE);
-#if !defined(EMBEDDED_LIBRARY)
- if (WaitForSingleObject(hEventShutdown,INFINITE)==WAIT_OBJECT_0)
-#endif /* EMBEDDED_LIBRARY */
- kill_server(MYSQL_KILL_SIGNAL);
- return 0;
-}
-#endif
-
#include <mysqld_default_groups.h>
#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY)
@@ -4090,14 +3918,16 @@ static void my_malloc_size_cb_func(long long size, my_bool is_thread_specific)
{
THD *thd= current_thd;
- if (is_thread_specific) /* If thread specific memory */
- {
- /*
- When thread specfic is set, both mysqld_server_initialized and thd
- must be set
- */
- DBUG_ASSERT(mysqld_server_initialized && thd);
+ /*
+ When thread specific is set, both mysqld_server_initialized and thd
+ must be set, and we check that with DBUG_ASSERT.
+ However, do not crash, if current_thd is NULL, in release version.
+ */
+ DBUG_ASSERT(!is_thread_specific || (mysqld_server_initialized && thd));
+
+ if (is_thread_specific && likely(thd)) /* If thread specific memory */
+ {
DBUG_PRINT("info", ("thd memory_used: %lld size: %lld",
(longlong) thd->status_var.local_memory_used,
size));
@@ -4489,6 +4319,11 @@ static int init_common_variables()
/* MyISAM requires two file handles per table. */
wanted_files= (extra_files + max_connections + extra_max_connections +
tc_size * 2);
+#if defined(HAVE_POOL_OF_THREADS) && !defined(__WIN__)
+ // add epoll or kevent fd for each threadpool group, in case pool of threads is used
+ wanted_files+= (thread_handling > SCHEDULER_NO_THREADS) ? 0 : threadpool_size;
+#endif
+
min_tc_size= MY_MIN(tc_size, TABLE_OPEN_CACHE_MIN);
org_max_connections= max_connections;
org_tc_size= tc_size;
@@ -5628,100 +5463,17 @@ static int init_server_components()
#ifndef EMBEDDED_LIBRARY
-
-static void create_shutdown_thread()
+#ifdef _WIN32
+static void create_shutdown_event()
{
-#ifdef __WIN__
hEventShutdown=CreateEvent(0, FALSE, FALSE, shutdown_event_name);
- pthread_t hThread;
- int error;
- if (unlikely((error= mysql_thread_create(key_thread_handle_shutdown,
- &hThread, &connection_attrib,
- handle_shutdown, 0))))
- sql_print_warning("Can't create thread to handle shutdown requests"
- " (errno= %d)", error);
-
// On "Stop Service" we have to do regular shutdown
Service.SetShutdownEvent(hEventShutdown);
-#endif /* __WIN__ */
}
-
-#endif /* EMBEDDED_LIBRARY */
-
-#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
-static void handle_connections_methods()
-{
- pthread_t hThread;
- int error;
- DBUG_ENTER("handle_connections_methods");
- if (hPipe == INVALID_HANDLE_VALUE &&
- (!have_tcpip || opt_disable_networking) &&
- !opt_enable_shared_memory)
- {
- sql_print_error("TCP/IP, --shared-memory, or --named-pipe should be configured on NT OS");
- unireg_abort(1); // Will not return
- }
-
- mysql_mutex_lock(&LOCK_start_thread);
- mysql_cond_init(key_COND_handler_count, &COND_handler_count, NULL);
- handler_count=0;
- if (hPipe != INVALID_HANDLE_VALUE)
- {
- handler_count++;
- if ((error= mysql_thread_create(key_thread_handle_con_namedpipes,
- &hThread, &connection_attrib,
- handle_connections_namedpipes, 0)))
- {
- sql_print_warning("Can't create thread to handle named pipes"
- " (errno= %d)", error);
- handler_count--;
- }
- }
- if (have_tcpip && !opt_disable_networking)
- {
- handler_count++;
- if ((error= mysql_thread_create(key_thread_handle_con_sockets,
- &hThread, &connection_attrib,
- handle_connections_sockets_thread, 0)))
- {
- sql_print_warning("Can't create thread to handle TCP/IP",
- " (errno= %d)", error);
- handler_count--;
- }
- }
-#ifdef HAVE_SMEM
- if (opt_enable_shared_memory)
- {
- handler_count++;
- if ((error= mysql_thread_create(key_thread_handle_con_sharedmem,
- &hThread, &connection_attrib,
- handle_connections_shared_memory, 0)))
- {
- sql_print_warning("Can't create thread to handle shared memory",
- " (errno= %d)", error);
- handler_count--;
- }
- }
+#else /*_WIN32*/
+#define create_shutdown_event()
#endif
-
- while (handler_count > 0)
- mysql_cond_wait(&COND_handler_count, &LOCK_start_thread);
- mysql_mutex_unlock(&LOCK_start_thread);
- DBUG_VOID_RETURN;
-}
-
-void decrement_handler_count()
-{
- mysql_mutex_lock(&LOCK_start_thread);
- if (--handler_count == 0)
- mysql_cond_signal(&COND_handler_count);
- mysql_mutex_unlock(&LOCK_start_thread);
- my_thread_end();
-}
-#else
-#define decrement_handler_count()
-#endif /* defined(_WIN32) || defined(HAVE_SMEM) */
-
+#endif /* EMBEDDED_LIBRARY */
#ifndef EMBEDDED_LIBRARY
@@ -5769,6 +5521,11 @@ int win_main(int argc, char **argv)
int mysqld_main(int argc, char **argv)
#endif
{
+#ifndef _WIN32
+ /* We can't close stdin just now, because it may be booststrap mode. */
+ bool please_close_stdin= fcntl(STDIN_FILENO, F_GETFD) >= 0;
+#endif
+
/*
Perform basic thread library and malloc initialization,
to be able to read defaults files and parse options.
@@ -6119,7 +5876,7 @@ int mysqld_main(int argc, char **argv)
}
}
- create_shutdown_thread();
+ create_shutdown_event();
start_handle_manager();
/* Copy default global rpl_filter to global_rpl_filter */
@@ -6166,7 +5923,7 @@ int mysqld_main(int argc, char **argv)
#ifndef _WIN32
// try to keep fd=0 busy
- if (!freopen("/dev/null", "r", stdin))
+ if (please_close_stdin && !freopen("/dev/null", "r", stdin))
{
// fall back on failure
fclose(stdin);
@@ -6188,11 +5945,12 @@ int mysqld_main(int argc, char **argv)
/* Memory used when everything is setup */
start_memory_used= global_status_var.global_memory_used;
-#if defined(_WIN32) || defined(HAVE_SMEM)
- handle_connections_methods();
+#ifdef _WIN32
+ handle_connections_win();
+ kill_server(0);
#else
handle_connections_sockets();
-#endif /* _WIN32 || HAVE_SMEM */
+#endif /* _WIN32 */
/* (void) pthread_attr_destroy(&connection_attrib); */
@@ -6601,7 +6359,7 @@ void create_thread_to_handle_connection(CONNECT *connect)
@param[in,out] thd Thread handle of future thread.
*/
-static void create_new_thread(CONNECT *connect)
+void create_new_thread(CONNECT *connect)
{
DBUG_ENTER("create_new_thread");
@@ -6669,18 +6427,107 @@ inline void kill_broken_server()
#ifndef EMBEDDED_LIBRARY
+void handle_accepted_socket(MYSQL_SOCKET new_sock, MYSQL_SOCKET sock)
+{
+ CONNECT *connect;
+ bool is_unix_sock;
+
+#ifdef FD_CLOEXEC
+ (void) fcntl(mysql_socket_getfd(new_sock), F_SETFD, FD_CLOEXEC);
+#endif
+
+#ifdef HAVE_LIBWRAP
+ {
+ if (mysql_socket_getfd(sock) == mysql_socket_getfd(base_ip_sock) ||
+ mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock))
+ {
+ struct request_info req;
+ signal(SIGCHLD, SIG_DFL);
+ request_init(&req, RQ_DAEMON, libwrapName, RQ_FILE,
+ mysql_socket_getfd(new_sock), NULL);
+ my_fromhost(&req);
+ if (!my_hosts_access(&req))
+ {
+ /*
+ This may be stupid but refuse() includes an exit(0)
+ which we surely don't want...
+ clean_exit() - same stupid thing ...
+ */
+ syslog(deny_severity, "refused connect from %s",
+ my_eval_client(&req));
+
+ /*
+ C++ sucks (the gibberish in front just translates the supplied
+ sink function pointer in the req structure from a void (*sink)();
+ to a void(*sink)(int) if you omit the cast, the C++ compiler
+ will cry...
+ */
+ if (req.sink)
+ ((void(*)(int))req.sink)(req.fd);
+
+ (void)mysql_socket_shutdown(new_sock, SHUT_RDWR);
+ (void)mysql_socket_close(new_sock);
+ /*
+ The connection was refused by TCP wrappers.
+ There are no details (by client IP) available to update the
+ host_cache.
+ */
+ statistic_increment(connection_errors_tcpwrap, &LOCK_status);
+ return;
+ }
+ }
+ }
+#endif /* HAVE_LIBWRAP */
+
+ DBUG_PRINT("info", ("Creating CONNECT for new connection"));
+
+ if ((connect= new CONNECT()))
+ {
+ is_unix_sock= (mysql_socket_getfd(sock) ==
+ mysql_socket_getfd(unix_sock));
+
+ if (!(connect->vio=
+ mysql_socket_vio_new(new_sock,
+ is_unix_sock ? VIO_TYPE_SOCKET :
+ VIO_TYPE_TCPIP,
+ is_unix_sock ? VIO_LOCALHOST : 0)))
+ {
+ delete connect;
+ connect= 0; // Error handling below
+ }
+ }
+
+ if (!connect)
+ {
+ /* Connect failure */
+ (void)mysql_socket_close(new_sock);
+ statistic_increment(aborted_connects, &LOCK_status);
+ statistic_increment(connection_errors_internal, &LOCK_status);
+ return;
+ }
+
+ if (is_unix_sock)
+ connect->host= my_localhost;
+
+ if (mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock))
+ {
+ connect->extra_port= 1;
+ connect->scheduler= extra_thread_scheduler;
+ }
+ create_new_thread(connect);
+}
+
+#ifndef _WIN32
void handle_connections_sockets()
{
MYSQL_SOCKET sock= mysql_socket_invalid();
MYSQL_SOCKET new_sock= mysql_socket_invalid();
uint error_count=0;
- CONNECT *connect;
struct sockaddr_storage cAddr;
int ip_flags __attribute__((unused))=0;
int socket_flags __attribute__((unused))= 0;
int extra_ip_flags __attribute__((unused))=0;
int flags=0,retval;
- bool is_unix_sock;
#ifdef HAVE_POLL
int socket_count= 0;
struct pollfd fds[3]; // for ip_sock, unix_sock and extra_ip_sock
@@ -6812,10 +6659,7 @@ void handle_connections_sockets()
}
#endif
}
-#if !defined(NO_FCNTL_NONBLOCK)
- if (!(test_flags & TEST_BLOCKING))
- fcntl(mysql_socket_getfd(sock), F_SETFL, flags);
-#endif
+
if (mysql_socket_getfd(new_sock) == INVALID_SOCKET)
{
/*
@@ -6831,442 +6675,18 @@ void handle_connections_sockets()
sleep(1); // Give other threads some time
continue;
}
-#ifdef FD_CLOEXEC
- (void) fcntl(mysql_socket_getfd(new_sock), F_SETFD, FD_CLOEXEC);
+#if !defined(NO_FCNTL_NONBLOCK)
+ if (!(test_flags & TEST_BLOCKING))
+ fcntl(mysql_socket_getfd(sock), F_SETFL, flags);
#endif
-
-#ifdef HAVE_LIBWRAP
- {
- if (mysql_socket_getfd(sock) == mysql_socket_getfd(base_ip_sock) ||
- mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock))
- {
- struct request_info req;
- signal(SIGCHLD, SIG_DFL);
- request_init(&req, RQ_DAEMON, libwrapName, RQ_FILE,
- mysql_socket_getfd(new_sock), NULL);
- my_fromhost(&req);
- if (!my_hosts_access(&req))
- {
- /*
- This may be stupid but refuse() includes an exit(0)
- which we surely don't want...
- clean_exit() - same stupid thing ...
- */
- syslog(deny_severity, "refused connect from %s",
- my_eval_client(&req));
-
- /*
- C++ sucks (the gibberish in front just translates the supplied
- sink function pointer in the req structure from a void (*sink)();
- to a void(*sink)(int) if you omit the cast, the C++ compiler
- will cry...
- */
- if (req.sink)
- ((void (*)(int))req.sink)(req.fd);
-
- (void) mysql_socket_shutdown(new_sock, SHUT_RDWR);
- (void) mysql_socket_close(new_sock);
- /*
- The connection was refused by TCP wrappers.
- There are no details (by client IP) available to update the
- host_cache.
- */
- statistic_increment(connection_errors_tcpwrap, &LOCK_status);
- continue;
- }
- }
- }
-#endif /* HAVE_LIBWRAP */
-
- DBUG_PRINT("info", ("Creating CONNECT for new connection"));
-
- if ((connect= new CONNECT()))
- {
- is_unix_sock= (mysql_socket_getfd(sock) ==
- mysql_socket_getfd(unix_sock));
-
- if (!(connect->vio=
- mysql_socket_vio_new(new_sock,
- is_unix_sock ? VIO_TYPE_SOCKET :
- VIO_TYPE_TCPIP,
- is_unix_sock ? VIO_LOCALHOST: 0)))
- {
- delete connect;
- connect= 0; // Error handling below
- }
- }
-
- if (!connect)
- {
- /* Connect failure */
- (void) mysql_socket_shutdown(new_sock, SHUT_RDWR);
- (void) mysql_socket_close(new_sock);
- statistic_increment(aborted_connects,&LOCK_status);
- statistic_increment(connection_errors_internal, &LOCK_status);
- continue;
- }
-
- if (is_unix_sock)
- connect->host= my_localhost;
-
- if (mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock))
- {
- connect->extra_port= 1;
- connect->scheduler= extra_thread_scheduler;
- }
- create_new_thread(connect);
+ handle_accepted_socket(new_sock, sock);
}
sd_notify(0, "STOPPING=1\n"
"STATUS=Shutdown in progress\n");
DBUG_VOID_RETURN;
}
-
-#ifdef _WIN32
-pthread_handler_t handle_connections_sockets_thread(void *arg)
-{
- my_thread_init();
- handle_connections_sockets();
- decrement_handler_count();
- return 0;
-}
-
-pthread_handler_t handle_connections_namedpipes(void *arg)
-{
- HANDLE hConnectedPipe;
- OVERLAPPED connectOverlapped= {0};
- my_thread_init();
- DBUG_ENTER("handle_connections_namedpipes");
- connectOverlapped.hEvent= CreateEvent(NULL, TRUE, FALSE, NULL);
- if (!connectOverlapped.hEvent)
- {
- sql_print_error("Can't create event, last error=%u", GetLastError());
- unireg_abort(1);
- }
- DBUG_PRINT("general",("Waiting for named pipe connections."));
- while (!abort_loop)
- {
- /* wait for named pipe connection */
- BOOL fConnected= ConnectNamedPipe(hPipe, &connectOverlapped);
- if (!fConnected && (GetLastError() == ERROR_IO_PENDING))
- {
- /*
- ERROR_IO_PENDING says async IO has started but not yet finished.
- GetOverlappedResult will wait for completion.
- */
- DWORD bytes;
- fConnected= GetOverlappedResult(hPipe, &connectOverlapped,&bytes, TRUE);
- }
- if (abort_loop)
- break;
- if (!fConnected)
- fConnected = GetLastError() == ERROR_PIPE_CONNECTED;
- if (!fConnected)
- {
- CloseHandle(hPipe);
- if ((hPipe= CreateNamedPipe(pipe_name,
- PIPE_ACCESS_DUPLEX |
- FILE_FLAG_OVERLAPPED,
- PIPE_TYPE_BYTE |
- PIPE_READMODE_BYTE |
- PIPE_WAIT,
- PIPE_UNLIMITED_INSTANCES,
- (int) global_system_variables.
- net_buffer_length,
- (int) global_system_variables.
- net_buffer_length,
- NMPWAIT_USE_DEFAULT_WAIT,
- &saPipeSecurity)) ==
- INVALID_HANDLE_VALUE)
- {
- sql_perror("Can't create new named pipe!");
- break; // Abort
- }
- }
- hConnectedPipe = hPipe;
- /* create new pipe for new connection */
- if ((hPipe = CreateNamedPipe(pipe_name,
- PIPE_ACCESS_DUPLEX |
- FILE_FLAG_OVERLAPPED,
- PIPE_TYPE_BYTE |
- PIPE_READMODE_BYTE |
- PIPE_WAIT,
- PIPE_UNLIMITED_INSTANCES,
- (int) global_system_variables.net_buffer_length,
- (int) global_system_variables.net_buffer_length,
- NMPWAIT_USE_DEFAULT_WAIT,
- &saPipeSecurity)) ==
- INVALID_HANDLE_VALUE)
- {
- sql_perror("Can't create new named pipe!");
- hPipe=hConnectedPipe;
- continue; // We have to try again
- }
- CONNECT *connect;
- if (!(connect= new CONNECT) ||
- !(connect->vio= vio_new_win32pipe(hConnectedPipe)))
- {
- DisconnectNamedPipe(hConnectedPipe);
- CloseHandle(hConnectedPipe);
- delete connect;
- statistic_increment(aborted_connects,&LOCK_status);
- statistic_increment(connection_errors_internal, &LOCK_status);
- continue;
- }
- connect->host= my_localhost;
- create_new_thread(connect);
- }
- CloseHandle(connectOverlapped.hEvent);
- DBUG_LEAVE;
- decrement_handler_count();
- return 0;
-}
-#endif /* _WIN32 */
-
-
-#ifdef HAVE_SMEM
-
-/**
- Thread of shared memory's service.
-
- @param arg Arguments of thread
-*/
-pthread_handler_t handle_connections_shared_memory(void *arg)
-{
- /* file-mapping object, use for create shared memory */
- HANDLE handle_connect_file_map= 0;
- char *handle_connect_map= 0; // pointer on shared memory
- HANDLE event_connect_answer= 0;
- ulong smem_buffer_length= shared_memory_buffer_length + 4;
- ulong connect_number= 1;
- char *tmp= NULL;
- char *suffix_pos;
- char connect_number_char[22], *p;
- const char *errmsg= 0;
- SECURITY_ATTRIBUTES *sa_event= 0, *sa_mapping= 0;
- my_thread_init();
- DBUG_ENTER("handle_connections_shared_memorys");
- DBUG_PRINT("general",("Waiting for allocated shared memory."));
-
- /*
- get enough space base-name + '_' + longest suffix we might ever send
- */
- if (!(tmp= (char *)my_malloc(strlen(shared_memory_base_name) + 32L,
- MYF(MY_FAE))))
- goto error;
-
- if (my_security_attr_create(&sa_event, &errmsg,
- GENERIC_ALL, SYNCHRONIZE | EVENT_MODIFY_STATE))
- goto error;
-
- if (my_security_attr_create(&sa_mapping, &errmsg,
- GENERIC_ALL, FILE_MAP_READ | FILE_MAP_WRITE))
- goto error;
-
- /*
- The name of event and file-mapping events create agree next rule:
- shared_memory_base_name+unique_part
- Where:
- shared_memory_base_name is unique value for each server
- unique_part is unique value for each object (events and file-mapping)
- */
- suffix_pos= strxmov(tmp,shared_memory_base_name,"_",NullS);
- strmov(suffix_pos, "CONNECT_REQUEST");
- if ((smem_event_connect_request= CreateEvent(sa_event,
- FALSE, FALSE, tmp)) == 0)
- {
- errmsg= "Could not create request event";
- goto error;
- }
- strmov(suffix_pos, "CONNECT_ANSWER");
- if ((event_connect_answer= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
- {
- errmsg="Could not create answer event";
- goto error;
- }
- strmov(suffix_pos, "CONNECT_DATA");
- if ((handle_connect_file_map=
- CreateFileMapping(INVALID_HANDLE_VALUE, sa_mapping,
- PAGE_READWRITE, 0, sizeof(connect_number), tmp)) == 0)
- {
- errmsg= "Could not create file mapping";
- goto error;
- }
- if ((handle_connect_map= (char *)MapViewOfFile(handle_connect_file_map,
- FILE_MAP_WRITE,0,0,
- sizeof(DWORD))) == 0)
- {
- errmsg= "Could not create shared memory service";
- goto error;
- }
-
- while (!abort_loop)
- {
- /* Wait a request from client */
- WaitForSingleObject(smem_event_connect_request,INFINITE);
-
- /*
- it can be after shutdown command
- */
- if (abort_loop)
- goto error;
-
- HANDLE handle_client_file_map= 0;
- char *handle_client_map= 0;
- HANDLE event_client_wrote= 0;
- HANDLE event_client_read= 0; // for transfer data server <-> client
- HANDLE event_server_wrote= 0;
- HANDLE event_server_read= 0;
- HANDLE event_conn_closed= 0;
- CONNECT *connect= 0;
-
- p= int10_to_str(connect_number, connect_number_char, 10);
- /*
- The name of event and file-mapping events create agree next rule:
- shared_memory_base_name+unique_part+number_of_connection
- Where:
- shared_memory_base_name is uniquel value for each server
- unique_part is unique value for each object (events and file-mapping)
- number_of_connection is connection-number between server and client
- */
- suffix_pos= strxmov(tmp,shared_memory_base_name,"_",connect_number_char,
- "_",NullS);
- strmov(suffix_pos, "DATA");
- if ((handle_client_file_map=
- CreateFileMapping(INVALID_HANDLE_VALUE, sa_mapping,
- PAGE_READWRITE, 0, smem_buffer_length, tmp)) == 0)
- {
- errmsg= "Could not create file mapping";
- goto errorconn;
- }
- if ((handle_client_map= (char*)MapViewOfFile(handle_client_file_map,
- FILE_MAP_WRITE,0,0,
- smem_buffer_length)) == 0)
- {
- errmsg= "Could not create memory map";
- goto errorconn;
- }
- strmov(suffix_pos, "CLIENT_WROTE");
- if ((event_client_wrote= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
- {
- errmsg= "Could not create client write event";
- goto errorconn;
- }
- strmov(suffix_pos, "CLIENT_READ");
- if ((event_client_read= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
- {
- errmsg= "Could not create client read event";
- goto errorconn;
- }
- strmov(suffix_pos, "SERVER_READ");
- if ((event_server_read= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
- {
- errmsg= "Could not create server read event";
- goto errorconn;
- }
- strmov(suffix_pos, "SERVER_WROTE");
- if ((event_server_wrote= CreateEvent(sa_event,
- FALSE, FALSE, tmp)) == 0)
- {
- errmsg= "Could not create server write event";
- goto errorconn;
- }
- strmov(suffix_pos, "CONNECTION_CLOSED");
- if ((event_conn_closed= CreateEvent(sa_event,
- TRUE, FALSE, tmp)) == 0)
- {
- errmsg= "Could not create closed connection event";
- goto errorconn;
- }
- if (abort_loop)
- goto errorconn;
-
- if (!(connect= new CONNECT))
- {
- errmsg= "Could not create CONNECT object";
- goto errorconn;
- }
-
- /* Send number of connection to client */
- int4store(handle_connect_map, connect_number);
- if (!SetEvent(event_connect_answer))
- {
- errmsg= "Could not send answer event";
- goto errorconn;
- }
- /* Set event that client should receive data */
- if (!SetEvent(event_client_read))
- {
- errmsg= "Could not set client to read mode";
- goto errorconn;
- }
- if (!(connect->vio= vio_new_win32shared_memory(handle_client_file_map,
- handle_client_map,
- event_client_wrote,
- event_client_read,
- event_server_wrote,
- event_server_read,
- event_conn_closed)))
- {
- errmsg= "Could not create VIO object";
- goto errorconn;
- }
- connect->host= my_localhost; /* Host is unknown */
- create_new_thread(connect);
- connect_number++;
- continue;
-
-errorconn:
- /* Could not form connection; Free used handlers/memort and retry */
- if (errmsg)
- {
- char buff[180];
- strxmov(buff, "Can't create shared memory connection: ", errmsg, ".",
- NullS);
- sql_perror(buff);
- }
- if (handle_client_file_map)
- CloseHandle(handle_client_file_map);
- if (handle_client_map)
- UnmapViewOfFile(handle_client_map);
- if (event_server_wrote)
- CloseHandle(event_server_wrote);
- if (event_server_read)
- CloseHandle(event_server_read);
- if (event_client_wrote)
- CloseHandle(event_client_wrote);
- if (event_client_read)
- CloseHandle(event_client_read);
- if (event_conn_closed)
- CloseHandle(event_conn_closed);
-
- delete connect;
- statistic_increment(aborted_connects,&LOCK_status);
- statistic_increment(connection_errors_internal, &LOCK_status);
- }
-
- /* End shared memory handling */
-error:
- if (tmp)
- my_free(tmp);
-
- if (errmsg)
- {
- char buff[180];
- strxmov(buff, "Can't create shared memory service: ", errmsg, ".", NullS);
- sql_perror(buff);
- }
- my_security_attr_free(sa_event);
- my_security_attr_free(sa_mapping);
- if (handle_connect_map) UnmapViewOfFile(handle_connect_map);
- if (handle_connect_file_map) CloseHandle(handle_connect_file_map);
- if (event_connect_answer) CloseHandle(event_connect_answer);
- if (smem_event_connect_request) CloseHandle(smem_event_connect_request);
- DBUG_LEAVE;
- decrement_handler_count();
- return 0;
-}
-#endif /* HAVE_SMEM */
+#endif /* _WIN32*/
#endif /* EMBEDDED_LIBRARY */
@@ -8330,7 +7750,7 @@ my_asn1_time_to_string(const ASN1_TIME *time, char *buf, size_t len)
if (bio == NULL)
return NULL;
- if (!ASN1_TIME_print(bio, time))
+ if (!ASN1_TIME_print(bio, const_cast<ASN1_TIME*>(time)))
goto end;
n_read= BIO_read(bio, buf, (int) (len - 1));
@@ -8956,7 +8376,9 @@ static int mysql_init_variables(void)
character_set_filesystem= &my_charset_bin;
opt_specialflag= SPECIAL_ENGLISH;
+#ifndef EMBEDDED_LIBRARY
unix_sock= base_ip_sock= extra_ip_sock= MYSQL_INVALID_SOCKET;
+#endif
mysql_home_ptr= mysql_home;
log_error_file_ptr= log_error_file;
protocol_version= PROTOCOL_VERSION;
@@ -9070,9 +8492,6 @@ static int mysql_init_variables(void)
ssl_acceptor_fd= 0;
#endif /* ! EMBEDDED_LIBRARY */
#endif /* HAVE_OPENSSL */
-#ifdef HAVE_SMEM
- shared_memory_base_name= default_shared_memory_base_name;
-#endif
#if defined(__WIN__)
/* Allow Win32 users to move MySQL anywhere */
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 4a392eaf196..75f35a6df24 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -24,6 +24,7 @@
#include "mysql_com.h" /* SERVER_VERSION_LENGTH */
#include "my_atomic.h"
#include "mysql/psi/mysql_file.h" /* MYSQL_FILE */
+#include "mysql/psi/mysql_socket.h" /* MYSQL_SOCKET */
#include "sql_list.h" /* I_List */
#include "sql_cmd.h"
#include <my_rnd.h>
@@ -92,6 +93,8 @@ void refresh_status(THD *thd);
bool is_secure_file_path(char *path);
void dec_connection_count(scheduler_functions *scheduler);
extern void init_net_server_extension(THD *thd);
+extern void handle_accepted_socket(MYSQL_SOCKET new_sock, MYSQL_SOCKET sock);
+extern void create_new_thread(CONNECT *connect);
extern "C" MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info;
extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *files_charset_info ;
@@ -152,6 +155,7 @@ extern ulong opt_replicate_events_marked_for_skip;
extern char *default_tz_name;
extern Time_zone *default_tz;
extern char *my_bind_addr_str;
+extern int server_socket_ai_family;
extern char *default_storage_engine, *default_tmp_storage_engine;
extern char *enforced_storage_engine;
extern char *gtid_pos_auto_engines;
@@ -169,11 +173,13 @@ extern ulong opt_tc_log_size, tc_log_max_pages_used, tc_log_page_size;
extern ulong tc_log_page_waits;
extern my_bool relay_log_purge, opt_innodb_safe_binlog, opt_innodb;
extern my_bool relay_log_recovery;
-extern uint test_flags,select_errors,ha_open_options;
+extern uint select_errors,ha_open_options;
+extern ulonglong test_flags;
extern uint protocol_version, mysqld_port, dropping_tables;
extern ulong delay_key_write_options;
extern char *opt_logname, *opt_slow_logname, *opt_bin_logname,
*opt_relay_logname;
+extern char *opt_binlog_index_name;
extern char *opt_backup_history_logname, *opt_backup_progress_logname,
*opt_backup_settings_name;
extern const char *log_output_str;
@@ -758,7 +764,7 @@ enum enum_query_type
/* query_id */
extern query_id_t global_query_id;
-ATTRIBUTE_NORETURN void unireg_end(void);
+void unireg_end(void);
/* increment query_id and return it. */
inline __attribute__((warn_unused_result)) query_id_t next_query_id()
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 576ef5009b5..c289fb2bc85 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -110,7 +110,7 @@ void sql_print_error(const char *format,...);
extern, but as it's hard to include sql_priv.h here, we have to
live with this for a while.
*/
-extern uint test_flags;
+extern ulonglong test_flags;
extern ulong bytes_sent, bytes_received, net_big_packet_count;
#ifdef HAVE_QUERY_CACHE
#define USE_QUERY_CACHE
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 9134ad5ab62..b9b74bdd0c4 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -2845,13 +2845,19 @@ bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param,
for (field_ptr= table->field; *field_ptr; field_ptr++)
{
- if (bitmap_is_set(used_fields, (*field_ptr)->field_index))
+ Column_statistics* col_stats= (*field_ptr)->read_stats;
+ if (bitmap_is_set(used_fields, (*field_ptr)->field_index)
+ && col_stats && !col_stats->no_stat_values_provided()
+ && !((*field_ptr)->type() == MYSQL_TYPE_GEOMETRY))
parts++;
}
KEY_PART *key_part;
uint keys= 0;
+ if (!parts)
+ return TRUE;
+
if (!(key_part= (KEY_PART *) alloc_root(param->mem_root,
sizeof(KEY_PART) * parts)))
return TRUE;
@@ -2863,6 +2869,9 @@ bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param,
if (bitmap_is_set(used_fields, (*field_ptr)->field_index))
{
Field *field= *field_ptr;
+ if (field->type() == MYSQL_TYPE_GEOMETRY)
+ continue;
+
uint16 store_length;
uint16 max_key_part_length= (uint16) table->file->max_key_part_length();
key_part->key= keys;
@@ -3020,7 +3029,18 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
table->cond_selectivity= 1.0;
- if (!*cond || table_records == 0)
+ if (table_records == 0)
+ DBUG_RETURN(FALSE);
+
+ QUICK_SELECT_I *quick;
+ if ((quick=table->reginfo.join_tab->quick) &&
+ quick->get_type() == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
+ {
+ table->cond_selectivity*= (quick->records/table_records);
+ DBUG_RETURN(FALSE);
+ }
+
+ if (!*cond)
DBUG_RETURN(FALSE);
if (table->pos_in_table_list->schema_table)
@@ -3137,7 +3157,8 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
*/
if (thd->variables.optimizer_use_condition_selectivity > 2 &&
- !bitmap_is_clear_all(used_fields))
+ !bitmap_is_clear_all(used_fields) &&
+ thd->variables.use_stat_tables > 0)
{
PARAM param;
MEM_ROOT alloc;
@@ -3226,6 +3247,12 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
}
+ if (quick && (quick->get_type() == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
+ quick->get_type() == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE))
+ {
+ table->cond_selectivity*= (quick->records/table_records);
+ }
+
bitmap_union(used_fields, &handled_columns);
/* Check if we can improve selectivity estimates by using sampling */
@@ -7628,9 +7655,8 @@ SEL_TREE *Item_bool_func::get_full_func_mm_tree(RANGE_OPT_PARAM *param,
param->current_table);
#ifdef HAVE_SPATIAL
Field::geometry_type sav_geom_type;
- LINT_INIT_STRUCT(sav_geom_type);
-
- if (field_item->field->type() == MYSQL_TYPE_GEOMETRY)
+ const bool geometry= field_item->field->type() == MYSQL_TYPE_GEOMETRY;
+ if (geometry)
{
sav_geom_type= ((Field_geom*) field_item->field)->geom_type;
/* We have to be able to store all sorts of spatial features here */
@@ -7665,7 +7691,7 @@ SEL_TREE *Item_bool_func::get_full_func_mm_tree(RANGE_OPT_PARAM *param,
}
#ifdef HAVE_SPATIAL
- if (field_item->field->type() == MYSQL_TYPE_GEOMETRY)
+ if (geometry)
{
((Field_geom*) field_item->field)->geom_type= sav_geom_type;
}
@@ -14833,6 +14859,32 @@ void QUICK_GROUP_MIN_MAX_SELECT::add_keys_and_lengths(String *key_names,
}
+/* Check whether the number for equality ranges exceeds the set threshold */
+
+bool eq_ranges_exceeds_limit(RANGE_SEQ_IF *seq, void *seq_init_param,
+ uint limit)
+{
+ KEY_MULTI_RANGE range;
+ range_seq_t seq_it;
+ uint count = 0;
+
+ if (limit == 0)
+ {
+ /* 'Statistics instead of index dives' feature is turned off */
+ return false;
+ }
+ seq_it= seq->init(seq_init_param, 0, 0);
+ while (!seq->next(seq_it, &range))
+ {
+ if ((range.range_flag & EQ_RANGE) && !(range.range_flag & NULL_RANGE))
+ {
+ if (++count >= limit)
+ return true;
+ }
+ }
+ return false;
+}
+
#ifndef DBUG_OFF
static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map,
diff --git a/sql/opt_range.h b/sql/opt_range.h
index bd85a12d4a1..d5416988b88 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -242,7 +242,7 @@ public:
Number of children of this element in the RB-tree, plus 1 for this
element itself.
*/
- uint16 elements;
+ uint32 elements;
/*
Valid only for elements which are RB-tree roots: Number of times this
RB-tree is referred to (it is referred by SEL_ARG::next_key_part or by
@@ -1724,6 +1724,9 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond);
+bool eq_ranges_exceeds_limit(RANGE_SEQ_IF *seq, void *seq_init_param,
+ uint limit);
+
#ifdef WITH_PARTITION_STORAGE_ENGINE
bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond);
#endif
diff --git a/sql/opt_range_mrr.cc b/sql/opt_range_mrr.cc
index 515d94e8748..2981c8182ea 100644
--- a/sql/opt_range_mrr.cc
+++ b/sql/opt_range_mrr.cc
@@ -72,6 +72,7 @@ typedef struct st_sel_arg_range_seq
range_seq_t sel_arg_range_seq_init(void *init_param, uint n_ranges, uint flags)
{
SEL_ARG_RANGE_SEQ *seq= (SEL_ARG_RANGE_SEQ*)init_param;
+ seq->param->range_count=0;
seq->at_start= TRUE;
seq->stack[0].key_tree= NULL;
seq->stack[0].min_key= seq->param->min_key;
@@ -272,25 +273,44 @@ walk_up_n_right:
key_info= NULL;
else
key_info= &seq->param->table->key_info[seq->real_keyno];
-
+
/*
- Conditions below:
- (1) - range analysis is used for estimating condition selectivity
- (2) - This is a unique key, and we have conditions for all its
- user-defined key parts.
- (3) - The table uses extended keys, this key covers all components,
- and we have conditions for all key parts.
+ This is an equality range (keypart_0=X and ... and keypart_n=Z) if
+ (1) - There are no flags indicating open range (e.g.,
+ "keypart_x > y") or GIS.
+ (2) - The lower bound and the upper bound of the range has the
+ same value (min_key == max_key).
*/
- if (!(cur->min_key_flag & ~NULL_RANGE) && !cur->max_key_flag &&
- (!key_info || // (1)
- ((uint)key_tree->part+1 == key_info->user_defined_key_parts && // (2)
- key_info->flags & HA_NOSAME) || // (2)
- ((key_info->flags & HA_EXT_NOSAME) && // (3)
- (uint)key_tree->part+1 == key_info->ext_key_parts) // (3)
- ) &&
- range->start_key.length == range->end_key.length &&
- !memcmp(seq->param->min_key,seq->param->max_key,range->start_key.length))
- range->range_flag= UNIQUE_RANGE | (cur->min_key_flag & NULL_RANGE);
+ const uint is_open_range =
+ (NO_MIN_RANGE | NO_MAX_RANGE | NEAR_MIN | NEAR_MAX | GEOM_FLAG);
+ const bool is_eq_range_pred =
+ !(cur->min_key_flag & is_open_range) && // (1)
+ !(cur->max_key_flag & is_open_range) && // (1)
+ range->start_key.length == range->end_key.length && // (2)
+ !memcmp(seq->param->min_key, seq->param->max_key, // (2)
+ range->start_key.length);
+
+ if (is_eq_range_pred)
+ {
+ range->range_flag = EQ_RANGE;
+
+ /*
+ Conditions below:
+ (1) - Range analysis is used for estimating condition selectivity
+ (2) - This is a unique key, and we have conditions for all its
+ user-defined key parts.
+ (3) - The table uses extended keys, this key covers all components,
+ and we have conditions for all key parts.
+ */
+ if (
+ !key_info || // (1)
+ ((uint)key_tree->part+1 == key_info->user_defined_key_parts && // (2)
+ key_info->flags & HA_NOSAME) || // (2)
+ ((key_info->flags & HA_EXT_NOSAME) && // (3)
+ (uint)key_tree->part+1 == key_info->ext_key_parts) // (3)
+ )
+ range->range_flag |= UNIQUE_RANGE | (cur->min_key_flag & NULL_RANGE);
+ }
if (seq->param->is_ror_scan)
{
diff --git a/sql/opt_split.cc b/sql/opt_split.cc
index 37853bdbbe9..fc3f08464f4 100644
--- a/sql/opt_split.cc
+++ b/sql/opt_split.cc
@@ -267,6 +267,13 @@ void TABLE::deny_splitting()
}
+double TABLE::get_materialization_cost()
+{
+ DBUG_ASSERT(spl_opt_info != NULL);
+ return spl_opt_info->unsplit_cost;
+}
+
+
/* This structure is auxiliary and used only in the function that follows it */
struct SplM_field_ext_info: public SplM_field_info
{
@@ -413,7 +420,8 @@ bool JOIN::check_for_splittable_materialized()
for (cand= cand_start; cand < cand_end; cand++)
{
- if (cand->underlying_field->field_index + 1 == fldnr)
+ if (cand->underlying_field->table == table &&
+ cand->underlying_field->field_index + 1 == fldnr)
{
cand->is_usable_for_ref_access= true;
break;
@@ -887,6 +895,8 @@ SplM_plan_info * JOIN_TAB::choose_best_splitting(double record_count,
continue;
JOIN_TAB *tab= join->map2table[tablenr];
TABLE *table= tab->table;
+ if (keyuse_ext->table != table)
+ continue;
do
{
uint key= keyuse_ext->key;
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 06358b3cc20..c4c30c9b50d 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -441,6 +441,7 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs);
static bool replace_where_subcondition(JOIN *, Item **, Item *, Item *, bool);
static int subq_sj_candidate_cmp(Item_in_subselect* el1, Item_in_subselect* el2,
void *arg);
+static void reset_equality_number_for_subq_conds(Item * cond);
static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred);
static bool convert_subq_to_jtbm(JOIN *parent_join,
Item_in_subselect *subq_pred, bool *remove);
@@ -816,6 +817,9 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
details)
* require that compared columns have exactly the same type. This is
a temporary measure to avoid BUG#36752-type problems.
+
+ JOIN_TAB::keyuse_is_valid_for_access_in_chosen_plan expects that for Semi Join Materialization
+ Scan all the items in the select list of the IN Subquery are of the type Item::FIELD_ITEM.
*/
static
@@ -1430,6 +1434,67 @@ static int subq_sj_candidate_cmp(Item_in_subselect* el1, Item_in_subselect* el2,
}
+/**
+ @brief
+ reset the value of the field in_eqaulity_no for all Item_func_eq
+ items in the where clause of the subquery.
+
+ Look for in_equality_no description in Item_func_eq class
+
+ DESCRIPTION
+ Lets have an example:
+ SELECT t1.a FROM t1 WHERE t1.a IN
+ (SELECT t2.a FROM t2 where t2.b IN
+ (select t3.b from t3 where t3.c=27 ))
+
+ So for such a query we have the parent, child and
+ grandchild select.
+
+ So for the equality t2.b = t3.b we set the value for in_equality_no to
+ 0 according to its description. Wewe do the same for t1.a = t2.a.
+ But when we look at the child select (with the grandchild select merged),
+ the query would be
+
+ SELECT t1.a FROM t1 WHERE t1.a IN
+ (SELECT t2.a FROM t2 where t2.b = t3.b and t3.c=27)
+
+ and then when the child select is merged into the parent select the query
+ would look like
+
+ SELECT t1.a FROM t1, semi-join-nest(t2,t3)
+ WHERE t1.a =t2.a and t2.b = t3.b and t3.c=27
+
+ Still we would have in_equality_no set for t2.b = t3.b
+ though it does not take part in the semi-join equality for the parent select,
+ so we should reset its value to UINT_MAX.
+
+ @param cond WHERE clause of the subquery
+*/
+
+static void reset_equality_number_for_subq_conds(Item * cond)
+{
+ if (!cond)
+ return;
+ if (cond->type() == Item::COND_ITEM)
+ {
+ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ Item *item;
+ while ((item=li++))
+ {
+ if (item->type() == Item::FUNC_ITEM &&
+ ((Item_func*)item)->functype()== Item_func::EQ_FUNC)
+ ((Item_func_eq*)item)->in_equality_no= UINT_MAX;
+ }
+ }
+ else
+ {
+ if (cond->type() == Item::FUNC_ITEM &&
+ ((Item_func*)cond)->functype()== Item_func::EQ_FUNC)
+ ((Item_func_eq*)cond)->in_equality_no= UINT_MAX;
+ }
+ return;
+}
+
/*
Convert a subquery predicate into a TABLE_LIST semi-join nest
@@ -1694,6 +1759,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
*/
sj_nest->sj_in_exprs= subq_pred->left_expr->cols();
sj_nest->nested_join->sj_outer_expr_list.empty();
+ reset_equality_number_for_subq_conds(sj_nest->sj_on_expr);
if (subq_pred->left_expr->cols() == 1)
{
@@ -3506,7 +3572,8 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
first= tablenr - sjm->tables + 1;
join->best_positions[first].n_sj_tables= sjm->tables;
join->best_positions[first].sj_strategy= SJ_OPT_MATERIALIZE;
- join->sjm_lookup_tables|= s->table->map;
+ for (uint i= first; i < first+ sjm->tables; i++)
+ join->sjm_lookup_tables |= join->best_positions[i].table->table->map;
}
else if (pos->sj_strategy == SJ_OPT_MATERIALIZE_SCAN)
{
@@ -5445,7 +5512,7 @@ int select_value_catcher::send_data(List<Item> &items)
/**
@brief
- Conjugate conditions after optimize_cond() call
+ Add new conditions after optimize_cond() call
@param thd the thread handle
@param cond the condition where to attach new conditions
@@ -5494,8 +5561,8 @@ Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond,
Item::Context(Item::ANY_SUBST,
((Item_func_equal *)item)->compare_type_handler(),
((Item_func_equal *)item)->compare_collation()),
- ((Item_func *)item)->arguments()[0]->real_item(),
- ((Item_func *)item)->arguments()[1]->real_item(),
+ ((Item_func *)item)->arguments()[0],
+ ((Item_func *)item)->arguments()[1],
&new_cond_equal))
li.remove();
}
@@ -5600,31 +5667,31 @@ Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond,
}
}
+ if (is_mult_eq)
+ {
+ Item_equal *eq_cond= (Item_equal *)cond;
+ eq_cond->upper_levels= 0;
+ eq_cond->merge_into_list(thd, &new_cond_equal.current_level,
+ false, false);
+
+ while ((equality= it++))
+ {
+ if (equality->const_item() && !equality->val_int())
+ is_simplified_cond= true;
+ }
+ (*cond_eq)->copy(new_cond_equal);
+ }
+
if (new_cond_equal.current_level.elements > 0)
{
- if (is_mult_eq)
+ if (new_cond_equal.current_level.elements +
+ new_conds_list.elements == 1)
{
- Item_equal *eq_cond= (Item_equal *)cond;
- eq_cond->upper_levels= 0;
- eq_cond->merge_into_list(thd, &new_cond_equal.current_level,
- false, false);
-
- while ((equality= it++))
- {
- if (equality->const_item() && !equality->val_int())
- is_simplified_cond= true;
- }
-
- if (new_cond_equal.current_level.elements +
- new_conds_list.elements == 1)
- {
- it.rewind();
- equality= it++;
- equality->fixed= 0;
- if (equality->fix_fields(thd, NULL))
- return NULL;
- }
- (*cond_eq)->copy(new_cond_equal);
+ it.rewind();
+ equality= it++;
+ equality->fixed= 0;
+ if (equality->fix_fields(thd, NULL))
+ return NULL;
}
new_conds_list.append((List<Item> *)&new_cond_equal.current_level);
}
diff --git a/sql/partition_info.h b/sql/partition_info.h
index e00a2c44341..a0cde570d03 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -394,12 +394,13 @@ public:
bool has_unique_name(partition_element *element);
bool vers_init_info(THD *thd);
- bool vers_set_interval(Item *item, interval_type int_type, my_time_t start)
+ bool vers_set_interval(THD *thd, Item *item,
+ interval_type int_type, my_time_t start)
{
DBUG_ASSERT(part_type == VERSIONING_PARTITION);
vers_info->interval.type= int_type;
vers_info->interval.start= start;
- return get_interval_value(item, int_type, &vers_info->interval.step) ||
+ return get_interval_value(thd, item, int_type, &vers_info->interval.step) ||
vers_info->interval.step.neg || vers_info->interval.step.second_part ||
!(vers_info->interval.step.year || vers_info->interval.step.month ||
vers_info->interval.step.day || vers_info->interval.step.hour ||
diff --git a/sql/procedure.h b/sql/procedure.h
index 8826b397fb2..050cc3817c0 100644
--- a/sql/procedure.h
+++ b/sql/procedure.h
@@ -69,9 +69,9 @@ public:
DBUG_ASSERT(0); // impossible
return mark_unsupported_function("proc", arg, VCOL_IMPOSSIBLE);
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate);
}
Item* get_copy(THD *thd) { return 0; }
};
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 29004fe24e4..7eee9283989 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -711,7 +711,7 @@ uchar *net_store_data(uchar *to, const uchar *from, size_t length)
uchar *net_store_data(uchar *to,int32 from)
{
- char buff[20];
+ char buff[22];
uint length=(uint) (int10_to_str(from,buff,10)-buff);
to=net_store_length_fast(to,length);
memcpy(to,buff,length);
@@ -1137,7 +1137,7 @@ bool Protocol_text::store_tiny(longlong from)
DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_TINY);
field_pos++;
#endif
- char buff[20];
+ char buff[22];
return net_store_data((uchar*) buff,
(size_t) (int10_to_str((int) from, buff, -10) - buff));
}
@@ -1151,7 +1151,7 @@ bool Protocol_text::store_short(longlong from)
field_types[field_pos] == MYSQL_TYPE_SHORT);
field_pos++;
#endif
- char buff[20];
+ char buff[22];
return net_store_data((uchar*) buff,
(size_t) (int10_to_str((int) from, buff, -10) -
buff));
@@ -1166,7 +1166,7 @@ bool Protocol_text::store_long(longlong from)
field_types[field_pos] == MYSQL_TYPE_LONG);
field_pos++;
#endif
- char buff[20];
+ char buff[22];
return net_store_data((uchar*) buff,
(size_t) (int10_to_str((long int)from, buff,
(from <0)?-10:10)-buff));
diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc
index ad885c925d9..322b84130f2 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -79,7 +79,7 @@ rpl_slave_state::record_and_update_gtid(THD *thd, rpl_group_info *rgi)
rgi->gtid_pending= false;
if (rgi->gtid_ignore_duplicate_state!=rpl_group_info::GTID_DUPLICATE_IGNORE)
{
- if (record_gtid(thd, &rgi->current_gtid, sub_id, false, false, &hton))
+ if (record_gtid(thd, &rgi->current_gtid, sub_id, NULL, false, &hton))
DBUG_RETURN(1);
update_state_hash(sub_id, &rgi->current_gtid, hton, rgi);
}
@@ -331,6 +331,10 @@ rpl_slave_state::update(uint32 domain_id, uint32 server_id, uint64 sub_id,
}
}
rgi->gtid_ignore_duplicate_state= rpl_group_info::GTID_DUPLICATE_NULL;
+
+#ifdef HAVE_REPLICATION
+ rgi->pending_gtid_deletes_clear();
+#endif
}
if (!(list_elem= (list_element *)my_malloc(sizeof(*list_elem), MYF(MY_WME))))
@@ -381,15 +385,24 @@ int
rpl_slave_state::put_back_list(uint32 domain_id, list_element *list)
{
element *e;
+ int err= 0;
+
+ mysql_mutex_lock(&LOCK_slave_state);
if (!(e= (element *)my_hash_search(&hash, (const uchar *)&domain_id, 0)))
- return 1;
+ {
+ err= 1;
+ goto end;
+ }
while (list)
{
list_element *next= list->next;
e->add(list);
list= next;
}
- return 0;
+
+end:
+ mysql_mutex_unlock(&LOCK_slave_state);
+ return err;
}
@@ -403,6 +416,8 @@ rpl_slave_state::truncate_state_table(THD *thd)
tlist.init_one_table(&MYSQL_SCHEMA_NAME, &rpl_gtid_slave_state_table_name, NULL, TL_WRITE);
if (!(err= open_and_lock_tables(thd, &tlist, FALSE, 0)))
{
+ tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED, "mysql",
+ rpl_gtid_slave_state_table_name.str, false);
err= tlist.table->file->ha_truncate();
if (err)
@@ -557,12 +572,12 @@ rpl_slave_state::select_gtid_pos_table(THD *thd, LEX_CSTRING *out_tablename)
/*
Write a gtid to the replication slave state table.
- Do it as part of the transaction, to get slave crash safety, or as a separate
- transaction if !in_transaction (eg. MyISAM or DDL).
-
gtid The global transaction id for this event group.
sub_id Value allocated within the sub_id when the event group was
read (sub_id must be consistent with commit order in master binlog).
+ rgi rpl_group_info context, if we are recording the gtid transactionally
+ as part of replicating a transactional event. NULL if called from
+ outside of a replicated transaction.
Note that caller must later ensure that the new gtid and sub_id is inserted
into the appropriate HASH element with rpl_slave_state.add(), so that it can
@@ -570,7 +585,7 @@ rpl_slave_state::select_gtid_pos_table(THD *thd, LEX_CSTRING *out_tablename)
*/
int
rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
- bool in_transaction, bool in_statement,
+ rpl_group_info *rgi, bool in_statement,
void **out_hton)
{
TABLE_LIST tlist;
@@ -669,7 +684,7 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
thd->wsrep_ignore_table= true;
#endif
- if (!in_transaction)
+ if (!rgi)
{
DBUG_PRINT("info", ("resetting OPTION_BEGIN"));
thd->variables.option_bits&=
@@ -774,7 +789,8 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
table->file->print_error(err, MYF(0));
goto end;
}
- while (delete_list)
+ cur = delete_list;
+ while (cur)
{
uchar key_buffer[4+8];
@@ -784,9 +800,9 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
/* `break' does not work inside DBUG_EXECUTE_IF */
goto dbug_break; });
- next= delete_list->next;
+ next= cur->next;
- table->field[1]->store(delete_list->sub_id, true);
+ table->field[1]->store(cur->sub_id, true);
/* domain_id is already set in table->record[0] from write_row() above. */
key_copy(key_buffer, table->record[0], &table->key_info[0], 0, false);
if (table->file->ha_index_read_map(table->record[1], key_buffer,
@@ -800,8 +816,7 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
not want to endlessly error on the same element in case of table
corruption or such.
*/
- my_free(delete_list);
- delete_list= next;
+ cur= next;
if (err)
break;
}
@@ -824,18 +839,35 @@ end:
*/
if (delete_list)
{
- mysql_mutex_lock(&LOCK_slave_state);
put_back_list(gtid->domain_id, delete_list);
- mysql_mutex_unlock(&LOCK_slave_state);
+ delete_list = 0;
}
ha_rollback_trans(thd, FALSE);
}
close_thread_tables(thd);
- if (in_transaction)
+ if (rgi)
+ {
thd->mdl_context.release_statement_locks();
+ /*
+ Save the list of old gtid entries we deleted. If this transaction
+ fails later for some reason and is rolled back, the deletion of those
+ entries will be rolled back as well, and we will need to put them back
+ on the to-be-deleted list so we can re-do the deletion. Otherwise
+ redundant rows in mysql.gtid_slave_pos may accumulate if transactions
+ are rolled back and retried after record_gtid().
+ */
+#ifdef HAVE_REPLICATION
+ rgi->pending_gtid_deletes_save(gtid->domain_id, delete_list);
+#endif
+ }
else
+ {
thd->mdl_context.release_transactional_locks();
+#ifdef HAVE_REPLICATION
+ rpl_group_info::pending_gtid_deletes_free(delete_list);
+#endif
+ }
}
thd->lex->restore_backup_query_tables_list(&lex_backup);
thd->variables.option_bits= thd_saved_option;
@@ -1219,7 +1251,7 @@ rpl_slave_state::load(THD *thd, const char *state_from_master, size_t len,
if (gtid_parser_helper(&state_from_master, end, &gtid) ||
!(sub_id= next_sub_id(gtid.domain_id)) ||
- record_gtid(thd, &gtid, sub_id, false, in_statement, &hton) ||
+ record_gtid(thd, &gtid, sub_id, NULL, in_statement, &hton) ||
update(gtid.domain_id, gtid.server_id, sub_id, gtid.seq_no, hton, NULL))
return 1;
if (state_from_master == end)
@@ -2022,10 +2054,10 @@ rpl_binlog_state::drop_domain(DYNAMIC_ARRAY *ids,
for (ulong i= 0; i < ids->elements; i++)
{
rpl_binlog_state::element *elem= NULL;
- ulong *ptr_domain_id;
+ uint32 *ptr_domain_id;
bool not_match;
- ptr_domain_id= (ulong*) dynamic_array_ptr(ids, i);
+ ptr_domain_id= (uint32*) dynamic_array_ptr(ids, i);
elem= (rpl_binlog_state::element *)
my_hash_search(&hash, (const uchar *) ptr_domain_id, 0);
if (!elem)
@@ -2046,7 +2078,7 @@ rpl_binlog_state::drop_domain(DYNAMIC_ARRAY *ids,
if (not_match)
{
- sprintf(errbuf, "binlog files may contain gtids from the domain ('%lu') "
+ sprintf(errbuf, "binlog files may contain gtids from the domain ('%u') "
"being deleted. Make sure to first purge those files",
*ptr_domain_id);
errmsg= errbuf;
diff --git a/sql/rpl_gtid.h b/sql/rpl_gtid.h
index 604289acd6b..0fc92d5e33c 100644
--- a/sql/rpl_gtid.h
+++ b/sql/rpl_gtid.h
@@ -233,7 +233,7 @@ struct rpl_slave_state
int truncate_state_table(THD *thd);
void select_gtid_pos_table(THD *thd, LEX_CSTRING *out_tablename);
int record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
- bool in_transaction, bool in_statement, void **out_hton);
+ rpl_group_info *rgi, bool in_statement, void **out_hton);
uint64 next_sub_id(uint32 domain_id);
int iterate(int (*cb)(rpl_gtid *, void *), void *data,
rpl_gtid *extra_gtids, uint32 num_extra,
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc
index a12bbba5a1f..144b12a9fdf 100644
--- a/sql/rpl_parallel.cc
+++ b/sql/rpl_parallel.cc
@@ -1657,21 +1657,31 @@ int rpl_parallel_resize_pool_if_no_slaves(void)
/**
- Resize pool if not active or busy (in which case we may be in
- resize to 0
+ Pool activation is preceeded by taking a "lock" of pool_mark_busy
+ which guarantees the number of running slaves drops to zero atomicly
+ with the number of pool workers.
+ This resolves race between the function caller thread and one
+ that may be attempting to deactivate the pool.
*/
-
int
rpl_parallel_activate_pool(rpl_parallel_thread_pool *pool)
{
- bool resize;
- mysql_mutex_lock(&pool->LOCK_rpl_thread_pool);
- resize= !pool->count || pool->busy;
- mysql_mutex_unlock(&pool->LOCK_rpl_thread_pool);
- if (resize)
- return rpl_parallel_change_thread_count(pool, opt_slave_parallel_threads,
- 0);
- return 0;
+ int rc= 0;
+
+ if ((rc= pool_mark_busy(pool, current_thd)))
+ return rc; // killed
+
+ if (!pool->count)
+ {
+ pool_mark_not_busy(pool);
+ rc= rpl_parallel_change_thread_count(pool, opt_slave_parallel_threads,
+ 0);
+ }
+ else
+ {
+ pool_mark_not_busy(pool);
+ }
+ return rc;
}
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 9e09a5cf067..b275ad884bd 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -2086,6 +2086,7 @@ rpl_group_info::reinit(Relay_log_info *rli)
long_find_row_note_printed= false;
did_mark_start_commit= false;
gtid_ev_flags2= 0;
+ pending_gtid_delete_list= NULL;
last_master_timestamp = 0;
gtid_ignore_duplicate_state= GTID_DUPLICATE_NULL;
speculation= SPECULATE_NO;
@@ -2216,6 +2217,12 @@ void rpl_group_info::cleanup_context(THD *thd, bool error)
erroneously update the GTID position.
*/
gtid_pending= false;
+
+ /*
+ Rollback will have undone any deletions of old rows we might have made
+ in mysql.gtid_slave_pos. Put those rows back on the list to be deleted.
+ */
+ pending_gtid_deletes_put_back();
}
m_table_map.clear_tables();
slave_close_thread_tables(thd);
@@ -2441,6 +2448,78 @@ rpl_group_info::unmark_start_commit()
}
+/*
+ When record_gtid() has deleted any old rows from the table
+ mysql.gtid_slave_pos as part of a replicated transaction, save the list of
+ rows deleted here.
+
+ If later the transaction fails (eg. optimistic parallel replication), the
+ deletes will be undone when the transaction is rolled back. Then we can
+ put back the list of rows into the rpl_global_gtid_slave_state, so that
+ we can re-do the deletes and avoid accumulating old rows in the table.
+*/
+void
+rpl_group_info::pending_gtid_deletes_save(uint32 domain_id,
+ rpl_slave_state::list_element *list)
+{
+ /*
+ We should never get to a state where we try to save a new pending list of
+ gtid deletes while we still have an old one. But make sure we handle it
+ anyway just in case, so we avoid leaving stray entries in the
+ mysql.gtid_slave_pos table.
+ */
+ DBUG_ASSERT(!pending_gtid_delete_list);
+ if (unlikely(pending_gtid_delete_list))
+ pending_gtid_deletes_put_back();
+
+ pending_gtid_delete_list= list;
+ pending_gtid_delete_list_domain= domain_id;
+}
+
+
+/*
+ Take the list recorded by pending_gtid_deletes_save() and put it back into
+ rpl_global_gtid_slave_state. This is needed if deletion of the rows was
+ rolled back due to transaction failure.
+*/
+void
+rpl_group_info::pending_gtid_deletes_put_back()
+{
+ if (pending_gtid_delete_list)
+ {
+ rpl_global_gtid_slave_state->put_back_list(pending_gtid_delete_list_domain,
+ pending_gtid_delete_list);
+ pending_gtid_delete_list= NULL;
+ }
+}
+
+
+/*
+ Free the list recorded by pending_gtid_deletes_save(). Done when the deletes
+ in the list have been permanently committed.
+*/
+void
+rpl_group_info::pending_gtid_deletes_clear()
+{
+ pending_gtid_deletes_free(pending_gtid_delete_list);
+ pending_gtid_delete_list= NULL;
+}
+
+
+void
+rpl_group_info::pending_gtid_deletes_free(rpl_slave_state::list_element *list)
+{
+ rpl_slave_state::list_element *next;
+
+ while (list)
+ {
+ next= list->next;
+ my_free(list);
+ list= next;
+ }
+}
+
+
rpl_sql_thread_info::rpl_sql_thread_info(Rpl_filter *filter)
: rpl_filter(filter)
{
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index b8b153c34be..d9f0e0e5d3b 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -757,6 +757,11 @@ struct rpl_group_info
/* Needs room for "Gtid D-S-N\x00". */
char gtid_info_buf[5+10+1+10+1+20+1];
+ /* List of not yet committed deletions in mysql.gtid_slave_pos. */
+ rpl_slave_state::list_element *pending_gtid_delete_list;
+ /* Domain associated with pending_gtid_delete_list. */
+ uint32 pending_gtid_delete_list_domain;
+
/*
The timestamp, from the master, of the commit event.
Used to do delayed update of rli->last_master_timestamp, for getting
@@ -898,6 +903,12 @@ struct rpl_group_info
char *gtid_info();
void unmark_start_commit();
+ static void pending_gtid_deletes_free(rpl_slave_state::list_element *list);
+ void pending_gtid_deletes_save(uint32 domain_id,
+ rpl_slave_state::list_element *list);
+ void pending_gtid_deletes_put_back();
+ void pending_gtid_deletes_clear();
+
longlong get_row_stmt_start_timestamp()
{
return row_stmt_start_timestamp;
diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc
index 31035fb5dcc..e170b4772c1 100644
--- a/sql/rpl_utility.cc
+++ b/sql/rpl_utility.cc
@@ -817,14 +817,44 @@ can_convert_field_to(Field *field,
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_YEAR:
- case MYSQL_TYPE_NEWDATE:
case MYSQL_TYPE_NULL:
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_SET:
case MYSQL_TYPE_TIMESTAMP2:
- case MYSQL_TYPE_DATETIME2:
case MYSQL_TYPE_TIME2:
DBUG_RETURN(false);
+ case MYSQL_TYPE_NEWDATE:
+ {
+ if (field->real_type() == MYSQL_TYPE_DATETIME2 ||
+ field->real_type() == MYSQL_TYPE_DATETIME)
+ {
+ *order_var= -1;
+ DBUG_RETURN(is_conversion_ok(*order_var, rli));
+ }
+ else
+ {
+ DBUG_RETURN(false);
+ }
+ }
+ break;
+
+ //case MYSQL_TYPE_DATETIME: TODO: fix MDEV-17394 and uncomment.
+ //
+ //The "old" type does not specify the fraction part size which is required
+ //for correct conversion.
+ case MYSQL_TYPE_DATETIME2:
+ {
+ if (field->real_type() == MYSQL_TYPE_NEWDATE)
+ {
+ *order_var= 1;
+ DBUG_RETURN(is_conversion_ok(*order_var, rli));
+ }
+ else
+ {
+ DBUG_RETURN(false);
+ }
+ }
+ break;
}
DBUG_RETURN(false); // To keep GCC happy
}
diff --git a/sql/semisync_master_ack_receiver.cc b/sql/semisync_master_ack_receiver.cc
index ac17c7de40b..fc36ee35d5d 100644
--- a/sql/semisync_master_ack_receiver.cc
+++ b/sql/semisync_master_ack_receiver.cc
@@ -43,8 +43,7 @@ Ack_receiver::Ack_receiver()
DBUG_ENTER("Ack_receiver::Ack_receiver");
m_status= ST_DOWN;
- mysql_mutex_init(key_LOCK_ack_receiver, &m_mutex,
- MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_ack_receiver, &m_mutex, NULL);
mysql_cond_init(key_COND_ack_receiver, &m_cond, NULL);
m_pid= 0;
diff --git a/sql/semisync_slave.cc b/sql/semisync_slave.cc
index 86d0176dac1..df8baf045ac 100644
--- a/sql/semisync_slave.cc
+++ b/sql/semisync_slave.cc
@@ -144,8 +144,7 @@ void Repl_semi_sync_slave::kill_connection(MYSQL *mysql)
{
sql_print_information("cannot connect to master to kill slave io_thread's "
"connection");
- if (!ret)
- mysql_close(kill_mysql);
+ mysql_close(kill_mysql);
return;
}
size_t kill_buffer_length = my_snprintf(kill_buffer, 30, "KILL %lu",
diff --git a/sql/share/CMakeLists.txt b/sql/share/CMakeLists.txt
index 1461c57c5c3..2980e6153f5 100644
--- a/sql/share/CMakeLists.txt
+++ b/sql/share/CMakeLists.txt
@@ -45,12 +45,14 @@ SET(files
errmsg-utf8.txt
)
-FOREACH (dir ${dirs})
- INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${dir}
- DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT Server)
-ENDFOREACH()
INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/charsets DESTINATION ${INSTALL_MYSQLSHAREDIR}
COMPONENT Common PATTERN "languages.html" EXCLUDE
)
-INSTALL(FILES ${files} DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT Server)
+IF (NOT WITHOUT_SERVER)
+ FOREACH (dir ${dirs})
+ INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${dir}
+ DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT Server)
+ ENDFOREACH()
+ INSTALL(FILES ${files} DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT Server)
+ENDIF()
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 77347472521..e73666cfb58 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -6570,7 +6570,7 @@ ER_ACCESS_DENIED_NO_PASSWORD_ERROR 28000
ukr "Доступ заборонено для користувача: '%s'@'%s'"
ER_SET_PASSWORD_AUTH_PLUGIN
- eng "SET PASSWORD has no significance for users authenticating via plugins"
+ eng "SET PASSWORD is ignored for users authenticating via %s plugin"
ER_GRANT_PLUGIN_USER_EXISTS
eng "GRANT with IDENTIFIED WITH is illegal because the user %-.*s already exists"
@@ -7919,3 +7919,5 @@ ER_VERS_QUERY_IN_PARTITION
eng "SYSTEM_TIME partitions in table %`s does not support historical query"
ER_KEY_DOESNT_SUPPORT
eng "%s index %`s does not support this operation"
+ER_ALTER_OPERATION_TABLE_OPTIONS_NEED_REBUILD
+ eng "Changing table options requires the table to be rebuilt"
diff --git a/sql/slave.cc b/sql/slave.cc
index bb1300d36e6..16fa890d86c 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -4304,6 +4304,19 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli,
This is the case for pre-10.0 events without GTID, and for handling
slave_skip_counter.
*/
+ if (!(ev->is_artificial_event() || ev->is_relay_log_event() || (ev->when == 0)))
+ {
+ /*
+ Ignore FD's timestamp as it does not reflect the slave execution
+ state but likely to reflect a deep past. Consequently when the first
+ data modification event execution last long all this time
+ Seconds_Behind_Master is zero.
+ */
+ if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
+ rli->last_master_timestamp= ev->when + (time_t) ev->exec_time;
+
+ DBUG_ASSERT(rli->last_master_timestamp >= 0);
+ }
}
if (typ == GTID_EVENT)
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index d00ee3e07ef..052c5ada3a2 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2016, Oracle and/or its affiliates.
+/* Copyright (c) 2000, 2018, Oracle and/or its affiliates.
Copyright (c) 2009, 2018, MariaDB
This program is free software; you can redistribute it and/or modify
@@ -57,6 +57,8 @@
#include "sql_plugin_compat.h"
+#define MAX_SCRAMBLE_LENGTH 1024
+
bool mysql_user_table_is_in_short_password_format= false;
static LEX_CSTRING native_password_plugin_name= {
@@ -85,11 +87,19 @@ LEX_CSTRING current_role= { STRING_WITH_LEN("*current_role") };
LEX_CSTRING current_user_and_current_role= { STRING_WITH_LEN("*current_user_and_current_role") };
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
static plugin_ref old_password_plugin;
-#endif
static plugin_ref native_password_plugin;
+static plugin_ref get_auth_plugin(THD *thd, const LEX_CSTRING &name, bool *locked)
+{
+ if (name.str == native_password_plugin_name.str)
+ return native_password_plugin;
+ else if (name.str == old_password_plugin_name.str)
+ return old_password_plugin;
+ *locked=true;
+ return my_plugin_lock_by_name(thd, &name, MYSQL_AUTHENTICATION_PLUGIN);
+}
+
/* Classes */
struct acl_host_and_ip
@@ -119,13 +129,10 @@ public:
char *db;
};
-class ACL_USER_BASE :public ACL_ACCESS
+class ACL_USER_BASE :public ACL_ACCESS, public Sql_alloc
{
public:
- static void *operator new(size_t size, MEM_ROOT *mem_root)
- { return (void*) alloc_root(mem_root, size); }
- static void operator delete(void *, MEM_ROOT *){}
uchar flags; // field used to store various state information
LEX_CSTRING user;
/* list to hold references to granted roles (ACL_ROLE instances) */
@@ -138,13 +145,12 @@ public:
acl_host_and_ip host;
size_t hostname_length;
USER_RESOURCES user_resource;
- uint8 salt[SCRAMBLE_LENGTH + 1]; // scrambled password in binary form
- uint8 salt_len; // 0 - no password, 4 - 3.20, 8 - 4.0, 20 - 4.1.1
enum SSL_type ssl_type;
const char *ssl_cipher, *x509_issuer, *x509_subject;
LEX_CSTRING plugin;
LEX_CSTRING auth_string;
LEX_CSTRING default_rolename;
+ LEX_CSTRING salt;
ACL_USER *copy(MEM_ROOT *root)
{
@@ -152,8 +158,7 @@ public:
if (!dst)
return 0;
*dst= *this;
- dst->user.str= safe_strdup_root(root, user.str);
- dst->user.length= user.length;
+ dst->user= safe_lexcstrdup_root(root, user);
dst->ssl_cipher= safe_strdup_root(root, ssl_cipher);
dst->x509_issuer= safe_strdup_root(root, x509_issuer);
dst->x509_subject= safe_strdup_root(root, x509_subject);
@@ -161,11 +166,11 @@ public:
plugin.str == old_password_plugin_name.str)
dst->plugin= plugin;
else
- dst->plugin.str= strmake_root(root, plugin.str, plugin.length);
- dst->auth_string.str= safe_strdup_root(root, auth_string.str);
+ dst->plugin= safe_lexcstrdup_root(root, plugin);
+ dst->auth_string= safe_lexcstrdup_root(root, auth_string);
+ dst->salt= safe_lexcstrdup_root(root, salt);
dst->host.hostname= safe_strdup_root(root, host.hostname);
- dst->default_rolename.str= safe_strdup_root(root, default_rolename.str);
- dst->default_rolename.length= default_rolename.length;
+ dst->default_rolename= safe_lexcstrdup_root(root, default_rolename);
bzero(&dst->role_grants, sizeof(role_grants));
return dst;
}
@@ -174,7 +179,7 @@ public:
{
CHARSET_INFO *cs= system_charset_info;
int res;
- res= strcmp(safe_str(user.str), safe_str(user2));
+ res= strcmp(user.str, user2);
if (!res)
res= my_strcasecmp(cs, host.hostname, host2);
return res;
@@ -184,7 +189,7 @@ public:
bool wild_eq(const char *user2, const char *host2, const char *ip2)
{
- if (strcmp(safe_str(user.str), safe_str(user2)))
+ if (strcmp(user.str, user2))
return false;
return compare_hostname(&host, host2, ip2 ? ip2 : host2);
@@ -275,10 +280,9 @@ public:
const char *proxied_host_arg, const char *proxied_user_arg,
bool with_grant_arg)
{
- user= (user_arg && *user_arg) ? user_arg : NULL;
+ user= user_arg;
update_hostname (&host, (host_arg && *host_arg) ? host_arg : NULL);
- proxied_user= (proxied_user_arg && *proxied_user_arg) ?
- proxied_user_arg : NULL;
+ proxied_user= proxied_user_arg;
update_hostname (&proxied_host,
(proxied_host_arg && *proxied_host_arg) ?
proxied_host_arg : NULL);
@@ -291,11 +295,10 @@ public:
bool with_grant_arg)
{
init ((host_arg && *host_arg) ? strdup_root (mem, host_arg) : NULL,
- (user_arg && *user_arg) ? strdup_root (mem, user_arg) : NULL,
+ strdup_root (mem, user_arg),
(proxied_host_arg && *proxied_host_arg) ?
strdup_root (mem, proxied_host_arg) : NULL,
- (proxied_user_arg && *proxied_user_arg) ?
- strdup_root (mem, proxied_user_arg) : NULL,
+ strdup_root (mem, proxied_user_arg),
with_grant_arg);
}
@@ -308,7 +311,7 @@ public:
const char *get_proxied_host() { return proxied_host.hostname; }
void set_user(MEM_ROOT *mem, const char *user_arg)
{
- user= user_arg && *user_arg ? strdup_root(mem, user_arg) : NULL;
+ user= *user_arg ? strdup_root(mem, user_arg) : "";
}
void set_host(MEM_ROOT *mem, const char *host_arg)
{
@@ -323,9 +326,8 @@ public:
{
sql_print_warning("'proxies_priv' entry '%s@%s %s@%s' "
"ignored in --skip-name-resolve mode.",
- safe_str(proxied_user),
- safe_str(proxied_host.hostname),
- safe_str(user),
+ proxied_user,
+ safe_str(proxied_host.hostname), user,
safe_str(host.hostname));
return TRUE;
}
@@ -345,11 +347,10 @@ public:
proxied_user_arg, proxied_user));
DBUG_RETURN(compare_hostname(&host, host_arg, ip_arg) &&
compare_hostname(&proxied_host, host_arg, ip_arg) &&
- (!user ||
+ (!*user ||
(user_arg && !wild_compare(user_arg, user, TRUE))) &&
- (!proxied_user ||
- (proxied_user && !wild_compare(proxied_user_arg,
- proxied_user, TRUE))));
+ (!*proxied_user ||
+ !wild_compare(proxied_user_arg, proxied_user, TRUE)));
}
@@ -381,8 +382,7 @@ public:
bool granted_on(const char *host_arg, const char *user_arg)
{
- return (((!user && (!user_arg || !user_arg[0])) ||
- (user && user_arg && !strcmp(user, user_arg))) &&
+ return (!strcmp(user, user_arg) &&
((!host.hostname && (!host_arg || !host_arg[0])) ||
(host.hostname && host_arg && !strcmp(host.hostname, host_arg))));
}
@@ -391,17 +391,15 @@ public:
void print_grant(String *str)
{
str->append(STRING_WITH_LEN("GRANT PROXY ON '"));
- if (proxied_user)
- str->append(proxied_user, strlen(proxied_user));
+ str->append(proxied_user);
str->append(STRING_WITH_LEN("'@'"));
if (proxied_host.hostname)
str->append(proxied_host.hostname, strlen(proxied_host.hostname));
str->append(STRING_WITH_LEN("' TO '"));
- if (user)
- str->append(user, strlen(user));
+ str->append(user);
str->append(STRING_WITH_LEN("'@'"));
if (host.hostname)
- str->append(host.hostname, strlen(host.hostname));
+ str->append(host.hostname);
str->append(STRING_WITH_LEN("'"));
if (with_grant)
str->append(STRING_WITH_LEN(" WITH GRANT OPTION"));
@@ -622,8 +620,8 @@ static ACL_USER *find_user_wild(const char *host, const char *user, const char *
static ACL_ROLE *find_acl_role(const char *user);
static ROLE_GRANT_PAIR *find_role_grant_pair(const LEX_CSTRING *u, const LEX_CSTRING *h, const LEX_CSTRING *r);
static ACL_USER_BASE *find_acl_user_base(const char *user, const char *host);
-static bool update_user_table(THD *, const User_table &, const char *, const char *, const
- char *, size_t new_password_len);
+static bool update_user_table_password(THD *, const User_table&,
+ const ACL_USER &);
static bool acl_load(THD *thd, const Grant_tables& grant_tables);
static inline void get_grantor(THD *thd, char* grantor);
static bool add_role_user_mapping(const char *uname, const char *hname, const char *rname);
@@ -1306,9 +1304,9 @@ void ACL_PROXY_USER::init(const Proxies_priv_table& proxies_priv_table,
MEM_ROOT *mem)
{
init(get_field(mem, proxies_priv_table.host()),
- get_field(mem, proxies_priv_table.user()),
+ safe_str(get_field(mem, proxies_priv_table.user())),
get_field(mem, proxies_priv_table.proxied_host()),
- get_field(mem, proxies_priv_table.proxied_user()),
+ safe_str(get_field(mem, proxies_priv_table.proxied_user())),
proxies_priv_table.with_grant()->val_int() != 0);
}
@@ -1337,8 +1335,7 @@ ACL_ROLE::ACL_ROLE(ACL_USER *user, MEM_ROOT *root) : counter(0)
access= user->access;
/* set initial role access the same as the table row privileges */
initial_role_access= user->access;
- this->user.str= safe_strdup_root(root, user->user.str);
- this->user.length= user->user.length;
+ this->user= user->user;
bzero(&role_grants, sizeof(role_grants));
bzero(&parent_grantee, sizeof(parent_grantee));
flags= IS_ROLE;
@@ -1388,7 +1385,7 @@ static bool has_validation_plugins()
MariaDB_PASSWORD_VALIDATION_PLUGIN, NULL);
}
-struct validation_data { LEX_CSTRING *user, *password; };
+struct validation_data { const LEX_CSTRING *user, *password; };
static my_bool do_validate(THD *, plugin_ref plugin, void *arg)
{
@@ -1399,13 +1396,13 @@ static my_bool do_validate(THD *, plugin_ref plugin, void *arg)
}
-static bool validate_password(LEX_USER *user, THD *thd)
+static bool validate_password(THD *thd, const LEX_CSTRING &user,
+ const LEX_CSTRING &pwtext, bool has_hash)
{
- if (user->pwtext.length || !user->pwhash.length)
+ if (pwtext.length || !has_hash)
{
- struct validation_data data= { &user->user,
- user->pwtext.str ? &user->pwtext :
- const_cast<LEX_CSTRING *>(&empty_clex_str) };
+ struct validation_data data= { &user,
+ pwtext.str ? &pwtext : &empty_clex_str };
if (plugin_foreach(NULL, do_validate,
MariaDB_PASSWORD_VALIDATION_PLUGIN, &data))
{
@@ -1426,45 +1423,87 @@ static bool validate_password(LEX_USER *user, THD *thd)
}
/**
- Convert scrambled password to binary form, according to scramble type,
- Binary form is stored in user.salt.
-
- @param acl_user The object where to store the salt
- @param password The password hash containing the salt
- @param password_len The length of the password hash
-
- Despite the name of the function it is used when loading ACLs from disk
- to store the password hash in the ACL_USER object.
-*/
+ Fills in ACL_USER::auth_string and ACL_USER::salt fields, as needed
-static void
-set_user_salt(ACL_USER *acl_user, const char *password, size_t password_len)
+ hashes the plain-text password (if provided) to auth_string,
+ converts auth_string to salt.
+
+ Fails if the plain-text password fails validation, if the plugin is
+ not loaded, if the auth_string is invalid.
+
+ Using NULL for a password disables validation
+ (needed for loading from mysql.user table).
+*/
+static int set_user_auth(THD *thd, ACL_USER *acl_user, const LEX_CSTRING *pwtext)
{
- if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH)
+ const char *plugin_name= acl_user->plugin.str;
+ bool unlock_plugin= false;
+ plugin_ref plugin= get_auth_plugin(thd, acl_user->plugin, &unlock_plugin);
+ int res= 1;
+
+ if (!plugin)
{
- get_salt_from_password(acl_user->salt, password);
- acl_user->salt_len= SCRAMBLE_LENGTH;
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_PLUGIN_IS_NOT_LOADED,
+ ER_THD(thd, ER_PLUGIN_IS_NOT_LOADED), plugin_name);
+ return res;
}
- else if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
+
+ acl_user->salt= acl_user->auth_string;
+
+ st_mysql_auth *auth= (st_mysql_auth *) plugin_decl(plugin)->info;
+ if (auth->interface_version >= 0x0202)
{
- get_salt_from_password_323((ulong *) acl_user->salt, password);
- acl_user->salt_len= SCRAMBLE_LENGTH_323;
+ if (pwtext)
+ {
+ if (auth->hash_password &&
+ validate_password(thd, acl_user->user, *pwtext,
+ acl_user->auth_string.length))
+ goto end;
+ if (pwtext->length)
+ {
+ if (auth->hash_password)
+ {
+ char buf[MAX_SCRAMBLE_LENGTH];
+ size_t len= sizeof(buf) - 1;
+ if (auth->hash_password(pwtext->str, pwtext->length, buf, &len))
+ goto end; // OOM?
+ buf[len] = 0;
+ acl_user->auth_string.str= (char*)memdup_root(&acl_memroot, buf, len+1);
+ acl_user->auth_string.length= len;
+ }
+ else
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_SET_PASSWORD_AUTH_PLUGIN,
+ ER_THD(thd, ER_SET_PASSWORD_AUTH_PLUGIN),
+ acl_user->plugin.str);
+ }
+ }
+ }
+
+ if (acl_user->auth_string.length)
+ {
+ if (auth->preprocess_hash)
+ {
+ uchar buf[MAX_SCRAMBLE_LENGTH];
+ size_t len= sizeof(buf);
+ if (auth->preprocess_hash(acl_user->auth_string.str,
+ acl_user->auth_string.length, buf, &len))
+ goto end; // ER_PASSWD_LENGTH?
+ acl_user->salt.str= (char*)memdup_root(&acl_memroot, buf, len);
+ acl_user->salt.length= len;
+ }
+ else
+ acl_user->salt= acl_user->auth_string;
+ }
}
- else
- acl_user->salt_len= 0;
-}
-static const char *fix_plugin_ptr(const char *name)
-{
- if (my_strcasecmp(system_charset_info, name,
- native_password_plugin_name.str) == 0)
- return native_password_plugin_name.str;
- else
- if (my_strcasecmp(system_charset_info, name,
- old_password_plugin_name.str) == 0)
- return old_password_plugin_name.str;
- else
- return name;
+ res= 0;
+end:
+ if (unlock_plugin)
+ plugin_unlock(thd, plugin);
+ return res;
}
/**
@@ -1475,8 +1514,6 @@ static const char *fix_plugin_ptr(const char *name)
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
*/
@@ -1489,98 +1526,6 @@ static bool fix_user_plugin_ptr(ACL_USER *user)
user->plugin= 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;
-}
-
-
-/*
- Validates the password, calculates password hash, transforms
- equivalent LEX_USER representations.
-
- Upon entering this function:
-
- - if user->plugin is specified, user->auth is the plugin auth data.
- - if user->plugin is mysql_native_password or mysql_old_password,
- user->auth is the password hash, and LEX_USER is transformed
- to match the next case (that is, user->plugin is cleared).
- - if user->plugin is NOT specified, built-in auth is assumed, that is
- mysql_native_password or mysql_old_password. In that case,
- user->pwhash is the password hash. And user->pwtext is the original
- plain-text password. Either one can be set or both.
-
- Upon exiting this function:
-
- - user->pwtext is left untouched
- - user->pwhash is the password hash, as the mysql.user.password column
- - user->plugin is the plugin name, as the mysql.user.plugin column
- - user->auth is the plugin auth data, as the mysql.user.authentication_string column
-*/
-static bool fix_lex_user(THD *thd, LEX_USER *user)
-{
- size_t check_length;
-
- DBUG_ASSERT(user->plugin.length || !user->auth.length);
- DBUG_ASSERT(!(user->plugin.length && (user->pwtext.length || user->pwhash.length)));
-
- if (lex_string_eq(&user->plugin, &native_password_plugin_name))
- check_length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
- else
- if (lex_string_eq(&user->plugin, &old_password_plugin_name))
- check_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
- else
- if (user->plugin.length)
- return false; // nothing else to do
- else if (thd->variables.old_passwords == 1 ||
- user->pwhash.length == SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
- check_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
- else
- check_length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
-
- if (user->plugin.length)
- {
- user->pwhash= user->auth;
- user->plugin= empty_clex_str;
- user->auth= empty_clex_str;
- }
-
- if (user->pwhash.length && user->pwhash.length != check_length)
- {
- my_error(ER_PASSWD_LENGTH, MYF(0), (int) check_length);
- return true;
- }
-
- if (user->pwtext.length && !user->pwhash.length)
- {
- size_t scramble_length;
- void (*make_scramble)(char *, const char *, size_t);
-
- if (thd->variables.old_passwords == 1)
- {
- scramble_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
- make_scramble= my_make_scrambled_password_323;
- }
- else
- {
- scramble_length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
- make_scramble= my_make_scrambled_password;
- }
-
- Query_arena *arena, backup;
- arena= thd->activate_stmt_arena_if_needed(&backup);
- char *buff= (char *) thd->alloc(scramble_length + 1);
- if (arena)
- thd->restore_active_arena(arena, &backup);
-
- if (buff == NULL)
- return true;
- make_scramble(buff, user->pwtext.str, user->pwtext.length);
- user->pwhash.str= buff;
- user->pwhash.length= scramble_length;
- }
-
return false;
}
@@ -1661,23 +1606,22 @@ bool acl_init(bool dont_read_acl_tables)
Choose from either native or old password plugins when assigning a password
*/
-static bool set_user_plugin (ACL_USER *user, size_t password_len)
+static LEX_CSTRING &guess_auth_plugin(THD *thd, size_t password_len)
{
- switch (password_len)
- {
- case 0: /* no password */
- case SCRAMBLED_PASSWORD_CHAR_LENGTH:
- user->plugin= native_password_plugin_name;
- return FALSE;
- case SCRAMBLED_PASSWORD_CHAR_LENGTH_323:
- user->plugin= old_password_plugin_name;
- return FALSE;
- default:
- sql_print_warning("Found invalid password for user: '%s@%s'; "
- "Ignoring user", safe_str(user->user.str),
- safe_str(user->host.hostname));
- return TRUE;
- }
+ if (thd->variables.old_passwords == 1 ||
+ password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
+ return old_password_plugin_name;
+ else
+ return native_password_plugin_name;
+}
+
+
+static void push_new_user(const ACL_USER &user)
+{
+ push_dynamic(&acl_users, &user);
+ if (!user.host.hostname ||
+ (user.host.hostname[0] == wild_many && !user.host.hostname[1]))
+ allow_all_hosts=1; // Anyone can connect
}
@@ -1702,7 +1646,6 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
READ_RECORD read_record_info;
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
char tmp_name[SAFE_NAME_LEN+1];
- int password_length;
Sql_mode_save old_mode_save(thd);
DBUG_ENTER("acl_load");
@@ -1775,8 +1718,8 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
USERNAME_CHAR_LENGTH);
if (user_table.password()) // Password column might be missing. (MySQL 5.7.6+)
{
- password_length= user_table.password()->field_length /
- user_table.password()->charset()->mbmaxlen;
+ int password_length= user_table.password()->field_length /
+ user_table.password()->charset()->mbmaxlen;
if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
{
sql_print_error("Fatal error: mysql.user table is damaged or in "
@@ -1826,9 +1769,9 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
bool is_role= FALSE;
bzero(&user, sizeof(user));
update_hostname(&user.host, get_field(&acl_memroot, user_table.host()));
- char *username= get_field(&acl_memroot, user_table.user());
+ char *username= safe_str(get_field(&acl_memroot, user_table.user()));
user.user.str= username;
- user.user.length= safe_strlen(username);
+ user.user.length= strlen(username);
/*
If the user entry is a role, skip password and hostname checks
@@ -1846,186 +1789,189 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
hostname_requires_resolving(user.host.hostname))
{
sql_print_warning("'user' entry '%s@%s' "
- "ignored in --skip-name-resolve mode.",
- safe_str(user.user.str),
+ "ignored in --skip-name-resolve mode.", user.user.str,
safe_str(user.host.hostname));
continue;
}
- char *password= const_cast<char*>("");
if (user_table.password())
- password= get_field(&acl_memroot, user_table.password());
- size_t password_len= safe_strlen(password);
- user.auth_string.str= safe_str(password);
- user.auth_string.length= password_len;
- set_user_salt(&user, password, password_len);
+ {
+ const char *p= safe_str(get_field(&acl_memroot, user_table.password()));
+ user.auth_string.str= p;
+ user.auth_string.length= strlen(p);
+ }
+ else
+ user.auth_string= empty_clex_str;
- if (!is_role && set_user_plugin(&user, password_len))
- continue;
+ user.plugin= guess_auth_plugin(thd, user.auth_string.length);
- {
- user.access= user_table.get_access() & GLOBAL_ACLS;
- /*
- if it is pre 5.0.1 privilege table then map CREATE privilege on
- CREATE VIEW & SHOW VIEW privileges
- */
- if (user_table.num_fields() <= 31 && (user.access & CREATE_ACL))
- user.access|= (CREATE_VIEW_ACL | SHOW_VIEW_ACL);
+ user.access= user_table.get_access() & GLOBAL_ACLS;
+ /*
+ if it is pre 5.0.1 privilege table then map CREATE privilege on
+ CREATE VIEW & SHOW VIEW privileges
+ */
+ if (user_table.num_fields() <= 31 && (user.access & CREATE_ACL))
+ user.access|= (CREATE_VIEW_ACL | SHOW_VIEW_ACL);
- /*
- if it is pre 5.0.2 privilege table then map CREATE/ALTER privilege on
- CREATE PROCEDURE & ALTER PROCEDURE privileges
- */
- if (user_table.num_fields() <= 33 && (user.access & CREATE_ACL))
- user.access|= CREATE_PROC_ACL;
- if (user_table.num_fields() <= 33 && (user.access & ALTER_ACL))
- user.access|= ALTER_PROC_ACL;
+ /*
+ if it is pre 5.0.2 privilege table then map CREATE/ALTER privilege on
+ CREATE PROCEDURE & ALTER PROCEDURE privileges
+ */
+ if (user_table.num_fields() <= 33 && (user.access & CREATE_ACL))
+ user.access|= CREATE_PROC_ACL;
+ if (user_table.num_fields() <= 33 && (user.access & ALTER_ACL))
+ user.access|= ALTER_PROC_ACL;
- /*
- pre 5.0.3 did not have CREATE_USER_ACL
- */
- if (user_table.num_fields() <= 36 && (user.access & GRANT_ACL))
- user.access|= CREATE_USER_ACL;
+ /*
+ pre 5.0.3 did not have CREATE_USER_ACL
+ */
+ if (user_table.num_fields() <= 36 && (user.access & GRANT_ACL))
+ user.access|= CREATE_USER_ACL;
- /*
- if it is pre 5.1.6 privilege table then map CREATE privilege on
- CREATE|ALTER|DROP|EXECUTE EVENT
- */
- if (user_table.num_fields() <= 37 && (user.access & SUPER_ACL))
- user.access|= EVENT_ACL;
+ /*
+ if it is pre 5.1.6 privilege table then map CREATE privilege on
+ CREATE|ALTER|DROP|EXECUTE EVENT
+ */
+ if (user_table.num_fields() <= 37 && (user.access & SUPER_ACL))
+ user.access|= EVENT_ACL;
- /*
- if it is pre 5.1.6 privilege then map TRIGGER privilege on CREATE.
- */
- if (user_table.num_fields() <= 38 && (user.access & SUPER_ACL))
- user.access|= TRIGGER_ACL;
+ /*
+ if it is pre 5.1.6 privilege then map TRIGGER privilege on CREATE.
+ */
+ if (user_table.num_fields() <= 38 && (user.access & SUPER_ACL))
+ user.access|= TRIGGER_ACL;
- if (user_table.num_fields() <= 46 && (user.access & DELETE_ACL))
- user.access|= DELETE_HISTORY_ACL;
+ if (user_table.num_fields() <= 46 && (user.access & DELETE_ACL))
+ user.access|= DELETE_HISTORY_ACL;
- user.sort= get_sort(2, user.host.hostname, user.user.str);
- user.hostname_length= safe_strlen(user.host.hostname);
- user.user_resource.user_conn= 0;
- user.user_resource.max_statement_time= 0.0;
+ user.sort= get_sort(2, user.host.hostname, user.user.str);
+ user.hostname_length= safe_strlen(user.host.hostname);
+ user.user_resource.user_conn= 0;
+ user.user_resource.max_statement_time= 0.0;
- /* Starting from 4.0.2 we have more fields */
- if (user_table.ssl_type())
+ /* Starting from 4.0.2 we have more fields */
+ if (user_table.ssl_type())
+ {
+ char *ssl_type=get_field(thd->mem_root, user_table.ssl_type());
+ if (!ssl_type)
+ user.ssl_type=SSL_TYPE_NONE;
+ else if (!strcmp(ssl_type, "ANY"))
+ user.ssl_type=SSL_TYPE_ANY;
+ else if (!strcmp(ssl_type, "X509"))
+ user.ssl_type=SSL_TYPE_X509;
+ else /* !strcmp(ssl_type, "SPECIFIED") */
+ user.ssl_type=SSL_TYPE_SPECIFIED;
+
+ user.ssl_cipher= get_field(&acl_memroot, user_table.ssl_cipher());
+ user.x509_issuer= get_field(&acl_memroot, user_table.x509_issuer());
+ user.x509_subject= get_field(&acl_memroot, user_table.x509_subject());
+
+ char *ptr = get_field(thd->mem_root, user_table.max_questions());
+ user.user_resource.questions=ptr ? atoi(ptr) : 0;
+ ptr = get_field(thd->mem_root, user_table.max_updates());
+ user.user_resource.updates=ptr ? atoi(ptr) : 0;
+ ptr = get_field(thd->mem_root, user_table.max_connections());
+ user.user_resource.conn_per_hour= ptr ? atoi(ptr) : 0;
+ if (user.user_resource.questions || user.user_resource.updates ||
+ user.user_resource.conn_per_hour)
+ mqh_used=1;
+
+ if (user_table.max_user_connections())
{
- char *ssl_type=get_field(thd->mem_root, user_table.ssl_type());
- if (!ssl_type)
- user.ssl_type=SSL_TYPE_NONE;
- else if (!strcmp(ssl_type, "ANY"))
- user.ssl_type=SSL_TYPE_ANY;
- else if (!strcmp(ssl_type, "X509"))
- user.ssl_type=SSL_TYPE_X509;
- else /* !strcmp(ssl_type, "SPECIFIED") */
- user.ssl_type=SSL_TYPE_SPECIFIED;
-
- user.ssl_cipher= get_field(&acl_memroot, user_table.ssl_cipher());
- user.x509_issuer= get_field(&acl_memroot, user_table.x509_issuer());
- user.x509_subject= get_field(&acl_memroot, user_table.x509_subject());
-
- char *ptr = get_field(thd->mem_root, user_table.max_questions());
- user.user_resource.questions=ptr ? atoi(ptr) : 0;
- ptr = get_field(thd->mem_root, user_table.max_updates());
- user.user_resource.updates=ptr ? atoi(ptr) : 0;
- ptr = get_field(thd->mem_root, user_table.max_connections());
- user.user_resource.conn_per_hour= ptr ? atoi(ptr) : 0;
- if (user.user_resource.questions || user.user_resource.updates ||
- user.user_resource.conn_per_hour)
- mqh_used=1;
-
- if (user_table.max_user_connections())
- {
- /* Starting from 5.0.3 we have max_user_connections field */
- ptr= get_field(thd->mem_root, user_table.max_user_connections());
- user.user_resource.user_conn= ptr ? atoi(ptr) : 0;
- }
+ /* Starting from 5.0.3 we have max_user_connections field */
+ ptr= get_field(thd->mem_root, user_table.max_user_connections());
+ user.user_resource.user_conn= ptr ? atoi(ptr) : 0;
+ }
- if (!is_role && user_table.plugin())
+ if (!is_role && user_table.plugin())
+ {
+ /* We may have plugin & auth_string fields */
+ char *tmpstr= get_field(&acl_memroot, user_table.plugin());
+ if (tmpstr)
{
- /* We may have plugin & auth_String fields */
- char *tmpstr= get_field(&acl_memroot, user_table.plugin());
- if (tmpstr)
+ LEX_CSTRING password= user.auth_string;
+ user.plugin.str= tmpstr;
+ user.plugin.length= strlen(user.plugin.str);
+ user.auth_string.str=
+ safe_str(get_field(&acl_memroot,
+ user_table.authentication_string()));
+ user.auth_string.length= strlen(user.auth_string.str);
+
+ if (password.length)
{
- user.plugin.str= tmpstr;
- user.plugin.length= strlen(user.plugin.str);
- user.auth_string.str=
- safe_str(get_field(&acl_memroot,
- user_table.authentication_string()));
- user.auth_string.length= strlen(user.auth_string.str);
-
- if (user.auth_string.length && password_len)
+ if (user.auth_string.length &&
+ (user.auth_string.length != password.length ||
+ memcmp(user.auth_string.str, password.str, password.length)))
{
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.user.str, safe_str(user.host.hostname));
}
-
- fix_user_plugin_ptr(&user);
+ else
+ user.auth_string= password;
}
- }
- if (user_table.max_statement_time())
- {
- /* Starting from 10.1.1 we can have max_statement_time */
- ptr= get_field(thd->mem_root,
- user_table.max_statement_time());
- user.user_resource.max_statement_time= ptr ? atof(ptr) : 0.0;
+ fix_user_plugin_ptr(&user);
}
}
- else
+
+ if (user_table.max_statement_time())
{
- user.ssl_type=SSL_TYPE_NONE;
+ /* Starting from 10.1.1 we can have max_statement_time */
+ ptr= get_field(thd->mem_root,
+ user_table.max_statement_time());
+ user.user_resource.max_statement_time= ptr ? atof(ptr) : 0.0;
+ }
+ }
+ else
+ {
+ user.ssl_type=SSL_TYPE_NONE;
#ifndef TO_BE_REMOVED
- if (user_table.num_fields() <= 13)
- { // Without grant
- if (user.access & CREATE_ACL)
- user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
- }
- /* Convert old privileges */
- user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL;
- if (user.access & FILE_ACL)
- user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL;
- if (user.access & PROCESS_ACL)
- user.access|= SUPER_ACL | EXECUTE_ACL;
-#endif
+ if (user_table.num_fields() <= 13)
+ { // Without grant
+ if (user.access & CREATE_ACL)
+ user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
}
+ /* Convert old privileges */
+ user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL;
+ if (user.access & FILE_ACL)
+ user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL;
+ if (user.access & PROCESS_ACL)
+ user.access|= SUPER_ACL | EXECUTE_ACL;
+#endif
+ }
- (void) my_init_dynamic_array(&user.role_grants,sizeof(ACL_ROLE *),
- 8, 8, MYF(0));
+ my_init_dynamic_array(&user.role_grants, sizeof(ACL_ROLE *), 0, 8, MYF(0));
- /* check default role, if any */
- if (!is_role && user_table.default_role())
- {
- user.default_rolename.str=
- get_field(&acl_memroot, user_table.default_role());
- user.default_rolename.length= safe_strlen(user.default_rolename.str);
- }
+ /* check default role, if any */
+ if (!is_role && user_table.default_role())
+ {
+ user.default_rolename.str=
+ get_field(&acl_memroot, user_table.default_role());
+ user.default_rolename.length= safe_strlen(user.default_rolename.str);
+ }
- if (is_role)
- {
- DBUG_PRINT("info", ("Found role %s", user.user.str));
- ACL_ROLE *entry= new (&acl_memroot) ACL_ROLE(&user, &acl_memroot);
- entry->role_grants = user.role_grants;
- (void) my_init_dynamic_array(&entry->parent_grantee,
- sizeof(ACL_USER_BASE *), 8, 8, MYF(0));
- my_hash_insert(&acl_roles, (uchar *)entry);
+ if (set_user_auth(thd, &user, NULL))
+ {
+ thd->clear_error(); // the warning is still issued
+ continue;
+ }
- continue;
- }
- else
- {
- DBUG_PRINT("info", ("Found user %s", user.user.str));
- (void) push_dynamic(&acl_users,(uchar*) &user);
- }
- if (!user.host.hostname ||
- (user.host.hostname[0] == wild_many && !user.host.hostname[1]))
- allow_all_hosts=1; // Anyone can connect
+ if (is_role)
+ {
+ DBUG_PRINT("info", ("Found role %s", user.user.str));
+ ACL_ROLE *entry= new (&acl_memroot) ACL_ROLE(&user, &acl_memroot);
+ entry->role_grants = user.role_grants;
+ my_init_dynamic_array(&entry->parent_grantee,
+ sizeof(ACL_USER_BASE *), 0, 8, MYF(0));
+ my_hash_insert(&acl_roles, (uchar *)entry);
+
+ continue;
}
+ DBUG_PRINT("info", ("Found user %s", user.user.str));
+ push_new_user(user);
}
my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
sizeof(ACL_USER),(qsort_cmp) acl_compare);
@@ -2039,7 +1985,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
{
ACL_DB db;
char *db_name;
- db.user=get_field(&acl_memroot, db_table.user());
+ db.user=safe_str(get_field(&acl_memroot, db_table.user()));
const char *hostname= get_field(&acl_memroot, db_table.host());
if (!hostname && find_acl_role(db.user))
hostname= "";
@@ -2054,7 +2000,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
{
sql_print_warning("'db' entry '%s %s@%s' "
"ignored in --skip-name-resolve mode.",
- db.db, safe_str(db.user), safe_str(db.host.hostname));
+ db.db, db.user, safe_str(db.host.hostname));
continue;
}
db.access= db_table.get_access();
@@ -2079,7 +2025,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
"case that has been forced to lowercase because "
"lower_case_table_names is set. It will not be "
"possible to remove this privilege using REVOKE.",
- db.db, safe_str(db.user), safe_str(db.host.hostname));
+ db.db, db.user, safe_str(db.host.hostname));
}
}
db.sort=get_sort(3,db.host.hostname,db.db,db.user);
@@ -2407,7 +2353,7 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host,
DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', db: '%s'",
host, ip, user, db));
- sctx->user= user;
+ sctx->user= *user ? user : NULL;
sctx->host= host;
sctx->ip= ip;
sctx->host_or_ip= host ? host : (safe_str(ip));
@@ -2437,8 +2383,7 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host,
for (i=0 ; i < acl_dbs.elements ; i++)
{
ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*);
- if (!acl_db->user ||
- (user && user[0] && !strcmp(user, acl_db->user)))
+ if (!*acl_db->user || !strcmp(user, acl_db->user))
{
if (compare_hostname(&acl_db->host, host, ip))
{
@@ -2452,8 +2397,7 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host,
}
sctx->master_access= acl_user->access;
- if (acl_user->user.str)
- strmake_buf(sctx->priv_user, user);
+ strmake_buf(sctx->priv_user, user);
if (acl_user->host.hostname)
strmake_buf(sctx->priv_host, acl_user->host.hostname);
@@ -2468,8 +2412,7 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host,
for (i=0 ; i < acl_dbs.elements ; i++)
{
ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*);
- if (!acl_db->user ||
- (user && user[0] && !strcmp(user, acl_db->user)))
+ if (!*acl_db->user || !strcmp(user, acl_db->user))
{
if (compare_hostname(&acl_db->host, "", ""))
{
@@ -2483,8 +2426,7 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host,
}
sctx->master_access= acl_role->access;
- if (acl_role->user.str)
- strmake_buf(sctx->priv_role, user);
+ strmake_buf(sctx->priv_role, user);
}
}
@@ -2607,66 +2549,55 @@ static void acl_update_role(const char *rolename, ulong privileges)
}
-static void acl_update_user(const char *user, const char *host,
- const char *password, size_t password_len,
- enum SSL_type ssl_type,
- const char *ssl_cipher,
- const char *x509_issuer,
- const char *x509_subject,
- USER_RESOURCES *mqh,
- ulong privileges,
- const LEX_CSTRING *plugin,
- const LEX_CSTRING *auth)
+static int acl_user_update(THD *thd, ACL_USER *acl_user, const ACL_USER *from,
+ const LEX_USER &combo, enum SSL_type ssl_type,
+ const char *ssl_cipher, const char *x509_issuer,
+ const char *x509_subject, const USER_RESOURCES *mqh,
+ ulong privileges)
{
- mysql_mutex_assert_owner(&acl_cache->lock);
+ if (from)
+ *acl_user= *from;
+ else
+ {
+ bzero(acl_user, sizeof(*acl_user));
+ acl_user->user= safe_lexcstrdup_root(&acl_memroot, combo.user);
+ update_hostname(&acl_user->host, safe_strdup_root(&acl_memroot, combo.host.str));
+ acl_user->hostname_length= combo.host.length;
+ acl_user->sort= get_sort(2, acl_user->host.hostname, acl_user->user.str);
+ acl_user->plugin= native_password_plugin_name;
+ acl_user->salt= acl_user->auth_string= empty_clex_str;
+ my_init_dynamic_array(&acl_user->role_grants, sizeof(ACL_USER *),
+ 0, 8, MYF(0));
+ }
- for (uint i=0 ; i < acl_users.elements ; i++)
+ if (combo.plugin.length)
{
- ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
- if (acl_user->eq(user, host))
- {
- if (plugin->str[0])
- {
- acl_user->plugin= *plugin;
- 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))
- acl_user->plugin.str= strmake_root(&acl_memroot, plugin->str, plugin->length);
- }
- else
- if (password[0])
- {
- acl_user->auth_string.str= strmake_root(&acl_memroot, password, password_len);
- acl_user->auth_string.length= password_len;
- set_user_salt(acl_user, password, password_len);
- set_user_plugin(acl_user, password_len);
- }
- acl_user->access=privileges;
- if (mqh->specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
- acl_user->user_resource.questions=mqh->questions;
- if (mqh->specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
- acl_user->user_resource.updates=mqh->updates;
- if (mqh->specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
- acl_user->user_resource.conn_per_hour= mqh->conn_per_hour;
- if (mqh->specified_limits & USER_RESOURCES::USER_CONNECTIONS)
- acl_user->user_resource.user_conn= mqh->user_conn;
- if (mqh->specified_limits & USER_RESOURCES::MAX_STATEMENT_TIME)
- acl_user->user_resource.max_statement_time= mqh->max_statement_time;
- if (ssl_type != SSL_TYPE_NOT_SPECIFIED)
- {
- acl_user->ssl_type= ssl_type;
- acl_user->ssl_cipher= (ssl_cipher ? strdup_root(&acl_memroot,ssl_cipher) :
- 0);
- acl_user->x509_issuer= (x509_issuer ? strdup_root(&acl_memroot,x509_issuer) :
- 0);
- acl_user->x509_subject= (x509_subject ?
- strdup_root(&acl_memroot,x509_subject) : 0);
- }
- /* search complete: */
- break;
- }
+ acl_user->plugin= combo.plugin;
+ acl_user->auth_string= safe_lexcstrdup_root(&acl_memroot, combo.auth);
+ if (fix_user_plugin_ptr(acl_user))
+ acl_user->plugin= safe_lexcstrdup_root(&acl_memroot, combo.plugin);
+ if (set_user_auth(thd, acl_user, &combo.pwtext))
+ return 1;
+ }
+ acl_user->access= privileges;
+ if (mqh->specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
+ acl_user->user_resource.questions= mqh->questions;
+ if (mqh->specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
+ acl_user->user_resource.updates= mqh->updates;
+ if (mqh->specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
+ acl_user->user_resource.conn_per_hour= mqh->conn_per_hour;
+ if (mqh->specified_limits & USER_RESOURCES::USER_CONNECTIONS)
+ acl_user->user_resource.user_conn= mqh->user_conn;
+ if (mqh->specified_limits & USER_RESOURCES::MAX_STATEMENT_TIME)
+ acl_user->user_resource.max_statement_time= mqh->max_statement_time;
+ if (ssl_type != SSL_TYPE_NOT_SPECIFIED)
+ {
+ acl_user->ssl_type= ssl_type;
+ acl_user->ssl_cipher= safe_strdup_root(&acl_memroot, ssl_cipher);
+ acl_user->x509_issuer= safe_strdup_root(&acl_memroot,x509_issuer);
+ acl_user->x509_subject= safe_strdup_root(&acl_memroot,x509_subject);
}
+ return 0;
}
@@ -2676,82 +2607,14 @@ static void acl_insert_role(const char *rolename, ulong privileges)
mysql_mutex_assert_owner(&acl_cache->lock);
entry= new (&acl_memroot) ACL_ROLE(rolename, privileges, &acl_memroot);
- (void) my_init_dynamic_array(&entry->parent_grantee,
- sizeof(ACL_USER_BASE *), 8, 8, MYF(0));
- (void) my_init_dynamic_array(&entry->role_grants,sizeof(ACL_ROLE *),
- 8, 8, MYF(0));
+ my_init_dynamic_array(&entry->parent_grantee,
+ sizeof(ACL_USER_BASE *), 0, 8, MYF(0));
+ my_init_dynamic_array(&entry->role_grants, sizeof(ACL_ROLE *), 0, 8, MYF(0));
my_hash_insert(&acl_roles, (uchar *)entry);
}
-static void acl_insert_user(const char *user, const char *host,
- const char *password, size_t password_len,
- enum SSL_type ssl_type,
- const char *ssl_cipher,
- const char *x509_issuer,
- const char *x509_subject,
- USER_RESOURCES *mqh,
- ulong privileges,
- const LEX_CSTRING *plugin,
- const LEX_CSTRING *auth)
-{
- ACL_USER acl_user;
-
- mysql_mutex_assert_owner(&acl_cache->lock);
-
- bzero(&acl_user, sizeof(acl_user));
- acl_user.user.str=*user ? strdup_root(&acl_memroot,user) : 0;
- acl_user.user.length= strlen(user);
- update_hostname(&acl_user.host, safe_strdup_root(&acl_memroot, host));
- if (plugin->str[0])
- {
- acl_user.plugin= *plugin;
- 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))
- acl_user.plugin.str= strmake_root(&acl_memroot, plugin->str, plugin->length);
- }
- else
- {
- acl_user.auth_string.str= strmake_root(&acl_memroot, password, password_len);
- acl_user.auth_string.length= password_len;
- set_user_salt(&acl_user, password, password_len);
- set_user_plugin(&acl_user, password_len);
- }
-
- acl_user.flags= 0;
- acl_user.access=privileges;
- acl_user.user_resource = *mqh;
- acl_user.sort=get_sort(2, acl_user.host.hostname, acl_user.user.str);
- acl_user.hostname_length=(uint) strlen(host);
- acl_user.ssl_type= (ssl_type != SSL_TYPE_NOT_SPECIFIED ?
- ssl_type : SSL_TYPE_NONE);
- acl_user.ssl_cipher= ssl_cipher ? strdup_root(&acl_memroot,ssl_cipher) : 0;
- acl_user.x509_issuer= x509_issuer ? strdup_root(&acl_memroot,x509_issuer) : 0;
- acl_user.x509_subject=x509_subject ? strdup_root(&acl_memroot,x509_subject) : 0;
- (void) my_init_dynamic_array(&acl_user.role_grants, sizeof(ACL_USER *),
- 8, 8, MYF(0));
-
- (void) push_dynamic(&acl_users,(uchar*) &acl_user);
- if (!acl_user.host.hostname ||
- (acl_user.host.hostname[0] == wild_many && !acl_user.host.hostname[1]))
- allow_all_hosts=1; // Anyone can connect /* purecov: tested */
- my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
- sizeof(ACL_USER),(qsort_cmp) acl_compare);
-
- /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
- rebuild_check_host();
-
- /*
- Rebuild every user's role_grants since 'acl_users' has been sorted
- and old pointers to ACL_USER elements are no longer valid
- */
- rebuild_role_grants();
-}
-
-
static bool acl_update_db(const char *user, const char *host, const char *db,
ulong privileges)
{
@@ -2762,13 +2625,10 @@ static bool acl_update_db(const char *user, const char *host, const char *db,
for (uint i=0 ; i < acl_dbs.elements ; i++)
{
ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
- if ((!acl_db->user && !user[0]) ||
- (acl_db->user &&
- !strcmp(user,acl_db->user)))
+ if (!strcmp(user, acl_db->user))
{
if ((!acl_db->host.hostname && !host[0]) ||
- (acl_db->host.hostname &&
- !strcmp(host, acl_db->host.hostname)))
+ (acl_db->host.hostname && !strcmp(host, acl_db->host.hostname)))
{
if ((!acl_db->db && !db[0]) ||
(acl_db->db && !strcmp(db,acl_db->db)))
@@ -2866,7 +2726,7 @@ ulong acl_get(const char *host, const char *ip,
for (i=0 ; i < acl_dbs.elements ; i++)
{
ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
- if (!acl_db->user || !strcmp(user,acl_db->user))
+ if (!*acl_db->user || !strcmp(user, acl_db->user))
{
if (compare_hostname(&acl_db->host,host,ip))
{
@@ -3223,8 +3083,7 @@ bool check_change_password(THD *thd, LEX_USER *user)
{
LEX_USER *real_user= get_current_user(thd, user);
- if (fix_and_copy_user(real_user, user, thd) ||
- validate_password(real_user, thd))
+ if (fix_and_copy_user(real_user, user, thd))
return true;
*user= *real_user;
@@ -3254,8 +3113,8 @@ bool change_password(THD *thd, LEX_USER *user)
const CSET_STRING query_save __attribute__((unused)) = thd->query_string;
DBUG_ENTER("change_password");
DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'",
- user->host.str, user->user.str, user->pwhash.str));
- DBUG_ASSERT(user->host.str != 0); // Ensured by parent
+ user->host.str, user->user.str, user->auth.str));
+ DBUG_ASSERT(user->host.str != 0); // Ensured by caller
/*
This statement will be replicated as a statement, even when using
@@ -3266,19 +3125,8 @@ bool change_password(THD *thd, LEX_USER *user)
*/
save_binlog_format= thd->set_current_stmt_binlog_format_stmt();
- if (mysql_bin_log.is_open() ||
- (WSREP(thd) && !IF_WSREP(thd->wsrep_applier, 0)))
- {
- query_length= sprintf(buff, "SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'",
- safe_str(user->user.str), safe_str(user->host.str),
- safe_str(user->pwhash.str));
- }
-
if (WSREP(thd) && !IF_WSREP(thd->wsrep_applier, 0))
- {
- thd->set_query(buff, query_length, system_charset_info);
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, (char*)"user", NULL);
- }
if ((result= tables.open_and_lock(thd)))
DBUG_RETURN(result != 1);
@@ -3295,25 +3143,21 @@ bool change_password(THD *thd, LEX_USER *user)
goto end;
}
- /* update loaded acl entry: */
if (acl_user->plugin.str == native_password_plugin_name.str ||
acl_user->plugin.str == old_password_plugin_name.str)
{
- acl_user->auth_string.str= strmake_root(&acl_memroot, user->pwhash.str, user->pwhash.length);
- acl_user->auth_string.length= user->pwhash.length;
- set_user_salt(acl_user, user->pwhash.str, user->pwhash.length);
+ /* historical hack of auto-changing the plugin */
+ acl_user->plugin= guess_auth_plugin(thd, user->auth.length);
+ }
- set_user_plugin(acl_user, user->pwhash.length);
+ acl_user->auth_string= safe_lexcstrdup_root(&acl_memroot, user->auth);
+ if (set_user_auth(thd, acl_user, &user->pwtext))
+ {
+ mysql_mutex_unlock(&acl_cache->lock);
+ goto end;
}
- else
- push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_SET_PASSWORD_AUTH_PLUGIN,
- ER_THD(thd, ER_SET_PASSWORD_AUTH_PLUGIN));
- if (update_user_table(thd, tables.user_table(),
- safe_str(acl_user->host.hostname),
- safe_str(acl_user->user.str),
- user->pwhash.str, user->pwhash.length))
+ if (update_user_table_password(thd, tables.user_table(), *acl_user))
{
mysql_mutex_unlock(&acl_cache->lock); /* purecov: deadcode */
goto end;
@@ -3324,6 +3168,8 @@ bool change_password(THD *thd, LEX_USER *user)
result= 0;
if (mysql_bin_log.is_open())
{
+ query_length= sprintf(buff, "SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'",
+ user->user.str, safe_str(user->host.str), acl_user->auth_string.str);
DBUG_ASSERT(query_length);
thd->clear_error();
result= thd->binlog_query(THD::STMT_QUERY_TYPE, buff, query_length,
@@ -3333,7 +3179,7 @@ end:
close_mysql_tables(thd);
#ifdef WITH_WSREP
-error: // this label is used in WSREP_TO_ISOLATION_BEGIN
+wsrep_error_label:
if (WSREP(thd) && !thd->wsrep_applier)
{
WSREP_TO_ISOLATION_END;
@@ -3362,12 +3208,12 @@ int acl_set_default_role(THD *thd, const char *host, const char *user,
ulong query_length= 0;
bool clear_role= FALSE;
char buff[512];
- enum_binlog_format save_binlog_format;
+ enum_binlog_format save_binlog_format= thd->get_current_stmt_binlog_format();
const CSET_STRING query_save __attribute__((unused)) = thd->query_string;
DBUG_ENTER("acl_set_default_role");
DBUG_PRINT("enter",("host: '%s' user: '%s' rolename: '%s'",
- safe_str(user), safe_str(host), safe_str(rolename)));
+ user, safe_str(host), safe_str(rolename)));
if (rolename == current_role.str) {
if (!thd->security_ctx->priv_role[0])
@@ -3387,7 +3233,7 @@ int acl_set_default_role(THD *thd, const char *host, const char *user,
{
query_length=
sprintf(buff,"SET DEFAULT ROLE '%-.120s' FOR '%-.120s'@'%-.120s'",
- safe_str(rolename), safe_str(user), safe_str(host));
+ safe_str(rolename), user, safe_str(host));
}
/*
@@ -3402,6 +3248,7 @@ int acl_set_default_role(THD *thd, const char *host, const char *user,
if (WSREP(thd) && !IF_WSREP(thd->wsrep_applier, 0))
{
thd->set_query(buff, query_length, system_charset_info);
+ // Attention!!! here is implicit goto error;
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, (char*)"user", NULL);
}
@@ -3494,7 +3341,7 @@ int acl_set_default_role(THD *thd, const char *host, const char *user,
}
#ifdef WITH_WSREP
-error: // this label is used in WSREP_TO_ISOLATION_END
+wsrep_error_label:
if (WSREP(thd) && !thd->wsrep_applier)
{
WSREP_TO_ISOLATION_END;
@@ -3555,7 +3402,7 @@ static ACL_USER *find_user_or_anon(const char *host, const char *user, const cha
for (uint i=0; i < acl_users.elements; i++)
{
ACL_USER *acl_user_tmp= dynamic_element(&acl_users, i, ACL_USER*);
- if ((!acl_user_tmp->user.str ||
+ if ((!acl_user_tmp->user.length ||
!strcmp(user, acl_user_tmp->user.str)) &&
compare_hostname(&acl_user_tmp->host, host, ip))
{
@@ -3570,13 +3417,13 @@ static ACL_USER *find_user_or_anon(const char *host, const char *user, const cha
/*
Find first entry that matches the specified user@host pair
*/
-static ACL_USER * find_user_exact(const char *host, const char *user)
+static ACL_USER *find_user_exact(const char *host, const char *user)
{
mysql_mutex_assert_owner(&acl_cache->lock);
for (uint i=0 ; i < acl_users.elements ; i++)
{
- ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
+ ACL_USER *acl_user=dynamic_element(&acl_users, i, ACL_USER*);
if (acl_user->eq(user, host))
return acl_user;
}
@@ -3611,7 +3458,7 @@ static ACL_ROLE *find_acl_role(const char *role)
mysql_mutex_assert_owner(&acl_cache->lock);
ACL_ROLE *r= (ACL_ROLE *)my_hash_search(&acl_roles, (uchar *)role,
- safe_strlen(role));
+ strlen(role));
DBUG_RETURN(r);
}
@@ -3763,53 +3610,24 @@ bool hostname_requires_resolving(const char *hostname)
}
-void set_authentication_plugin_from_password(const User_table& user_table,
- const char* password, size_t password_length)
-{
- if (password_length == SCRAMBLED_PASSWORD_CHAR_LENGTH ||
- password_length == 0)
- {
- user_table.plugin()->store(native_password_plugin_name.str,
- native_password_plugin_name.length,
- system_charset_info);
- }
- else
- {
- DBUG_ASSERT(password_length == SCRAMBLED_PASSWORD_CHAR_LENGTH_323);
- user_table.plugin()->store(old_password_plugin_name.str,
- old_password_plugin_name.length,
- system_charset_info);
- }
- user_table.authentication_string()->store(password,
- password_length,
- system_charset_info);
-}
/**
Update record for user in mysql.user privilege table with new password.
- @param thd THD
- @param table Pointer to TABLE object for open mysql.user table
- @param host Hostname
- @param user Username
- @param new_password New password hash
- @param new_password_len Length of new password hash
-
@see change_password
*/
-static bool update_user_table(THD *thd, const User_table& user_table,
- const char *host, const char *user,
- const char *new_password, size_t new_password_len)
+static bool update_user_table_password(THD *thd, const User_table& user_table,
+ const ACL_USER &user)
{
+ CHARSET_INFO *cs= system_charset_info;
char user_key[MAX_KEY_LENGTH];
int error;
- DBUG_ENTER("update_user_table");
- DBUG_PRINT("enter",("user: %s host: %s",user,host));
+ DBUG_ENTER("update_user_table_password");
TABLE *table= user_table.table();
table->use_all_columns();
- user_table.host()->store(host,(uint) strlen(host), system_charset_info);
- user_table.user()->store(user,(uint) strlen(user), system_charset_info);
+ user_table.host()->store(user.host.hostname, user.hostname_length, cs);
+ user_table.user()->store(user.user.str, user.user.length, cs);
key_copy((uchar *) user_key, table->record[0], table->key_info,
table->key_info->key_length);
@@ -3825,14 +3643,13 @@ static bool update_user_table(THD *thd, const User_table& user_table,
if (user_table.plugin())
{
- set_authentication_plugin_from_password(user_table, new_password,
- new_password_len);
- new_password_len= 0;
+ if (user_table.password())
+ user_table.password()->reset();
+ user_table.plugin()->store(user.plugin.str, user.plugin.length, cs);
+ user_table.authentication_string()->store(user.auth_string.str, user.auth_string.length, cs);
}
-
- if (user_table.password())
- user_table.password()->store(new_password, new_password_len, system_charset_info);
-
+ else
+ user_table.password()->store(user.auth_string.str, user.auth_string.length, cs);
if (unlikely(error= table->file->ha_update_row(table->record[1],
table->record[0])) &&
@@ -3884,7 +3701,7 @@ static bool test_if_create_new_users(THD *thd)
****************************************************************************/
static int replace_user_table(THD *thd, const User_table &user_table,
- LEX_USER &combo,
+ LEX_USER *combo,
ulong rights, bool revoke_grant,
bool can_create_user, bool no_auto_create)
{
@@ -3892,26 +3709,14 @@ static int replace_user_table(THD *thd, const User_table &user_table,
bool old_row_exists=0;
char what= (revoke_grant) ? 'N' : 'Y';
uchar user_key[MAX_KEY_LENGTH];
- bool handle_as_role= combo.is_role();
+ bool handle_as_role= combo->is_role();
LEX *lex= thd->lex;
TABLE *table= user_table.table();
+ ACL_USER new_acl_user, *old_acl_user;
DBUG_ENTER("replace_user_table");
mysql_mutex_assert_owner(&acl_cache->lock);
- if (combo.pwhash.str && combo.pwhash.str[0])
- {
- if (combo.pwhash.length != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
- combo.pwhash.length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
- {
- DBUG_ASSERT(0);
- my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
- DBUG_RETURN(-1);
- }
- }
- else
- combo.pwhash= empty_clex_str;
-
/* if the user table is not up to date, we can't handle role updates */
if (!user_table.is_role() && handle_as_role)
{
@@ -3922,9 +3727,9 @@ static int replace_user_table(THD *thd, const User_table &user_table,
}
table->use_all_columns();
- user_table.host()->store(combo.host.str,combo.host.length,
+ user_table.host()->store(combo->host.str,combo->host.length,
system_charset_info);
- user_table.user()->store(combo.user.str,combo.user.length,
+ user_table.user()->store(combo->user.str,combo->user.length,
system_charset_info);
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
@@ -3936,7 +3741,7 @@ static int replace_user_table(THD *thd, const User_table &user_table,
/* what == 'N' means revoke */
if (what == 'N')
{
- my_error(ER_NONEXISTING_GRANT, MYF(0), combo.user.str, combo.host.str);
+ my_error(ER_NONEXISTING_GRANT, MYF(0), combo->user.str, combo->host.str);
goto end;
}
/*
@@ -3952,7 +3757,8 @@ static int replace_user_table(THD *thd, const User_table &user_table,
see also test_if_create_new_users()
*/
- else if (!combo.pwhash.length && !combo.plugin.length && no_auto_create)
+ else if (!combo->auth.length && !combo->plugin.length &&
+ !combo->pwtext.length && no_auto_create)
{
my_error(ER_PASSWORD_NO_MATCH, MYF(0));
goto end;
@@ -3962,32 +3768,37 @@ static int replace_user_table(THD *thd, const User_table &user_table,
my_error(ER_CANT_CREATE_USER_WITH_GRANT, MYF(0));
goto end;
}
- else if (combo.plugin.str[0])
+ else if (combo->plugin.length)
{
- if (!plugin_is_ready(&combo.plugin, MYSQL_AUTHENTICATION_PLUGIN))
+ if (!plugin_is_ready(&combo->plugin, MYSQL_AUTHENTICATION_PLUGIN))
{
- my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), combo.plugin.str);
+ my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), combo->plugin.str);
goto end;
}
}
+ else /* combo->plugin.length == 0 */
+ {
+ combo->plugin= guess_auth_plugin(thd, combo->auth.length);
+ }
old_row_exists = 0;
restore_record(table,s->default_values);
- user_table.host()->store(combo.host.str,combo.host.length,
+ user_table.host()->store(combo->host.str,combo->host.length,
system_charset_info);
- user_table.user()->store(combo.user.str,combo.user.length,
+ user_table.user()->store(combo->user.str,combo->user.length,
system_charset_info);
}
else
{
old_row_exists = 1;
store_record(table,record[1]); // Save copy for update
+ if (!combo->plugin.length && (combo->auth.length || combo->pwtext.length))
+ {
+ /* GRANT ... IDENTIFIED BY */
+ combo->plugin= guess_auth_plugin(thd, combo->auth.length);
+ }
}
- if (!old_row_exists || combo.pwtext.length || combo.pwhash.length)
- if (!handle_as_role && validate_password(&combo, thd))
- goto end;
-
/* Update table columns with new privileges */
ulong priv;
@@ -4000,122 +3811,112 @@ static int replace_user_table(THD *thd, const User_table &user_table,
rights= user_table.get_access();
- DBUG_PRINT("info",("table fields: %d", user_table.num_fields()));
- /* If we don't have a password column, we'll use the authentication_string
- column later. */
- if (combo.pwhash.str[0] && user_table.password())
- user_table.password()->store(combo.pwhash.str, combo.pwhash.length,
- system_charset_info);
- /* We either have the password column, the plugin column, or both. Otherwise
- we have a corrupt user table. */
- DBUG_ASSERT(user_table.password() || user_table.plugin());
- if (user_table.ssl_type()) /* From 4.0.0 we have more fields */
- {
- /* We write down SSL related ACL stuff */
- switch (lex->ssl_type) {
- case SSL_TYPE_ANY:
- user_table.ssl_type()->store(STRING_WITH_LEN("ANY"),
- &my_charset_latin1);
- user_table.ssl_cipher()->store("", 0, &my_charset_latin1);
- user_table.x509_issuer()->store("", 0, &my_charset_latin1);
- user_table.x509_subject()->store("", 0, &my_charset_latin1);
- break;
- case SSL_TYPE_X509:
- user_table.ssl_type()->store(STRING_WITH_LEN("X509"),
- &my_charset_latin1);
- user_table.ssl_cipher()->store("", 0, &my_charset_latin1);
- user_table.x509_issuer()->store("", 0, &my_charset_latin1);
- user_table.x509_subject()->store("", 0, &my_charset_latin1);
- break;
- case SSL_TYPE_SPECIFIED:
- user_table.ssl_type()->store(STRING_WITH_LEN("SPECIFIED"),
- &my_charset_latin1);
- user_table.ssl_cipher()->store("", 0, &my_charset_latin1);
- user_table.x509_issuer()->store("", 0, &my_charset_latin1);
- user_table.x509_subject()->store("", 0, &my_charset_latin1);
- if (lex->ssl_cipher)
- user_table.ssl_cipher()->store(lex->ssl_cipher,
- strlen(lex->ssl_cipher),
- system_charset_info);
- if (lex->x509_issuer)
- user_table.x509_issuer()->store(lex->x509_issuer,
- strlen(lex->x509_issuer),
- system_charset_info);
- if (lex->x509_subject)
- user_table.x509_subject()->store(lex->x509_subject,
- strlen(lex->x509_subject),
- system_charset_info);
- break;
- case SSL_TYPE_NOT_SPECIFIED:
- break;
- case SSL_TYPE_NONE:
- user_table.ssl_type()->store("", 0, &my_charset_latin1);
- user_table.ssl_cipher()->store("", 0, &my_charset_latin1);
- user_table.x509_issuer()->store("", 0, &my_charset_latin1);
- user_table.x509_subject()->store("", 0, &my_charset_latin1);
- break;
+ if (handle_as_role)
+ {
+ if (old_row_exists && !user_table.check_is_role())
+ {
+ goto end;
+ }
+ user_table.is_role()->store("Y", 1, system_charset_info);
+ }
+ else
+ {
+ old_acl_user= find_user_exact(combo->host.str, combo->user.str);
+ if ((old_acl_user != NULL) != old_row_exists)
+ {
+ my_error(ER_PASSWORD_NO_MATCH, MYF(0));
+ goto end;
}
+ if (acl_user_update(thd, &new_acl_user,
+ old_row_exists ? old_acl_user : NULL,
+ *combo, lex->ssl_type, lex->ssl_cipher,
+ lex->x509_issuer, lex->x509_subject, &lex->mqh,
+ rights))
+ goto end;
- USER_RESOURCES mqh= lex->mqh;
- if (mqh.specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
- user_table.max_questions()->store((longlong) mqh.questions, TRUE);
- if (mqh.specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
- user_table.max_updates()->store((longlong) mqh.updates, TRUE);
- if (mqh.specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
- user_table.max_connections()->store((longlong) mqh.conn_per_hour, TRUE);
- if (user_table.max_user_connections() &&
- (mqh.specified_limits & USER_RESOURCES::USER_CONNECTIONS))
- user_table.max_user_connections()->store((longlong) mqh.user_conn, FALSE);
- if (user_table.plugin())
- {
- user_table.plugin()->set_notnull();
- user_table.authentication_string()->set_notnull();
- if (combo.plugin.str[0])
- {
- DBUG_ASSERT(combo.pwhash.str[0] == 0);
- if (user_table.password())
- user_table.password()->reset();
- user_table.plugin()->store(combo.plugin.str, combo.plugin.length,
- system_charset_info);
- user_table.authentication_string()->store(combo.auth.str, combo.auth.length,
- system_charset_info);
+ DBUG_PRINT("info",("table fields: %d", user_table.num_fields()));
+ /* We either have the password column, the plugin column, or both. Otherwise
+ we have a corrupt user table. */
+ DBUG_ASSERT(user_table.password() || user_table.plugin());
+ if (user_table.ssl_type()) /* From 4.0.0 we have more fields */
+ {
+ /* We write down SSL related ACL stuff */
+ switch (lex->ssl_type) {
+ case SSL_TYPE_ANY:
+ user_table.ssl_type()->store(STRING_WITH_LEN("ANY"),
+ &my_charset_latin1);
+ user_table.ssl_cipher()->store("", 0, &my_charset_latin1);
+ user_table.x509_issuer()->store("", 0, &my_charset_latin1);
+ user_table.x509_subject()->store("", 0, &my_charset_latin1);
+ break;
+ case SSL_TYPE_X509:
+ user_table.ssl_type()->store(STRING_WITH_LEN("X509"),
+ &my_charset_latin1);
+ user_table.ssl_cipher()->store("", 0, &my_charset_latin1);
+ user_table.x509_issuer()->store("", 0, &my_charset_latin1);
+ user_table.x509_subject()->store("", 0, &my_charset_latin1);
+ break;
+ case SSL_TYPE_SPECIFIED:
+ user_table.ssl_type()->store(STRING_WITH_LEN("SPECIFIED"),
+ &my_charset_latin1);
+ user_table.ssl_cipher()->store("", 0, &my_charset_latin1);
+ user_table.x509_issuer()->store("", 0, &my_charset_latin1);
+ user_table.x509_subject()->store("", 0, &my_charset_latin1);
+ if (lex->ssl_cipher)
+ user_table.ssl_cipher()->store(lex->ssl_cipher,
+ strlen(lex->ssl_cipher),
+ system_charset_info);
+ if (lex->x509_issuer)
+ user_table.x509_issuer()->store(lex->x509_issuer,
+ strlen(lex->x509_issuer),
+ system_charset_info);
+ if (lex->x509_subject)
+ user_table.x509_subject()->store(lex->x509_subject,
+ strlen(lex->x509_subject),
+ system_charset_info);
+ break;
+ case SSL_TYPE_NOT_SPECIFIED:
+ break;
+ case SSL_TYPE_NONE:
+ user_table.ssl_type()->store("", 0, &my_charset_latin1);
+ user_table.ssl_cipher()->store("", 0, &my_charset_latin1);
+ user_table.x509_issuer()->store("", 0, &my_charset_latin1);
+ user_table.x509_subject()->store("", 0, &my_charset_latin1);
+ break;
}
- if (combo.pwhash.str[0])
+
+ USER_RESOURCES mqh= lex->mqh;
+ if (mqh.specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
+ user_table.max_questions()->store((longlong) mqh.questions, TRUE);
+ if (mqh.specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
+ user_table.max_updates()->store((longlong) mqh.updates, TRUE);
+ if (mqh.specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
+ user_table.max_connections()->store((longlong) mqh.conn_per_hour, TRUE);
+ if (user_table.max_user_connections() &&
+ (mqh.specified_limits & USER_RESOURCES::USER_CONNECTIONS))
+ user_table.max_user_connections()->store((longlong) mqh.user_conn, FALSE);
+ if (user_table.plugin())
{
- DBUG_ASSERT(combo.plugin.str[0] == 0);
- /* We have Password column. */
- if (user_table.password())
+ user_table.plugin()->set_notnull();
+ user_table.authentication_string()->set_notnull();
+ if (new_acl_user.plugin.length)
{
- user_table.plugin()->reset();
- user_table.authentication_string()->reset();
+ if (user_table.password())
+ user_table.password()->reset();
+ user_table.plugin()->store(new_acl_user.plugin.str,
+ new_acl_user.plugin.length, system_charset_info);
+ user_table.authentication_string()->store(new_acl_user.auth_string.str,
+ new_acl_user.auth_string.length, system_charset_info);
}
- else
+
+ if (user_table.max_statement_time())
{
- /* We do not have Password column. Use PLUGIN && Authentication_string
- columns instead. */
- set_authentication_plugin_from_password(user_table,
- combo.pwhash.str,
- combo.pwhash.length);
+ if (mqh.specified_limits & USER_RESOURCES::MAX_STATEMENT_TIME)
+ user_table.max_statement_time()->store(mqh.max_statement_time);
}
}
-
- if (user_table.max_statement_time())
- {
- if (mqh.specified_limits & USER_RESOURCES::MAX_STATEMENT_TIME)
- user_table.max_statement_time()->store(mqh.max_statement_time);
- }
- }
- mqh_used= (mqh_used || mqh.questions || mqh.updates || mqh.conn_per_hour ||
- mqh.user_conn || mqh.max_statement_time != 0.0);
-
- /* table format checked earlier */
- if (handle_as_role)
- {
- if (old_row_exists && !user_table.check_is_role())
- {
- goto end;
- }
- user_table.is_role()->store("Y", 1, system_charset_info);
+ mqh_used= (mqh_used || mqh.questions || mqh.updates || mqh.conn_per_hour ||
+ mqh.user_conn || mqh.max_statement_time != 0.0);
}
}
@@ -4155,37 +3956,32 @@ end:
if (likely(!error))
{
acl_cache->clear(1); // Clear privilege cache
- if (old_row_exists)
+ if (handle_as_role)
{
- if (handle_as_role)
- acl_update_role(combo.user.str, rights);
+ if (old_row_exists)
+ acl_update_role(combo->user.str, rights);
else
- acl_update_user(combo.user.str, combo.host.str,
- combo.pwhash.str, combo.pwhash.length,
- lex->ssl_type,
- lex->ssl_cipher,
- lex->x509_issuer,
- lex->x509_subject,
- &lex->mqh,
- rights,
- &combo.plugin,
- &combo.auth);
+ acl_insert_role(combo->user.str, rights);
}
else
{
- if (handle_as_role)
- acl_insert_role(combo.user.str, rights);
+ if (old_acl_user)
+ *old_acl_user= new_acl_user;
else
- acl_insert_user(combo.user.str, combo.host.str,
- combo.pwhash.str, combo.pwhash.length,
- lex->ssl_type,
- lex->ssl_cipher,
- lex->x509_issuer,
- lex->x509_subject,
- &lex->mqh,
- rights,
- &combo.plugin,
- &combo.auth);
+ {
+ push_new_user(new_acl_user);
+ my_qsort(dynamic_element(&acl_users, 0, ACL_USER*), acl_users.elements,
+ sizeof(ACL_USER),(qsort_cmp) acl_compare);
+
+ /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
+ rebuild_check_host();
+
+ /*
+ Rebuild every user's role_grants since 'acl_users' has been sorted
+ and old pointers to ACL_USER elements are no longer valid
+ */
+ rebuild_role_grants();
+ }
}
}
DBUG_RETURN(error);
@@ -6288,7 +6084,7 @@ static bool merge_one_role_privileges(ACL_ROLE *grantee)
static bool has_auth(LEX_USER *user, LEX *lex)
{
- return user->pwtext.length || user->pwhash.length || user->plugin.length || user->auth.length ||
+ return user->pwtext.length || user->plugin.length || user->auth.length ||
lex->ssl_type != SSL_TYPE_NOT_SPECIFIED || lex->ssl_cipher ||
lex->x509_issuer || lex->x509_subject ||
lex->mqh.specified_limits;
@@ -6300,14 +6096,9 @@ static bool fix_and_copy_user(LEX_USER *to, LEX_USER *from, THD *thd)
{
/* preserve authentication information, if LEX_USER was reallocated */
to->pwtext= from->pwtext;
- to->pwhash= from->pwhash;
to->plugin= from->plugin;
to->auth= from->auth;
}
-
- if (fix_lex_user(thd, to))
- return true;
-
return false;
}
@@ -6471,7 +6262,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
}
/* Create user if needed */
error= copy_and_check_auth(Str, tmp_Str, thd) ||
- replace_user_table(thd, tables.user_table(), *Str,
+ replace_user_table(thd, tables.user_table(), Str,
0, revoke_grant, create_new_users,
MY_TEST(thd->variables.sql_mode &
MODE_NO_AUTO_CREATE_USER));
@@ -6650,7 +6441,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list,
}
/* Create user if needed */
if (copy_and_check_auth(Str, tmp_Str, thd) ||
- replace_user_table(thd, tables.user_table(), *Str,
+ replace_user_table(thd, tables.user_table(), Str,
0, revoke_grant, create_new_users,
MY_TEST(thd->variables.sql_mode &
MODE_NO_AUTO_CREATE_USER)))
@@ -6926,7 +6717,7 @@ bool mysql_grant_role(THD *thd, List <LEX_USER> &list, bool revoke)
user_combo.user = username;
if (copy_and_check_auth(&user_combo, &user_combo, thd) ||
- replace_user_table(thd, tables.user_table(), user_combo, 0,
+ replace_user_table(thd, tables.user_table(), &user_combo, 0,
false, create_new_user,
no_auto_create_user))
{
@@ -7096,7 +6887,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
}
if (copy_and_check_auth(Str, tmp_Str, thd) ||
- replace_user_table(thd, tables.user_table(), *Str,
+ replace_user_table(thd, tables.user_table(), Str,
(!db ? rights : 0), revoke_grant, create_new_users,
MY_TEST(thd->variables.sql_mode &
MODE_NO_AUTO_CREATE_USER)))
@@ -7260,8 +7051,7 @@ static bool grant_load(THD *thd,
{
sql_print_warning("'tables_priv' entry '%s %s@%s' "
"ignored in --skip-name-resolve mode.",
- mem_check->tname,
- safe_str(mem_check->user),
+ mem_check->tname, mem_check->user,
safe_str(mem_check->host.hostname));
continue;
}
@@ -8346,7 +8136,6 @@ static void add_user_parameters(String *result, ACL_USER* acl_user,
{
if (acl_user->auth_string.length)
{
- DBUG_ASSERT(acl_user->salt_len);
result->append(STRING_WITH_LEN(" IDENTIFIED BY PASSWORD '"));
result->append(&acl_user->auth_string);
result->append('\'');
@@ -8866,7 +8655,7 @@ static bool show_database_privileges(THD *thd, const char *username,
const char *user, *host;
acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
- user= safe_str(acl_db->user);
+ user= acl_db->user;
host=acl_db->host.hostname;
/*
@@ -8952,7 +8741,7 @@ static bool show_table_and_column_privileges(THD *thd, const char *username,
GRANT_TABLE *grant_table= (GRANT_TABLE*)
my_hash_element(&column_priv_hash, index);
- user= safe_str(grant_table->user);
+ user= grant_table->user;
host= grant_table->host.hostname;
/*
@@ -9094,7 +8883,7 @@ static int show_routine_grants(THD* thd,
const char *user, *host;
GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, index);
- user= safe_str(grant_proc->user);
+ user= grant_proc->user;
host= grant_proc->host.hostname;
/*
@@ -9606,8 +9395,7 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
my_hash_delete(&acl_roles, (uchar*) acl_role);
DBUG_RETURN(1);
}
- acl_role->user.str= strdup_root(&acl_memroot, user_to->user.str);
- acl_role->user.length= user_to->user.length;
+ acl_role->user= safe_lexcstrdup_root(&acl_memroot, user_to->user);
my_hash_update(&acl_roles, (uchar*) acl_role, (uchar*) old_key,
old_key_length);
@@ -9703,8 +9491,6 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
default:
DBUG_ASSERT(0);
}
- if (! user)
- user= "";
if (! host)
host= "";
@@ -9798,8 +9584,7 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
{
switch ( struct_no ) {
case USER_ACL:
- acl_user->user.str= strdup_root(&acl_memroot, user_to->user.str);
- acl_user->user.length= user_to->user.length;
+ acl_user->user= safe_lexcstrdup_root(&acl_memroot, user_to->user);
update_hostname(&acl_user->host, strdup_root(&acl_memroot, user_to->host.str));
acl_user->hostname_length= strlen(acl_user->host.hostname);
break;
@@ -10182,13 +9967,6 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list, bool handle_as_role)
if (!user_name->host.str)
user_name->host= host_not_specified;
- if (fix_lex_user(thd, user_name))
- {
- append_user(thd, &wrong_users, user_name);
- result= TRUE;
- continue;
- }
-
/*
Search all in-memory structures and grant tables
for a mention of the new user/role name.
@@ -10231,7 +10009,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list, bool handle_as_role)
}
}
- if (replace_user_table(thd, tables.user_table(), *user_name, 0, 0, 1, 0))
+ if (replace_user_table(thd, tables.user_table(), user_name, 0, 0, 1, 0))
{
append_user(thd, &wrong_users, user_name);
result= TRUE;
@@ -10520,10 +10298,8 @@ int mysql_alter_user(THD* thd, List<LEX_USER> &users_list)
while ((tmp_lex_user= users_list_iterator++))
{
LEX_USER* lex_user= get_current_user(thd, tmp_lex_user, false);
- if (!lex_user ||
- fix_lex_user(thd, lex_user) ||
- replace_user_table(thd, tables.user_table(), *lex_user, 0,
- false, false, true))
+ if (!lex_user || replace_user_table(thd, tables.user_table(), lex_user, 0,
+ false, false, true))
{
thd->clear_error();
append_user(thd, &wrong_users, tmp_lex_user);
@@ -10572,7 +10348,7 @@ mysql_revoke_sp_privs(THD *thd,
{
const char *user,*host;
GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter);
- user= safe_str(grant_proc->user);
+ user= grant_proc->user;
host= safe_str(grant_proc->host.hostname);
if (!strcmp(lex_user->user.str, user) &&
@@ -10647,7 +10423,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
continue;
}
- if (replace_user_table(thd, tables.user_table(), *lex_user,
+ if (replace_user_table(thd, tables.user_table(), lex_user,
~(ulong)0, 1, 0, 0))
{
result= -1;
@@ -10668,7 +10444,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
- user= safe_str(acl_db->user);
+ user= acl_db->user;
host= safe_str(acl_db->host.hostname);
if (!strcmp(lex_user->user.str, user) &&
@@ -10700,7 +10476,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
const char *user,*host;
GRANT_TABLE *grant_table=
(GRANT_TABLE*) my_hash_element(&column_priv_hash, counter);
- user= safe_str(grant_table->user);
+ user= grant_table->user;
host= safe_str(grant_table->host.hostname);
if (!strcmp(lex_user->user.str,user) &&
@@ -10984,17 +10760,11 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
if (!(combo=(LEX_USER*) thd->alloc(sizeof(LEX_USER))))
DBUG_RETURN(TRUE);
- combo->user.str= sctx->user;
+ combo->user.str= (char *) sctx->priv_user;
mysql_mutex_lock(&acl_cache->lock);
-
- if ((au= find_user_wild(combo->host.str=(char*)sctx->host_or_ip, combo->user.str)))
- goto found_acl;
- if ((au= find_user_wild(combo->host.str=(char*)sctx->host, combo->user.str)))
- goto found_acl;
- if ((au= find_user_wild(combo->host.str=(char*)sctx->ip, combo->user.str)))
- goto found_acl;
- if ((au= find_user_wild(combo->host.str=(char*)"%", combo->user.str)))
+ if ((au= find_user_exact(combo->host.str= (char *) sctx->priv_host,
+ combo->user.str)))
goto found_acl;
mysql_mutex_unlock(&acl_cache->lock);
@@ -11316,7 +11086,7 @@ bool check_role_is_granted(const char *username,
ACL_USER_BASE *root;
mysql_mutex_lock(&acl_cache->lock);
if (hostname)
- root= find_user_exact(username, hostname);
+ root= find_user_exact(hostname, username);
else
root= find_acl_role(username);
@@ -11490,7 +11260,7 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
{
const char *user,*host, *is_grantable="YES";
acl_user=dynamic_element(&acl_users,counter,ACL_USER*);
- user= safe_str(acl_user->user.str);
+ user= acl_user->user.str;
host= safe_str(acl_user->host.hostname);
if (no_global_access &&
@@ -11564,7 +11334,7 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
const char *user, *host, *is_grantable="YES";
acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
- user= safe_str(acl_db->user);
+ user= acl_db->user;
host= safe_str(acl_db->host.hostname);
if (no_global_access &&
@@ -11636,7 +11406,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
const char *user, *host, *is_grantable= "YES";
GRANT_TABLE *grant_table= (GRANT_TABLE*) my_hash_element(&column_priv_hash,
index);
- user= safe_str(grant_table->user);
+ user= grant_table->user;
host= safe_str(grant_table->host.hostname);
if (no_global_access &&
@@ -11718,7 +11488,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
const char *user, *host, *is_grantable= "YES";
GRANT_TABLE *grant_table= (GRANT_TABLE*) my_hash_element(&column_priv_hash,
index);
- user= safe_str(grant_table->user);
+ user= grant_table->user;
host= safe_str(grant_table->host.hostname);
if (no_global_access &&
@@ -12289,7 +12059,7 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
const char *client_auth_plugin=
((st_mysql_auth *) (plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
- DBUG_EXECUTE_IF("auth_disconnect", { vio_close(net->vio); DBUG_RETURN(1); });
+ DBUG_EXECUTE_IF("auth_disconnect", { DBUG_RETURN(1); });
DBUG_ASSERT(client_auth_plugin);
/*
@@ -12302,8 +12072,9 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
user account, it's the plugin that the client need to use to login.
*/
bool switch_from_long_to_short_scramble=
- native_password_plugin_name.str == mpvio->cached_client_reply.plugin &&
- client_auth_plugin == old_password_plugin_name.str;
+ client_auth_plugin == old_password_plugin_name.str &&
+ my_strcasecmp(system_charset_info, mpvio->cached_client_reply.plugin,
+ native_password_plugin_name.str) == 0;
if (switch_from_long_to_short_scramble)
DBUG_RETURN (secure_auth(mpvio->auth_info.thd) ||
@@ -12316,8 +12087,9 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
ask an old 4.0 client to use the new 4.1 authentication protocol.
*/
bool switch_from_short_to_long_scramble=
- old_password_plugin_name.str == mpvio->cached_client_reply.plugin &&
- client_auth_plugin == native_password_plugin_name.str;
+ client_auth_plugin == native_password_plugin_name.str &&
+ my_strcasecmp(system_charset_info, mpvio->cached_client_reply.plugin,
+ old_password_plugin_name.str) == 0;
if (switch_from_short_to_long_scramble)
{
@@ -12407,9 +12179,9 @@ static bool find_mpvio_user(MPVIO_EXT *mpvio)
mpvio->auth_info.user_name= sctx->user;
mpvio->auth_info.user_name_length= (uint)strlen(sctx->user);
- mpvio->auth_info.auth_string= mpvio->acl_user->auth_string.str;
- mpvio->auth_info.auth_string_length= (unsigned long) mpvio->acl_user->auth_string.length;
- strmake_buf(mpvio->auth_info.authenticated_as, safe_str(mpvio->acl_user->user.str));
+ mpvio->auth_info.auth_string= mpvio->acl_user->salt.str;
+ mpvio->auth_info.auth_string_length= (unsigned long) mpvio->acl_user->salt.length;
+ strmake_buf(mpvio->auth_info.authenticated_as, mpvio->acl_user->user.str);
DBUG_PRINT("info", ("exit: user=%s, auth_string=%s, authenticated as=%s"
"plugin=%s",
@@ -12560,7 +12332,7 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
MYF(0));
DBUG_RETURN(1);
}
- client_plugin= fix_plugin_ptr(next_field);
+ client_plugin= next_field;
next_field+= strlen(next_field) + 1;
}
else
@@ -12805,7 +12577,6 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
if ((thd->client_capabilities & CLIENT_PLUGIN_AUTH) &&
(client_plugin < (char *)net->read_pos + pkt_len))
{
- client_plugin= fix_plugin_ptr(client_plugin);
next_field+= strlen(next_field) + 1;
}
else
@@ -13144,17 +12915,7 @@ static int do_auth_once(THD *thd, const LEX_CSTRING *auth_plugin_name,
{
int res= CR_OK, old_status= MPVIO_EXT::FAILURE;
bool unlock_plugin= false;
- plugin_ref plugin= NULL;
-
- if (auth_plugin_name->str == native_password_plugin_name.str)
- plugin= native_password_plugin;
-#ifndef EMBEDDED_LIBRARY
- else if (auth_plugin_name->str == old_password_plugin_name.str)
- plugin= old_password_plugin;
- else if ((plugin= my_plugin_lock_by_name(thd, auth_plugin_name,
- MYSQL_AUTHENTICATION_PLUGIN)))
- unlock_plugin= true;
-#endif
+ plugin_ref plugin= get_auth_plugin(thd, *auth_plugin_name, &unlock_plugin);
mpvio->plugin= plugin;
old_status= mpvio->status;
@@ -13342,7 +13103,7 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bool is_proxy_user= FALSE;
- const char *auth_user = safe_str(acl_user->user.str);
+ const char *auth_user = acl_user->user.str;
ACL_PROXY_USER *proxy_user;
/* check if the user is allowed to proxy as another user */
proxy_user= acl_find_proxy_user(auth_user, sctx->host, sctx->ip,
@@ -13388,10 +13149,7 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
#endif
sctx->master_access= acl_user->access;
- if (acl_user->user.str)
- strmake_buf(sctx->priv_user, acl_user->user.str);
- else
- *sctx->priv_user= 0;
+ strmake_buf(sctx->priv_user, acl_user->user.str);
if (acl_user->host.hostname)
strmake_buf(sctx->priv_host, acl_user->host.hostname);
@@ -13603,15 +13361,16 @@ static int native_password_authenticate(MYSQL_PLUGIN_VIO *vio,
DBUG_EXECUTE_IF("native_password_bad_reply", { pkt_len= 12; });
if (pkt_len == 0) /* no password */
- DBUG_RETURN(mpvio->acl_user->salt_len != 0 ? CR_AUTH_USER_CREDENTIALS : CR_OK);
+ DBUG_RETURN(info->auth_string_length != 0
+ ? CR_AUTH_USER_CREDENTIALS : CR_OK);
info->password_used= PASSWORD_USED_YES;
if (pkt_len == SCRAMBLE_LENGTH)
{
- if (!mpvio->acl_user->salt_len)
+ if (!info->auth_string_length)
DBUG_RETURN(CR_AUTH_USER_CREDENTIALS);
- if (check_scramble(pkt, thd->scramble, mpvio->acl_user->salt))
+ if (check_scramble(pkt, thd->scramble, (uchar*)info->auth_string))
DBUG_RETURN(CR_AUTH_USER_CREDENTIALS);
else
DBUG_RETURN(CR_OK);
@@ -13621,6 +13380,41 @@ static int native_password_authenticate(MYSQL_PLUGIN_VIO *vio,
DBUG_RETURN(CR_AUTH_HANDSHAKE);
}
+static int native_password_make_scramble(const char *password,
+ size_t password_length, char *hash, size_t *hash_length)
+{
+ DBUG_ASSERT(*hash_length >= SCRAMBLED_PASSWORD_CHAR_LENGTH);
+ if (password_length == 0)
+ *hash_length= 0;
+ else
+ {
+ *hash_length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
+ my_make_scrambled_password(hash, password, password_length);
+ }
+ return 0;
+}
+
+static int native_password_get_salt(const char *hash, size_t hash_length,
+ unsigned char *out, size_t *out_length)
+{
+ DBUG_ASSERT(*out_length >= SCRAMBLE_LENGTH);
+ if (hash_length == 0)
+ {
+ *out_length= 0;
+ return 0;
+ }
+
+ if (hash_length != SCRAMBLED_PASSWORD_CHAR_LENGTH)
+ {
+ my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
+ return 1;
+ }
+
+ *out_length= SCRAMBLE_LENGTH;
+ get_salt_from_password(out, hash);
+ return 0;
+}
+
static int old_password_authenticate(MYSQL_PLUGIN_VIO *vio,
MYSQL_SERVER_AUTH_INFO *info)
{
@@ -13664,30 +13458,64 @@ static int old_password_authenticate(MYSQL_PLUGIN_VIO *vio,
if (pkt_len == SCRAMBLE_LENGTH_323)
{
- if (!mpvio->acl_user->salt_len)
+ if (!info->auth_string_length)
return CR_AUTH_USER_CREDENTIALS;
- return check_scramble_323(pkt, thd->scramble,
- (ulong *) mpvio->acl_user->salt) ?
- CR_AUTH_USER_CREDENTIALS : CR_OK;
+ return check_scramble_323(pkt, thd->scramble, (ulong *) info->auth_string)
+ ? CR_AUTH_USER_CREDENTIALS : CR_OK;
}
my_error(ER_HANDSHAKE_ERROR, MYF(0));
return CR_AUTH_HANDSHAKE;
}
+static int old_password_make_scramble(const char *password,
+ size_t password_length, char *hash, size_t *hash_length)
+{
+ DBUG_ASSERT(*hash_length >= SCRAMBLED_PASSWORD_CHAR_LENGTH_323);
+ if (password_length == 0)
+ *hash_length= 0;
+ else
+ {
+ *hash_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
+ my_make_scrambled_password_323(hash, password, password_length);
+ }
+ return 0;
+}
+
+#define SALT_LENGTH_323 (sizeof(ulong)*2)
+static int old_password_get_salt(const char *hash, size_t hash_length,
+ unsigned char *out, size_t *out_length)
+{
+ DBUG_ASSERT(*out_length >= SALT_LENGTH_323);
+
+ if (hash_length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
+ {
+ my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH_323);
+ return 1;
+ }
+
+ *out_length= SALT_LENGTH_323;
+ get_salt_from_password_323((ulong*)out, hash);
+ return 0;
+}
+
static struct st_mysql_auth native_password_handler=
{
MYSQL_AUTHENTICATION_INTERFACE_VERSION,
native_password_plugin_name.str,
- native_password_authenticate
+ native_password_authenticate,
+ native_password_make_scramble,
+ native_password_get_salt
};
static struct st_mysql_auth old_password_handler=
{
MYSQL_AUTHENTICATION_INTERFACE_VERSION,
old_password_plugin_name.str,
- old_password_authenticate
+ old_password_authenticate,
+ old_password_make_scramble,
+ old_password_get_salt
};
maria_declare_plugin(mysql_password)
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index 9f92af61eec..d0d959de8f9 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -1325,6 +1325,9 @@ bool Sql_cmd_analyze_table::execute(THD *thd)
m_lex->query_tables= first_table;
error:
+#ifdef WITH_WSREP
+wsrep_error_label:
+#endif
DBUG_RETURN(res);
}
@@ -1382,6 +1385,9 @@ bool Sql_cmd_optimize_table::execute(THD *thd)
m_lex->query_tables= first_table;
error:
+#ifdef WITH_WSREP
+wsrep_error_label:
+#endif
DBUG_RETURN(res);
}
@@ -1417,5 +1423,8 @@ bool Sql_cmd_repair_table::execute(THD *thd)
m_lex->query_tables= first_table;
error:
+#ifdef WITH_WSREP
+wsrep_error_label:
+#endif
DBUG_RETURN(res);
}
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index 700b4699430..05a71d7785d 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -476,15 +476,17 @@ bool Sql_cmd_alter_table::execute(THD *thd)
thd->work_part_info= 0;
#endif
-#ifdef WITH_WSREP
- if ((!thd->is_current_stmt_binlog_format_row() ||
+ if (WSREP(thd) &&
+ (!thd->is_current_stmt_binlog_format_row() ||
!thd->find_temporary_table(first_table)))
{
- WSREP_TO_ISOLATION_BEGIN(((lex->name.str) ? select_lex->db.str : NULL),
- ((lex->name.str) ? lex->name.str : NULL),
- first_table);
+ WSREP_TO_ISOLATION_BEGIN_ALTER((lex->name.str ? select_lex->db.str : NULL),
+ (lex->name.str ? lex->name.str : NULL),
+ first_table, &alter_info);
+
+ thd->variables.auto_increment_offset = 1;
+ thd->variables.auto_increment_increment = 1;
}
-#endif /* WITH_WSREP */
result= mysql_alter_table(thd, &select_lex->db, &lex->name,
&create_info,
@@ -495,12 +497,11 @@ bool Sql_cmd_alter_table::execute(THD *thd)
lex->ignore);
DBUG_RETURN(result);
-
#ifdef WITH_WSREP
-error:
+wsrep_error_label:
WSREP_WARN("ALTER TABLE isolation failure");
DBUG_RETURN(TRUE);
-#endif /* WITH_WSREP */
+#endif
}
bool Sql_cmd_discard_import_tablespace::execute(THD *thd)
diff --git a/sql/sql_alter.h b/sql/sql_alter.h
index 108b98afdd7..14242015bd2 100644
--- a/sql/sql_alter.h
+++ b/sql/sql_alter.h
@@ -83,7 +83,7 @@ public:
// Columns and keys to be dropped.
List<Alter_drop> drop_list;
- // Columns for ALTER_COLUMN_CHANGE_DEFAULT.
+ // Columns for ALTER_CHANGE_COLUMN_DEFAULT.
List<Alter_column> alter_list;
// List of keys, used by both CREATE and ALTER TABLE.
List<Key> key_list;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 98fd601b6d5..fc8a20404a3 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -414,9 +414,10 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables,
for (TABLE_LIST *table_list= tables_to_reopen; table_list;
table_list= table_list->next_global)
{
+ int err;
/* A check that the table was locked for write is done by the caller. */
TABLE *table= find_table_for_mdl_upgrade(thd, table_list->db.str,
- table_list->table_name.str, TRUE);
+ table_list->table_name.str, &err);
/* May return NULL if this table has already been closed via an alias. */
if (! table)
@@ -597,6 +598,7 @@ bool close_cached_connection_tables(THD *thd, LEX_CSTRING *connection)
static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table)
{
+ DBUG_ENTER("mark_used_tables_as_free_for_reuse");
for (; table ; table= table->next)
{
DBUG_ASSERT(table->pos_in_locked_tables == NULL ||
@@ -607,6 +609,7 @@ static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table)
table->file->ha_reset();
}
}
+ DBUG_VOID_RETURN;
}
@@ -648,6 +651,7 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
size_t key_length= share->table_cache_key.length;
const char *db= key;
const char *table_name= db + share->db.length + 1;
+ bool remove_from_locked_tables= extra != HA_EXTRA_NOT_USED;
memcpy(key, share->table_cache_key.str, key_length);
@@ -661,7 +665,7 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
{
thd->locked_tables_list.unlink_from_list(thd,
table->pos_in_locked_tables,
- extra != HA_EXTRA_NOT_USED);
+ remove_from_locked_tables);
/* Inform handler that there is a drop table or a rename going on */
if (extra != HA_EXTRA_NOT_USED && table->db_stat)
{
@@ -1499,6 +1503,65 @@ static int set_partitions_as_used(TABLE_LIST *tl, TABLE *t)
/**
+ Check if the given table is actually a VIEW that was LOCK-ed
+
+ @param thd Thread context.
+ @param t Table to check.
+
+ @retval TRUE The 't'-table is a locked view
+ needed to remedy problem before retrying again.
+ @retval FALSE 't' was not locked, not a VIEW or an error happened.
+*/
+bool is_locked_view(THD *thd, TABLE_LIST *t)
+{
+ DBUG_ENTER("check_locked_view");
+ /*
+ Is this table a view and not a base table?
+ (it is work around to allow to open view with locked tables,
+ real fix will be made after definition cache will be made)
+
+ Since opening of view which was not explicitly locked by LOCK
+ TABLES breaks metadata locking protocol (potentially can lead
+ to deadlocks) it should be disallowed.
+ */
+ if (thd->mdl_context.is_lock_owner(MDL_key::TABLE, t->db.str,
+ t->table_name.str, MDL_SHARED))
+ {
+ char path[FN_REFLEN + 1];
+ build_table_filename(path, sizeof(path) - 1,
+ t->db.str, t->table_name.str, reg_ext, 0);
+ /*
+ Note that we can't be 100% sure that it is a view since it's
+ possible that we either simply have not found unused TABLE
+ instance in THD::open_tables list or were unable to open table
+ during prelocking process (in this case in theory we still
+ should hold shared metadata lock on it).
+ */
+ if (dd_frm_is_view(thd, path))
+ {
+ /*
+ If parent_l of the table_list is non null then a merge table
+ has this view as child table, which is not supported.
+ */
+ if (t->parent_l)
+ {
+ my_error(ER_WRONG_MRG_TABLE, MYF(0));
+ DBUG_RETURN(FALSE);
+ }
+
+ if (!tdc_open_view(thd, t, CHECK_METADATA_VERSION))
+ {
+ DBUG_ASSERT(t->view != 0);
+ DBUG_RETURN(TRUE); // VIEW
+ }
+ }
+ }
+
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
Open a base table.
@param thd Thread context.
@@ -1652,49 +1715,10 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
#endif
goto reset;
}
- /*
- Is this table a view and not a base table?
- (it is work around to allow to open view with locked tables,
- real fix will be made after definition cache will be made)
- Since opening of view which was not explicitly locked by LOCK
- TABLES breaks metadata locking protocol (potentially can lead
- to deadlocks) it should be disallowed.
- */
- if (thd->mdl_context.is_lock_owner(MDL_key::TABLE,
- table_list->db.str,
- table_list->table_name.str,
- MDL_SHARED))
- {
- char path[FN_REFLEN + 1];
- build_table_filename(path, sizeof(path) - 1,
- table_list->db.str, table_list->table_name.str, reg_ext, 0);
- /*
- Note that we can't be 100% sure that it is a view since it's
- possible that we either simply have not found unused TABLE
- instance in THD::open_tables list or were unable to open table
- during prelocking process (in this case in theory we still
- should hold shared metadata lock on it).
- */
- if (dd_frm_is_view(thd, path))
- {
- /*
- If parent_l of the table_list is non null then a merge table
- has this view as child table, which is not supported.
- */
- if (table_list->parent_l)
- {
- my_error(ER_WRONG_MRG_TABLE, MYF(0));
- DBUG_RETURN(true);
- }
+ if (is_locked_view(thd, table_list))
+ DBUG_RETURN(FALSE); // VIEW
- if (!tdc_open_view(thd, table_list, CHECK_METADATA_VERSION))
- {
- DBUG_ASSERT(table_list->view != 0);
- DBUG_RETURN(FALSE); // VIEW
- }
- }
- }
/*
No table in the locked tables list. In case of explicit LOCK TABLES
this can happen if a user did not include the table into the list.
@@ -2064,8 +2088,9 @@ TABLE *find_locked_table(TABLE *list, const char *db, const char *table_name)
@param thd Thread context
@param db Database name.
@param table_name Name of table.
- @param no_error Don't emit error if no suitable TABLE
- instance were found.
+ @param p_error In the case of an error (when the function returns NULL)
+ the error number is stored there.
+ If the p_error is NULL, function launches the error itself.
@note This function checks if the connection holds a global IX
metadata lock. If no such lock is found, it is not safe to
@@ -2078,15 +2103,15 @@ TABLE *find_locked_table(TABLE *list, const char *db, const char *table_name)
*/
TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db,
- const char *table_name, bool no_error)
+ const char *table_name, int *p_error)
{
TABLE *tab= find_locked_table(thd->open_tables, db, table_name);
+ int error;
if (unlikely(!tab))
{
- if (!no_error)
- my_error(ER_TABLE_NOT_LOCKED, MYF(0), table_name);
- return NULL;
+ error= ER_TABLE_NOT_LOCKED;
+ goto err_exit;
}
/*
@@ -2098,9 +2123,8 @@ TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db,
if (unlikely(!thd->mdl_context.is_lock_owner(MDL_key::GLOBAL, "", "",
MDL_INTENTION_EXCLUSIVE)))
{
- if (!no_error)
- my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_name);
- return NULL;
+ error= ER_TABLE_NOT_LOCKED_FOR_WRITE;
+ goto err_exit;
}
while (tab->mdl_ticket != NULL &&
@@ -2108,10 +2132,21 @@ TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db,
(tab= find_locked_table(tab->next, db, table_name)))
continue;
- if (unlikely(!tab && !no_error))
- my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_name);
+ if (unlikely(!tab))
+ {
+ error= ER_TABLE_NOT_LOCKED_FOR_WRITE;
+ goto err_exit;
+ }
return tab;
+
+err_exit:
+ if (p_error)
+ *p_error= error;
+ else
+ my_error(error, MYF(0), table_name);
+
+ return NULL;
}
@@ -3399,6 +3434,15 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
*/
if (tables->with)
{
+ if (tables->is_recursive_with_table() &&
+ !tables->is_with_table_recursive_reference())
+ {
+ tables->with->rec_outer_references++;
+ With_element *with_elem= tables->with;
+ while ((with_elem= with_elem->get_next_mutually_recursive()) !=
+ tables->with)
+ with_elem->rec_outer_references++;
+ }
if (tables->set_as_with_table(thd, tables->with))
DBUG_RETURN(1);
else
@@ -3813,6 +3857,10 @@ lock_table_names(THD *thd, const DDL_options_st &options,
mdl_requests.push_front(&global_request);
if (create_table)
+#ifdef WITH_WSREP
+ if (thd->lex->sql_command != SQLCOM_CREATE_TABLE &&
+ thd->wsrep_exec_mode != REPL_RECV)
+#endif
lock_wait_timeout= 0; // Don't wait for timeout
}
@@ -3917,7 +3965,8 @@ open_tables_check_upgradable_mdl(THD *thd, TABLE_LIST *tables_start,
Note that find_table_for_mdl_upgrade() will report an error if
no suitable ticket is found.
*/
- if (!find_table_for_mdl_upgrade(thd, table->db.str, table->table_name.str, false))
+ if (!find_table_for_mdl_upgrade(thd, table->db.str, table->table_name.str,
+ NULL))
return TRUE;
}
@@ -4248,6 +4297,9 @@ restart:
}
error:
+#ifdef WITH_WSREP
+wsrep_error_label:
+#endif
THD_STAGE_INFO(thd, stage_after_opening_tables);
thd_proc_info(thd, 0);
@@ -4314,9 +4366,8 @@ handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
@note this can be changed to use a hash, instead of scanning the linked
list, if the performance of this function will ever become an issue
*/
-static bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_CSTRING *db,
- LEX_CSTRING *table,
- thr_lock_type lock_type)
+bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_CSTRING *db,
+ LEX_CSTRING *table, thr_lock_type lock_type)
{
for (; tl; tl= tl->next_global )
{
@@ -6835,6 +6886,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join,
Query_arena *arena, backup;
bool result= TRUE;
List<Natural_join_column> *non_join_columns;
+ List<Natural_join_column> *join_columns;
DBUG_ENTER("store_natural_using_join_columns");
DBUG_ASSERT(!natural_using_join->join_columns);
@@ -6842,7 +6894,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join,
arena= thd->activate_stmt_arena_if_needed(&backup);
if (!(non_join_columns= new List<Natural_join_column>) ||
- !(natural_using_join->join_columns= new List<Natural_join_column>))
+ !(join_columns= new List<Natural_join_column>))
goto err;
/* Append the columns of the first join operand. */
@@ -6851,7 +6903,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join,
nj_col_1= it_1.get_natural_column_ref();
if (nj_col_1->is_common)
{
- natural_using_join->join_columns->push_back(nj_col_1, thd->mem_root);
+ join_columns->push_back(nj_col_1, thd->mem_root);
/* Reset the common columns for the next call to mark_common_columns. */
nj_col_1->is_common= FALSE;
}
@@ -6872,7 +6924,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join,
{
const char *using_field_name_ptr= using_field_name->c_ptr();
List_iterator_fast<Natural_join_column>
- it(*(natural_using_join->join_columns));
+ it(*join_columns);
Natural_join_column *common_field;
for (;;)
@@ -6905,15 +6957,28 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join,
}
if (non_join_columns->elements > 0)
- natural_using_join->join_columns->append(non_join_columns);
+ join_columns->append(non_join_columns);
+ natural_using_join->join_columns= join_columns;
natural_using_join->is_join_columns_complete= TRUE;
result= FALSE;
-err:
if (arena)
thd->restore_active_arena(arena, &backup);
DBUG_RETURN(result);
+
+err:
+ /*
+ Actually we failed to build join columns list, so we have to
+ clear it to avoid problems with half-build join on next run.
+ The list was created in mark_common_columns().
+ */
+ table_ref_1->remove_join_columns();
+ table_ref_2->remove_join_columns();
+
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
+ DBUG_RETURN(TRUE);
}
@@ -7137,7 +7202,6 @@ static bool setup_natural_join_row_types(THD *thd,
DBUG_PRINT("info", ("using cached setup_natural_join_row_types"));
DBUG_RETURN(false);
}
- context->select_lex->first_natural_join_processing= false;
List_iterator_fast<TABLE_LIST> table_ref_it(*from_clause);
TABLE_LIST *table_ref; /* Current table reference. */
@@ -7182,6 +7246,7 @@ static bool setup_natural_join_row_types(THD *thd,
change on re-execution
*/
context->natural_join_first_table= context->first_name_resolution_table;
+ context->select_lex->first_natural_join_processing= false;
DBUG_RETURN (false);
}
@@ -7295,8 +7360,7 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
thd->column_usage= column_usage;
DBUG_PRINT("info", ("thd->column_usage: %d", thd->column_usage));
if (allow_sum_func)
- thd->lex->allow_sum_func|=
- (nesting_map)1 << thd->lex->current_select->nest_level;
+ thd->lex->allow_sum_func.set_bit(thd->lex->current_select->nest_level);
thd->where= THD::DEFAULT_WHERE;
save_is_item_list_lookup= thd->lex->current_select->is_item_list_lookup;
thd->lex->current_select->is_item_list_lookup= 0;
@@ -8768,6 +8832,13 @@ open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
void
close_system_tables(THD *thd, Open_tables_backup *backup)
{
+ /*
+ Inform the transaction handler that we are closing the
+ system tables and we don't need the read view anymore.
+ */
+ for (TABLE *table= thd->open_tables ; table ; table= table->next)
+ table->file->extra(HA_EXTRA_PREPARE_FOR_FORCED_CLOSE);
+
close_thread_tables(thd);
thd->restore_backup_open_tables_state(backup);
}
diff --git a/sql/sql_base.h b/sql/sql_base.h
index 59c849086e6..0ebed4159ab 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -126,6 +126,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
MYSQL_OPEN_GET_NEW_TABLE |\
MYSQL_OPEN_HAS_MDL_LOCK)
+bool is_locked_view(THD *thd, TABLE_LIST *t);
bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx);
bool get_key_map_from_key_list(key_map *map, TABLE *table,
@@ -141,6 +142,8 @@ thr_lock_type read_lock_type_for_table(THD *thd,
my_bool mysql_rm_tmp_tables(void);
void close_tables_for_reopen(THD *thd, TABLE_LIST **tables,
const MDL_savepoint &start_of_statement_svp);
+bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_CSTRING *db,
+ LEX_CSTRING *table, thr_lock_type lock_type);
TABLE_LIST *find_table_in_list(TABLE_LIST *table,
TABLE_LIST *TABLE_LIST::*link,
const LEX_CSTRING *db_name,
@@ -300,7 +303,8 @@ bool tdc_open_view(THD *thd, TABLE_LIST *table_list, uint flags);
TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db,
const char *table_name,
- bool no_error);
+ int *p_error);
+void mark_tmp_table_for_reuse(TABLE *table);
int dynamic_column_error_message(enum_dyncol_func_result rc);
diff --git a/sql/sql_basic_types.h b/sql/sql_basic_types.h
index 1e97262cdf0..362ab0f1259 100644
--- a/sql/sql_basic_types.h
+++ b/sql/sql_basic_types.h
@@ -22,4 +22,87 @@
typedef ulonglong sql_mode_t;
typedef int64 query_id_t;
+
+
+/*
+ "fuzzydate" with strict data type control.
+ Please keep "explicit" in constructors and conversion methods.
+*/
+class date_mode_t
+{
+public:
+ enum value_t
+ {
+ FUZZY_DATES= 1U, // C_TIME_FUZZY_DATES
+ TIME_ONLY= 4U, // C_TIME_TIME_ONLY
+ NO_ZERO_IN_DATE= (1UL << 23), // MODE_NO_ZERO_IN_DATE
+ NO_ZERO_DATE= (1UL << 24), // MODE_NO_ZERO_DATE
+ INVALID_DATES= (1UL << 25) // MODE_INVALID_DATES
+ };
+
+private:
+ value_t m_mode;
+public:
+
+ // Constructors
+ explicit date_mode_t(ulonglong fuzzydate)
+ :m_mode((value_t) fuzzydate)
+ { }
+
+ // Conversion operators
+ explicit operator ulonglong() const
+ {
+ return m_mode;
+ }
+ explicit operator bool() const
+ {
+ return m_mode != 0;
+ }
+
+ // Unary operators
+ date_mode_t operator~() const
+ {
+ return date_mode_t(~m_mode);
+ }
+
+ // Dyadic bitwise operators
+ date_mode_t operator&(const date_mode_t &other) const
+ {
+ return date_mode_t(m_mode & other.m_mode);
+ }
+
+ date_mode_t operator|(const date_mode_t &other) const
+ {
+ return date_mode_t(m_mode | other.m_mode);
+ }
+
+ // Dyadic bitwise assignment operators
+ date_mode_t &operator&=(const date_mode_t &other)
+ {
+ m_mode= value_t(m_mode & other.m_mode);
+ return *this;
+ }
+
+ date_mode_t &operator|=(const date_mode_t &other)
+ {
+ m_mode= value_t(m_mode | other.m_mode);
+ return *this;
+ }
+};
+
+
+const date_mode_t
+ TIME_FUZZY_DATES (date_mode_t::value_t::FUZZY_DATES),
+ TIME_TIME_ONLY (date_mode_t::value_t::TIME_ONLY),
+ TIME_NO_ZERO_IN_DATE (date_mode_t::value_t::NO_ZERO_IN_DATE),
+ TIME_NO_ZERO_DATE (date_mode_t::value_t::NO_ZERO_DATE),
+ TIME_INVALID_DATES (date_mode_t::value_t::INVALID_DATES);
+
+// Flags understood by str_to_datetime, str_to_time, number_to_time, check_date
+static const date_mode_t
+ TIME_MODE_FOR_XXX_TO_DATE (date_mode_t::NO_ZERO_IN_DATE |
+ date_mode_t::NO_ZERO_DATE |
+ date_mode_t::INVALID_DATES |
+ date_mode_t::TIME_ONLY);
+
#endif
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index d6b2cd6fd76..0dd82351719 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1363,6 +1363,11 @@ void THD::change_user(void)
cleanup_done= 0;
reset_killed();
thd_clear_errors(this);
+
+ /* Clear warnings. */
+ if (!get_stmt_da()->is_warning_info_empty())
+ get_stmt_da()->clear_warning_info(0);
+
init();
stmt_map.reset();
my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
@@ -4781,6 +4786,14 @@ extern "C" int thd_slave_thread(const MYSQL_THD thd)
return(thd->slave_thread);
}
+
+extern "C" int thd_rpl_stmt_based(const MYSQL_THD thd)
+{
+ return !thd->is_current_stmt_binlog_format_row() &&
+ !thd->is_current_stmt_binlog_disabled();
+}
+
+
/* Returns high resolution timestamp for the start
of the current query. */
extern "C" unsigned long long thd_start_utime(const MYSQL_THD thd)
@@ -7696,7 +7709,7 @@ Query_arena_stmt::~Query_arena_stmt()
bool THD::timestamp_to_TIME(MYSQL_TIME *ltime, my_time_t ts,
- ulong sec_part, ulonglong fuzzydate)
+ ulong sec_part, date_mode_t fuzzydate)
{
time_zone_used= 1;
if (ts == 0 && sec_part == 0)
diff --git a/sql/sql_class.h b/sql/sql_class.h
index aaa54447c0b..d9ff1743fd6 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -581,6 +581,7 @@ typedef struct system_variables
ha_rows max_join_size;
ha_rows expensive_subquery_limit;
ulong auto_increment_increment, auto_increment_offset;
+ uint eq_range_index_dive_limit;
ulong column_compression_zlib_strategy;
ulong lock_wait_timeout;
ulong join_cache_level;
@@ -3124,6 +3125,9 @@ public:
it returned an error on master, and this is OK on the slave.
*/
bool is_slave_error;
+ /* True if we have printed something to the error log for this statement */
+ bool error_printed_to_log;
+
/*
True when a transaction is queued up for binlog group commit.
Used so that if another transaction needs to wait for a row lock held by
@@ -3407,7 +3411,7 @@ public:
}
const Type_handler *type_handler_for_date() const;
bool timestamp_to_TIME(MYSQL_TIME *ltime, my_time_t ts,
- ulong sec_part, ulonglong fuzzydate);
+ ulong sec_part, date_mode_t fuzzydate);
inline my_time_t query_start() { return start_time; }
inline ulong query_start_sec_part()
{ query_start_sec_part_used=1; return start_time_sec_part; }
@@ -4037,6 +4041,10 @@ public:
*format= (enum_binlog_format) variables.binlog_format;
*current_format= current_stmt_binlog_format;
}
+ inline enum_binlog_format get_current_stmt_binlog_format()
+ {
+ return current_stmt_binlog_format;
+ }
inline void set_binlog_format(enum_binlog_format format,
enum_binlog_format current_format)
{
@@ -4082,11 +4090,6 @@ public:
DBUG_VOID_RETURN;
}
- inline enum_binlog_format get_current_stmt_binlog_format()
- {
- return current_stmt_binlog_format;
- }
-
inline void set_current_stmt_binlog_format(enum_binlog_format format)
{
current_stmt_binlog_format= format;
@@ -4693,6 +4696,7 @@ public:
TMP_TABLE_SHARE* save_tmp_table_share(TABLE *table);
void restore_tmp_table_share(TMP_TABLE_SHARE *share);
+ void close_unused_temporary_table_instances(const TABLE_LIST *tl);
private:
/* Whether a lock has been acquired? */
@@ -4950,10 +4954,17 @@ my_eof(THD *thd)
(A)->variables.sql_log_bin_off= 0;}
-inline sql_mode_t sql_mode_for_dates(THD *thd)
+inline date_mode_t sql_mode_for_dates(THD *thd)
{
- return thd->variables.sql_mode &
- (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE | MODE_INVALID_DATES);
+ static_assert(C_TIME_FUZZY_DATES == date_mode_t::FUZZY_DATES &&
+ C_TIME_TIME_ONLY == date_mode_t::TIME_ONLY,
+ "sql_mode_t and pure C library date flags must be equal");
+ static_assert(MODE_NO_ZERO_DATE == date_mode_t::NO_ZERO_DATE &&
+ MODE_NO_ZERO_IN_DATE == date_mode_t::NO_ZERO_IN_DATE &&
+ MODE_INVALID_DATES == date_mode_t::INVALID_DATES,
+ "sql_mode_t and date_mode_t values must be equal");
+ return date_mode_t(thd->variables.sql_mode &
+ (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE | MODE_INVALID_DATES));
}
/*
@@ -5022,7 +5033,8 @@ protected:
SELECT_LEX_UNIT *unit;
/* Something used only by the parser: */
public:
- select_result(THD *thd_arg): select_result_sink(thd_arg) {}
+ ha_rows est_records; /* estimated number of records in the result */
+ select_result(THD *thd_arg): select_result_sink(thd_arg), est_records(0) {}
void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; }
virtual ~select_result() {};
/**
@@ -5594,7 +5606,6 @@ public:
TMP_TABLE_PARAM tmp_table_param;
int write_err; /* Error code from the last send_data->ha_write_row call. */
TABLE *table;
- ha_rows records;
select_unit(THD *thd_arg):
select_result_interceptor(thd_arg),
@@ -5632,7 +5643,6 @@ public:
curr_sel= UINT_MAX;
step= UNION_TYPE;
write_err= 0;
- records= 0;
}
void change_select();
};
@@ -5646,10 +5656,16 @@ class select_union_recursive :public select_unit
TABLE *first_rec_table_to_update;
/* The temporary tables used for recursive table references */
List<TABLE> rec_tables;
+ /*
+ The count of how many times cleanup() was called with cleaned==false
+ for the unit specifying the recursive CTE for which this object was created
+ or for the unit specifying a CTE that mutually recursive with this CTE.
+ */
+ uint cleanup_count;
select_union_recursive(THD *thd_arg):
select_unit(thd_arg),
- incr_table(0), first_rec_table_to_update(0) {};
+ incr_table(0), first_rec_table_to_update(0), cleanup_count(0) {};
int send_data(List<Item> &items);
bool create_result_table(THD *thd, List<Item> *column_types,
diff --git a/sql/sql_const.h b/sql/sql_const.h
index e28a0649f04..be26de872df 100644
--- a/sql/sql_const.h
+++ b/sql/sql_const.h
@@ -84,7 +84,7 @@
#define MAX_FIELDS 4096 /* Limit in the .frm file */
#define MAX_PARTITIONS 8192
-#define MAX_SELECT_NESTING (sizeof(nesting_map)*8-1)
+#define MAX_SELECT_NESTING (SELECT_NESTING_MAP_SIZE - 1)
#define MAX_SORT_MEMORY 2048*1024
#define MIN_SORT_MEMORY 1024
diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc
index a518f991892..c89f49aaefc 100644
--- a/sql/sql_cte.cc
+++ b/sql/sql_cte.cc
@@ -751,9 +751,10 @@ bool With_clause::prepare_unreferenced_elements(THD *thd)
@brief
Save the specification of the given with table as a string
- @param thd The context of the statement containing this with element
- @param spec_start The beginning of the specification in the input string
- @param spec_end The end of the specification in the input string
+ @param thd The context of the statement containing this with element
+ @param spec_start The beginning of the specification in the input string
+ @param spec_end The end of the specification in the input string
+ @param spec_offset The offset of the specification in the input string
@details
The method creates for a string copy of the specification used in this
@@ -765,10 +766,17 @@ bool With_clause::prepare_unreferenced_elements(THD *thd)
true on failure
*/
-bool With_element::set_unparsed_spec(THD *thd, char *spec_start, char *spec_end)
+bool With_element::set_unparsed_spec(THD *thd, char *spec_start, char *spec_end,
+ my_ptrdiff_t spec_offset)
{
+ stmt_prepare_mode= thd->m_parser_state->m_lip.stmt_prepare_mode;
unparsed_spec.length= spec_end - spec_start;
- unparsed_spec.str= thd->strmake(spec_start, unparsed_spec.length);
+
+ if (stmt_prepare_mode || !thd->lex->sphead)
+ unparsed_spec.str= spec_start;
+ else
+ unparsed_spec.str= thd->strmake(spec_start, unparsed_spec.length);
+ unparsed_spec_offset= spec_offset;
if (!unparsed_spec.str)
{
@@ -838,12 +846,27 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd,
TABLE_LIST *spec_tables_tail;
st_select_lex *with_select;
+ char save_end= unparsed_spec.str[unparsed_spec.length];
+ ((char*) &unparsed_spec.str[unparsed_spec.length])[0]= '\0';
if (parser_state.init(thd, (char*) unparsed_spec.str, (unsigned int)unparsed_spec.length))
goto err;
+ parser_state.m_lip.stmt_prepare_mode= stmt_prepare_mode;
+ parser_state.m_lip.multi_statements= false;
+ parser_state.m_lip.m_digest= NULL;
+
lex_start(thd);
+ lex->clone_spec_offset= unparsed_spec_offset;
+ lex->param_list= old_lex->param_list;
+ lex->sphead= old_lex->sphead;
+ lex->spname= old_lex->spname;
+ lex->spcont= old_lex->spcont;
+ lex->sp_chistics= old_lex->sp_chistics;
+
lex->stmt_lex= old_lex;
parse_status= parse_sql(thd, &parser_state, 0);
+ ((char*) &unparsed_spec.str[unparsed_spec.length])[0]= save_end;
with_select= lex->first_select_lex();
+
if (parse_status)
goto err;
@@ -888,6 +911,7 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd,
with_select));
if (check_dependencies_in_with_clauses(lex->with_clauses_list))
res= NULL;
+ lex->sphead= NULL; // in order not to delete lex->sphead
lex_end(lex);
err:
if (arena)
@@ -1262,7 +1286,7 @@ bool With_element::check_unrestricted_recursive(st_select_lex *sel,
With_element *with_elem= unit->with_element;
if (encountered & with_elem->get_elem_map())
unrestricted|= with_elem->mutually_recursive;
- else
+ else if (with_elem ==this)
encountered|= with_elem->get_elem_map();
}
}
diff --git a/sql/sql_cte.h b/sql/sql_cte.h
index 4a194b2a38f..03c697bf746 100644
--- a/sql/sql_cte.h
+++ b/sql/sql_cte.h
@@ -90,6 +90,11 @@ private:
It used to build clones of the specification if they are needed.
*/
LEX_CSTRING unparsed_spec;
+ /* Offset of the specification in the input string */
+ my_ptrdiff_t unparsed_spec_offset;
+
+ /* True if the with element is used a prepared statement */
+ bool stmt_prepare_mode;
/* Return the map where 1 is set only in the position for this element */
table_map get_elem_map() { return (table_map) 1 << number; }
@@ -114,7 +119,14 @@ public:
for the definition of this element
*/
bool is_recursive;
-
+ /*
+ For a simple recursive CTE: the number of references to the CTE from
+ outside of the CTE specification.
+ For a CTE mutually recursive with other CTEs : the total number of
+ references to all these CTEs outside of their specification.
+ Each of these mutually recursive CTEs has the same value in this field.
+ */
+ uint rec_outer_references;
/*
Any non-recursive select in the specification of a recursive
with element is a called anchor. In the case mutually recursive
@@ -158,7 +170,7 @@ public:
top_level_dep_map(0), sq_rec_ref(NULL),
next_mutually_recursive(NULL), references(0),
query_name(name), column_list(list), spec(unit),
- is_recursive(false), with_anchor(false),
+ is_recursive(false), rec_outer_references(0), with_anchor(false),
level(0), rec_result(NULL)
{ unit->with_element= this; }
@@ -185,7 +197,8 @@ public:
TABLE_LIST *find_first_sq_rec_ref_in_select(st_select_lex *sel);
- bool set_unparsed_spec(THD *thd, char *spec_start, char *spec_end);
+ bool set_unparsed_spec(THD *thd, char *spec_start, char *spec_end,
+ my_ptrdiff_t spec_offset);
st_select_lex_unit *clone_parsed_spec(THD *thd, TABLE_LIST *with_table);
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 80ee4a22419..148c2371a6b 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -323,12 +323,16 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
DBUG_ASSERT(table);
DBUG_ASSERT(!conds || thd->stmt_arena->is_stmt_execute());
- if (select_lex->vers_setup_conds(thd, table_list))
- DBUG_RETURN(TRUE);
- DBUG_ASSERT(!conds);
- conds= table_list->on_expr;
- table_list->on_expr= NULL;
+ // conds could be cached from previous SP call
+ if (!conds)
+ {
+ if (select_lex->vers_setup_conds(thd, table_list))
+ DBUG_RETURN(TRUE);
+
+ conds= table_list->on_expr;
+ table_list->on_expr= NULL;
+ }
}
if (mysql_handle_list_of_derived(thd->lex, table_list, DT_MERGE_FOR_INSERT))
@@ -932,7 +936,7 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list,
List<Item> all_fields;
*delete_while_scanning= true;
- thd->lex->allow_sum_func= 0;
+ thd->lex->allow_sum_func.clear_all();
if (setup_tables_and_check_access(thd,
&thd->lex->first_select_lex()->context,
&thd->lex->first_select_lex()->
@@ -1212,6 +1216,7 @@ multi_delete::~multi_delete()
{
TABLE *table= table_being_deleted->table;
table->no_keyread=0;
+ table->no_cache= 0;
}
for (uint counter= 0; counter < num_of_tables; counter++)
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index d65969d2160..878aa715b84 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -1107,6 +1107,7 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
DBUG_ASSERT(derived->table && derived->table->is_created());
select_unit *derived_result= derived->derived_result;
SELECT_LEX *save_current_select= lex->current_select;
+ bool derived_recursive_is_filled= false;
if (unit->executed && !derived_is_recursive &&
(unit->uncacheable & UNCACHEABLE_DEPENDENT))
@@ -1135,6 +1136,7 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
{
/* In this case all iteration are performed */
res= derived->fill_recursive(thd);
+ derived_recursive_is_filled= true;
}
}
else if (unit->is_unit_op())
@@ -1190,7 +1192,8 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
}
}
err:
- if (res || (!lex->describe && !derived_is_recursive && !unit->uncacheable))
+ if (res || (!lex->describe && !unit->uncacheable &&
+ (!derived_is_recursive || derived_recursive_is_filled)))
unit->cleanup();
lex->current_select= save_current_select;
diff --git a/sql/sql_error.h b/sql/sql_error.h
index 88355e529b5..6586c49a125 100644
--- a/sql/sql_error.h
+++ b/sql/sql_error.h
@@ -18,11 +18,11 @@
#define SQL_ERROR_H
#include "sql_list.h" /* Sql_alloc, MEM_ROOT, list */
-#include "m_string.h" /* LEX_STRING */
-#include "sql_string.h" /* String */
-#include "sql_plist.h" /* I_P_List */
-#include "mysql_com.h" /* MYSQL_ERRMSG_SIZE */
-#include "my_time.h" /* MYSQL_TIME */
+#include "sql_type_int.h" // Longlong_hybrid
+#include "sql_string.h" /* String */
+#include "sql_plist.h" /* I_P_List */
+#include "mysql_com.h" /* MYSQL_ERRMSG_SIZE */
+#include "my_time.h" /* MYSQL_TIME */
#include "decimal.h"
class THD;
@@ -814,11 +814,48 @@ private:
extern char *err_conv(char *buff, uint to_length, const char *from,
uint from_length, CHARSET_INFO *from_cs);
-class ErrConv
+class ErrBuff
{
protected:
mutable char err_buffer[MYSQL_ERRMSG_SIZE];
public:
+ ErrBuff()
+ {
+ err_buffer[0]= '\0';
+ }
+ const char *ptr() const { return err_buffer; }
+ const char *set_longlong(const Longlong_hybrid &nr) const
+ {
+ return nr.is_unsigned() ? ullstr(nr.value(), err_buffer) :
+ llstr(nr.value(), err_buffer);
+ }
+ const char *set_double(double nr) const
+ {
+ my_gcvt(nr, MY_GCVT_ARG_DOUBLE, sizeof(err_buffer), err_buffer, 0);
+ return err_buffer;
+ }
+ const char *set_decimal(const decimal_t *d) const
+ {
+ int len= sizeof(err_buffer);
+ decimal2string(d, err_buffer, &len, 0, 0, ' ');
+ return err_buffer;
+ }
+ const char *set_str(const char *str, size_t len, CHARSET_INFO *cs) const
+ {
+ DBUG_ASSERT(len < UINT_MAX32);
+ return err_conv(err_buffer, (uint) sizeof(err_buffer), str, (uint) len, cs);
+ }
+ const char *set_mysql_time(const MYSQL_TIME *ltime) const
+ {
+ my_TIME_to_str(ltime, err_buffer, AUTO_SEC_PART_DIGITS);
+ return err_buffer;
+ }
+};
+
+
+class ErrConv: public ErrBuff
+{
+public:
ErrConv() {}
virtual ~ErrConv() {}
virtual const char *ptr() const = 0;
@@ -838,22 +875,18 @@ public:
: ErrConv(), str(s->ptr()), len(s->length()), cs(s->charset()) {}
const char *ptr() const
{
- DBUG_ASSERT(len < UINT_MAX32);
- return err_conv(err_buffer, (uint) sizeof(err_buffer), str, (uint) len, cs);
+ return set_str(str, len, cs);
}
};
-class ErrConvInteger : public ErrConv
+class ErrConvInteger : public ErrConv, public Longlong_hybrid
{
- longlong m_value;
- bool m_unsigned;
public:
- ErrConvInteger(longlong num_arg, bool unsigned_flag= false) :
- ErrConv(), m_value(num_arg), m_unsigned(unsigned_flag) {}
+ ErrConvInteger(const Longlong_hybrid &nr)
+ : ErrConv(), Longlong_hybrid(nr) { }
const char *ptr() const
{
- return m_unsigned ? ullstr(m_value, err_buffer) :
- llstr(m_value, err_buffer);
+ return set_longlong(static_cast<Longlong_hybrid>(*this));
}
};
@@ -864,8 +897,7 @@ public:
ErrConvDouble(double num_arg) : ErrConv(), num(num_arg) {}
const char *ptr() const
{
- my_gcvt(num, MY_GCVT_ARG_DOUBLE, sizeof(err_buffer), err_buffer, 0);
- return err_buffer;
+ return set_double(num);
}
};
@@ -876,8 +908,7 @@ public:
ErrConvTime(const MYSQL_TIME *ltime_arg) : ErrConv(), ltime(ltime_arg) {}
const char *ptr() const
{
- my_TIME_to_str(ltime, err_buffer, AUTO_SEC_PART_DIGITS);
- return err_buffer;
+ return set_mysql_time(ltime);
}
};
@@ -888,9 +919,7 @@ public:
ErrConvDecimal(const decimal_t *d_arg) : ErrConv(), d(d_arg) {}
const char *ptr() const
{
- int len= sizeof(err_buffer);
- decimal2string(d, err_buffer, &len, 0, 0, ' ');
- return err_buffer;
+ return set_decimal(d);
}
};
diff --git a/sql/sql_get_diagnostics.cc b/sql/sql_get_diagnostics.cc
index 1b64819732c..b7da889340f 100644
--- a/sql/sql_get_diagnostics.cc
+++ b/sql/sql_get_diagnostics.cc
@@ -11,7 +11,7 @@
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., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301 USA */
#include "mariadb.h"
#include "sql_list.h" // Sql_alloc, List, List_iterator
diff --git a/sql/sql_get_diagnostics.h b/sql/sql_get_diagnostics.h
index f34820757f5..6f1652bb146 100644
--- a/sql/sql_get_diagnostics.h
+++ b/sql/sql_get_diagnostics.h
@@ -11,7 +11,7 @@
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., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301 USA */
#ifndef SQL_GET_DIAGNOSTICS_H
#define SQL_GET_DIAGNOSTICS_H
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 51acf10a98a..127b4b10eb4 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -2518,7 +2518,8 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
The thread could be killed with an error message if
di->handle_inserts() or di->open_and_lock_table() fails.
The thread could be killed without an error message if
- killed using kill_delayed_threads_for_table().
+ killed using THD::notify_shared_lock() or
+ kill_delayed_threads_for_table().
*/
if (!thd.is_error())
my_message(ER_QUERY_INTERRUPTED, ER_THD(&thd, ER_QUERY_INTERRUPTED),
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 20b1eb413cf..2f5a845d18c 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -693,6 +693,7 @@ void LEX::start(THD *thd_arg)
curr_with_clause= 0;
with_clauses_list= 0;
with_clauses_list_last_next= &with_clauses_list;
+ clone_spec_offset= 0;
create_view= NULL;
field_list.empty();
value_list.empty();
@@ -744,7 +745,7 @@ void LEX::start(THD *thd_arg)
profile_options= PROFILE_NONE;
nest_level= 0;
builtin_select.nest_level_base= &unit;
- allow_sum_func= 0;
+ allow_sum_func.clear_all();
in_sum_func= NULL;
used_tables= 0;
@@ -2388,7 +2389,7 @@ void st_select_lex::init_select()
m_non_agg_field_used= false;
m_agg_func_used= false;
m_custom_agg_func_used= false;
- name_visibility_map= 0;
+ name_visibility_map.clear_all();
with_dep= 0;
join= 0;
lock_type= TL_READ_DEFAULT;
@@ -3169,7 +3170,7 @@ LEX::LEX()
INITIAL_LEX_PLUGIN_LIST_SIZE, 0);
reset_query_tables_list(TRUE);
mi.init();
- init_dynamic_array2(&delete_gtid_domain, sizeof(ulong*),
+ init_dynamic_array2(&delete_gtid_domain, sizeof(uint32),
gtid_domain_static_buffer,
initial_gtid_domain_buffer_size,
initial_gtid_domain_buffer_size, 0);
@@ -4765,18 +4766,18 @@ void SELECT_LEX::increase_derived_records(ha_rows records)
return;
}
- select_unit *result= (select_unit*)unit->result;
+ select_result *result= unit->result;
switch (linkage)
{
case INTERSECT_TYPE:
// result of intersect can't be more then one of components
- set_if_smaller(result->records, records);
+ set_if_smaller(result->est_records, records);
case EXCEPT_TYPE:
// in worse case none of record will be removed
break;
default:
// usual UNION
- result->records+= records;
+ result->est_records+= records;
break;
}
}
@@ -5249,6 +5250,9 @@ LEX::create_unit(SELECT_LEX *first_sel)
SELECT_LEX_UNIT *unit;
DBUG_ENTER("LEX::create_unit");
+ if (first_sel->master_unit())
+ DBUG_RETURN(first_sel->master_unit());
+
if (!(unit= alloc_unit()))
DBUG_RETURN(NULL);
@@ -6937,6 +6941,14 @@ Item *LEX::make_item_sysvar(THD *thd,
}
+static bool param_push_or_clone(THD *thd, LEX *lex, Item_param *item)
+{
+ return !lex->clone_spec_offset ?
+ lex->param_list.push_back(item, thd->mem_root) :
+ item->add_as_clone(thd);
+}
+
+
Item_param *LEX::add_placeholder(THD *thd, const LEX_CSTRING *name,
const char *start, const char *end)
{
@@ -6953,7 +6965,7 @@ Item_param *LEX::add_placeholder(THD *thd, const LEX_CSTRING *name,
Query_fragment pos(thd, sphead, start, end);
Item_param *item= new (thd->mem_root) Item_param(thd, name,
pos.pos(), pos.length());
- if (unlikely(!item) || unlikely(param_list.push_back(item, thd->mem_root)))
+ if (unlikely(!item) || unlikely(param_push_or_clone(thd, this, item)))
{
my_error(ER_OUT_OF_RESOURCES, MYF(0));
return NULL;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 24788158d26..8dab2a06973 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -33,6 +33,10 @@
#include "sql_tvc.h"
#include "item.h"
+/* Used for flags of nesting constructs */
+#define SELECT_NESTING_MAP_SIZE 64
+typedef Bitmap<SELECT_NESTING_MAP_SIZE> nesting_map;
+
/* YACC and LEX Definitions */
@@ -2935,6 +2939,11 @@ public:
with clause in the current statement
*/
With_clause **with_clauses_list_last_next;
+ /*
+ When a copy of a with element is parsed this is set to the offset of
+ the with element in the input string, otherwise it's set to 0
+ */
+ my_ptrdiff_t clone_spec_offset;
Create_view_info *create_view;
@@ -3280,7 +3289,7 @@ public:
*/
DYNAMIC_ARRAY delete_gtid_domain;
static const ulong initial_gtid_domain_buffer_size= 16;
- ulong gtid_domain_static_buffer[initial_gtid_domain_buffer_size];
+ uint32 gtid_domain_static_buffer[initial_gtid_domain_buffer_size];
inline void set_limit_rows_examined()
{
diff --git a/sql/sql_list.h b/sql/sql_list.h
index 9f4eaae43f1..27827b42be5 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -278,10 +278,13 @@ public:
*/
inline void swap(base_list &rhs)
{
+ list_node **rhs_last=rhs.last;
swap_variables(list_node *, first, rhs.first);
- swap_variables(list_node **, last, rhs.last);
swap_variables(uint, elements, rhs.elements);
+ rhs.last= last == &first ? &rhs.first : last;
+ last = rhs_last == &rhs.first ? &first : rhs_last;
}
+
inline list_node* last_node() { return *last; }
inline list_node* first_node() { return first;}
inline void *head() { return first->info; }
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 1baa26ab465..1f9cd305847 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -109,6 +109,7 @@
#include "../storage/maria/ha_maria.h"
#endif
+#include "wsrep.h"
#include "wsrep_mysqld.h"
#include "wsrep_thd.h"
@@ -736,6 +737,9 @@ void init_update_queries(void)
/* We don't want to replicate DROP for temp tables in row format */
sql_command_flags[SQLCOM_DROP_TABLE]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT;
sql_command_flags[SQLCOM_DROP_SEQUENCE]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT;
+ /* We don't want to replicate CREATE/DROP INDEX for temp tables in row format */
+ sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT;
+ sql_command_flags[SQLCOM_DROP_INDEX]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT;
/* One can change replication mode with SET */
sql_command_flags[SQLCOM_SET_OPTION]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT;
@@ -1597,10 +1601,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (thd->wsrep_conflict_state == ABORTED &&
command != COM_STMT_CLOSE && command != COM_QUIT)
{
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
my_message(ER_LOCK_DEADLOCK, "Deadlock: wsrep aborted transaction",
MYF(0));
WSREP_DEBUG("Deadlock error for: %s", thd->query());
- mysql_mutex_unlock(&thd->LOCK_thd_data);
thd->reset_killed();
thd->mysys_var->abort = 0;
thd->wsrep_conflict_state = NO_CONFLICT;
@@ -2562,6 +2566,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
case SCH_TABLE_NAMES:
case SCH_TABLES:
+ case SCH_CHECK_CONSTRAINTS:
case SCH_VIEWS:
case SCH_TRIGGERS:
case SCH_EVENTS:
@@ -3006,7 +3011,7 @@ static int mysql_create_routine(THD *thd, LEX *lex)
if (sp_process_definer(thd))
return true;
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
if (!lex->sphead->m_handler->sp_create_routine(thd, lex->sphead))
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -3076,7 +3081,7 @@ static int mysql_create_routine(THD *thd, LEX *lex)
return false;
}
#ifdef WITH_WSREP
-error: /* Used by WSREP_TO_ISOLATION_BEGIN */
+wsrep_error_label:
#endif
return true;
}
@@ -6297,7 +6302,10 @@ end_with_restore_list:
goto finish;
error:
- res= TRUE;
+#ifdef WITH_WSREP
+wsrep_error_label:
+#endif
+ res= true;
finish:
@@ -7590,8 +7598,14 @@ void THD::reset_for_next_command(bool do_clear_error)
DBUG_ASSERT(!in_sub_stmt);
if (likely(do_clear_error))
+ {
clear_error(1);
-
+ /*
+ The following variable can't be reset in clear_error() as
+ clear_error() is called during auto_repair of table
+ */
+ error_printed_to_log= 0;
+ }
free_list= 0;
/*
We also assign stmt_lex in lex_start(), but during bootstrap this
@@ -7863,7 +7877,9 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
"WAIT_FOR wsrep_retry_autocommit_continue";
DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
});
+ WSREP_DEBUG("Retry autocommit query: %s", thd->query());
}
+
mysql_parse(thd, rawbuf, length, parser_state, is_com_multi,
is_next_command);
@@ -7895,36 +7911,46 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
thd->lex->sql_command != SQLCOM_SELECT &&
(thd->wsrep_retry_counter < thd->variables.wsrep_retry_autocommit))
{
- WSREP_DEBUG("wsrep retrying AC query: %s",
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+ WSREP_DEBUG("wsrep retrying AC query: %s",
(thd->query()) ? thd->query() : "void");
/* 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;
+ // Released thd->LOCK_thd_data above as below could end up
+ // close_thread_tables()/close_open_tables()/close_thread_table()/mysql_mutex_lock(&thd->LOCK_thd_data)
close_thread_tables(thd);
+ mysql_mutex_lock(&thd->LOCK_thd_data);
thd->wsrep_conflict_state= RETRY_AUTOCOMMIT;
thd->wsrep_retry_counter++; // grow
wsrep_copy_query(thd);
thd->set_time();
parser_state->reset(rawbuf, length);
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
}
else
{
- WSREP_DEBUG("%s, thd: %lld is_AC: %d, retry: %lu - %lu SQL: %s",
- (thd->wsrep_conflict_state == ABORTED) ?
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+ // This does dirty read to wsrep variables but it is only a debug code
+ WSREP_DEBUG("%s, thd: %lld is_AC: %d, retry: %lu - %lu SQL: %s",
+ (thd->wsrep_conflict_state == ABORTED) ?
"BF Aborted" : "cert failure",
(longlong) thd->thread_id, is_autocommit,
- thd->wsrep_retry_counter,
+ thd->wsrep_retry_counter,
thd->variables.wsrep_retry_autocommit, thd->query());
my_message(ER_LOCK_DEADLOCK, "Deadlock: wsrep aborted transaction",
MYF(0));
+
+ mysql_mutex_lock(&thd->LOCK_thd_data);
thd->wsrep_conflict_state= NO_CONFLICT;
if (thd->wsrep_conflict_state != REPLAYING)
thd->wsrep_retry_counter= 0; // reset
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
}
- mysql_mutex_unlock(&thd->LOCK_thd_data);
+
thd->reset_killed();
}
else
@@ -7960,6 +7986,7 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
#endif /* WITH_WSREP */
}
+
/*
When you modify mysql_parse(), you may need to modify
mysql_test_parse_for_slave() in this same file.
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 3133b94fa5b..96e07b19dd8 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -853,7 +853,7 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
const bool save_agg_field= thd->lex->current_select->non_agg_field_used();
const bool save_agg_func= thd->lex->current_select->agg_func_used();
const nesting_map saved_allow_sum_func= thd->lex->allow_sum_func;
- thd->lex->allow_sum_func= 0;
+ thd->lex->allow_sum_func.clear_all();
if (likely(!(error= func_expr->fix_fields_if_needed(thd, (Item**)&func_expr))))
func_expr->walk(&Item::post_fix_fields_part_expr_processor, 0, NULL);
@@ -1559,7 +1559,7 @@ static bool check_vers_constants(THD *thd, partition_info *part_info)
my_tz_OFFSET0->gmt_sec_to_TIME(&ltime, vers_info->interval.start);
while ((el= it++)->id < hist_parts)
{
- if (date_add_interval(&ltime, vers_info->interval.type,
+ if (date_add_interval(thd, &ltime, vers_info->interval.type,
vers_info->interval.step))
goto err;
uint error= 0;
@@ -2571,6 +2571,18 @@ static int add_key_with_algorithm(String *str, partition_info *part_info)
return err;
}
+char *generate_partition_syntax_for_frm(THD *thd, partition_info *part_info,
+ uint *buf_length,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info)
+{
+ sql_mode_t old_mode= thd->variables.sql_mode;
+ thd->variables.sql_mode &= ~MODE_ANSI_QUOTES;
+ char *res= generate_partition_syntax(thd, part_info, buf_length,
+ true, create_info, alter_info);
+ thd->variables.sql_mode= old_mode;
+ return res;
+}
/*
Generate the partition syntax from the partition data structure.
@@ -8205,7 +8217,7 @@ static int get_part_iter_for_interval_via_mapping(partition_info *part_info,
field->type() == MYSQL_TYPE_DATETIME))
{
/* Monotonic, but return NULL for dates with zeros in month/day. */
- zero_in_start_date= field->get_date(&start_date, 0);
+ zero_in_start_date= field->get_date(&start_date, date_mode_t(0));
DBUG_PRINT("info", ("zero start %u %04d-%02d-%02d",
zero_in_start_date, start_date.year,
start_date.month, start_date.day));
@@ -8229,7 +8241,7 @@ static int get_part_iter_for_interval_via_mapping(partition_info *part_info,
!part_info->part_expr->null_value)
{
MYSQL_TIME end_date;
- bool zero_in_end_date= field->get_date(&end_date, 0);
+ bool zero_in_end_date= field->get_date(&end_date, date_mode_t(0));
/*
This is an optimization for TO_DAYS()/TO_SECONDS() to avoid scanning
the NULL partition for ranges that cannot include a date with 0 as
diff --git a/sql/sql_partition.h b/sql/sql_partition.h
index 170ae8ccee1..83cac8f24ba 100644
--- a/sql/sql_partition.h
+++ b/sql/sql_partition.h
@@ -276,6 +276,10 @@ char *generate_partition_syntax(THD *thd, partition_info *part_info,
bool show_partition_options,
HA_CREATE_INFO *create_info,
Alter_info *alter_info);
+char *generate_partition_syntax_for_frm(THD *thd, partition_info *part_info,
+ uint *buf_length,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info);
bool verify_data_with_partition(TABLE *table, TABLE *part_table,
uint32 part_id);
bool compare_partition_options(HA_CREATE_INFO *table_create_info,
diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc
index 2cc3f247e95..71ab7477391 100644
--- a/sql/sql_partition_admin.cc
+++ b/sql/sql_partition_admin.cc
@@ -1,6 +1,6 @@
/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2014, SkySQL Ab.
- Copyright (c) 2016, MariaDB Corporation
+ Copyright (c) 2016, 2018, MariaDB Corporation.
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
@@ -99,7 +99,7 @@ bool Sql_cmd_alter_table_exchange_partition::execute(THD *thd)
thd->prepare_logs_for_admin_command();
DBUG_RETURN(exchange_partition(thd, first_table, &alter_info));
#ifdef WITH_WSREP
- error:
+ wsrep_error_label:
/* handle errors in TO_ISOLATION here */
DBUG_RETURN(true);
#endif /* WITH_WSREP */
diff --git a/sql/sql_plist.h b/sql/sql_plist.h
index bb9889cc534..4d279af7a0d 100644
--- a/sql/sql_plist.h
+++ b/sql/sql_plist.h
@@ -184,7 +184,12 @@ public:
list= &a;
current= a.m_first;
}
- /* Operator for it++ */
+ /**
+ Operator for it++
+
+ @note since we save next element pointer, caller may remove current element.
+ Such modification doesn't invalidate iterator.
+ */
inline T* operator++(int)
{
T *result= current;
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 8c231d9b8f7..d448b7b9e02 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -280,6 +280,7 @@ struct st_mysql_sys_var
MYSQL_PLUGIN_VAR_HEADER;
};
+enum install_status { INSTALL_GOOD, INSTALL_FAIL_WARN_OK, INSTALL_FAIL_NOT_OK };
/*
sys_var class for access to all plugin variables visible to the user
*/
@@ -1077,7 +1078,7 @@ static st_plugin_int *plugin_insert_or_reuse(struct st_plugin_int *plugin)
NOTE
Requires that a write-lock is held on LOCK_system_variables_hash
*/
-static bool plugin_add(MEM_ROOT *tmp_root,
+static enum install_status plugin_add(MEM_ROOT *tmp_root, bool if_not_exists,
const LEX_CSTRING *name, LEX_CSTRING *dl, myf MyFlags)
{
struct st_plugin_int tmp, *maybe_dupe;
@@ -1088,14 +1089,16 @@ static bool plugin_add(MEM_ROOT *tmp_root,
if (name->str && plugin_find_internal(name, MYSQL_ANY_PLUGIN))
{
+ if (if_not_exists)
+ MyFlags|= ME_NOTE;
my_error(ER_PLUGIN_INSTALLED, MyFlags, name->str);
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(if_not_exists ? INSTALL_FAIL_WARN_OK : INSTALL_FAIL_NOT_OK);
}
/* Clear the whole struct to catch future extensions. */
bzero((char*) &tmp, sizeof(tmp));
fix_dl_name(tmp_root, dl);
if (! (tmp.plugin_dl= plugin_dl_add(dl, MyFlags)))
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(INSTALL_FAIL_NOT_OK);
/* Find plugin by name */
for (plugin= tmp.plugin_dl->plugins; plugin->info; plugin++)
{
@@ -1121,7 +1124,7 @@ static bool plugin_add(MEM_ROOT *tmp_root,
if (plugin->name != maybe_dupe->plugin->name)
{
my_error(ER_UDF_EXISTS, MyFlags, plugin->name);
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(INSTALL_FAIL_NOT_OK);
}
dupes++;
continue; // already installed
@@ -1173,7 +1176,7 @@ static bool plugin_add(MEM_ROOT *tmp_root,
init_alloc_root(&tmp_plugin_ptr->mem_root, "plugin", 4096, 4096, MYF(0));
if (name->str)
- DBUG_RETURN(FALSE); // all done
+ DBUG_RETURN(INSTALL_GOOD); // all done
oks++;
tmp.plugin_dl->ref_count++;
@@ -1191,7 +1194,9 @@ err:
my_error(ER_CANT_FIND_DL_ENTRY, MyFlags, name->str);
plugin_dl_del(tmp.plugin_dl);
- DBUG_RETURN(errs > 0 || oks + dupes == 0);
+ if (errs > 0 || oks + dupes == 0)
+ DBUG_RETURN(INSTALL_FAIL_NOT_OK);
+ DBUG_RETURN(INSTALL_GOOD);
}
static void plugin_variables_deinit(struct st_plugin_int *plugin)
@@ -1847,7 +1852,7 @@ static void plugin_load(MEM_ROOT *tmp_root)
the mutex here to satisfy the assert
*/
mysql_mutex_lock(&LOCK_plugin);
- plugin_add(tmp_root, &name, &dl, MYF(ME_ERROR_LOG));
+ plugin_add(tmp_root, false, &name, &dl, MYF(ME_ERROR_LOG));
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
mysql_mutex_unlock(&LOCK_plugin);
}
@@ -1870,7 +1875,7 @@ end:
static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list)
{
char buffer[FN_REFLEN];
- LEX_STRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name;
+ LEX_CSTRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name;
char *p= buffer;
DBUG_ENTER("plugin_load_list");
while (list)
@@ -1889,7 +1894,7 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list)
#ifndef __WIN__
case ':': /* can't use this as delimiter as it may be drive letter */
#endif
- str->str[str->length]= '\0';
+ p[-1]= 0;
if (str == &name) // load all plugins in named module
{
if (!name.length)
@@ -1902,16 +1907,16 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list)
mysql_mutex_lock(&LOCK_plugin);
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
name.str= 0; // load everything
- if (plugin_add(tmp_root, (LEX_CSTRING*) &name, (LEX_CSTRING*) &dl,
- MYF(ME_ERROR_LOG)))
+ if (plugin_add(tmp_root, false, &name, &dl,
+ MYF(ME_ERROR_LOG)) != INSTALL_GOOD)
goto error;
}
else
{
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
mysql_mutex_lock(&LOCK_plugin);
- if (plugin_add(tmp_root, (LEX_CSTRING*) &name, (LEX_CSTRING*) &dl,
- MYF(ME_ERROR_LOG)))
+ if (plugin_add(tmp_root, false, &name, &dl,
+ MYF(ME_ERROR_LOG)) != INSTALL_GOOD)
goto error;
}
mysql_mutex_unlock(&LOCK_plugin);
@@ -1923,7 +1928,7 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list)
case '#':
if (str == &name)
{
- name.str[name.length]= '\0';
+ p[-1]= 0;
str= &dl;
str->str= p;
continue;
@@ -2146,7 +2151,7 @@ bool mysql_install_plugin(THD *thd, const LEX_CSTRING *name,
TABLE_LIST tables;
TABLE *table;
LEX_CSTRING dl= *dl_arg;
- bool error;
+ enum install_status error;
int argc=orig_argc;
char **argv=orig_argv;
unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE] =
@@ -2194,12 +2199,14 @@ bool mysql_install_plugin(THD *thd, const LEX_CSTRING *name,
mysql_audit_acquire_plugins(thd, event_class_mask);
mysql_mutex_lock(&LOCK_plugin);
- error= plugin_add(thd->mem_root, name, &dl, MYF(0));
- if (unlikely(error))
+ error= plugin_add(thd->mem_root, thd->lex->create_info.if_not_exists(),
+ name, &dl, MYF(0));
+ if (unlikely(error != INSTALL_GOOD))
goto err;
if (name->str)
- error= finalize_install(thd, table, name, &argc, argv);
+ error= finalize_install(thd, table, name, &argc, argv)
+ ? INSTALL_FAIL_NOT_OK : INSTALL_GOOD;
else
{
st_plugin_dl *plugin_dl= plugin_dl_find(&dl);
@@ -2207,11 +2214,12 @@ bool mysql_install_plugin(THD *thd, const LEX_CSTRING *name,
for (plugin= plugin_dl->plugins; plugin->info; plugin++)
{
LEX_CSTRING str= { plugin->name, strlen(plugin->name) };
- error|= finalize_install(thd, table, &str, &argc, argv);
+ if (finalize_install(thd, table, &str, &argc, argv))
+ error= INSTALL_FAIL_NOT_OK;
}
}
- if (unlikely(error))
+ if (unlikely(error != INSTALL_GOOD))
{
reap_needed= true;
reap_plugins();
@@ -2220,11 +2228,11 @@ err:
mysql_mutex_unlock(&LOCK_plugin);
if (argv)
free_defaults(argv);
- DBUG_RETURN(error);
+ DBUG_RETURN(error == INSTALL_FAIL_NOT_OK);
#ifdef WITH_WSREP
-error:
- DBUG_RETURN(TRUE);
-#endif /* WITH_WSREP */
+wsrep_error_label:
+ DBUG_RETURN(true);
+#endif
}
@@ -2236,8 +2244,9 @@ static bool do_uninstall(THD *thd, TABLE *table, const LEX_CSTRING *name)
if (!(plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)) ||
plugin->state & (PLUGIN_IS_UNINITIALIZED | PLUGIN_IS_DYING))
{
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str);
- return 1;
+ myf MyFlags= thd->lex->if_exists() ? ME_NOTE : 0;
+ my_error(ER_SP_DOES_NOT_EXIST, MyFlags, "PLUGIN", name->str);
+ return !MyFlags;
}
if (!plugin->plugin_dl)
{
@@ -2300,7 +2309,7 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_CSTRING *name,
if (!opt_noacl && check_table_access(thd, DELETE_ACL, &tables, FALSE, 1, FALSE))
DBUG_RETURN(TRUE);
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
/* need to open before acquiring LOCK_plugin or it will deadlock */
if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
@@ -2359,8 +2368,9 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_CSTRING *name,
}
else
{
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SONAME", dl.str);
- error= true;
+ myf MyFlags= thd->lex->if_exists() ? ME_NOTE : 0;
+ my_error(ER_SP_DOES_NOT_EXIST, MyFlags, "SONAME", dl.str);
+ error|= !MyFlags;
}
}
reap_plugins();
@@ -2368,9 +2378,9 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_CSTRING *name,
mysql_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(error);
#ifdef WITH_WSREP
-error:
- DBUG_RETURN(TRUE);
-#endif /* WITH_WSREP */
+wsrep_error_label:
+ DBUG_RETURN(true);
+#endif
}
diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic
index 47decf38973..8de53aa2161 100644
--- a/sql/sql_plugin_services.ic
+++ b/sql/sql_plugin_services.ic
@@ -181,7 +181,8 @@ static struct wsrep_service_st wsrep_handler = {
wsrep_thd_ws_handle,
wsrep_trx_is_aborting,
wsrep_trx_order_before,
- wsrep_unlock_rollback
+ wsrep_unlock_rollback,
+ wsrep_set_data_home_dir
};
static struct thd_specifics_service_st thd_specifics_handler=
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index c615356b354..6def798b1c7 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -893,6 +893,7 @@ static bool insert_params(Prepared_statement *stmt, uchar *null_array,
DBUG_RETURN(1);
if (param->convert_str_value(stmt->thd))
DBUG_RETURN(1); /* out of memory */
+ param->sync_clones();
}
DBUG_RETURN(0);
}
@@ -941,6 +942,7 @@ static bool insert_bulk_params(Prepared_statement *stmt,
}
else
DBUG_RETURN(1); // long is not supported here
+ param->sync_clones();
}
DBUG_RETURN(0);
}
@@ -969,6 +971,7 @@ static bool set_conversion_functions(Prepared_statement *stmt,
read_pos+= 2;
(**it).unsigned_flag= MY_TEST(typecode & signed_bit);
(*it)->setup_conversion(thd, (uchar) (typecode & 0xff));
+ (*it)->sync_clones();
}
*data= read_pos;
DBUG_RETURN(0);
@@ -1039,6 +1042,7 @@ static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
if (param->has_no_value())
DBUG_RETURN(1);
}
+ param->sync_clones();
}
if (param->convert_str_value(thd))
DBUG_RETURN(1); /* out of memory */
@@ -1081,6 +1085,7 @@ static bool emb_insert_params_with_log(Prepared_statement *stmt, String *query)
if (param->convert_str_value(thd))
DBUG_RETURN(1); /* out of memory */
+ param->sync_clones();
}
if (acc.finalize())
DBUG_RETURN(1);
@@ -1136,7 +1141,11 @@ swap_parameter_array(Item_param **param_array_dst,
Item_param **end= param_array_dst + param_count;
for (; dst < end; ++src, ++dst)
+ {
(*dst)->set_param_type_and_swap_value(*src);
+ (*dst)->sync_clones();
+ (*src)->sync_clones();
+ }
}
@@ -1167,6 +1176,7 @@ insert_params_from_actual_params(Prepared_statement *stmt,
if (ps_param->save_in_param(stmt->thd, param) ||
param->convert_str_value(stmt->thd))
DBUG_RETURN(1);
+ param->sync_clones();
}
DBUG_RETURN(0);
}
@@ -1209,6 +1219,8 @@ insert_params_from_actual_params_with_log(Prepared_statement *stmt,
if (param->convert_str_value(thd))
DBUG_RETURN(1);
+
+ param->sync_clones();
}
if (acc.finalize())
DBUG_RETURN(1);
@@ -1582,7 +1594,7 @@ static bool mysql_test_do_fields(Prepared_statement *stmt,
DBUG_RETURN(TRUE);
if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL,
- DT_PREPARE | DT_CREATE))
+ DT_INIT | DT_PREPARE | DT_CREATE))
DBUG_RETURN(TRUE);
DBUG_RETURN(setup_fields(thd, Ref_ptr_array(),
*values, COLUMNS_READ, 0, NULL, 0));
@@ -1614,7 +1626,7 @@ static bool mysql_test_set_fields(Prepared_statement *stmt,
if ((tables &&
check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE)) ||
open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL,
- DT_PREPARE | DT_CREATE))
+ DT_INIT | DT_PREPARE | DT_CREATE))
goto error;
while ((var= it++))
@@ -1651,7 +1663,8 @@ static bool mysql_test_call_fields(Prepared_statement *stmt,
if ((tables &&
check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE)) ||
- open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL, DT_PREPARE))
+ open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL,
+ DT_INIT | DT_PREPARE))
goto err;
while ((item= it++))
@@ -1777,7 +1790,7 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
if (open_normal_and_derived_tables(stmt->thd, lex->query_tables,
MYSQL_OPEN_FORCE_SHARED_MDL,
- DT_PREPARE | DT_CREATE))
+ DT_INIT | DT_PREPARE | DT_CREATE))
DBUG_RETURN(TRUE);
select_lex->context.resolve_in_select_list= TRUE;
@@ -1798,7 +1811,7 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
*/
if (open_normal_and_derived_tables(stmt->thd, lex->query_tables,
MYSQL_OPEN_FORCE_SHARED_MDL,
- DT_PREPARE))
+ DT_INIT | DT_PREPARE))
DBUG_RETURN(TRUE);
}
@@ -2025,7 +2038,7 @@ static bool mysql_test_create_view(Prepared_statement *stmt)
lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW;
if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL,
- DT_PREPARE))
+ DT_INIT | DT_PREPARE))
goto err;
res= select_like_stmt_test(stmt, 0, 0);
@@ -3030,7 +3043,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
lex->result->cleanup();
lex->result->set_thd(thd);
}
- lex->allow_sum_func= 0;
+ lex->allow_sum_func.clear_all();
lex->in_sum_func= NULL;
DBUG_VOID_RETURN;
}
@@ -3201,7 +3214,7 @@ static void mysql_stmt_execute_common(THD *thd,
sp_cache_enforce_limit(thd->sp_package_body_cache, stored_program_cache_size);
/* Close connection socket; for use with client testing (Bug#43560). */
- DBUG_EXECUTE_IF("close_conn_after_stmt_execute", vio_close(thd->net.vio););
+ DBUG_EXECUTE_IF("close_conn_after_stmt_execute", vio_shutdown(thd->net.vio,SHUT_RD););
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc
index 9bcb9a30a4c..abdf9d76d15 100644
--- a/sql/sql_reload.cc
+++ b/sql/sql_reload.cc
@@ -289,9 +289,18 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
*/
if (tables)
{
+ int err;
for (TABLE_LIST *t= tables; t; t= t->next_local)
- if (!find_table_for_mdl_upgrade(thd, t->db.str, t->table_name.str, false))
- return 1;
+ if (!find_table_for_mdl_upgrade(thd, t->db.str, t->table_name.str, &err))
+ {
+ if (is_locked_view(thd, t))
+ t->next_local= t->next_global;
+ else
+ {
+ my_error(err, MYF(0), t->table_name.str);
+ return 1;
+ }
+ }
}
else
{
@@ -616,4 +625,3 @@ static void disable_checkpoints(THD *thd)
ha_checkpoint_state(1); // Disable checkpoints
}
}
-
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 616fea0f401..8f55497d8d0 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -293,6 +293,9 @@ static bool find_order_in_list(THD *, Ref_ptr_array, TABLE_LIST *, ORDER *,
static double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
table_map rem_tables);
void set_postjoin_aggr_write_func(JOIN_TAB *tab);
+
+static Item **get_sargable_cond(JOIN *join, TABLE *table);
+
#ifndef DBUG_OFF
/*
@@ -643,7 +646,7 @@ setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array,
const bool saved_non_agg_field_used= select->non_agg_field_used();
DBUG_ENTER("setup_without_group");
- thd->lex->allow_sum_func&= ~((nesting_map)1 << select->nest_level);
+ thd->lex->allow_sum_func.clear_bit(select->nest_level);
res= setup_conds(thd, tables, leaves, conds);
if (thd->lex->current_select->first_cond_optimization)
{
@@ -656,18 +659,18 @@ setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array,
/* it's not wrong to have non-aggregated columns in a WHERE */
select->set_non_agg_field_used(saved_non_agg_field_used);
- thd->lex->allow_sum_func|= (nesting_map)1 << select->nest_level;
+ thd->lex->allow_sum_func.set_bit(select->nest_level);
save_place= thd->lex->current_select->context_analysis_place;
thd->lex->current_select->context_analysis_place= IN_ORDER_BY;
res= res || setup_order(thd, ref_pointer_array, tables, fields, all_fields,
order);
- thd->lex->allow_sum_func&= ~((nesting_map)1 << select->nest_level);
+ thd->lex->allow_sum_func.clear_bit(select->nest_level);
thd->lex->current_select->context_analysis_place= IN_GROUP_BY;
res= res || setup_group(thd, ref_pointer_array, tables, fields, all_fields,
group, hidden_group_fields);
thd->lex->current_select->context_analysis_place= save_place;
- thd->lex->allow_sum_func|= (nesting_map)1 << select->nest_level;
+ thd->lex->allow_sum_func.set_bit(select->nest_level);
res= res || setup_windows(thd, ref_pointer_array, tables, fields, all_fields,
win_specs, win_funcs);
thd->lex->allow_sum_func= save_allow_sum_func;
@@ -1115,7 +1118,7 @@ JOIN::prepare(TABLE_LIST *tables_init,
select_lex->master_unit()->global_parameters())
{
nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
- thd->lex->allow_sum_func|= (nesting_map)1 << select_lex->nest_level;
+ thd->lex->allow_sum_func.set_bit(select_lex->nest_level);
thd->where= "order clause";
for (ORDER *order= select_lex->order_list.first; order; order= order->next)
{
@@ -1133,7 +1136,7 @@ JOIN::prepare(TABLE_LIST *tables_init,
{
nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
thd->where="having clause";
- thd->lex->allow_sum_func|= (nesting_map)1 << select_lex_arg->nest_level;
+ thd->lex->allow_sum_func.set_bit(select_lex_arg->nest_level);
select_lex->having_fix_field= 1;
/*
Wrap alone field in HAVING clause in case it will be outer field
@@ -1643,6 +1646,13 @@ JOIN::optimize_inner()
if (optimize_constant_subqueries())
DBUG_RETURN(1);
+ if (conds && conds->with_subquery())
+ (void) conds->walk(&Item::cleanup_is_expensive_cache_processor,
+ 0, (void *) 0);
+ if (having && having->with_subquery())
+ (void) having->walk(&Item::cleanup_is_expensive_cache_processor,
+ 0, (void *) 0);
+
List<Item> eq_list;
if (setup_degenerate_jtbm_semi_joins(this, join_list, eq_list))
@@ -1688,8 +1698,14 @@ JOIN::optimize_inner()
conds= optimize_cond(this, conds, join_list, FALSE,
&cond_value, &cond_equal, OPT_LINK_EQUAL_FIELDS);
- if (thd->lex->sql_command == SQLCOM_SELECT &&
- optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY))
+ if (thd->is_error())
+ {
+ error= 1;
+ DBUG_PRINT("error",("Error from optimize_cond"));
+ DBUG_RETURN(1);
+ }
+
+ if (optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY))
{
TABLE_LIST *tbl;
List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables);
@@ -1714,8 +1730,7 @@ JOIN::optimize_inner()
DBUG_RETURN(TRUE);
}
- if (thd->lex->sql_command == SQLCOM_SELECT &&
- optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED))
+ if (optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED))
{
TABLE_LIST *tbl;
List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables);
@@ -1753,13 +1768,6 @@ JOIN::optimize_inner()
DBUG_RETURN(1);
}
- if (unlikely(thd->is_error()))
- {
- error= 1;
- DBUG_PRINT("error",("Error from optimize_cond"));
- DBUG_RETURN(1);
- }
-
{
having= optimize_cond(this, having, join_list, TRUE,
&having_value, &having_equal);
@@ -1810,19 +1818,9 @@ JOIN::optimize_inner()
List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables);
while ((tbl= li++))
{
- /*
- If tbl->embedding!=NULL that means that this table is in the inner
- part of the nested outer join, and we can't do partition pruning
- (TODO: check if this limitation can be lifted)
- */
- if (!tbl->embedding ||
- (tbl->embedding && tbl->embedding->sj_on_expr))
- {
- Item *prune_cond= tbl->on_expr? tbl->on_expr : conds;
- tbl->table->all_partitions_pruned_away= prune_partitions(thd,
- tbl->table,
- prune_cond);
- }
+ Item **prune_cond= get_sargable_cond(this, tbl->table);
+ tbl->table->all_partitions_pruned_away=
+ prune_partitions(thd, tbl->table, *prune_cond);
}
}
#endif
@@ -1919,6 +1917,14 @@ JOIN::optimize_inner()
error= 1;
DBUG_RETURN(1);
}
+ if (!group_list)
+ {
+ /* The output has only one row */
+ order=0;
+ simple_order=1;
+ group_optimized_away= 1;
+ select_distinct=0;
+ }
}
/* Calculate how to do the join */
@@ -3159,7 +3165,7 @@ bool JOIN::make_aggr_tables_info()
remove_duplicates() assumes there is a preceding computation step (and
in the degenerate join, there's none)
*/
- if (top_join_tab_count)
+ if (top_join_tab_count && tables_list)
curr_tab->distinct= true;
having= NULL;
@@ -3805,7 +3811,7 @@ bool JOIN::save_explain_data(Explain_query *output, bool can_overwrite,
If there is SELECT in this statement with the same number it must be the
same SELECT
*/
- DBUG_ASSERT(select_lex->select_number == UINT_MAX ||
+ DBUG_SLOW_ASSERT(select_lex->select_number == UINT_MAX ||
select_lex->select_number == INT_MAX ||
!output ||
!output->get_select(select_lex->select_number) ||
@@ -4342,6 +4348,84 @@ struct SARGABLE_PARAM
};
+/*
+ Mark all tables inside a join nest as constant.
+
+ @detail This is called when there is a local "Impossible WHERE" inside
+ a multi-table LEFT JOIN.
+*/
+
+void mark_join_nest_as_const(JOIN *join,
+ TABLE_LIST *join_nest,
+ table_map *found_const_table_map,
+ uint *const_count)
+{
+ List_iterator<TABLE_LIST> it(join_nest->nested_join->join_list);
+ TABLE_LIST *tbl;
+ while ((tbl= it++))
+ {
+ if (tbl->nested_join)
+ {
+ mark_join_nest_as_const(join, tbl, found_const_table_map, const_count);
+ continue;
+ }
+ JOIN_TAB *tab= tbl->table->reginfo.join_tab;
+
+ if (!(join->const_table_map & tab->table->map))
+ {
+ tab->type= JT_CONST;
+ tab->info= ET_IMPOSSIBLE_ON_CONDITION;
+ tab->table->const_table= 1;
+
+ join->const_table_map|= tab->table->map;
+ *found_const_table_map|= tab->table->map;
+ set_position(join,(*const_count)++,tab,(KEYUSE*) 0);
+ mark_as_null_row(tab->table); // All fields are NULL
+ }
+ }
+}
+
+
+/*
+ @brief Get the condition that can be used to do range analysis/partition
+ pruning/etc
+
+ @detail
+ Figure out which condition we can use:
+ - For INNER JOIN, we use the WHERE,
+ - "t1 LEFT JOIN t2 ON ..." uses t2's ON expression
+ - "t1 LEFT JOIN (...) ON ..." uses the join nest's ON expression.
+*/
+
+static Item **get_sargable_cond(JOIN *join, TABLE *table)
+{
+ Item **retval;
+ if (table->pos_in_table_list->on_expr)
+ {
+ /*
+ This is an inner table from a single-table LEFT JOIN, "t1 LEFT JOIN
+ t2 ON cond". Use the condition cond.
+ */
+ retval= &table->pos_in_table_list->on_expr;
+ }
+ else if (table->pos_in_table_list->embedding &&
+ !table->pos_in_table_list->embedding->sj_on_expr)
+ {
+ /*
+ This is the inner side of a multi-table outer join. Use the
+ appropriate ON expression.
+ */
+ retval= &(table->pos_in_table_list->embedding->on_expr);
+ }
+ else
+ {
+ /* The table is not inner wrt some LEFT JOIN. Use the WHERE clause */
+ retval= &join->conds;
+ }
+ return retval;
+}
+
+
/**
Calculate the best possible join and initialize the join structure.
@@ -4619,8 +4703,8 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
int ref_changed;
do
{
- more_const_tables_found:
ref_changed = 0;
+ more_const_tables_found:
found_ref=0;
/*
@@ -4789,7 +4873,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
}
}
}
- } while (join->const_table_map & found_ref && ref_changed);
+ } while (ref_changed);
join->sort_by_table= get_sort_by_table(join->order, join->group_list,
join->select_lex->leaf_tables,
@@ -4913,39 +4997,38 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
/*
Perform range analysis if there are keys it could use (1).
- Don't do range analysis if we're on the inner side of an outer join (2).
- Do range analysis if we're on the inner side of a semi-join (3).
- Don't do range analysis for materialized subqueries (4).
- Don't do range analysis for materialized derived tables (5)
+ Don't do range analysis for materialized subqueries (2).
+ Don't do range analysis for materialized derived tables (3)
*/
if ((!s->const_keys.is_clear_all() ||
!bitmap_is_clear_all(&s->table->cond_set)) && // (1)
- (!s->table->pos_in_table_list->embedding || // (2)
- (s->table->pos_in_table_list->embedding && // (3)
- s->table->pos_in_table_list->embedding->sj_on_expr)) && // (3)
- !s->table->is_filled_at_execution() && // (4)
- !(s->table->pos_in_table_list->derived && // (5)
- s->table->pos_in_table_list->is_materialized_derived())) // (5)
+ !s->table->is_filled_at_execution() && // (2)
+ !(s->table->pos_in_table_list->derived && // (3)
+ s->table->pos_in_table_list->is_materialized_derived())) // (3)
{
bool impossible_range= FALSE;
ha_rows records= HA_POS_ERROR;
SQL_SELECT *select= 0;
+ Item **sargable_cond= NULL;
if (!s->const_keys.is_clear_all())
{
+ sargable_cond= get_sargable_cond(join, s->table);
+
select= make_select(s->table, found_const_table_map,
found_const_table_map,
- *s->on_expr_ref ? *s->on_expr_ref : join->conds,
+ *sargable_cond,
(SORT_INFO*) 0,
1, &error);
if (!select)
goto error;
records= get_quick_record_count(join->thd, select, s->table,
&s->const_keys, join->row_limit);
- /* Range analyzer could modify the condition. */
- if (*s->on_expr_ref)
- *s->on_expr_ref= select->cond;
- else
- join->conds= select->cond;
+
+ /*
+ Range analyzer might have modified the condition. Put it the new
+ condition to where we got it from.
+ */
+ *sargable_cond= select->cond;
s->quick=select->quick;
s->needed_reg=select->needed_reg;
@@ -4958,10 +5041,11 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
}
if (!impossible_range)
{
+ if (!sargable_cond)
+ sargable_cond= get_sargable_cond(join, s->table);
if (join->thd->variables.optimizer_use_condition_selectivity > 1)
calculate_cond_selectivity_for_table(join->thd, s->table,
- *s->on_expr_ref ?
- s->on_expr_ref : &join->conds);
+ sargable_cond);
if (s->table->reginfo.impossible_range)
{
impossible_range= TRUE;
@@ -4970,23 +5054,33 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
}
if (impossible_range)
{
- /*
- Impossible WHERE or ON expression
- In case of ON, we mark that the we match one empty NULL row.
- In case of WHERE, don't set found_const_table_map to get the
- caller to abort with a zero row result.
- */
- join->const_table_map|= s->table->map;
- set_position(join,const_count++,s,(KEYUSE*) 0);
- s->type= JT_CONST;
- s->table->const_table= 1;
- if (*s->on_expr_ref)
- {
- /* Generate empty row */
- s->info= ET_IMPOSSIBLE_ON_CONDITION;
- found_const_table_map|= s->table->map;
- mark_as_null_row(s->table); // All fields are NULL
- }
+ /*
+ Impossible WHERE or ON expression
+ In case of ON, we mark that the we match one empty NULL row.
+ In case of WHERE, don't set found_const_table_map to get the
+ caller to abort with a zero row result.
+ */
+ TABLE_LIST *emb= s->table->pos_in_table_list->embedding;
+ if (emb && !emb->sj_on_expr)
+ {
+ /* Mark all tables in a multi-table join nest as const */
+ mark_join_nest_as_const(join, emb, &found_const_table_map,
+ &const_count);
+ }
+ else
+ {
+ join->const_table_map|= s->table->map;
+ set_position(join,const_count++,s,(KEYUSE*) 0);
+ s->type= JT_CONST;
+ s->table->const_table= 1;
+ if (*s->on_expr_ref)
+ {
+ /* Generate empty row */
+ s->info= ET_IMPOSSIBLE_ON_CONDITION;
+ found_const_table_map|= s->table->map;
+ mark_as_null_row(s->table); // All fields are NULL
+ }
+ }
}
if (records != HA_POS_ERROR)
{
@@ -6575,7 +6669,7 @@ add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab)
Item_field *cur_item;
key_map possible_keys(0);
- if (join->group_list || join->simple_group)
+ if (join->group_list)
{ /* Collect all query fields referenced in the GROUP clause. */
for (cur_group= join->group_list; cur_group; cur_group= cur_group->next)
(*cur_group->item)->walk(&Item::collect_item_field_processor, 0,
@@ -7310,8 +7404,13 @@ best_access_path(JOIN *join,
tmp+= (s->records - rnd_records)/(double) TIME_FOR_COMPARE;
}
}
+
double best_records= rnd_records;
- tmp += s->startup_cost;
+ /* Splitting technique cannot be used with join cache */
+ if (s->table->is_splittable())
+ tmp+= s->table->get_materialization_cost();
+ else
+ tmp+= s->startup_cost;
filter= s->table->best_filter_for_current_join_order(MAX_KEY,
rnd_records,
@@ -7341,6 +7440,7 @@ best_access_path(JOIN *join,
best_ref_depends_map= 0;
best_uses_jbuf= MY_TEST(!disable_jbuf && !((s->table->map &
join->outer_join)));
+ spl_plan= 0;
}
}
@@ -9050,8 +9150,13 @@ bool JOIN_TAB::keyuse_is_valid_for_access_in_chosen_plan(JOIN *join,
st_select_lex *sjm_sel= emb_sj_nest->sj_subq_pred->unit->first_select();
for (uint i= 0; i < sjm_sel->item_list.elements; i++)
{
- if (sjm_sel->ref_pointer_array[i] == keyuse->val)
- return true;
+ DBUG_ASSERT(sjm_sel->ref_pointer_array[i]->real_item()->type() == Item::FIELD_ITEM);
+ if (keyuse->val->real_item()->type() == Item::FIELD_ITEM)
+ {
+ Field *field = ((Item_field*)sjm_sel->ref_pointer_array[i]->real_item())->field;
+ if (field->eq(((Item_field*)keyuse->val->real_item())->field))
+ return true;
+ }
}
return false;
}
@@ -9702,7 +9807,6 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
if (first_keyuse)
{
key_parts++;
- first_keyuse= FALSE;
}
else
{
@@ -9712,7 +9816,7 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
if (curr->keypart == keyuse->keypart &&
!(~used_tables & curr->used_tables) &&
join_tab->keyuse_is_valid_for_access_in_chosen_plan(join,
- keyuse) &&
+ curr) &&
are_tables_local(join_tab, curr->used_tables))
break;
}
@@ -9720,6 +9824,7 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
key_parts++;
}
}
+ first_keyuse= FALSE;
keyuse++;
} while (keyuse->table == table && keyuse->is_for_hash_join());
if (!key_parts)
@@ -11677,7 +11782,15 @@ uint check_join_cache_usage(JOIN_TAB *tab,
effort now.
*/
if (tab->table->pos_in_table_list->is_materialized_derived())
+ {
no_bka_cache= true;
+ /*
+ Don't use hash join algorithm if the temporary table for the rows
+ of the derived table will be created with an equi-join key.
+ */
+ if (tab->table->s->keys)
+ no_hashed_cache= true;
+ }
/*
Don't use join buffering if we're dictated not to by no_jbuf_after
@@ -22111,11 +22224,30 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
tmp_map.clear_all(); // Force the creation of quick select
tmp_map.set_bit(best_key); // only best_key.
select->quick= 0;
+
+ bool cond_saved= false;
+ Item *saved_cond;
+
+ /*
+ Index Condition Pushdown may have removed parts of the condition for
+ this table. Temporarily put them back because we want the whole
+ condition for the range analysis.
+ */
+ if (select->pre_idx_push_select_cond)
+ {
+ saved_cond= select->cond;
+ select->cond= select->pre_idx_push_select_cond;
+ cond_saved= true;
+ }
+
select->test_quick_select(join->thd, tmp_map, 0,
join->select_options & OPTION_FOUND_ROWS ?
HA_POS_ERROR :
join->unit->select_limit_cnt,
TRUE, FALSE, FALSE);
+
+ if (cond_saved)
+ select->cond= saved_cond;
}
order_direction= best_key_direction;
/*
@@ -23119,7 +23251,8 @@ setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
return 1;
}
}
- if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY)
+ if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
+ context_analysis_place == IN_GROUP_BY)
{
/*
Don't allow one to use fields that is not used in GROUP BY
@@ -26087,7 +26220,7 @@ void TABLE_LIST::print(THD *thd, table_map eliminated_tables, String *str,
LEX_CSTRING t_alias= alias;
str->append(' ');
- if (lower_case_table_names== 1)
+ if (lower_case_table_names == 1)
{
if (alias.str && alias.str[0])
{
@@ -27292,9 +27425,10 @@ AGGR_OP::end_send()
// Update ref array
join_tab->join->set_items_ref_array(*join_tab->ref_array);
+ bool keep_last_filesort_result = join_tab->filesort ? false : true;
if (join_tab->window_funcs_step)
{
- if (join_tab->window_funcs_step->exec(join))
+ if (join_tab->window_funcs_step->exec(join, keep_last_filesort_result))
return NESTED_LOOP_ERROR;
}
@@ -27348,6 +27482,12 @@ AGGR_OP::end_send()
}
}
+ if (keep_last_filesort_result)
+ {
+ delete join_tab->filesort_result;
+ join_tab->filesort_result= NULL;
+ }
+
// Finish rnd scn after sending records
if (join_tab->table->file->inited)
join_tab->table->file->ha_rnd_end();
diff --git a/sql/sql_select.h b/sql/sql_select.h
index de3dff46189..1d08b746279 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -263,8 +263,12 @@ typedef struct st_join_table {
/*
Pointer to the associated ON expression. on_expr_ref=!NULL except for
degenerate joins.
- *on_expr_ref!=NULL for tables that are first inner tables within an outer
- join.
+
+ Optimization phase: *on_expr_ref!=NULL for tables that are the single
+ tables on the inner side of the outer join (t1 LEFT JOIN t2 ON...)
+
+ Execution phase: *on_expr_ref!=NULL for tables that are first inner tables
+ within an outer join (which may have multiple tables)
*/
Item **on_expr_ref;
COND_EQUAL *cond_equal; /**< multiple equalities for the on expression */
diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc
index baaa4571c9e..1ed0bb38e64 100644
--- a/sql/sql_sequence.cc
+++ b/sql/sql_sequence.cc
@@ -542,7 +542,8 @@ void sequence_definition::adjust_values(longlong next_value)
if ((real_increment= global_system_variables.auto_increment_increment)
!= 1)
- offset= global_system_variables.auto_increment_offset;
+ offset= (global_system_variables.auto_increment_offset %
+ global_system_variables.auto_increment_increment);
/*
Ensure that next_free_value has the right offset, so that we
@@ -564,7 +565,7 @@ void sequence_definition::adjust_values(longlong next_value)
else
{
next_free_value+= to_add;
- DBUG_ASSERT(next_free_value % real_increment == offset);
+ DBUG_ASSERT(llabs(next_free_value % real_increment) == offset);
}
}
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index e8f42003691..b98f8aabdc1 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2616,7 +2616,7 @@ static int show_create_view(THD *thd, TABLE_LIST *table, String *buff)
We can't just use table->query, because our SQL_MODE may trigger
a different syntax, like when ANSI_QUOTES is defined.
*/
- table->view->unit.print(buff, enum_query_type(QT_ORDINARY |
+ table->view->unit.print(buff, enum_query_type(QT_VIEW_INTERNAL |
QT_ITEM_ORIGINAL_FUNC_NULLIF));
if (table->with_check != VIEW_CHECK_NONE)
@@ -5009,9 +5009,7 @@ public:
const char* msg,
Sql_condition ** cond_hdl)
{
- if (sql_errno == ER_PARSE_ERROR ||
- sql_errno == ER_TRG_NO_DEFINER ||
- sql_errno == ER_TRG_NO_CREATION_CTX)
+ if (sql_errno == ER_TRG_NO_DEFINER || sql_errno == ER_TRG_NO_CREATION_CTX)
return true;
if (*level != Sql_condition::WARN_LEVEL_ERROR)
@@ -6795,6 +6793,42 @@ store_constraints(THD *thd, TABLE *table, const LEX_CSTRING *db_name,
return schema_table_store_record(thd, table);
}
+static int get_check_constraints_record(THD *thd, TABLE_LIST *tables,
+ TABLE *table, bool res,
+ const LEX_CSTRING *db_name,
+ const LEX_CSTRING *table_name)
+{
+ DBUG_ENTER("get_check_constraints_record");
+ if (res)
+ {
+ if (thd->is_error())
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ thd->get_stmt_da()->sql_errno(),
+ thd->get_stmt_da()->message());
+ thd->clear_error();
+ DBUG_RETURN(0);
+ }
+ else if (!tables->view)
+ {
+ if (tables->table->s->table_check_constraints)
+ {
+ for (uint i= 0; i < tables->table->s->table_check_constraints; i++)
+ {
+ StringBuffer<MAX_FIELD_WIDTH> str(system_charset_info);
+ Virtual_column_info *check= tables->table->check_constraints[i];
+ restore_record(table, s->default_values);
+ table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info);
+ table->field[1]->store(db_name->str, db_name->length, system_charset_info);
+ table->field[2]->store(check->name.str, check->name.length, system_charset_info);
+ table->field[3]->store(table_name->str, table_name->length, system_charset_info);
+ check->print(&str);
+ table->field[4]->store(str.ptr(), str.length(), system_charset_info);
+ schema_table_store_record(thd, table);
+ }
+ }
+ }
+ DBUG_RETURN(res);
+}
static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables,
TABLE *table, bool res,
@@ -9715,6 +9749,18 @@ ST_FIELD_INFO spatial_ref_sys_fields_info[]=
#endif /*HAVE_SPATIAL*/
+ST_FIELD_INFO check_constraints_fields_info[]=
+{
+ {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
+ {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
+ OPEN_FULL_TABLE},
+ {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
+ OPEN_FULL_TABLE},
+ {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
+ {"CHECK_CLAUSE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
+ OPEN_FULL_TABLE},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+};
/*
Description of ST_FIELD_INFO in table.h
@@ -9730,6 +9776,8 @@ ST_SCHEMA_TABLE schema_tables[]=
fill_schema_applicable_roles, 0, 0, -1, -1, 0, 0},
{"CHARACTER_SETS", charsets_fields_info, 0,
fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0, 0},
+ {"CHECK_CONSTRAINTS", check_constraints_fields_info, 0,
+ get_all_tables, 0, get_check_constraints_record, 1, 2, 0, OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
{"COLLATIONS", collation_fields_info, 0,
fill_schema_collation, make_old_format, 0, -1, -1, 0, 0},
{"COLLATION_CHARACTER_SET_APPLICABILITY", coll_charset_app_fields_info,
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index 00ed7fb0202..04806f07b3b 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -3060,6 +3060,39 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
/**
+ @breif
+ Cleanup of min/max statistical values for table share
+*/
+
+void delete_stat_values_for_table_share(TABLE_SHARE *table_share)
+{
+ TABLE_STATISTICS_CB *stats_cb= &table_share->stats_cb;
+ Table_statistics *table_stats= stats_cb->table_stats;
+ if (!table_stats)
+ return;
+ Column_statistics *column_stats= table_stats->column_stats;
+ if (!column_stats)
+ return;
+
+ for (Field **field_ptr= table_share->field;
+ *field_ptr;
+ field_ptr++, column_stats++)
+ {
+ if (column_stats->min_value)
+ {
+ delete column_stats->min_value;
+ column_stats->min_value= NULL;
+ }
+ if (column_stats->max_value)
+ {
+ delete column_stats->max_value;
+ column_stats->max_value= NULL;
+ }
+ }
+}
+
+
+/**
@brief
Check whether any statistics is to be read for tables from a table list
@@ -3239,6 +3272,9 @@ int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables)
if (!tl->is_view_or_derived() && !is_temporary_table(tl) && tl->table)
{
TABLE_SHARE *table_share= tl->table->s;
+ if (table_share && !(table_share->table_category == TABLE_CATEGORY_USER))
+ continue;
+
if (table_share &&
table_share->stats_cb.stats_can_be_read &&
!table_share->stats_cb.stats_is_read)
@@ -3289,7 +3325,7 @@ int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables)
The function is called when executing the statement DROP TABLE 'tab'.
*/
-int delete_statistics_for_table(THD *thd, LEX_CSTRING *db, LEX_CSTRING *tab)
+int delete_statistics_for_table(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *tab)
{
int err;
enum_binlog_format save_binlog_format;
diff --git a/sql/sql_statistics.h b/sql/sql_statistics.h
index 7ec742b70db..39cddf95188 100644
--- a/sql/sql_statistics.h
+++ b/sql/sql_statistics.h
@@ -21,7 +21,7 @@ enum enum_use_stat_tables_mode
{
NEVER,
COMPLEMENTARY,
- PEFERABLY,
+ PREFERABLY,
} Use_stat_tables_mode;
typedef
@@ -92,9 +92,10 @@ int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables);
int collect_statistics_for_table(THD *thd, TABLE *table);
int alloc_statistics_for_table_share(THD* thd, TABLE_SHARE *share,
bool is_safe);
+void delete_stat_values_for_table_share(TABLE_SHARE *table_share);
int alloc_statistics_for_table(THD *thd, TABLE *table);
int update_statistics_for_table(THD *thd, TABLE *table);
-int delete_statistics_for_table(THD *thd, LEX_CSTRING *db, LEX_CSTRING *tab);
+int delete_statistics_for_table(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *tab);
int delete_statistics_for_column(THD *thd, TABLE *tab, Field *col);
int delete_statistics_for_index(THD *thd, TABLE *tab, KEY *key_info,
bool ext_prefixes_only);
@@ -332,12 +333,17 @@ private:
public:
Histogram histogram;
+
+ uint32 no_values_provided_bitmap()
+ {
+ return
+ ((1 << (COLUMN_STAT_HISTOGRAM-COLUMN_STAT_COLUMN_NAME))-1) <<
+ (COLUMN_STAT_COLUMN_NAME+1);
+ }
void set_all_nulls()
{
- column_stat_nulls=
- ((1 << (COLUMN_STAT_HISTOGRAM-COLUMN_STAT_COLUMN_NAME))-1) <<
- (COLUMN_STAT_COLUMN_NAME+1);
+ column_stat_nulls= no_values_provided_bitmap();
}
void set_not_null(uint stat_field_no)
@@ -383,8 +389,22 @@ public:
bool min_max_values_are_provided()
{
return !is_null(COLUMN_STAT_MIN_VALUE) &&
- !is_null(COLUMN_STAT_MIN_VALUE);
- }
+ !is_null(COLUMN_STAT_MAX_VALUE);
+ }
+ /*
+ This function checks whether the values for the fields of the statistical
+ tables that were NULL by DEFAULT for a column have changed or not.
+
+ @retval
+ TRUE: Statistics are not present for a column
+ FALSE: Statisitics are present for a column
+ */
+ bool no_stat_values_provided()
+ {
+ if (column_stat_nulls == no_values_provided_bitmap())
+ return true;
+ return false;
+ }
};
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index e7acabe8bee..39d9438d5bf 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -237,9 +237,9 @@ bool String::copy(const String &str)
bool String::copy(const char *str,size_t arg_length, CHARSET_INFO *cs)
{
+ DBUG_ASSERT(arg_length < UINT_MAX32);
if (alloc(arg_length))
return TRUE;
- DBUG_ASSERT(arg_length < UINT_MAX32);
if (Ptr == str && arg_length == uint32(str_length))
{
/*
@@ -256,6 +256,24 @@ bool String::copy(const char *str,size_t arg_length, CHARSET_INFO *cs)
return FALSE;
}
+/*
+ Copy string, where strings may overlap.
+ Same as String::copy, but use memmove instead of memcpy to avoid warnings
+ from valgrind
+*/
+
+bool String::copy_or_move(const char *str,size_t arg_length, CHARSET_INFO *cs)
+{
+ DBUG_ASSERT(arg_length < UINT_MAX32);
+ if (alloc(arg_length))
+ return TRUE;
+ if ((str_length=uint32(arg_length)))
+ memmove(Ptr,str,arg_length);
+ Ptr[arg_length]=0;
+ str_charset=cs;
+ return FALSE;
+}
+
/*
Checks that the source string can be just copied to the destination string
@@ -389,8 +407,9 @@ bool String::set_or_copy_aligned(const char *str, size_t arg_length,
/* How many bytes are in incomplete character */
size_t offset= (arg_length % cs->mbminlen);
- if (!offset) /* All characters are complete, just copy */
+ if (!offset)
{
+ /* All characters are complete, just use given string */
set(str, arg_length, cs);
return FALSE;
}
diff --git a/sql/sql_string.h b/sql/sql_string.h
index d9d3f10777c..0ae68cb3796 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -437,6 +437,7 @@ public:
bool copy(); // Alloc string if not alloced
bool copy(const String &s); // Allocate new string
bool copy(const char *s,size_t arg_length, CHARSET_INFO *cs); // Allocate new string
+ bool copy_or_move(const char *s,size_t arg_length, CHARSET_INFO *cs);
static bool needs_conversion(size_t arg_length,
CHARSET_INFO *cs_from, CHARSET_INFO *cs_to,
uint32 *offset);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 2b7333b4c24..3e204c4945b 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -29,7 +29,7 @@
#include "lock.h" // mysql_unlock_tables
#include "strfunc.h" // find_type2, find_set
#include "sql_truncate.h" // regenerate_locked_table
-#include "sql_partition.h" // generate_partition_syntax,
+#include "sql_partition.h" // mem_alloc_error,
// partition_info
// NOT_A_PARTITION_ID
#include "sql_db.h" // load_db_opt_by_name
@@ -1838,13 +1838,10 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
partition_info *part_info= lpt->table->part_info;
if (part_info)
{
- if (!(part_syntax_buf= generate_partition_syntax(lpt->thd, part_info,
- &syntax_len, TRUE,
- lpt->create_info,
- lpt->alter_info)))
- {
+ part_syntax_buf= generate_partition_syntax_for_frm(lpt->thd, part_info,
+ &syntax_len, lpt->create_info, lpt->alter_info);
+ if (!part_syntax_buf)
DBUG_RETURN(TRUE);
- }
part_info->part_info_string= part_syntax_buf;
part_info->part_info_len= syntax_len;
}
@@ -1921,10 +1918,9 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
{
TABLE_SHARE *share= lpt->table->s;
char *tmp_part_syntax_str;
- if (!(part_syntax_buf= generate_partition_syntax(lpt->thd, part_info,
- &syntax_len, TRUE,
- lpt->create_info,
- lpt->alter_info)))
+ part_syntax_buf= generate_partition_syntax_for_frm(lpt->thd,
+ part_info, &syntax_len, lpt->create_info, lpt->alter_info);
+ if (!part_syntax_buf)
{
error= 1;
goto err;
@@ -2113,7 +2109,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, bool if_exists,
in its elements.
*/
table->table= find_table_for_mdl_upgrade(thd, table->db.str,
- table->table_name.str, false);
+ table->table_name.str, NULL);
if (!table->table)
DBUG_RETURN(true);
table->mdl_request.ticket= table->table->mdl_ticket;
@@ -2939,20 +2935,6 @@ uint Column_definition::pack_flag_numeric(uint dec) const
bool Column_definition::prepare_stage2_varchar(ulonglong table_flags)
{
-#ifndef QQ_ALL_HANDLERS_SUPPORT_VARCHAR
- if (table_flags & HA_NO_VARCHAR)
- {
- /* convert VARCHAR to CHAR because handler is not yet up to date */
- set_handler(&type_handler_var_string);
- pack_length= type_handler()->calc_pack_length((uint) length);
- if ((length / charset->mbmaxlen) > MAX_FIELD_CHARLENGTH)
- {
- my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), field_name.str,
- static_cast<ulong>(MAX_FIELD_CHARLENGTH));
- return true;
- }
- }
-#endif
pack_flag= (charset->state & MY_CS_BINSORT) ? FIELDFLAG_BINARY : 0;
return false;
}
@@ -3456,6 +3438,10 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
!(sql_field->charset= find_bin_collation(sql_field->charset)))
DBUG_RETURN(true);
+ /* Virtual fields are always NULL */
+ if (sql_field->vcol_info)
+ sql_field->flags&= ~NOT_NULL_FLAG;
+
if (sql_field->prepare_stage1(thd, thd->mem_root,
file, file->ha_table_flags()))
DBUG_RETURN(true);
@@ -4148,7 +4134,9 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
if (!unique_key && !primary_key &&
- (file->ha_table_flags() & HA_REQUIRE_PRIMARY_KEY))
+ ((file->ha_table_flags() & HA_REQUIRE_PRIMARY_KEY) ||
+ ((file->ha_table_flags() & HA_WANTS_PRIMARY_KEY) &&
+ !create_info->sequence)))
{
my_message(ER_REQUIRES_PRIMARY_KEY, ER_THD(thd, ER_REQUIRES_PRIMARY_KEY),
MYF(0));
@@ -4260,11 +4248,9 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
/* Give warnings for not supported table options */
-#if defined(WITH_ARIA_STORAGE_ENGINE)
extern handlerton *maria_hton;
- if (file->partition_ht() != maria_hton)
-#endif
- if (create_info->transactional)
+ if (file->partition_ht() != maria_hton && create_info->transactional &&
+ !file->has_transaction_manager())
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
ER_THD(thd, ER_ILLEGAL_HA_CREATE_OPTION),
@@ -4615,11 +4601,8 @@ handler *mysql_create_frm_image(THD *thd,
We reverse the partitioning parser and generate a standard format
for syntax stored in frm file.
*/
- sql_mode_t old_mode= thd->variables.sql_mode;
- thd->variables.sql_mode &= ~MODE_ANSI_QUOTES;
- part_syntax_buf= generate_partition_syntax(thd, part_info, &syntax_len,
- true, create_info, alter_info);
- thd->variables.sql_mode= old_mode;
+ part_syntax_buf= generate_partition_syntax_for_frm(thd, part_info,
+ &syntax_len, create_info, alter_info);
if (!part_syntax_buf)
goto err;
part_info->part_info_string= part_syntax_buf;
@@ -4862,6 +4845,8 @@ int create_table_impl(THD *thd,
{
if (options.or_replace())
{
+ (void) delete_statistics_for_table(thd, db, table_name);
+
TABLE_LIST table_list;
table_list.init_one_table(db, table_name, 0, TL_WRITE_ALLOW_WRITE);
table_list.table= create_info->table;
@@ -5485,13 +5470,13 @@ mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db,
}
delete file;
- if (unlikely(error))
- {
- if (error == HA_ERR_WRONG_COMMAND)
- my_error(ER_NOT_SUPPORTED_YET, MYF(0), "ALTER TABLE");
- else
- my_error(ER_ERROR_ON_RENAME, MYF(0), from, to, error);
- }
+ if (error == HA_ERR_WRONG_COMMAND)
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0), "ALTER TABLE");
+ else if (error == ENOTDIR)
+ my_error(ER_BAD_DB_ERROR, MYF(0), new_db->str);
+ else if (error)
+ my_error(ER_ERROR_ON_RENAME, MYF(0), from, to, error);
+
else if (!(flags & FN_IS_TMP))
mysql_audit_rename_table(thd, old_db, old_name, new_db, new_name);
@@ -9563,8 +9548,6 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
}
DEBUG_SYNC(thd, "alter_table_before_create_table_no_lock");
- /* We can abort alter table for any table type */
- thd->abort_on_warning= !ignore && thd->is_strict_mode();
/*
Create .FRM for new version of table with a temporary name.
@@ -9594,7 +9577,6 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
C_ALTER_TABLE_FRM_ONLY, NULL,
&key_info, &key_count, &frm);
reenable_binlog(thd);
- thd->abort_on_warning= false;
if (unlikely(error))
{
my_free(const_cast<uchar*>(frm.str));
@@ -9797,8 +9779,10 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
Table can be found in the list of open tables in THD::all_temp_tables
list.
*/
- tbl.table= thd->find_temporary_table(&tbl);
+ if ((tbl.table= thd->find_temporary_table(&tbl)) == NULL)
+ goto err_new_table_cleanup;
new_table= tbl.table;
+ DBUG_ASSERT(new_table);
}
else
{
@@ -9812,10 +9796,60 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
alter_ctx.new_db.str,
alter_ctx.tmp_name.str,
true, true);
+ if (!new_table)
+ goto err_new_table_cleanup;
+
+ /*
+ Normally, an attempt to modify an FK parent table will cause
+ FK children to be prelocked, so the table-being-altered cannot
+ be modified by a cascade FK action, because ALTER holds a lock
+ and prelocking will wait.
+
+ But if a new FK is being added by this very ALTER, then the target
+ table is not locked yet (it's a temporary table). So, we have to
+ lock FK parents explicitly.
+ */
+ if (alter_info->flags & ALTER_ADD_FOREIGN_KEY)
+ {
+ List <FOREIGN_KEY_INFO> fk_list;
+ List_iterator<FOREIGN_KEY_INFO> fk_list_it(fk_list);
+ FOREIGN_KEY_INFO *fk;
+
+ /* tables_opened can be > 1 only for MERGE tables */
+ DBUG_ASSERT(tables_opened == 1);
+ DBUG_ASSERT(&table_list->next_global == thd->lex->query_tables_last);
+
+ new_table->file->get_foreign_key_list(thd, &fk_list);
+ while ((fk= fk_list_it++))
+ {
+ if (lower_case_table_names)
+ {
+ char buf[NAME_LEN];
+ size_t len;
+ strmake_buf(buf, fk->referenced_db->str);
+ len = my_casedn_str(files_charset_info, buf);
+ thd->make_lex_string(fk->referenced_db, buf, len);
+ strmake_buf(buf, fk->referenced_table->str);
+ len = my_casedn_str(files_charset_info, buf);
+ thd->make_lex_string(fk->referenced_table, buf, len);
+ }
+ if (table_already_fk_prelocked(table_list, fk->referenced_db,
+ fk->referenced_table, TL_READ_NO_INSERT))
+ continue;
+
+ TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST));
+ tl->init_one_table_for_prelocking(fk->referenced_db, fk->referenced_table,
+ NULL, TL_READ_NO_INSERT, TABLE_LIST::PRELOCK_FK,
+ NULL, 0, &thd->lex->query_tables_last);
+ }
+
+ if (open_tables(thd, &table_list->next_global, &tables_opened, 0,
+ &alter_prelocking_strategy))
+ goto err_new_table_cleanup;
+ }
}
- if (!new_table)
- goto err_new_table_cleanup;
new_table->s->orig_table_name= table->s->table_name.str;
+
/*
Note: In case of MERGE table, we do not attach children. We do not
copy data for MERGE tables. Only the children have data.
diff --git a/sql/sql_time.cc b/sql/sql_time.cc
index 430eb192052..9562394f11e 100644
--- a/sql/sql_time.cc
+++ b/sql/sql_time.cc
@@ -175,7 +175,7 @@ int calc_weekday(long daynr,bool sunday_first_day_of_week)
next week is week 1.
*/
-uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year)
+uint calc_week(const MYSQL_TIME *l_time, uint week_behaviour, uint *year)
{
uint days;
ulong daynr=calc_daynr(l_time->year,l_time->month,l_time->day);
@@ -264,7 +264,7 @@ bool get_date_from_daynr(long daynr,uint *ret_year,uint *ret_month,
ulong convert_period_to_month(ulong period)
{
ulong a,b;
- if (period == 0)
+ if (period == 0 || period > 999912)
return 0L;
if ((a=period/100) < YY_PART_YEAR)
a+=2000;
@@ -289,14 +289,14 @@ ulong convert_month_to_period(ulong month)
bool
-check_date_with_warn(const MYSQL_TIME *ltime, ulonglong fuzzy_date,
+check_date_with_warn(THD *thd, const MYSQL_TIME *ltime, date_mode_t fuzzydate,
timestamp_type ts_type)
{
int unused;
- if (check_date(ltime, fuzzy_date, &unused))
+ if (check_date(ltime, fuzzydate, &unused))
{
ErrConvTime str(ltime);
- make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
+ make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN,
&str, ts_type, 0);
return true;
}
@@ -305,7 +305,7 @@ check_date_with_warn(const MYSQL_TIME *ltime, ulonglong fuzzy_date,
bool
-adjust_time_range_with_warn(MYSQL_TIME *ltime, uint dec)
+adjust_time_range_with_warn(THD *thd, MYSQL_TIME *ltime, uint dec)
{
MYSQL_TIME copy= *ltime;
ErrConvTime str(&copy);
@@ -313,7 +313,7 @@ adjust_time_range_with_warn(MYSQL_TIME *ltime, uint dec)
if (check_time_range(ltime, dec, &warnings))
return true;
if (warnings)
- current_thd->push_warning_truncated_wrong_value("time", str.ptr());
+ thd->push_warning_truncated_wrong_value("time", str.ptr());
return false;
}
@@ -351,33 +351,63 @@ to_ascii(CHARSET_INFO *cs,
}
-/* Character set-aware version of str_to_time() */
-bool
-str_to_time(CHARSET_INFO *cs, const char *str, size_t length,
- MYSQL_TIME *l_time, ulonglong fuzzydate, MYSQL_TIME_STATUS *status)
+class TemporalAsciiBuffer: public LEX_CSTRING
{
char cnv[32];
- if ((cs->state & MY_CS_NONASCII) != 0)
+public:
+ TemporalAsciiBuffer(const char *str, size_t length, CHARSET_INFO *cs)
{
- length= to_ascii(cs, str, length, cnv, sizeof(cnv));
- str= cnv;
+ if ((cs->state & MY_CS_NONASCII) != 0)
+ {
+ LEX_CSTRING::str= cnv;
+ LEX_CSTRING::length= to_ascii(cs, str, length, cnv, sizeof(cnv));
+ }
+ else
+ {
+ LEX_CSTRING::str= str;
+ LEX_CSTRING::length= length;
+ }
}
- return str_to_time(str, length, l_time, fuzzydate, status);
+};
+
+
+/* Character set-aware version of str_to_time() */
+bool Temporal::str_to_time(MYSQL_TIME_STATUS *status,
+ const char *str, size_t length, CHARSET_INFO *cs,
+ date_mode_t fuzzydate)
+{
+ TemporalAsciiBuffer tmp(str, length, cs);
+ bool rc= ::str_to_time(tmp.str, tmp.length, this,
+ ulonglong(fuzzydate & TIME_MODE_FOR_XXX_TO_DATE),
+ status);
+ DBUG_ASSERT(status->warnings || !rc);
+ return rc;
}
/* Character set-aware version of str_to_datetime() */
-bool str_to_datetime(CHARSET_INFO *cs, const char *str, size_t length,
- MYSQL_TIME *l_time, ulonglong flags,
- MYSQL_TIME_STATUS *status)
+bool Temporal::str_to_datetime(MYSQL_TIME_STATUS *status,
+ const char *str, size_t length, CHARSET_INFO *cs,
+ date_mode_t flags)
{
- char cnv[32];
- if ((cs->state & MY_CS_NONASCII) != 0)
- {
- length= to_ascii(cs, str, length, cnv, sizeof(cnv));
- str= cnv;
- }
- return str_to_datetime(str, length, l_time, flags, status);
+ TemporalAsciiBuffer tmp(str, length, cs);
+ bool rc= ::str_to_datetime(tmp.str, tmp.length, this,
+ ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE),
+ status);
+ DBUG_ASSERT(status->warnings || !rc);
+ return rc;
+}
+
+
+/* Character set-aware version of str_to_DDhhmmssff() */
+bool Interval_DDhhmmssff::str_to_DDhhmmssff(MYSQL_TIME_STATUS *status,
+ const char *str, size_t length,
+ CHARSET_INFO *cs, ulong max_hour)
+{
+ TemporalAsciiBuffer tmp(str, length, cs);
+ bool rc= ::str_to_DDhhmmssff(tmp.str, tmp.length, this, UINT_MAX32, status);
+ DBUG_ASSERT(status->warnings || !rc);
+ return rc;
}
@@ -390,51 +420,46 @@ bool str_to_datetime(CHARSET_INFO *cs, const char *str, size_t length,
*/
bool
-str_to_datetime_with_warn(CHARSET_INFO *cs,
- const char *str, size_t length, MYSQL_TIME *l_time,
- ulonglong flags)
+str_to_datetime_with_warn(THD *thd, CHARSET_INFO *cs,
+ const char *str, size_t length, MYSQL_TIME *to,
+ date_mode_t mode)
{
- MYSQL_TIME_STATUS status;
- THD *thd= current_thd;
- bool ret_val= str_to_datetime(cs, str, length, l_time, flags, &status);
- if (ret_val || status.warnings)
- {
- const ErrConvString err(str, length, &my_charset_bin);
- make_truncated_value_warning(thd,
- ret_val ? Sql_condition::WARN_LEVEL_WARN :
- Sql_condition::time_warn_level(status.warnings),
- &err, flags & TIME_TIME_ONLY ?
- MYSQL_TIMESTAMP_TIME : l_time->time_type, NullS);
- }
- DBUG_EXECUTE_IF("str_to_datetime_warn",
- push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_YES, str););
- return ret_val;
+ Temporal::Warn_push warn(thd, NullS, to, mode);
+ Temporal_hybrid *t= new(to) Temporal_hybrid(thd, &warn, str, length, cs, mode);
+ return !t->is_valid_temporal();
}
-bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime,
- ulonglong fuzzydate, const char *field_name)
+bool double_to_datetime_with_warn(THD *thd, double value, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate, const char *field_name)
{
- const ErrConvDouble str(value);
- return Sec6(value).convert_to_mysql_time(ltime, fuzzydate, &str, field_name);
+ Temporal::Warn_push warn(thd, field_name, ltime, fuzzydate);
+ Temporal_hybrid *t= new (ltime) Temporal_hybrid(thd, &warn, value, fuzzydate);
+ return !t->is_valid_temporal();
}
-bool decimal_to_datetime_with_warn(const my_decimal *value, MYSQL_TIME *ltime,
- ulonglong fuzzydate, const char *field_name)
+bool decimal_to_datetime_with_warn(THD *thd, const my_decimal *value,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate, const char *field_name)
{
- const ErrConvDecimal str(value);
- return Sec6(value).convert_to_mysql_time(ltime, fuzzydate, &str, field_name);
+ Temporal::Warn_push warn(thd, field_name, ltime, fuzzydate);
+ Temporal_hybrid *t= new (ltime) Temporal_hybrid(thd, &warn, value, fuzzydate);
+ return !t->is_valid_temporal();
}
-bool int_to_datetime_with_warn(bool neg, ulonglong value, MYSQL_TIME *ltime,
- ulonglong fuzzydate, const char *field_name)
+bool int_to_datetime_with_warn(THD *thd, const Longlong_hybrid &nr,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate, const char *field_name)
{
- const ErrConvInteger str(neg ? - (longlong) value : (longlong) value, !neg);
- Sec6 sec(neg, value, 0);
- return sec.convert_to_mysql_time(ltime, fuzzydate, &str, field_name);
+ /*
+ Note: conversion from an integer to TIME can overflow to '838:59:59.999999',
+ so the conversion result can have fractional digits.
+ */
+ Temporal::Warn_push warn(thd, field_name, ltime, fuzzydate);
+ Temporal_hybrid *t= new (ltime) Temporal_hybrid(thd, &warn, nr, fuzzydate);
+ return !t->is_valid_temporal();
}
@@ -864,20 +889,7 @@ void make_truncated_value_warning(THD *thd,
timestamp_type time_type,
const char *field_name)
{
- const char *type_str;
-
- switch (time_type) {
- case MYSQL_TIMESTAMP_DATE:
- type_str= "date";
- break;
- case MYSQL_TIMESTAMP_TIME:
- type_str= "time";
- break;
- case MYSQL_TIMESTAMP_DATETIME: // FALLTHROUGH
- default:
- type_str= "datetime";
- break;
- }
+ const char *type_str= Temporal::type_name_by_timestamp_type(time_type);
return thd->push_warning_wrong_or_truncated_value(level,
time_type <= MYSQL_TIMESTAMP_ERROR,
type_str, sval->ptr(), field_name);
@@ -891,7 +903,7 @@ void make_truncated_value_warning(THD *thd,
(X)->second_part)
#define GET_PART(X, N) X % N ## LL; X/= N ## LL
-bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type,
+bool date_add_interval(THD *thd, MYSQL_TIME *ltime, interval_type int_type,
const INTERVAL &interval)
{
long period, sign;
@@ -1006,7 +1018,6 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type,
invalid_date:
{
- THD *thd= current_thd;
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_DATETIME_FUNCTION_OVERFLOW,
ER_THD(thd, ER_DATETIME_FUNCTION_OVERFLOW),
@@ -1073,10 +1084,10 @@ calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
}
microseconds= ((longlong)days * SECONDS_IN_24H +
- (longlong)(l_time1->hour*3600L +
+ (longlong)(l_time1->hour*3600LL +
l_time1->minute*60L +
l_time1->second) -
- l_sign*(longlong)(l_time2->hour*3600L +
+ l_sign*(longlong)(l_time2->hour*3600LL +
l_time2->minute*60L +
l_time2->second)) * 1000000LL +
(longlong)l_time1->second_part -
@@ -1095,7 +1106,7 @@ calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
- int l_sign, MYSQL_TIME *l_time3, ulonglong fuzzydate)
+ int l_sign, MYSQL_TIME *l_time3, date_mode_t fuzzydate)
{
ulonglong seconds;
ulong microseconds;
@@ -1174,56 +1185,6 @@ bool time_to_datetime(MYSQL_TIME *ltime)
}
-/**
- Return a valid DATE or DATETIME value from an arbitrary MYSQL_TIME.
- If ltime is TIME, it's first converted to DATETIME.
- If ts_type is DATE, hhmmss is set to zero.
- The date part of the result is checked against fuzzy_date.
-
- @param ltime The value to convert.
- @param fuzzy_date Flags to check date.
- @param ts_type The type to convert to.
- @return false on success, true of error (negative time).*/
-bool
-make_date_with_warn(MYSQL_TIME *ltime, ulonglong fuzzy_date,
- timestamp_type ts_type)
-{
- DBUG_ASSERT(ts_type == MYSQL_TIMESTAMP_DATE ||
- ts_type == MYSQL_TIMESTAMP_DATETIME);
- if (ltime->time_type == MYSQL_TIMESTAMP_TIME && time_to_datetime(ltime))
- {
- /* e.g. negative time */
- ErrConvTime str(ltime);
- make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
- &str, ts_type, 0);
- return true;
- }
- if ((ltime->time_type= ts_type) == MYSQL_TIMESTAMP_DATE)
- ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
- return check_date_with_warn(ltime, fuzzy_date, ts_type);
-}
-
-
-/*
- Convert a TIME value to DAY-TIME interval, e.g. for extraction:
- EXTRACT(DAY FROM x), EXTRACT(HOUR FROM x), etc.
- Moves full days from ltime->hour to ltime->day.
- Note, time_type is set to MYSQL_TIMESTAMP_NONE, to make sure that
- the structure is not used for anything else other than extraction:
- non-extraction TIME functions expect zero day value!
-*/
-void time_to_daytime_interval(MYSQL_TIME *ltime)
-{
- DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_TIME);
- DBUG_ASSERT(ltime->year == 0);
- DBUG_ASSERT(ltime->month == 0);
- DBUG_ASSERT(ltime->day == 0);
- ltime->day= ltime->hour / 24;
- ltime->hour%= 24;
- ltime->time_type= MYSQL_TIMESTAMP_NONE;
-}
-
-
/*** Conversion from TIME to DATETIME ***/
/*
@@ -1342,7 +1303,7 @@ time_to_datetime(THD *thd, const MYSQL_TIME *from, MYSQL_TIME *to)
bool
time_to_datetime_with_warn(THD *thd,
const MYSQL_TIME *from, MYSQL_TIME *to,
- ulonglong fuzzydate)
+ date_mode_t fuzzydate)
{
int warn= 0;
DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_TIME);
@@ -1406,10 +1367,3 @@ void unpack_time(longlong packed, MYSQL_TIME *my_time,
break;
}
}
-
-
-bool my_decimal::to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
- const char *field_name)
-{
- return decimal_to_datetime_with_warn(this, to, fuzzydate, field_name);
-}
diff --git a/sql/sql_time.h b/sql/sql_time.h
index 8c6e58856e6..433374e2e9a 100644
--- a/sql/sql_time.h
+++ b/sql/sql_time.h
@@ -17,6 +17,7 @@
#ifndef SQL_TIME_INCLUDED
#define SQL_TIME_INCLUDED
+#include "sql_basic_types.h"
#include "my_time.h"
#include "mysql_time.h" /* timestamp_type */
#include "sql_error.h" /* Sql_condition */
@@ -35,25 +36,28 @@ ulong convert_period_to_month(ulong period);
ulong convert_month_to_period(ulong month);
void set_current_date(THD *thd, MYSQL_TIME *to);
bool time_to_datetime(MYSQL_TIME *ltime);
-void time_to_daytime_interval(MYSQL_TIME *l_time);
bool get_date_from_daynr(long daynr,uint *year, uint *month, uint *day);
my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error_code);
-bool str_to_datetime_with_warn(CHARSET_INFO *cs, const char *str, size_t length, MYSQL_TIME *l_time,
- ulonglong flags);
-bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime,
- ulonglong fuzzydate,
+bool str_to_datetime_with_warn(THD *thd,
+ CHARSET_INFO *cs, const char *str, size_t length,
+ MYSQL_TIME *l_time,
+ date_mode_t flags);
+bool double_to_datetime_with_warn(THD *thd, double value, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate,
const char *name);
-bool decimal_to_datetime_with_warn(const my_decimal *value, MYSQL_TIME *ltime,
- ulonglong fuzzydate,
+bool decimal_to_datetime_with_warn(THD *thd,
+ const my_decimal *value, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate,
const char *name);
-bool int_to_datetime_with_warn(bool neg, ulonglong value, MYSQL_TIME *ltime,
- ulonglong fuzzydate,
+bool int_to_datetime_with_warn(THD *thd, const Longlong_hybrid &nr,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate,
const char *name);
bool time_to_datetime(THD *thd, const MYSQL_TIME *tm, MYSQL_TIME *dt);
bool time_to_datetime_with_warn(THD *thd,
const MYSQL_TIME *tm, MYSQL_TIME *dt,
- ulonglong fuzzydate);
+ date_mode_t fuzzydate);
inline void datetime_to_date(MYSQL_TIME *ltime)
{
@@ -86,7 +90,7 @@ const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
bool my_TIME_to_str(const MYSQL_TIME *ltime, String *str, uint dec);
/* MYSQL_TIME operations */
-bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type,
+bool date_add_interval(THD *thd, MYSQL_TIME *ltime, interval_type int_type,
const INTERVAL &interval);
bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
int l_sign, ulonglong *seconds_out, ulong *microseconds_out);
@@ -115,26 +119,17 @@ int append_interval(String *str, interval_type int_type,
@return false - otherwise
*/
bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
- int lsign, MYSQL_TIME *l_time3, ulonglong fuzzydate);
+ int lsign, MYSQL_TIME *l_time3, date_mode_t fuzzydate);
int my_time_compare(const MYSQL_TIME *a, const MYSQL_TIME *b);
void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);
void calc_time_from_sec(MYSQL_TIME *to, ulong seconds, ulong microseconds);
-uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year);
+uint calc_week(const MYSQL_TIME *l_time, uint week_behaviour, uint *year);
int calc_weekday(long daynr,bool sunday_first_day_of_week);
bool parse_date_time_format(timestamp_type format_type,
const char *format, uint format_length,
DATE_TIME_FORMAT *date_time_format);
-/* Character set-aware version of str_to_time() */
-bool str_to_time(CHARSET_INFO *cs, const char *str,size_t length,
- MYSQL_TIME *l_time, ulonglong fuzzydate,
- MYSQL_TIME_STATUS *status);
-/* Character set-aware version of str_to_datetime() */
-bool str_to_datetime(CHARSET_INFO *cs,
- const char *str, size_t length,
- MYSQL_TIME *l_time, ulonglong flags,
- MYSQL_TIME_STATUS *status);
/* convenience wrapper */
inline bool parse_date_time_format(timestamp_type format_type,
@@ -171,15 +166,14 @@ non_zero_date(const MYSQL_TIME *ltime)
non_zero_hhmmssuu(ltime));
}
static inline bool
-check_date(const MYSQL_TIME *ltime, ulonglong flags, int *was_cut)
+check_date(const MYSQL_TIME *ltime, date_mode_t flags, int *was_cut)
{
- return check_date(ltime, non_zero_date(ltime), flags, was_cut);
+ return check_date(ltime, non_zero_date(ltime),
+ ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE), was_cut);
}
-bool check_date_with_warn(const MYSQL_TIME *ltime, ulonglong fuzzy_date,
+bool check_date_with_warn(THD *thd, const MYSQL_TIME *ltime, date_mode_t fuzzy_date,
timestamp_type ts_type);
-bool make_date_with_warn(MYSQL_TIME *ltime,
- ulonglong fuzzy_date, timestamp_type ts_type);
-bool adjust_time_range_with_warn(MYSQL_TIME *ltime, uint dec);
+bool adjust_time_range_with_warn(THD *thd, MYSQL_TIME *ltime, uint dec);
longlong pack_time(const MYSQL_TIME *my_time);
void unpack_time(longlong packed, MYSQL_TIME *my_time,
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 9f26bff3321..b79c1a1adb1 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -35,16 +35,6 @@
#include "sp_cache.h" // sp_invalidate_cache
#include <mysys_err.h>
-LEX_CSTRING *make_lex_string(LEX_CSTRING *lex_str,
- const char* str, size_t length,
- MEM_ROOT *mem_root)
-{
- if (!(lex_str->str= strmake_root(mem_root, str, length)))
- return 0;
- lex_str->length= length;
- return lex_str;
-}
-
/*************************************************************************/
/**
@@ -515,7 +505,11 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
if (err_status)
goto end;
}
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
+#ifdef WITH_WSREP
+ if (thd->wsrep_exec_mode == LOCAL_STATE)
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+#endif
/* We should have only one table in table list. */
DBUG_ASSERT(tables->next_global == 0);
@@ -543,7 +537,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
/* Under LOCK TABLES we must only accept write locked tables. */
if (!(tables->table= find_table_for_mdl_upgrade(thd, tables->db.str,
tables->table_name.str,
- FALSE)))
+ NULL)))
goto end;
}
else
@@ -619,9 +613,9 @@ end:
DBUG_RETURN(result);
#ifdef WITH_WSREP
- error:
+wsrep_error_label:
DBUG_RETURN(true);
-#endif /* WITH_WSREP */
+#endif
}
@@ -1499,8 +1493,8 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *db,
if (likely((name= error_handler.get_trigger_name())))
{
- if (unlikely(!(make_lex_string(&trigger->name, name->str,
- name->length, &table->mem_root))))
+ trigger->name= safe_lexcstrdup_root(&table->mem_root, *name);
+ if (unlikely(!trigger->name.str))
goto err_with_lex_cleanup;
}
trigger->definer= ((!trg_definer || !trg_definer->length) ?
diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc
index d515aacd1d0..798e929170c 100644
--- a/sql/sql_truncate.cc
+++ b/sql/sql_truncate.cc
@@ -299,7 +299,7 @@ bool Sql_cmd_truncate_table::lock_table(THD *thd, TABLE_LIST *table_ref,
if (thd->locked_tables_mode)
{
if (!(table= find_table_for_mdl_upgrade(thd, table_ref->db.str,
- table_ref->table_name.str, FALSE)))
+ table_ref->table_name.str, NULL)))
DBUG_RETURN(TRUE);
*hton_can_recreate= ha_check_storage_engine_flag(table->file->ht,
@@ -350,7 +350,8 @@ bool Sql_cmd_truncate_table::lock_table(THD *thd, TABLE_LIST *table_ref,
{
DEBUG_SYNC(thd, "upgrade_lock_for_truncate");
/* To remove the table from the cache we need an exclusive lock. */
- if (wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_DROP))
+ if (wait_while_table_is_used(thd, table,
+ *hton_can_recreate ? HA_EXTRA_PREPARE_FOR_DROP : HA_EXTRA_NOT_USED))
DBUG_RETURN(TRUE);
m_ticket_downgrade= table->mdl_ticket;
/* Close if table is going to be recreated. */
@@ -400,6 +401,8 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
/* In RBR, the statement is not binlogged if the table is temporary. */
binlog_stmt= !thd->is_current_stmt_binlog_format_row();
+ thd->close_unused_temporary_table_instances(table_ref);
+
error= handler_truncate(thd, table_ref, TRUE);
/*
diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc
index 43edd2d506a..0e4caae7a2f 100644
--- a/sql/sql_tvc.cc
+++ b/sql/sql_tvc.cc
@@ -469,6 +469,7 @@ bool Item_func_in::create_value_list_for_tvc(THD *thd,
for (uint i=1; i < arg_count; i++)
{
+ char col_name[8];
List<Item> *tvc_value;
if (!(tvc_value= new (thd->mem_root) List<Item>()))
return true;
@@ -479,13 +480,27 @@ bool Item_func_in::create_value_list_for_tvc(THD *thd,
for (uint j=0; j < row_list->cols(); j++)
{
+ if (i == 1)
+ {
+ sprintf(col_name, "_col_%i", j+1);
+ row_list->element_index(j)->set_name(thd, col_name, strlen(col_name),
+ thd->charset());
+ }
if (tvc_value->push_back(row_list->element_index(j),
thd->mem_root))
return true;
}
}
- else if (tvc_value->push_back(args[i]->real_item()))
- return true;
+ else
+ {
+ if (i == 1)
+ {
+ sprintf(col_name, "_col_%i", 1);
+ args[i]->set_name(thd, col_name, strlen(col_name), thd->charset());
+ }
+ if (tvc_value->push_back(args[i]->real_item()))
+ return true;
+ }
if (values->push_back(tvc_value, thd->mem_root))
return true;
diff --git a/sql/sql_tvc.h b/sql/sql_tvc.h
index 420311cccb2..128cc883dd8 100644
--- a/sql/sql_tvc.h
+++ b/sql/sql_tvc.h
@@ -50,6 +50,8 @@ public:
have_query_plan(QEP_NOT_PRESENT_YET), explain(0),
select_options(select_options_arg)
{ };
+
+ ha_rows get_records() { return lists_of_values.elements; }
bool prepare(THD *thd_arg, SELECT_LEX *sl,
select_result *tmp_result,
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index e8dbf663df6..a432f37b580 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -154,12 +154,9 @@ VDec_op::VDec_op(Item_func_hybrid_field_type *item)
}
-bool Dec_ptr::to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
- Item *item)
+date_mode_t Temporal::sql_mode_for_dates(THD *thd)
{
- if (to_datetime_with_warn(to, fuzzydate, item->field_name_or_null()))
- return item->null_value|= item->make_zero_date(to, fuzzydate);
- return item->null_value= false;
+ return ::sql_mode_for_dates(thd);
}
@@ -176,9 +173,23 @@ my_decimal *Temporal::bad_to_decimal(my_decimal *to) const
}
-Temporal_hybrid::Temporal_hybrid(THD *thd, Item *item)
+void Temporal::make_from_str(THD *thd, Warn *warn,
+ const char *str, size_t length,
+ CHARSET_INFO *cs, date_mode_t fuzzydate)
{
- if (item->get_date(this, sql_mode_for_dates(thd)))
+ DBUG_EXECUTE_IF("str_to_datetime_warn",
+ push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_YES, ErrConvString(str, length,cs).ptr()););
+ if (str_to_datetime(warn, str, length, cs, fuzzydate))
+ make_fuzzy_date(&warn->warnings, fuzzydate);
+ if (warn->warnings)
+ warn->set_str(str, length, &my_charset_bin);
+}
+
+
+Temporal_hybrid::Temporal_hybrid(THD *thd, Item *item, date_mode_t fuzzydate)
+{
+ if (item->get_date(thd, this, fuzzydate))
time_type= MYSQL_TIMESTAMP_NONE;
}
@@ -211,80 +222,50 @@ void Sec6::make_truncated_warning(THD *thd, const char *type_str) const
{
char buff[1 + MAX_BIGINT_WIDTH + 1 + 6 + 1]; // '-' int '.' frac '\0'
to_string(buff, sizeof(buff));
- current_thd->push_warning_truncated_wrong_value(type_str, buff);
+ thd->push_warning_truncated_wrong_value(type_str, buff);
}
-bool Sec6::to_time_with_warn(MYSQL_TIME *to, const ErrConv *str,
- const char *field_name) const
+bool Sec6::convert_to_mysql_time(THD *thd, int *warn, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
{
- int was_cut;
- bool res= to_time(to, &was_cut);
- if (res || MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut))
- current_thd->
- push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN,
- res, "time", str->ptr(),
- field_name);
- return res;
-}
-
-
-bool Sec6::to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
- const ErrConv *str,
- const char *field_name) const
-{
- bool res, have_warnings= false;
- int was_cut;
- res= to_datetime(to, fuzzydate, &was_cut);
- have_warnings= was_cut && (fuzzydate & TIME_NO_ZERO_IN_DATE);
- if (res || have_warnings)
- current_thd->
- push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN,
- res, "datetime", str->ptr(),
- field_name);
- return res;
+ bool is_time= bool(fuzzydate & TIME_TIME_ONLY);
+ bool rc= is_time ? to_time(ltime, warn) : to_datetime(ltime, fuzzydate, warn);
+ DBUG_ASSERT(*warn || !rc);
+ if (truncated())
+ *warn|= MYSQL_TIME_WARN_TRUNCATED;
+ return rc;
}
-bool Sec6::convert_to_mysql_time(MYSQL_TIME *ltime, ulonglong fuzzydate,
- const ErrConv *str, const char *field_name)
- const
+void Temporal::push_conversion_warnings(THD *thd, bool totally_useless_value, int warn,
+ const char *typestr,
+ const char *field_name,
+ const char *value)
{
- bool is_time= fuzzydate & TIME_TIME_ONLY;
- if (truncated())
- {
- /*
- The value was already truncated at the constructor call time,
- and a truncation warning was issued. Here we convert silently
- to avoid double warnings.
- */
- current_thd->
- push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN,
- !is_time,
- is_time ? "time" : "datetime",
- str->ptr(), field_name);
- int warn;
- return is_time ? to_time(ltime, &warn) :
- to_datetime(ltime, fuzzydate, &warn);
- }
- return is_time ? to_time_with_warn(ltime, str, field_name) :
- to_datetime_with_warn(ltime, fuzzydate, str, field_name);
+ if (MYSQL_TIME_WARN_HAVE_WARNINGS(warn))
+ thd->push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN,
+ totally_useless_value,
+ typestr, value, field_name);
+ else if (MYSQL_TIME_WARN_HAVE_NOTES(warn))
+ thd->push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_NOTE,
+ false, typestr, value, field_name);
}
-VSec6::VSec6(Item *item, const char *type_str, ulonglong limit)
+VSec6::VSec6(THD *thd, Item *item, const char *type_str, ulonglong limit)
{
if (item->decimals == 0)
{ // optimize for an important special case
- longlong nr= item->val_int();
- make_from_int(nr, item->unsigned_flag);
+ Longlong_hybrid nr(item->val_int(), item->unsigned_flag);
+ make_from_int(nr);
m_is_null= item->null_value;
if (!m_is_null && m_sec > limit)
{
m_sec= limit;
m_truncated= true;
- ErrConvInteger err(nr, item->unsigned_flag);
- current_thd->push_warning_truncated_wrong_value(type_str, err.ptr());
+ ErrConvInteger err(nr);
+ thd->push_warning_truncated_wrong_value(type_str, err.ptr());
}
}
else if (item->cmp_type() == REAL_RESULT)
@@ -300,7 +281,7 @@ VSec6::VSec6(Item *item, const char *type_str, ulonglong limit)
if (m_truncated)
{
ErrConvDouble err(nr);
- current_thd->push_warning_truncated_wrong_value(type_str, err.ptr());
+ thd->push_warning_truncated_wrong_value(type_str, err.ptr());
}
}
else
@@ -315,7 +296,7 @@ VSec6::VSec6(Item *item, const char *type_str, ulonglong limit)
if (m_truncated)
{
ErrConvDecimal err(tmp.ptr());
- current_thd->push_warning_truncated_wrong_value(type_str, err.ptr());
+ thd->push_warning_truncated_wrong_value(type_str, err.ptr());
}
}
}
@@ -323,8 +304,8 @@ VSec6::VSec6(Item *item, const char *type_str, ulonglong limit)
Year::Year(longlong value, bool unsigned_flag, uint length)
{
- if ((m_truncated= (value < 0 && !unsigned_flag)))
- m_year= 0;
+ if ((m_truncated= (value < 0))) // Negative or huge unsigned
+ m_year= unsigned_flag ? 9999 : 0;
else if (value > 9999)
{
m_truncated= true;
@@ -349,24 +330,133 @@ uint Year::year_precision(const Item *item) const
VYear::VYear(Item *item)
- :Year_null(Year(item->val_int(), item->unsigned_flag,
- year_precision(item)), item->null_value)
+ :Year_null(item->to_longlong_null(), item->unsigned_flag, year_precision(item))
{ }
VYear_op::VYear_op(Item_func_hybrid_field_type *item)
- :Year_null(Year(item->int_op(), item->unsigned_flag,
- year_precision(item)), item->null_value)
+ :Year_null(item->to_longlong_null_op(), item->unsigned_flag,
+ year_precision(item))
{ }
-void Time::make_from_item(int *warn, Item *item, const Options opt)
+const LEX_CSTRING Interval_DDhhmmssff::m_type_name=
+ {STRING_WITH_LEN("INTERVAL DAY TO SECOND")};
+
+
+Interval_DDhhmmssff::Interval_DDhhmmssff(THD *thd, Status *st,
+ bool push_warnings,
+ Item *item, ulong max_hour)
+{
+ switch (item->cmp_type()) {
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ time_type= MYSQL_TIMESTAMP_NONE;
+ break;
+ case TIME_RESULT:
+ {
+ if (item->get_date(thd, this, TIME_TIME_ONLY))
+ time_type= MYSQL_TIMESTAMP_NONE;
+ else if (time_type != MYSQL_TIMESTAMP_TIME)
+ {
+ st->warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ push_warning_wrong_or_truncated_value(thd, ErrConvTime(this),
+ st->warnings);
+ time_type= MYSQL_TIMESTAMP_NONE;
+ }
+ break;
+ }
+ case INT_RESULT:
+ case REAL_RESULT:
+ case DECIMAL_RESULT:
+ case STRING_RESULT:
+ {
+ StringBuffer<STRING_BUFFER_USUAL_SIZE> tmp;
+ String *str= item->val_str(&tmp);
+ if (!str)
+ time_type= MYSQL_TIMESTAMP_NONE;
+ else if (str_to_DDhhmmssff(st, str->ptr(), str->length(), str->charset(),
+ UINT_MAX32))
+ {
+ if (push_warnings)
+ thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ m_type_name.str,
+ ErrConvString(str).ptr());
+ time_type= MYSQL_TIMESTAMP_NONE;
+ }
+ else
+ {
+ if (hour > max_hour)
+ {
+ st->warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ time_type= MYSQL_TIMESTAMP_NONE;
+ }
+ // Warn if hour or nanosecond truncation happened
+ if (push_warnings)
+ push_warning_wrong_or_truncated_value(thd, ErrConvString(str),
+ st->warnings);
+ }
+ }
+ break;
+ }
+ DBUG_ASSERT(is_valid_value_slow());
+}
+
+
+void
+Interval_DDhhmmssff::push_warning_wrong_or_truncated_value(THD *thd,
+ const ErrConv &str,
+ int warnings)
+{
+ if (warnings & MYSQL_TIME_WARN_OUT_OF_RANGE)
+ {
+ thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ m_type_name.str, str.ptr());
+ }
+ else if (MYSQL_TIME_WARN_HAVE_WARNINGS(warnings))
+ {
+ thd->push_warning_truncated_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ m_type_name.str, str.ptr());
+ }
+ else if (MYSQL_TIME_WARN_HAVE_NOTES(warnings))
+ {
+ thd->push_warning_truncated_wrong_value(Sql_condition::WARN_LEVEL_NOTE,
+ m_type_name.str, str.ptr());
+ }
+}
+
+
+uint Interval_DDhhmmssff::fsp(THD *thd, Item *item)
+{
+ switch (item->cmp_type()) {
+ case INT_RESULT:
+ case TIME_RESULT:
+ return item->decimals;
+ case REAL_RESULT:
+ case DECIMAL_RESULT:
+ return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ return 0;
+ case STRING_RESULT:
+ break;
+ }
+ if (!item->const_item() || item->is_expensive())
+ return TIME_SECOND_PART_DIGITS;
+ Status st;
+ Interval_DDhhmmssff it(thd, &st, false/*no warnings*/, item, UINT_MAX32);
+ return it.is_valid_interval_DDhhmmssff() ? st.precision :
+ TIME_SECOND_PART_DIGITS;
+}
+
+
+void Time::make_from_item(THD *thd, int *warn, Item *item, const Options opt)
{
*warn= 0;
- if (item->get_date(this, opt.get_date_flags()))
+ if (item->get_date(thd, this, opt.get_date_flags()))
time_type= MYSQL_TIMESTAMP_NONE;
else
- valid_MYSQL_TIME_to_valid_value(warn, opt);
+ valid_MYSQL_TIME_to_valid_value(thd, warn, opt);
}
@@ -404,6 +494,12 @@ void Time::make_from_datetime_with_days_diff(int *warn, const MYSQL_TIME *from,
from->second) * 1000000LL +
from->second_part);
unpack_time(timediff, this, MYSQL_TIMESTAMP_TIME);
+ if (year || month)
+ {
+ *warn|= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ year= month= day= 0;
+ hour= TIME_MAX_HOUR + 1;
+ }
}
// The above code can generate TIME values outside of the valid TIME range.
adjust_time_range_or_invalidate(warn);
@@ -469,7 +565,7 @@ Time::Time(int *warn, const MYSQL_TIME *from, long curdays)
}
-void Temporal_with_date::make_from_item(THD *thd, Item *item, sql_mode_t flags)
+void Temporal_with_date::make_from_item(THD *thd, Item *item, date_mode_t flags)
{
flags&= ~TIME_TIME_ONLY;
/*
@@ -479,10 +575,10 @@ void Temporal_with_date::make_from_item(THD *thd, Item *item, sql_mode_t flags)
In the legacy time->datetime conversion mode we do not add TIME_TIME_ONLY
and leave it to get_date() to check date.
*/
- ulonglong time_flag= (item->field_type() == MYSQL_TYPE_TIME &&
- !(thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST)) ?
- TIME_TIME_ONLY : 0;
- if (item->get_date(this, flags | time_flag))
+ date_mode_t time_flag= (item->field_type() == MYSQL_TYPE_TIME &&
+ !(thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST)) ?
+ TIME_TIME_ONLY : date_mode_t(0);
+ if (item->get_date(thd, this, flags | time_flag))
time_type= MYSQL_TIMESTAMP_NONE;
else if (time_type == MYSQL_TIMESTAMP_TIME)
{
@@ -501,15 +597,16 @@ void Temporal_with_date::make_from_item(THD *thd, Item *item)
}
-void Temporal_with_date::check_date_or_invalidate(int *warn, sql_mode_t flags)
+void Temporal_with_date::check_date_or_invalidate(int *warn, date_mode_t flags)
{
- if (check_date(this, pack_time(this) != 0, flags, warn))
+ if (check_date(this, pack_time(this) != 0,
+ ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE), warn))
time_type= MYSQL_TIMESTAMP_NONE;
}
void Datetime::make_from_time(THD *thd, int *warn, const MYSQL_TIME *from,
- sql_mode_t flags)
+ date_mode_t flags)
{
DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_TIME);
if (time_to_datetime(thd, from, this))
@@ -523,7 +620,7 @@ void Datetime::make_from_time(THD *thd, int *warn, const MYSQL_TIME *from,
void Datetime::make_from_datetime(THD *thd, int *warn, const MYSQL_TIME *from,
- sql_mode_t flags)
+ date_mode_t flags)
{
DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_DATE ||
from->time_type == MYSQL_TIMESTAMP_DATETIME);
@@ -540,9 +637,9 @@ void Datetime::make_from_datetime(THD *thd, int *warn, const MYSQL_TIME *from,
Datetime::Datetime(THD *thd, int *warn, const MYSQL_TIME *from,
- sql_mode_t flags)
+ date_mode_t flags)
{
- DBUG_ASSERT((flags & TIME_TIME_ONLY) == 0);
+ DBUG_ASSERT(bool(flags & TIME_TIME_ONLY) == false);
switch (from->time_type) {
case MYSQL_TIMESTAMP_ERROR:
case MYSQL_TIMESTAMP_NONE:
@@ -3024,14 +3121,14 @@ void Type_handler_row::Item_update_null_value(Item *item) const
void Type_handler_time_common::Item_update_null_value(Item *item) const
{
MYSQL_TIME ltime;
- (void) item->get_date(&ltime, TIME_TIME_ONLY);
+ (void) item->get_date(current_thd, &ltime, TIME_TIME_ONLY);
}
void Type_handler_temporal_with_date::Item_update_null_value(Item *item) const
{
MYSQL_TIME ltime;
- (void) item->get_date(&ltime, sql_mode_for_dates(current_thd));
+ (void) item->get_date(current_thd, &ltime, sql_mode_for_dates(current_thd));
}
@@ -3503,6 +3600,106 @@ bool Type_handler::
}
+bool Type_handler_temporal_result::
+ Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
+ Item **items, uint nitems) const
+{
+ bool rc= Type_handler::Item_func_min_max_fix_attributes(thd, func,
+ items, nitems);
+ bool is_time= func->field_type() == MYSQL_TYPE_TIME;
+ func->decimals= 0;
+ for (uint i= 0; i < nitems; i++)
+ {
+ uint deci= is_time ? items[i]->time_precision(thd) :
+ items[i]->datetime_precision(thd);
+ set_if_bigger(func->decimals, deci);
+ }
+
+ if (rc || func->maybe_null)
+ return rc;
+ /*
+ LEAST/GREATES(non-temporal, temporal) can return NULL.
+ CAST functions Item_{time|datetime|date}_typecast always set maybe_full
+ to true. Here we try to detect nullability more thoroughly.
+ Perhaps CAST functions should also reuse this idea eventually.
+ */
+ const Type_handler *hf= func->type_handler();
+ for (uint i= 0; i < nitems; i++)
+ {
+ /*
+ If items[i] does not need conversion to the current temporal data
+ type, then we trust items[i]->maybe_null, which was already ORred
+ to func->maybe_null in the argument loop in fix_fields().
+ If items[i] requires conversion to the current temporal data type,
+ then conversion can fail and return NULL even for NOT NULL items.
+ */
+ const Type_handler *ha= items[i]->type_handler();
+ if (hf == ha)
+ continue; // No conversion.
+ if (ha->cmp_type() != TIME_RESULT)
+ {
+ func->maybe_null= true; // Conversion from non-temporal is not safe
+ break;
+ }
+ timestamp_type tf= hf->mysql_timestamp_type();
+ timestamp_type ta= ha->mysql_timestamp_type();
+ if (tf == ta ||
+ (tf == MYSQL_TIMESTAMP_DATETIME && ta == MYSQL_TIMESTAMP_DATE))
+ {
+ /*
+ If handlers have the same mysql_timestamp_type(),
+ then conversion is NULL safe. Conversion from DATE to DATETIME
+ is also safe. This branch includes data type pairs:
+ Function return type Argument type Comment
+ -------------------- ------------- -------------
+ TIMESTAMP TIMESTAMP no conversion
+ TIMESTAMP DATETIME not possible
+ TIMESTAMP DATE not possible
+ DATETIME DATETIME no conversion
+ DATETIME TIMESTAMP safe conversion
+ DATETIME DATE safe conversion
+ DATE DATE no conversion
+ TIME TIME no conversion
+
+ Note, a function cannot return TIMESTAMP if it has non-TIMESTAMP
+ arguments (it would return DATETIME in such case).
+ */
+ DBUG_ASSERT(hf->field_type() != MYSQL_TYPE_TIMESTAMP || tf == ta);
+ continue;
+ }
+ /*
+ Here we have the following data type pairs that did not match
+ the condition above:
+
+ Function return type Argument type Comment
+ -------------------- ------------- -------
+ TIMESTAMP TIME Not possible
+ DATETIME TIME depends on OLD_MODE_ZERO_DATE_TIME_CAST
+ DATE TIMESTAMP Not possible
+ DATE DATETIME Not possible
+ DATE TIME Not possible
+ TIME TIMESTAMP Not possible
+ TIME DATETIME Not possible
+ TIME DATE Not possible
+
+ Most pairs are not possible, because the function data type
+ would be DATETIME (according to LEAST/GREATEST aggregation rules).
+ Conversion to DATETIME from TIME is not safe when
+ OLD_MODE_ZERO_DATE_TIME_CAST is set:
+ - negative TIME values cannot be converted to not-NULL DATETIME values
+ - TIME values can produce DATETIME values that do not pass
+ NO_ZERO_DATE and NO_ZERO_IN_DATE tests.
+ */
+ DBUG_ASSERT(hf->field_type() == MYSQL_TYPE_DATETIME);
+ if (!(thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST))
+ continue;
+ func->maybe_null= true;
+ break;
+ }
+ return rc;
+}
+
+
bool Type_handler_real_result::
Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
Item **items, uint nitems) const
@@ -3801,43 +3998,87 @@ bool Type_handler_string_result::Item_val_bool(Item *item) const
/*************************************************************************/
-bool Type_handler_int_result::Item_get_date(Item *item, MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+
+bool Type_handler::Item_get_date_with_warn(THD *thd, Item *item,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
{
- return item->get_date_from_int(ltime, fuzzydate);
+ Temporal::Warn_push warn(thd, item->field_name_or_null(), ltime, fuzzydate);
+ Item_get_date(thd, item, &warn, ltime, fuzzydate);
+ return ltime->time_type < 0;
}
-bool Type_handler_year::Item_get_date(Item *item, MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+bool Type_handler::Item_func_hybrid_field_type_get_date_with_warn(THD *thd,
+ Item_func_hybrid_field_type *item,
+ MYSQL_TIME *ltime,
+ date_mode_t mode) const
+{
+ Temporal::Warn_push warn(thd, item->field_name_or_null(), ltime, mode);
+ Item_func_hybrid_field_type_get_date(thd, item, &warn, ltime, mode);
+ return ltime->time_type < 0;
+}
+
+
+/************************************************************************/
+void Type_handler_decimal_result::Item_get_date(THD *thd, Item *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
+{
+ new(ltime) Temporal_hybrid(thd, warn, VDec(item).ptr(), fuzzydate);
+}
+
+
+void Type_handler_int_result::Item_get_date(THD *thd, Item *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *to,
+ date_mode_t mode) const
+{
+ new(to) Temporal_hybrid(thd, warn, item->to_longlong_hybrid_null(), mode);
+}
+
+
+void Type_handler_year::Item_get_date(THD *thd, Item *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
{
- return item->null_value=
- VYear(item).to_mysql_time_with_warn(ltime, fuzzydate,
- item->field_name_or_null());
+ VYear year(item);
+ DBUG_ASSERT(!year.truncated());
+ Longlong_hybrid_null nr(Longlong_null(year.to_YYYYMMDD(), year.is_null()),
+ item->unsigned_flag);
+ new(ltime) Temporal_hybrid(thd, warn, nr, fuzzydate);
}
-bool Type_handler_real_result::Item_get_date(Item *item, MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+void Type_handler_real_result::Item_get_date(THD *thd, Item *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
{
- return item->get_date_from_real(ltime, fuzzydate);
+ new(ltime) Temporal_hybrid(thd, warn, item->to_double_null(), fuzzydate);
}
-bool Type_handler_string_result::Item_get_date(Item *item, MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+void Type_handler_string_result::Item_get_date(THD *thd, Item *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *ltime,
+ date_mode_t mode) const
{
- return item->get_date_from_string(ltime, fuzzydate);
+ StringBuffer<40> tmp;
+ new(ltime) Temporal_hybrid(thd, warn, item->val_str(&tmp), mode);
}
-bool Type_handler_temporal_result::Item_get_date(Item *item, MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+void Type_handler_temporal_result::Item_get_date(THD *thd, Item *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
{
DBUG_ASSERT(0); // Temporal type items must implement native get_date()
item->null_value= true;
- set_zero_time(ltime, mysql_timestamp_type());
- return true;
+ set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
}
@@ -3978,24 +4219,31 @@ Type_handler_decimal_result::Item_func_hybrid_field_type_val_decimal(
}
-bool
+void
Type_handler_decimal_result::Item_func_hybrid_field_type_get_date(
+ THD *thd,
Item_func_hybrid_field_type *item,
+ Temporal::Warn *warn,
MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
- return VDec_op(item).to_datetime_with_warn(ltime, fuzzydate, item);
+ new (ltime) Temporal_hybrid(thd, warn, VDec_op(item).ptr(), fuzzydate);
}
-bool
+void
Type_handler_year::Item_func_hybrid_field_type_get_date(
+ THD *thd,
Item_func_hybrid_field_type *item,
+ Temporal::Warn *warn,
MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
- return item->null_value=
- VYear_op(item).to_mysql_time_with_warn(ltime, fuzzydate, NULL);
+ VYear_op year(item);
+ DBUG_ASSERT(!year.truncated());
+ Longlong_hybrid_null nr(Longlong_null(year.to_YYYYMMDD(), year.is_null()),
+ item->unsigned_flag);
+ new(ltime) Temporal_hybrid(thd, warn, nr, fuzzydate);
}
@@ -4038,17 +4286,18 @@ Type_handler_int_result::Item_func_hybrid_field_type_val_decimal(
}
-bool
+void
Type_handler_int_result::Item_func_hybrid_field_type_get_date(
+ THD *thd,
Item_func_hybrid_field_type *item,
- MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+ Temporal::Warn *warn,
+ MYSQL_TIME *to,
+ date_mode_t mode) const
{
- return item->get_date_from_int_op(ltime, fuzzydate);
+ new(to) Temporal_hybrid(thd, warn, item->to_longlong_hybrid_null_op(), mode);
}
-
/***************************************************************************/
String *
@@ -4087,13 +4336,15 @@ Type_handler_real_result::Item_func_hybrid_field_type_val_decimal(
}
-bool
+void
Type_handler_real_result::Item_func_hybrid_field_type_get_date(
+ THD *thd,
Item_func_hybrid_field_type *item,
- MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+ Temporal::Warn *warn,
+ MYSQL_TIME *to,
+ date_mode_t mode) const
{
- return item->get_date_from_real_op(ltime, fuzzydate);
+ new(to) Temporal_hybrid(thd, warn, item->to_double_null_op(), mode);
}
@@ -4135,13 +4386,16 @@ Type_handler_temporal_result::Item_func_hybrid_field_type_val_decimal(
}
-bool
+void
Type_handler_temporal_result::Item_func_hybrid_field_type_get_date(
+ THD *thd,
Item_func_hybrid_field_type *item,
+ Temporal::Warn *warn,
MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
- return item->date_op(ltime, fuzzydate);
+ if (item->date_op(thd, ltime, fuzzydate))
+ set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
}
@@ -4183,13 +4437,16 @@ Type_handler_time_common::Item_func_hybrid_field_type_val_decimal(
}
-bool
+void
Type_handler_time_common::Item_func_hybrid_field_type_get_date(
+ THD *thd,
Item_func_hybrid_field_type *item,
+ Temporal::Warn *warn,
MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
- return item->time_op(ltime);
+ if (item->time_op(thd, ltime))
+ set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
}
@@ -4231,13 +4488,18 @@ Type_handler_string_result::Item_func_hybrid_field_type_val_decimal(
}
-bool
+void
Type_handler_string_result::Item_func_hybrid_field_type_get_date(
+ THD *thd,
Item_func_hybrid_field_type *item,
+ Temporal::Warn *warn,
MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+ date_mode_t mode) const
{
- return item->get_date_from_str_op(ltime, fuzzydate);
+ StringBuffer<40> tmp;
+ String *res= item->str_op(&tmp);
+ DBUG_ASSERT((res == NULL) == item->null_value);
+ new(ltime) Temporal_hybrid(thd, warn, res, mode);
}
/***************************************************************************/
@@ -4560,13 +4822,30 @@ double Type_handler_string_result::
}
-double Type_handler_temporal_result::
+double Type_handler_time_common::
Item_func_min_max_val_real(Item_func_min_max *func) const
{
- MYSQL_TIME ltime;
- if (func->get_date(&ltime, 0))
- return 0;
- return TIME_to_double(&ltime);
+ return Time(current_thd, func).to_double();
+}
+
+
+double Type_handler_date_common::
+ Item_func_min_max_val_real(Item_func_min_max *func) const
+{
+ return Date(current_thd, func).to_double();
+}
+
+
+double Type_handler_datetime_common::
+ Item_func_min_max_val_real(Item_func_min_max *func) const
+{
+ return Datetime(current_thd, func).to_double();
+}
+
+double Type_handler_timestamp_common::
+ Item_func_min_max_val_real(Item_func_min_max *func) const
+{
+ return Datetime(current_thd, func).to_double();
}
@@ -4584,13 +4863,31 @@ longlong Type_handler_string_result::
}
-longlong Type_handler_temporal_result::
+longlong Type_handler_time_common::
Item_func_min_max_val_int(Item_func_min_max *func) const
{
- MYSQL_TIME ltime;
- if (func->get_date(&ltime, 0))
- return 0;
- return TIME_to_ulonglong(&ltime);
+ return Time(current_thd, func).to_longlong();
+}
+
+
+longlong Type_handler_date_common::
+ Item_func_min_max_val_int(Item_func_min_max *func) const
+{
+ return Date(current_thd, func).to_longlong();
+}
+
+
+longlong Type_handler_datetime_common::
+ Item_func_min_max_val_int(Item_func_min_max *func) const
+{
+ return Datetime(current_thd, func).to_longlong();
+}
+
+
+longlong Type_handler_timestamp_common::
+ Item_func_min_max_val_int(Item_func_min_max *func) const
+{
+ return Datetime(current_thd, func).to_longlong();
}
@@ -4617,20 +4914,41 @@ my_decimal *Type_handler_numeric::
}
-my_decimal *Type_handler_temporal_result::
+my_decimal *Type_handler_time_common::
Item_func_min_max_val_decimal(Item_func_min_max *func,
my_decimal *dec) const
{
- MYSQL_TIME ltime;
- if (func->get_date(&ltime, 0))
- return 0;
- return date2my_decimal(&ltime, dec);
+ return Time(current_thd, func).to_decimal(dec);
+}
+
+
+my_decimal *Type_handler_date_common::
+ Item_func_min_max_val_decimal(Item_func_min_max *func,
+ my_decimal *dec) const
+{
+ return Date(current_thd, func).to_decimal(dec);
+}
+
+
+my_decimal *Type_handler_datetime_common::
+ Item_func_min_max_val_decimal(Item_func_min_max *func,
+ my_decimal *dec) const
+{
+ return Datetime(current_thd, func).to_decimal(dec);
+}
+
+
+my_decimal *Type_handler_timestamp_common::
+ Item_func_min_max_val_decimal(Item_func_min_max *func,
+ my_decimal *dec) const
+{
+ return Datetime(current_thd, func).to_decimal(dec);
}
bool Type_handler_string_result::
- Item_func_min_max_get_date(Item_func_min_max *func,
- MYSQL_TIME *ltime, ulonglong fuzzydate) const
+ Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const
{
/*
just like ::val_int() method of a string item can be called,
@@ -4638,30 +4956,42 @@ bool Type_handler_string_result::
::get_date() can be called for non-temporal values,
for example, SELECT MONTH(GREATEST("2011-11-21", "2010-10-09"))
*/
- return func->get_date_from_string(ltime, fuzzydate);
+ return func->get_date_from_string(thd, ltime, fuzzydate);
}
bool Type_handler_numeric::
- Item_func_min_max_get_date(Item_func_min_max *func,
- MYSQL_TIME *ltime, ulonglong fuzzydate) const
+ Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const
{
- return Item_get_date(func, ltime, fuzzydate);
+ return Item_get_date_with_warn(thd, func, ltime, fuzzydate);
}
bool Type_handler_temporal_result::
- Item_func_min_max_get_date(Item_func_min_max *func,
- MYSQL_TIME *ltime, ulonglong fuzzydate) const
+ Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const
{
- return func->get_date_native(ltime, fuzzydate);
+ /*
+ - If the caller specified TIME_TIME_ONLY, then it's going to convert
+ a DATETIME or DATE to TIME. So we pass the default flags for date. This is
+ exactly the same with what Item_func_min_max_val_{int|real|decimal|str} or
+ Item_send_datetime() do. We return the value in accordance with the
+ current session date flags and let the caller further convert it to TIME.
+ - If the caller did not specify TIME_TIME_ONLY, then return the value
+ according to the flags supplied by the caller.
+ */
+ return func->get_date_native(thd, ltime,
+ fuzzydate & TIME_TIME_ONLY ?
+ sql_mode_for_dates(thd) :
+ fuzzydate);
}
bool Type_handler_time_common::
- Item_func_min_max_get_date(Item_func_min_max *func,
- MYSQL_TIME *ltime, ulonglong fuzzydate) const
+ Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const
{
- return func->get_time_native(ltime);
+ return func->get_time_native(thd, ltime);
}
/***************************************************************************/
@@ -5126,7 +5456,7 @@ bool Type_handler::
Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const
{
uint dec= item->decimals == NOT_FIXED_DEC ?
- item->arguments()[0]->time_precision() :
+ item->arguments()[0]->time_precision(current_thd) :
item->decimals;
item->fix_attributes_temporal(MIN_TIME_WIDTH, dec);
item->maybe_null= true;
@@ -5148,7 +5478,7 @@ bool Type_handler::
const
{
uint dec= item->decimals == NOT_FIXED_DEC ?
- item->arguments()[0]->datetime_precision() :
+ item->arguments()[0]->datetime_precision(current_thd) :
item->decimals;
item->fix_attributes_temporal(MAX_DATETIME_WIDTH, dec);
item->maybe_null= true;
@@ -5468,32 +5798,34 @@ bool Type_handler_string_result::
/***************************************************************************/
-uint Type_handler::Item_time_precision(Item *item) const
+uint Type_handler::Item_time_precision(THD *thd, Item *item) const
{
return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
}
-uint Type_handler::Item_datetime_precision(Item *item) const
+uint Type_handler::Item_datetime_precision(THD *thd, Item *item) const
{
return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
}
-uint Type_handler_string_result::Item_temporal_precision(Item *item,
+uint Type_handler_string_result::Item_temporal_precision(THD *thd, Item *item,
bool is_time) const
{
- MYSQL_TIME ltime;
StringBuffer<64> buf;
String *tmp;
MYSQL_TIME_STATUS status;
DBUG_ASSERT(item->is_fixed());
if ((tmp= item->val_str(&buf)) &&
- !(is_time ?
- str_to_time(tmp->charset(), tmp->ptr(), tmp->length(),
- &ltime, TIME_TIME_ONLY, &status) :
- str_to_datetime(tmp->charset(), tmp->ptr(), tmp->length(),
- &ltime, TIME_FUZZY_DATES, &status)))
+ (is_time ?
+ Time(thd, &status, tmp->ptr(), tmp->length(), tmp->charset(),
+ Time::Options(TIME_TIME_ONLY,
+ Time::DATETIME_TO_TIME_YYYYMMDD_TRUNCATE)).
+ is_valid_time() :
+ Datetime(&status, tmp->ptr(), tmp->length(), tmp->charset(),
+ TIME_FUZZY_DATES).
+ is_valid_datetime()))
return MY_MIN(status.precision, TIME_SECOND_PART_DIGITS);
return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
}
@@ -5682,7 +6014,7 @@ bool Type_handler::check_null(const Item *item, st_value *value) const
bool Type_handler_null::
- Item_save_in_value(Item *item, st_value *value) const
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
value->m_type= DYN_COL_NULL;
return true;
@@ -5690,7 +6022,7 @@ bool Type_handler_null::
bool Type_handler_row::
- Item_save_in_value(Item *item, st_value *value) const
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
DBUG_ASSERT(0);
value->m_type= DYN_COL_NULL;
@@ -5699,7 +6031,7 @@ bool Type_handler_row::
bool Type_handler_int_result::
- Item_save_in_value(Item *item, st_value *value) const
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
value->m_type= item->unsigned_flag ? DYN_COL_UINT : DYN_COL_INT;
value->value.m_longlong= item->val_int();
@@ -5708,7 +6040,7 @@ bool Type_handler_int_result::
bool Type_handler_real_result::
- Item_save_in_value(Item *item, st_value *value) const
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
value->m_type= DYN_COL_DOUBLE;
value->value.m_double= item->val_real();
@@ -5717,7 +6049,7 @@ bool Type_handler_real_result::
bool Type_handler_decimal_result::
- Item_save_in_value(Item *item, st_value *value) const
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
value->m_type= DYN_COL_DECIMAL;
my_decimal *dec= item->val_decimal(&value->m_decimal);
@@ -5728,7 +6060,7 @@ bool Type_handler_decimal_result::
bool Type_handler_string_result::
- Item_save_in_value(Item *item, st_value *value) const
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
value->m_type= DYN_COL_STRING;
String *str= item->val_str(&value->m_string);
@@ -5739,19 +6071,19 @@ bool Type_handler_string_result::
bool Type_handler_temporal_with_date::
- Item_save_in_value(Item *item, st_value *value) const
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
value->m_type= DYN_COL_DATETIME;
- item->get_date(&value->value.m_time, sql_mode_for_dates(current_thd));
+ item->get_date(thd, &value->value.m_time, sql_mode_for_dates(thd));
return check_null(item, value);
}
bool Type_handler_time_common::
- Item_save_in_value(Item *item, st_value *value) const
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
value->m_type= DYN_COL_DATETIME;
- item->get_time(&value->value.m_time);
+ item->get_time(thd, &value->value.m_time);
return check_null(item, value);
}
@@ -5935,7 +6267,8 @@ bool Type_handler::
bool Type_handler::
Item_send_datetime(Item *item, Protocol *protocol, st_value *buf) const
{
- item->get_date(&buf->value.m_time, sql_mode_for_dates(current_thd));
+ item->get_date(protocol->thd, &buf->value.m_time,
+ sql_mode_for_dates(protocol->thd));
if (!item->null_value)
return protocol->store(&buf->value.m_time, item->decimals);
return protocol->store_null();
@@ -5945,7 +6278,8 @@ bool Type_handler::
bool Type_handler::
Item_send_date(Item *item, Protocol *protocol, st_value *buf) const
{
- item->get_date(&buf->value.m_time, sql_mode_for_dates(current_thd));
+ item->get_date(protocol->thd, &buf->value.m_time,
+ sql_mode_for_dates(protocol->thd));
if (!item->null_value)
return protocol->store_date(&buf->value.m_time);
return protocol->store_null();
@@ -5955,7 +6289,7 @@ bool Type_handler::
bool Type_handler::
Item_send_time(Item *item, Protocol *protocol, st_value *buf) const
{
- item->get_time(&buf->value.m_time);
+ item->get_time(protocol->thd, &buf->value.m_time);
if (!item->null_value)
return protocol->store_time(&buf->value.m_time, item->decimals);
return protocol->store_null();
@@ -6014,7 +6348,7 @@ Item *Type_handler_time_common::
make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
{
Item_cache_temporal *cache;
- longlong value= item->val_time_packed();
+ longlong value= item->val_time_packed(thd);
if (item->null_value)
return new (thd->mem_root) Item_null(thd, item->name.str);
cache= new (thd->mem_root) Item_cache_time(thd);
@@ -6028,7 +6362,7 @@ Item *Type_handler_temporal_with_date::
make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
{
Item_cache_temporal *cache;
- longlong value= item->val_datetime_packed();
+ longlong value= item->val_datetime_packed(thd);
if (item->null_value)
return new (thd->mem_root) Item_null(thd, item->name.str);
cache= new (thd->mem_root) Item_cache_datetime(thd);
@@ -7047,8 +7381,8 @@ bool Type_handler_time_common::Item_eq_value(THD *thd,
const Type_cmp_attributes *attr,
Item *a, Item *b) const
{
- longlong value0= a->val_time_packed();
- longlong value1= b->val_time_packed();
+ longlong value0= a->val_time_packed(thd);
+ longlong value1= b->val_time_packed(thd);
return !a->null_value && !b->null_value && value0 == value1;
}
@@ -7057,8 +7391,8 @@ bool Type_handler_temporal_with_date::Item_eq_value(THD *thd,
const Type_cmp_attributes *attr,
Item *a, Item *b) const
{
- longlong value0= a->val_datetime_packed();
- longlong value1= b->val_datetime_packed();
+ longlong value0= a->val_datetime_packed(thd);
+ longlong value1= b->val_datetime_packed(thd);
return !a->null_value && !b->null_value && value0 == value1;
}
@@ -7124,7 +7458,7 @@ int Type_handler_temporal_with_date::stored_field_cmp_to_item(THD *thd,
{
MYSQL_TIME field_time, item_time, item_time2, *item_time_cmp= &item_time;
field->get_date(&field_time, TIME_INVALID_DATES);
- item->get_date(&item_time, TIME_INVALID_DATES);
+ item->get_date(thd, &item_time, TIME_INVALID_DATES);
if (item_time.time_type == MYSQL_TIMESTAMP_TIME &&
time_to_datetime(thd, &item_time, item_time_cmp= &item_time2))
return 1;
@@ -7138,7 +7472,7 @@ int Type_handler_time_common::stored_field_cmp_to_item(THD *thd,
{
MYSQL_TIME field_time, item_time;
field->get_time(&field_time);
- item->get_time(&item_time);
+ item->get_time(thd, &item_time);
return my_time_compare(&field_time, &item_time);
}
@@ -7202,7 +7536,7 @@ static bool have_important_literal_warnings(const MYSQL_TIME_STATUS *status)
static void literal_warn(THD *thd, const Item *item,
const char *str, size_t length, CHARSET_INFO *cs,
- const MYSQL_TIME *ltime,
+ timestamp_type time_type,
const MYSQL_TIME_STATUS *st,
const char *typestr, bool send_error)
{
@@ -7213,7 +7547,7 @@ static void literal_warn(THD *thd, const Item *item,
ErrConvString err(str, length, cs);
make_truncated_value_warning(thd,
Sql_condition::time_warn_level(st->warnings),
- &err, ltime->time_type, 0);
+ &err, time_type, 0);
}
}
else if (send_error)
@@ -7231,14 +7565,15 @@ Type_handler_date_common::create_literal_item(THD *thd,
CHARSET_INFO *cs,
bool send_error) const
{
- MYSQL_TIME_STATUS st;
- MYSQL_TIME ltime;
+ Temporal::Warn st;
Item_literal *item= NULL;
- sql_mode_t flags= sql_mode_for_dates(thd);
- if (!str_to_datetime(cs, str, length, &ltime, flags, &st) &&
- ltime.time_type == MYSQL_TIMESTAMP_DATE && !st.warnings)
- item= new (thd->mem_root) Item_date_literal(thd, &ltime);
- literal_warn(thd, item, str, length, cs, &ltime, &st, "DATE", send_error);
+ Temporal_hybrid tmp(thd, &st, str, length, cs, sql_mode_for_dates(thd));
+ if (tmp.is_valid_temporal() &&
+ tmp.get_mysql_time()->time_type == MYSQL_TIMESTAMP_DATE &&
+ !have_important_literal_warnings(&st))
+ item= new (thd->mem_root) Item_date_literal(thd, tmp.get_mysql_time());
+ literal_warn(thd, item, str, length, cs, MYSQL_TIMESTAMP_DATE,
+ &st, "DATE", send_error);
return item;
}
@@ -7250,15 +7585,16 @@ Type_handler_temporal_with_date::create_literal_item(THD *thd,
CHARSET_INFO *cs,
bool send_error) const
{
- MYSQL_TIME_STATUS st;
- MYSQL_TIME ltime;
+ Temporal::Warn st;
Item_literal *item= NULL;
- sql_mode_t flags= sql_mode_for_dates(thd);
- if (!str_to_datetime(cs, str, length, &ltime, flags, &st) &&
- ltime.time_type == MYSQL_TIMESTAMP_DATETIME &&
+ Temporal_hybrid tmp(thd, &st, str, length, cs, sql_mode_for_dates(thd));
+ if (tmp.is_valid_temporal() &&
+ tmp.get_mysql_time()->time_type == MYSQL_TIMESTAMP_DATETIME &&
!have_important_literal_warnings(&st))
- item= new (thd->mem_root) Item_datetime_literal(thd, &ltime, st.precision);
- literal_warn(thd, item, str, length, cs, &ltime, &st, "DATETIME", send_error);
+ item= new (thd->mem_root) Item_datetime_literal(thd, tmp.get_mysql_time(),
+ st.precision);
+ literal_warn(thd, item, str, length, cs, MYSQL_TIMESTAMP_DATETIME,
+ &st, "DATETIME", send_error);
return item;
}
@@ -7271,12 +7607,14 @@ Type_handler_time_common::create_literal_item(THD *thd,
bool send_error) const
{
MYSQL_TIME_STATUS st;
- MYSQL_TIME ltime;
Item_literal *item= NULL;
- if (!str_to_time(cs, str, length, &ltime, 0, &st) &&
- ltime.time_type == MYSQL_TIMESTAMP_TIME &&
+ Time::Options opt(TIME_TIME_ONLY, Time::DATETIME_TO_TIME_DISALLOW);
+ Time tmp(thd, &st, str, length, cs, opt);
+ if (tmp.is_valid_time() &&
!have_important_literal_warnings(&st))
- item= new (thd->mem_root) Item_time_literal(thd, &ltime, st.precision);
- literal_warn(thd, item, str, length, cs, &ltime, &st, "TIME", send_error);
+ item= new (thd->mem_root) Item_time_literal(thd, tmp.get_mysql_time(),
+ st.precision);
+ literal_warn(thd, item, str, length, cs, MYSQL_TIMESTAMP_TIME,
+ &st, "TIME", send_error);
return item;
}
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 40433fdaabd..5de4c8e431a 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -96,6 +96,7 @@ protected:
my_decimal *m_ptr;
Dec_ptr() { }
public:
+ Dec_ptr(my_decimal *ptr) :m_ptr(ptr) { }
bool is_null() const { return m_ptr == NULL; }
const my_decimal *ptr() const { return m_ptr; }
const my_decimal *ptr_or(const my_decimal *def) const
@@ -113,13 +114,6 @@ public:
longlong to_longlong(bool unsigned_flag)
{ return m_ptr ? m_ptr->to_longlong(unsigned_flag) : 0; }
bool to_bool() const { return m_ptr ? m_ptr->to_bool() : false; }
- bool to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
- const char *field_name)
- {
- return m_ptr ? m_ptr->to_datetime_with_warn(to, fuzzydate, field_name) :
- true;
- }
- bool to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate, Item *item);
String *to_string(String *to) const
{
return m_ptr ? m_ptr->to_string(to) : NULL;
@@ -224,10 +218,10 @@ protected:
bool m_truncated; // Indicates if the constructor truncated the value
void make_from_decimal(const my_decimal *d);
void make_from_double(double d);
- void make_from_int(longlong nr, bool unsigned_val)
+ void make_from_int(const Longlong_hybrid &nr)
{
- m_neg= nr < 0 && !unsigned_val;
- m_sec= m_neg ? (ulonglong) -nr : (ulonglong) nr;
+ m_neg= nr.neg();
+ m_sec= nr.abs();
m_usec= 0;
m_truncated= false;
}
@@ -237,20 +231,21 @@ protected:
}
Sec6() { }
public:
- Sec6(bool neg, ulonglong nr, ulong frac)
- :m_sec(nr), m_usec(frac), m_neg(neg), m_truncated(false)
- { }
- Sec6(double nr)
+ explicit Sec6(double nr)
{
make_from_double(nr);
}
- Sec6(const my_decimal *d)
+ explicit Sec6(const my_decimal *d)
{
make_from_decimal(d);
}
- Sec6(longlong nr, bool unsigned_val)
+ explicit Sec6(const Longlong_hybrid &nr)
+ {
+ make_from_int(nr);
+ }
+ explicit Sec6(longlong nr, bool unsigned_val)
{
- make_from_int(nr, unsigned_val);
+ make_from_int(Longlong_hybrid(nr, unsigned_val));
}
bool neg() const { return m_neg; }
bool truncated() const { return m_truncated; }
@@ -258,38 +253,41 @@ public:
long usec() const { return m_usec; }
/**
Converts Sec6 to MYSQL_TIME
-
- @param ltime converted value will be written here
+ @param thd current thd
+ @param [out] warn conversion warnings will be written here
+ @param [out] ltime converted value will be written here
@param fuzzydate conversion flags (TIME_INVALID_DATE, etc)
- @param str original number, as an ErrConv. For the warning
- @param field_name field name or NULL if not a field. For the warning
@returns false for success, true for a failure
*/
- bool convert_to_mysql_time(MYSQL_TIME *ltime, ulonglong fuzzydate,
- const ErrConv *str, const char *field_name) const;
+ bool convert_to_mysql_time(THD *thd,
+ int *warn,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const;
// Convert a number in format hhhmmss.ff to TIME'hhh:mm:ss.ff'
bool to_time(MYSQL_TIME *to, int *warn) const
{
- return number_to_time(m_neg, m_sec, m_usec, to, warn);
+ bool rc= number_to_time(m_neg, m_sec, m_usec, to, warn);
+ DBUG_ASSERT(*warn || !rc);
+ return rc;
}
- bool to_time_with_warn(MYSQL_TIME *to, const ErrConv *str,
- const char *field_name) const;
/*
Convert a number in format YYYYMMDDhhmmss.ff to
TIMESTAMP'YYYY-MM-DD hh:mm:ss.ff'
*/
- bool to_datetime(MYSQL_TIME *to, ulonglong flags, int *warn) const
+ bool to_datetime(MYSQL_TIME *to, date_mode_t flags, int *warn) const
{
if (m_neg)
{
*warn= MYSQL_TIME_WARN_OUT_OF_RANGE;
return true;
}
- return number_to_datetime(m_sec, m_usec, to, flags, warn) == -1;
+ bool rc= number_to_datetime(m_sec, m_usec, to,
+ ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE),
+ warn) == -1;
+ DBUG_ASSERT(*warn || !rc);
+ return rc;
}
- bool to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
- const ErrConv *str, const char *field_name) const;
// Convert elapsed seconds to TIME
bool sec_to_time(MYSQL_TIME *ltime, uint dec) const
{
@@ -325,7 +323,7 @@ class VSec6: public Sec6
{
bool m_is_null;
public:
- VSec6(Item *item, const char *type_str, ulonglong limit);
+ VSec6(THD *thd, Item *item, const char *type_str, ulonglong limit);
bool is_null() const { return m_is_null; }
};
@@ -368,13 +366,13 @@ public:
m_neg= !m_neg; // Swap sign
}
}
- bool to_time(MYSQL_TIME *ltime, uint decimals) const
+ bool to_time(THD *thd, MYSQL_TIME *ltime, uint decimals) const
{
if (m_error)
return true;
to_hh24mmssff(ltime, MYSQL_TIMESTAMP_TIME);
ltime->hour+= to_days_abs() * 24;
- return adjust_time_range_with_warn(ltime, decimals);
+ return adjust_time_range_with_warn(thd, ltime, decimals);
}
bool to_datetime(MYSQL_TIME *ltime) const
{
@@ -394,39 +392,23 @@ class Year
protected:
uint m_year;
bool m_truncated;
- bool to_mysql_time_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
- const char *field_name) const
- {
- longlong value= m_year * 10000; // Make it YYYYMMDD
- const ErrConvInteger str(value, true);
- Sec6 sec(false, value, 0);
- return sec.convert_to_mysql_time(to, fuzzydate, &str, field_name);
- }
uint year_precision(const Item *item) const;
public:
Year(): m_year(0), m_truncated(false) { }
Year(longlong value, bool unsigned_flag, uint length);
uint year() const { return m_year; }
+ uint to_YYYYMMDD() const { return m_year * 10000; }
bool truncated() const { return m_truncated; }
};
-class Year_null: public Year
+class Year_null: public Year, public Null_flag
{
-protected:
- bool m_is_null;
public:
- Year_null(const Year &other, bool is_null)
- :Year(is_null ? Year() : other),
- m_is_null(is_null)
+ Year_null(const Longlong_null &nr, bool unsigned_flag, uint length)
+ :Year(nr.is_null() ? 0 : nr.value(), unsigned_flag, length),
+ Null_flag(nr.is_null())
{ }
- bool is_null() const { return m_is_null; }
- bool to_mysql_time_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
- const char *field_name) const
- {
- return m_is_null ? true :
- Year::to_mysql_time_with_warn(to, fuzzydate, field_name);
- }
};
@@ -444,14 +426,110 @@ public:
};
-class Temporal: protected MYSQL_TIME
+class Double_null: public Null_flag
{
protected:
+ double m_value;
+public:
+ Double_null(double value, bool is_null)
+ :Null_flag(is_null), m_value(value)
+ { }
+ double value() const { return m_value; }
+};
+
+
+class Temporal: protected MYSQL_TIME
+{
+public:
+ class Status: public MYSQL_TIME_STATUS
+ {
+ public:
+ Status() { my_time_status_init(this); }
+ };
+
+ class Warn: public ErrBuff,
+ public Status
+ {
+ public:
+ void push_conversion_warnings(THD *thd, bool totally_useless_value, date_mode_t mode,
+ timestamp_type tstype, const char *name)
+ {
+ const char *typestr= tstype >= 0 ? type_name_by_timestamp_type(tstype) :
+ mode & TIME_TIME_ONLY ? "time" : "datetime";
+ Temporal::push_conversion_warnings(thd, totally_useless_value, warnings, typestr,
+ name, ptr());
+ }
+ };
+
+ class Warn_push: public Warn
+ {
+ THD *m_thd;
+ const char *m_name;
+ const MYSQL_TIME *m_ltime;
+ date_mode_t m_mode;
+ public:
+ Warn_push(THD *thd, const char *name,
+ const MYSQL_TIME *ltime, date_mode_t mode)
+ :m_thd(thd), m_name(name), m_ltime(ltime), m_mode(mode)
+ { }
+ ~Warn_push()
+ {
+ if (warnings)
+ push_conversion_warnings(m_thd, m_ltime->time_type < 0,
+ m_mode, m_ltime->time_type, m_name);
+ }
+ };
+
+public:
+ static date_mode_t sql_mode_for_dates(THD *thd);
bool is_valid_temporal() const
{
DBUG_ASSERT(time_type != MYSQL_TIMESTAMP_ERROR);
return time_type != MYSQL_TIMESTAMP_NONE;
}
+ static const char *type_name_by_timestamp_type(timestamp_type time_type)
+ {
+ switch (time_type) {
+ case MYSQL_TIMESTAMP_DATE: return "date";
+ case MYSQL_TIMESTAMP_TIME: return "time";
+ case MYSQL_TIMESTAMP_DATETIME: // FALLTHROUGH
+ default:
+ break;
+ }
+ return "datetime";
+ }
+ static void push_conversion_warnings(THD *thd, bool totally_useless_value, int warn,
+ const char *type_name,
+ const char *field_name,
+ const char *value);
+ /*
+ This method is used if the item was not null but convertion to
+ TIME/DATE/DATETIME failed. We return a zero date if allowed,
+ otherwise - null.
+ */
+ void make_fuzzy_date(int *warn, date_mode_t fuzzydate)
+ {
+ /*
+ In the following scenario:
+ - The caller expected to get a TIME value
+ - Item returned a not NULL string or numeric value
+ - But then conversion from string or number to TIME failed
+ we need to change the default time_type from MYSQL_TIMESTAMP_DATE
+ (which was set in bzero) to MYSQL_TIMESTAMP_TIME and therefore
+ return TIME'00:00:00' rather than DATE'0000-00-00'.
+ If we don't do this, methods like Item::get_time_with_conversion()
+ will erroneously subtract CURRENT_DATE from '0000-00-00 00:00:00'
+ and return TIME'-838:59:59' instead of TIME'00:00:00' as a result.
+ */
+ timestamp_type tstype= !(fuzzydate & TIME_FUZZY_DATES) ?
+ MYSQL_TIMESTAMP_NONE :
+ fuzzydate & TIME_TIME_ONLY ?
+ MYSQL_TIMESTAMP_TIME :
+ MYSQL_TIMESTAMP_DATETIME;
+ set_zero_time(this, tstype);
+ }
+
+protected:
my_decimal *bad_to_decimal(my_decimal *to) const;
my_decimal *to_decimal(my_decimal *to) const;
static double to_double(bool negate, ulonglong num, ulong frac)
@@ -465,7 +543,65 @@ protected:
*warn= MYSQL_TIME_WARN_OUT_OF_RANGE;
time_type= MYSQL_TIMESTAMP_NONE;
}
+ void make_from_sec6(THD *thd, MYSQL_TIME_STATUS *st,
+ const Sec6 &nr, date_mode_t mode)
+ {
+ if (nr.convert_to_mysql_time(thd, &st->warnings, this, mode))
+ make_fuzzy_date(&st->warnings, mode);
+ }
+ void make_from_str(THD *thd, Warn *warn,
+ const char *str, size_t length, CHARSET_INFO *cs,
+ date_mode_t fuzzydate);
+ void make_from_double(THD *thd, Warn *warn, double nr, date_mode_t mode)
+ {
+ make_from_sec6(thd, warn, Sec6(nr), mode);
+ if (warn->warnings)
+ warn->set_double(nr);
+ }
+ void make_from_longlong_hybrid(THD *thd, Warn *warn,
+ const Longlong_hybrid &nr, date_mode_t mode)
+ {
+ /*
+ Note: conversion from an integer to TIME can overflow to
+ '838:59:59.999999', so the conversion result can have fractional digits.
+ */
+ make_from_sec6(thd, warn, Sec6(nr), mode);
+ if (warn->warnings)
+ warn->set_longlong(nr);
+ }
+ void make_from_decimal(THD *thd, Warn *warn,
+ const my_decimal *nr, date_mode_t mode)
+ {
+ make_from_sec6(thd, warn, Sec6(nr), mode);
+ if (warn->warnings)
+ warn->set_decimal(nr);
+ }
+ bool str_to_time(MYSQL_TIME_STATUS *st, const char *str, size_t length,
+ CHARSET_INFO *cs, date_mode_t fuzzydate);
+ bool str_to_datetime(MYSQL_TIME_STATUS *st, const char *str, size_t length,
+ CHARSET_INFO *cs, date_mode_t fuzzydate);
+ bool has_valid_mmssff() const
+ {
+ return minute <= TIME_MAX_MINUTE &&
+ second <= TIME_MAX_SECOND &&
+ second_part <= TIME_MAX_SECOND_PART;
+ }
+ bool has_zero_YYYYMM() const
+ {
+ return year == 0 && month == 0;
+ }
+ bool has_zero_YYYYMMDD() const
+ {
+ return year == 0 && month == 0 && day == 0;
+ }
public:
+ static void *operator new(size_t size, MYSQL_TIME *ltime) throw()
+ {
+ DBUG_ASSERT(size == sizeof(MYSQL_TIME));
+ return ltime;
+ }
+ static void operator delete(void *ptr, MYSQL_TIME *ltime) { }
+
long fraction_remainder(uint dec) const
{
return my_time_fraction_remainder(second_part, dec);
@@ -481,8 +617,64 @@ public:
class Temporal_hybrid: public Temporal
{
public:
- Temporal_hybrid(THD *thd, Item *item);
- Temporal_hybrid(Item *item) { *this= Temporal_hybrid(current_thd, item); }
+ // Contructors for Item
+ Temporal_hybrid(THD *thd, Item *item, date_mode_t fuzzydate);
+ Temporal_hybrid(THD *thd, Item *item)
+ :Temporal_hybrid(thd, item, sql_mode_for_dates(thd))
+ { }
+ Temporal_hybrid(Item *item)
+ :Temporal_hybrid(current_thd, item)
+ { }
+
+ // Constructors for non-NULL values
+ Temporal_hybrid(THD *thd, Warn *warn,
+ const char *str, size_t length, CHARSET_INFO *cs,
+ date_mode_t fuzzydate)
+ {
+ make_from_str(thd, warn, str, length, cs, fuzzydate);
+ }
+ Temporal_hybrid(THD *thd, Warn *warn,
+ const Longlong_hybrid &nr, date_mode_t fuzzydate)
+ {
+ make_from_longlong_hybrid(thd, warn, nr, fuzzydate);
+ }
+ Temporal_hybrid(THD *thd, Warn *warn, double nr, date_mode_t fuzzydate)
+ {
+ make_from_double(thd, warn, nr, fuzzydate);
+ }
+
+ // Constructors for nullable values
+ Temporal_hybrid(THD *thd, Warn *warn, const String *str, date_mode_t mode)
+ {
+ if (!str)
+ time_type= MYSQL_TIMESTAMP_NONE;
+ else
+ make_from_str(thd, warn, str->ptr(), str->length(), str->charset(), mode);
+ }
+ Temporal_hybrid(THD *thd, Warn *warn,
+ const Longlong_hybrid_null &nr, date_mode_t fuzzydate)
+ {
+ if (nr.is_null())
+ time_type= MYSQL_TIMESTAMP_NONE;
+ else
+ make_from_longlong_hybrid(thd, warn, nr, fuzzydate);
+ }
+ Temporal_hybrid(THD *thd, Warn *warn, const Double_null &nr, date_mode_t mode)
+ {
+ if (nr.is_null())
+ time_type= MYSQL_TIMESTAMP_NONE;
+ else
+ make_from_double(thd, warn, nr.value(), mode);
+ }
+ Temporal_hybrid(THD *thd, Warn *warn, const my_decimal *nr, date_mode_t mode)
+ {
+ if (!nr)
+ time_type= MYSQL_TIMESTAMP_NONE;
+ else
+ make_from_decimal(thd, warn, nr, mode);
+ }
+ // End of constuctors
+
longlong to_longlong() const
{
if (!is_valid_temporal())
@@ -507,6 +699,182 @@ public:
str->length(my_TIME_to_str(this, const_cast<char*>(str->ptr()), dec));
return str;
}
+ const MYSQL_TIME *get_mysql_time() const
+ {
+ DBUG_ASSERT(is_valid_temporal());
+ return this;
+ }
+};
+
+
+/*
+ This class resembles the SQL standard <extract source>,
+ used in extract expressions, e.g: EXTRACT(DAY FROM dt)
+ <extract expression> ::=
+ EXTRACT <left paren> <extract field> FROM <extract source> <right paren>
+ <extract source> ::= <datetime value expression> | <interval value expression>
+*/
+class Extract_source: public Temporal_hybrid
+{
+ /*
+ Convert a TIME value to DAY-TIME interval, e.g. for extraction:
+ EXTRACT(DAY FROM x), EXTRACT(HOUR FROM x), etc.
+ Moves full days from ltime->hour to ltime->day.
+ */
+ void time_to_daytime_interval()
+ {
+ DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_TIME);
+ DBUG_ASSERT(has_zero_YYYYMMDD());
+ MYSQL_TIME::day= MYSQL_TIME::hour / 24;
+ MYSQL_TIME::hour%= 24;
+ }
+ bool is_valid_extract_source_slow() const
+ {
+ return is_valid_temporal() && MYSQL_TIME::hour < 24 &&
+ (has_zero_YYYYMM() || time_type != MYSQL_TIMESTAMP_TIME);
+ }
+ bool is_valid_value_slow() const
+ {
+ return time_type == MYSQL_TIMESTAMP_NONE || is_valid_extract_source_slow();
+ }
+public:
+ Extract_source(THD *thd, Item *item, date_mode_t mode)
+ :Temporal_hybrid(thd, item, mode)
+ {
+ if (MYSQL_TIME::time_type == MYSQL_TIMESTAMP_TIME)
+ time_to_daytime_interval();
+ DBUG_ASSERT(is_valid_value_slow());
+ }
+ inline const MYSQL_TIME *get_mysql_time() const
+ {
+ DBUG_ASSERT(is_valid_extract_source_slow());
+ return this;
+ }
+ bool is_valid_extract_source() const { return is_valid_temporal(); }
+ int sign() const { return get_mysql_time()->neg ? -1 : 1; }
+ uint year() const { return get_mysql_time()->year; }
+ uint month() const { return get_mysql_time()->month; }
+ int day() const { return (int) get_mysql_time()->day * sign(); }
+ int hour() const { return (int) get_mysql_time()->hour * sign(); }
+ int minute() const { return (int) get_mysql_time()->minute * sign(); }
+ int second() const { return (int) get_mysql_time()->second * sign(); }
+ int microsecond() const { return (int) get_mysql_time()->second_part * sign(); }
+
+ uint year_month() const { return year() * 100 + month(); }
+ uint quarter() const { return (month() + 2)/3; }
+ uint week(THD *thd) const;
+
+ longlong second_microsecond() const
+ {
+ return (second() * 1000000LL + microsecond());
+ }
+
+ // DAY TO XXX
+ longlong day_hour() const
+ {
+ return (longlong) day() * 100LL + hour();
+ }
+ longlong day_minute() const
+ {
+ return day_hour() * 100LL + minute();
+ }
+ longlong day_second() const
+ {
+ return day_minute() * 100LL + second();
+ }
+ longlong day_microsecond() const
+ {
+ return day_second() * 1000000LL + microsecond();
+ }
+
+ // HOUR TO XXX
+ int hour_minute() const
+ {
+ return hour() * 100 + minute();
+ }
+ int hour_second() const
+ {
+ return hour_minute() * 100 + second();
+ }
+ longlong hour_microsecond() const
+ {
+ return hour_second() * 1000000LL + microsecond();
+ }
+
+ // MINUTE TO XXX
+ int minute_second() const
+ {
+ return minute() * 100 + second();
+ }
+ longlong minute_microsecond() const
+ {
+ return minute_second() * 1000000LL + microsecond();
+ }
+};
+
+
+/*
+ This class is used for the "time_interval" argument of these SQL functions:
+ TIMESTAMP(tm,time_interval)
+ ADDTIME(tm,time_interval)
+ Features:
+ - DATE and DATETIME formats are treated as errors
+ - Preserves hours for TIME format as is, without limiting to TIME_MAX_HOUR
+*/
+class Interval_DDhhmmssff: public Temporal
+{
+ static const LEX_CSTRING m_type_name;
+ bool str_to_DDhhmmssff(MYSQL_TIME_STATUS *status,
+ const char *str, size_t length, CHARSET_INFO *cs,
+ ulong max_hour);
+ void push_warning_wrong_or_truncated_value(THD *thd,
+ const ErrConv &str,
+ int warnings);
+ bool is_valid_interval_DDhhmmssff_slow() const
+ {
+ return time_type == MYSQL_TIMESTAMP_TIME &&
+ has_zero_YYYYMMDD() && has_valid_mmssff();
+ }
+ bool is_valid_value_slow() const
+ {
+ return time_type == MYSQL_TIMESTAMP_NONE ||
+ is_valid_interval_DDhhmmssff_slow();
+ }
+public:
+ // Get fractional second precision from an Item
+ static uint fsp(THD *thd, Item *item);
+ /*
+ Maximum useful HOUR value:
+ TIMESTAMP'0001-01-01 00:00:00' + '87649415:59:59' = '9999-12-31 23:59:59'
+ This gives maximum possible interval values:
+ - '87649415:59:59.999999' (in 'hh:mm:ss.ff' format)
+ - '3652058 23:59:59.999999' (in 'DD hh:mm:ss.ff' format)
+ */
+ static uint max_useful_hour()
+ {
+ return 87649415;
+ }
+public:
+ Interval_DDhhmmssff(THD *thd, Status *st, bool push_warnings,
+ Item *item, ulong max_hour);
+ Interval_DDhhmmssff(THD *thd, Item *item)
+ {
+ Status st;
+ new(this) Interval_DDhhmmssff(thd, &st, true, item, max_useful_hour());
+ }
+ const MYSQL_TIME *get_mysql_time() const
+ {
+ DBUG_ASSERT(is_valid_interval_DDhhmmssff_slow());
+ return this;
+ }
+ bool is_valid_interval_DDhhmmssff() const
+ {
+ return time_type == MYSQL_TIMESTAMP_TIME;
+ }
+ bool is_valid_value() const
+ {
+ return time_type == MYSQL_TIMESTAMP_NONE || is_valid_interval_DDhhmmssff();
+ }
};
@@ -533,6 +901,7 @@ class Time: public Temporal
public:
enum datetime_to_time_mode_t
{
+ DATETIME_TO_TIME_DISALLOW,
DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS,
DATETIME_TO_TIME_YYYYMMDD_TRUNCATE,
DATETIME_TO_TIME_YYYYMMDD_00000000_ONLY,
@@ -540,22 +909,22 @@ public:
};
class Options
{
- sql_mode_t m_get_date_flags;
+ date_mode_t m_get_date_flags;
datetime_to_time_mode_t m_datetime_to_time_mode;
public:
Options()
:m_get_date_flags(flags_for_get_date()),
m_datetime_to_time_mode(DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS)
{ }
- Options(sql_mode_t flags)
+ Options(date_mode_t flags)
:m_get_date_flags(flags),
m_datetime_to_time_mode(DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS)
{ }
- Options(sql_mode_t flags, datetime_to_time_mode_t dtmode)
+ Options(date_mode_t flags, datetime_to_time_mode_t dtmode)
:m_get_date_flags(flags),
m_datetime_to_time_mode(dtmode)
{ }
- sql_mode_t get_date_flags() const
+ date_mode_t get_date_flags() const
{ return m_get_date_flags; }
datetime_to_time_mode_t datetime_to_time_mode() const
{ return m_datetime_to_time_mode; }
@@ -571,6 +940,10 @@ public:
Options_for_cast()
:Options(flags_for_get_date(), DATETIME_TO_TIME_YYYYMMDD_TRUNCATE)
{ }
+ Options_for_cast(date_mode_t mode)
+ :Options(flags_for_get_date() | (mode & TIME_FUZZY_DATES),
+ DATETIME_TO_TIME_YYYYMMDD_TRUNCATE)
+ { }
};
private:
bool is_valid_value_slow() const
@@ -580,10 +953,7 @@ private:
bool is_valid_time_slow() const
{
return time_type == MYSQL_TIMESTAMP_TIME &&
- year == 0 && month == 0 && day == 0 &&
- minute <= TIME_MAX_MINUTE &&
- second <= TIME_MAX_SECOND &&
- second_part <= TIME_MAX_SECOND_PART;
+ has_zero_YYYYMMDD() && has_valid_mmssff();
}
void hhmmssff_copy(const MYSQL_TIME *from)
{
@@ -611,7 +981,7 @@ private:
{
MYSQL_TIME current_date, tmp;
set_current_date(thd, &current_date);
- calc_time_diff(this, &current_date, 1, &tmp, 0);
+ calc_time_diff(this, &current_date, 1, &tmp, date_mode_t(0));
static_cast<MYSQL_TIME*>(this)[0]= tmp;
int warnings= 0;
(void) check_time_range(this, TIME_SECOND_PART_DIGITS, &warnings);
@@ -623,7 +993,7 @@ private:
e.g. returned from Item::get_date(), str_to_time(), number_to_time().
After this call, "this" is a valid TIME value.
*/
- void valid_datetime_to_valid_time(int *warn, const Options opt)
+ void valid_datetime_to_valid_time(THD *thd, int *warn, const Options opt)
{
DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_DATE ||
time_type == MYSQL_TIMESTAMP_DATETIME);
@@ -640,7 +1010,7 @@ private:
DBUG_ASSERT(hour < 24);
if (opt.datetime_to_time_mode() == DATETIME_TO_TIME_MINUS_CURRENT_DATE)
{
- datetime_to_time_minus_current_date(current_thd);
+ datetime_to_time_minus_current_date(thd);
}
else
{
@@ -665,7 +1035,7 @@ private:
- either a valid TIME (within the supported TIME range),
- or MYSQL_TIMESTAMP_NONE
*/
- void valid_MYSQL_TIME_to_valid_value(int *warn, const Options opt)
+ void valid_MYSQL_TIME_to_valid_value(THD *thd, int *warn, const Options opt)
{
switch (time_type) {
case MYSQL_TIMESTAMP_DATE:
@@ -674,8 +1044,10 @@ private:
DATETIME_TO_TIME_YYYYMMDD_00000000_ONLY &&
(year || month || day))
make_from_out_of_range(warn);
+ else if (opt.datetime_to_time_mode() == DATETIME_TO_TIME_DISALLOW)
+ make_from_out_of_range(warn);
else
- valid_datetime_to_valid_time(warn, opt);
+ valid_datetime_to_valid_time(thd, warn, opt);
break;
case MYSQL_TIMESTAMP_NONE:
break;
@@ -694,11 +1066,11 @@ private:
We trust that xxx_to_time() returns a valid TIME/DATE/DATETIME value,
so here we need to do only simple validation.
*/
- void xxx_to_time_result_to_valid_value(int *warn, const Options opt)
+ void xxx_to_time_result_to_valid_value(THD *thd, int *warn, const Options opt)
{
// str_to_time(), number_to_time() never return MYSQL_TIMESTAMP_ERROR
DBUG_ASSERT(time_type != MYSQL_TIMESTAMP_ERROR);
- valid_MYSQL_TIME_to_valid_value(warn, opt);
+ valid_MYSQL_TIME_to_valid_value(thd, warn, opt);
}
void adjust_time_range_or_invalidate(int *warn)
{
@@ -711,7 +1083,7 @@ private:
long curdays);
void make_from_time(int *warn, const MYSQL_TIME *from);
void make_from_datetime(int *warn, const MYSQL_TIME *from, long curdays);
- void make_from_item(int *warn, Item *item, const Options opt);
+ void make_from_item(THD *thd, int *warn, Item *item, const Options opt);
public:
/*
All constructors that accept an "int *warn" parameter initialize *warn.
@@ -719,44 +1091,62 @@ public:
*/
Time() { time_type= MYSQL_TIMESTAMP_NONE; }
Time(Item *item)
+ :Time(current_thd, item, Options())
+ { }
+ Time(THD *thd, Item *item, const Options opt)
{
int warn;
- make_from_item(&warn, item, Options());
- }
- Time(Item *item, const Options opt)
- {
- int warn;
- make_from_item(&warn, item, opt);
+ make_from_item(thd, &warn, item, opt);
}
+ Time(THD *thd, Item *item)
+ :Time(thd, item, Options())
+ { }
Time(int *warn, const MYSQL_TIME *from, long curdays);
- Time(int *warn, const char *str, size_t len, CHARSET_INFO *cs,
+ Time(THD *thd, MYSQL_TIME_STATUS *status,
+ const char *str, size_t len, CHARSET_INFO *cs,
const Options opt)
{
- MYSQL_TIME_STATUS status;
- if (str_to_time(cs, str, len, this, opt.get_date_flags(), &status))
+ if (str_to_time(status, str, len, cs, opt.get_date_flags()))
time_type= MYSQL_TIMESTAMP_NONE;
// The below call will optionally add notes to already collected warnings:
- xxx_to_time_result_to_valid_value(&status.warnings, opt);
- *warn= status.warnings;
+ xxx_to_time_result_to_valid_value(thd, &status->warnings, opt);
}
- Time(int *warn, const Sec6 &nr, const Options opt)
+ Time(THD *thd, int *warn, const Sec6 &nr, const Options opt)
{
if (nr.to_time(this, warn))
time_type= MYSQL_TIMESTAMP_NONE;
- xxx_to_time_result_to_valid_value(warn, opt);
+ xxx_to_time_result_to_valid_value(thd, warn, opt);
}
- Time(int *warn, double nr)
- :Temporal(Time(warn, Sec6(nr), Options()))
- { }
- Time(int *warn, longlong nr, bool unsigned_val)
- :Temporal(Time(warn, Sec6(nr, unsigned_val), Options()))
+ Time(THD *thd, int *warn, const Sec6 &nr)
+ :Time(thd, warn, nr, Options())
{ }
- Time(int *warn, const my_decimal *d)
- :Temporal(Time(warn, Sec6(d), Options()))
- { }
- static sql_mode_t flags_for_get_date()
+
+ Time(THD *thd, Item *item, const Options opt, uint dec)
+ :Time(thd, item, opt)
+ {
+ trunc(dec);
+ }
+ Time(int *warn, const MYSQL_TIME *from, long curdays, uint dec)
+ :Time(warn, from, curdays)
+ {
+ trunc(dec);
+ }
+ Time(THD *thd, MYSQL_TIME_STATUS *status,
+ const char *str, size_t len, CHARSET_INFO *cs,
+ const Options &opt, uint dec)
+ :Time(thd, status, str, len, cs, opt)
+ {
+ trunc(dec);
+ }
+ Time(THD *thd, int *warn, const Sec6 &nr, uint dec)
+ :Time(thd, warn, nr)
+ {
+ trunc(dec);
+ }
+
+ static date_mode_t flags_for_get_date()
{ return TIME_TIME_ONLY | TIME_INVALID_DATES; }
- static sql_mode_t comparison_flags_for_get_date()
+ static date_mode_t comparison_flags_for_get_date()
{ return TIME_TIME_ONLY | TIME_INVALID_DATES | TIME_FUZZY_DATES; }
bool is_valid_time() const
{
@@ -829,11 +1219,12 @@ public:
{
return is_valid_time() ? Temporal::to_packed() : 0;
}
- Time trunc(uint dec) const
+ Time &trunc(uint dec)
{
- Time tm(*this);
- my_time_trunc(&tm, dec);
- return tm;
+ if (is_valid_time())
+ my_time_trunc(this, dec);
+ DBUG_ASSERT(is_valid_value_slow());
+ return *this;
}
};
@@ -864,14 +1255,39 @@ public:
class Temporal_with_date: public Temporal
{
protected:
- void check_date_or_invalidate(int *warn, sql_mode_t flags);
- void make_from_item(THD *thd, Item *item, sql_mode_t flags);
+ void check_date_or_invalidate(int *warn, date_mode_t flags);
+ void make_from_item(THD *thd, Item *item, date_mode_t flags);
void make_from_item(THD *thd, Item *item);
+
+ ulong daynr() const
+ {
+ return (ulong) ::calc_daynr((uint) year, (uint) month, (uint) day);
+ }
+ ulong dayofyear() const
+ {
+ return (ulong) (daynr() - ::calc_daynr(year, 1, 1) + 1);
+ }
+ uint quarter() const
+ {
+ return (month + 2) / 3;
+ }
+ uint week(uint week_behaviour) const
+ {
+ uint year;
+ return calc_week(this, week_behaviour, &year);
+ }
+ uint yearweek(uint week_behaviour) const
+ {
+ uint year;
+ uint week= calc_week(this, week_behaviour, &year);
+ return week + year * 100;
+ }
+
Temporal_with_date()
{
time_type= MYSQL_TIMESTAMP_NONE;
}
- Temporal_with_date(THD *thd, Item *item, sql_mode_t flags)
+ Temporal_with_date(THD *thd, Item *item, date_mode_t flags)
{
make_from_item(thd, item, flags);
}
@@ -879,27 +1295,26 @@ protected:
{
make_from_item(thd, item);
}
- Temporal_with_date(int *warn, const Sec6 &nr, sql_mode_t flags)
+ Temporal_with_date(int *warn, const Sec6 &nr, date_mode_t flags)
{
- DBUG_ASSERT((flags & TIME_TIME_ONLY) == 0);
+ DBUG_ASSERT(bool(flags & TIME_TIME_ONLY) == false);
if (nr.to_datetime(this, flags, warn))
time_type= MYSQL_TIMESTAMP_NONE;
}
- Temporal_with_date(int *warn, const char *str, size_t len, CHARSET_INFO *cs,
- sql_mode_t flags)
+ Temporal_with_date(MYSQL_TIME_STATUS *status,
+ const char *str, size_t len, CHARSET_INFO *cs,
+ date_mode_t flags)
{
- DBUG_ASSERT((flags & TIME_TIME_ONLY) == 0);
- MYSQL_TIME_STATUS status;
- if (str_to_datetime(cs, str, len, this, flags, &status))
+ DBUG_ASSERT(bool(flags & TIME_TIME_ONLY) == false);
+ if (str_to_datetime(status, str, len, cs, flags))
time_type= MYSQL_TIMESTAMP_NONE;
- *warn= status.warnings;
}
public:
- bool check_date_with_warn(ulonglong flags)
+ bool check_date_with_warn(THD *thd, date_mode_t flags)
{
- return ::check_date_with_warn(this, flags, MYSQL_TIMESTAMP_ERROR);
+ return ::check_date_with_warn(thd, this, flags, MYSQL_TIMESTAMP_ERROR);
}
- static sql_mode_t comparison_flags_for_get_date()
+ static date_mode_t comparison_flags_for_get_date()
{ return TIME_INVALID_DATES | TIME_FUZZY_DATES; }
};
@@ -925,7 +1340,7 @@ class Date: public Temporal_with_date
return !check_datetime_range(this);
}
public:
- Date(THD *thd, Item *item, sql_mode_t flags)
+ Date(THD *thd, Item *item, date_mode_t flags)
:Temporal_with_date(thd, item, flags)
{
if (time_type == MYSQL_TIMESTAMP_DATETIME)
@@ -940,12 +1355,8 @@ public:
DBUG_ASSERT(is_valid_value_slow());
}
Date(Item *item)
- :Temporal_with_date(current_thd, item)
- {
- if (time_type == MYSQL_TIMESTAMP_DATETIME)
- datetime_to_date(this);
- DBUG_ASSERT(is_valid_value_slow());
- }
+ :Date(current_thd, item)
+ { }
Date(const Temporal_with_date *d)
:Temporal_with_date(*d)
{
@@ -973,6 +1384,32 @@ public:
*ltime= *this;
return false;
}
+ ulong daynr() const
+ {
+ DBUG_ASSERT(is_valid_date_slow());
+ return Temporal_with_date::daynr();
+ }
+ ulong dayofyear() const
+ {
+ DBUG_ASSERT(is_valid_date_slow());
+ return Temporal_with_date::dayofyear();
+ }
+ uint quarter() const
+ {
+ DBUG_ASSERT(is_valid_date_slow());
+ return Temporal_with_date::quarter();
+ }
+ uint week(uint week_behaviour) const
+ {
+ DBUG_ASSERT(is_valid_date_slow());
+ return Temporal_with_date::week(week_behaviour);
+ }
+ uint yearweek(uint week_behaviour) const
+ {
+ DBUG_ASSERT(is_valid_date_slow());
+ return Temporal_with_date::yearweek(week_behaviour);
+ }
+
longlong to_longlong() const
{
return is_valid_date() ? (longlong) TIME_to_ulonglong_date(this) : 0LL;
@@ -1024,11 +1461,11 @@ class Datetime: public Temporal_with_date
date_to_datetime(this);
}
void make_from_time(THD *thd, int *warn, const MYSQL_TIME *from,
- sql_mode_t flags);
+ date_mode_t flags);
void make_from_datetime(THD *thd, int *warn, const MYSQL_TIME *from,
- sql_mode_t flags);
+ date_mode_t flags);
public:
- Datetime(THD *thd, Item *item, sql_mode_t flags)
+ Datetime(THD *thd, Item *item, date_mode_t flags)
:Temporal_with_date(thd, item, flags)
{
date_to_datetime_if_needed();
@@ -1041,47 +1478,50 @@ public:
DBUG_ASSERT(is_valid_value_slow());
}
Datetime(Item *item)
- :Temporal_with_date(current_thd, item)
- {
- date_to_datetime_if_needed();
- DBUG_ASSERT(is_valid_value_slow());
- }
- Datetime(THD *thd, int *warn, const MYSQL_TIME *from, sql_mode_t flags);
+ :Datetime(current_thd, item)
+ { }
+ Datetime(THD *thd, int *warn, const MYSQL_TIME *from, date_mode_t flags);
Datetime()
{
set_zero_time(this, MYSQL_TIMESTAMP_DATETIME);
}
- Datetime(int *warn, const char *str, size_t len, CHARSET_INFO *cs,
- sql_mode_t flags)
- :Temporal_with_date(warn, str, len, cs, flags)
+ Datetime(MYSQL_TIME_STATUS *status,
+ const char *str, size_t len, CHARSET_INFO *cs,
+ date_mode_t flags)
+ :Temporal_with_date(status, str, len, cs, flags)
{
date_to_datetime_if_needed();
DBUG_ASSERT(is_valid_value_slow());
}
- Datetime(int *warn, double nr, sql_mode_t flags)
- :Temporal_with_date(warn, Sec6(nr), flags)
+ Datetime(int *warn, const Sec6 &nr, date_mode_t flags)
+ :Temporal_with_date(warn, nr, flags)
{
date_to_datetime_if_needed();
DBUG_ASSERT(is_valid_value_slow());
}
- Datetime(int *warn, const my_decimal *d, sql_mode_t flags)
- :Temporal_with_date(warn, Sec6(d), flags)
+
+ Datetime(THD *thd, Item *item, date_mode_t flags, uint dec)
+ :Datetime(thd, item, flags)
{
- date_to_datetime_if_needed();
- DBUG_ASSERT(is_valid_value_slow());
+ trunc(dec);
}
- /*
- Create a Datime object from a longlong number.
- Note, unlike in Time(), we don't need an "unsigned_val" here,
- as it's not important if overflow happened because
- of a negative number, or because of a huge positive number.
- */
- Datetime(int *warn, longlong sec, ulong usec, sql_mode_t flags)
- :Temporal_with_date(warn, Sec6(false, (ulonglong) sec, usec), flags)
+ Datetime(MYSQL_TIME_STATUS *status,
+ const char *str, size_t len, CHARSET_INFO *cs,
+ date_mode_t fuzzydate, uint dec)
+ :Datetime(status, str, len, cs, fuzzydate)
{
- Sec6 nr(false, (ulonglong) sec, usec);
- date_to_datetime_if_needed();
- DBUG_ASSERT(is_valid_value_slow());
+ trunc(dec);
+ }
+ Datetime(int *warn, const Sec6 &nr, date_mode_t fuzzydate, uint dec)
+ :Datetime(warn, nr, fuzzydate)
+ {
+ trunc(dec);
+ }
+ Datetime(THD *thd, int *warn, const MYSQL_TIME *from,
+ date_mode_t fuzzydate, uint dec)
+ :Datetime(thd, warn, from, fuzzydate)
+ {
+ trunc(dec);
}
bool is_valid_datetime() const
@@ -1093,11 +1533,42 @@ public:
DBUG_ASSERT(is_valid_value_slow());
return time_type == MYSQL_TIMESTAMP_DATETIME;
}
+ bool check_date(date_mode_t flags, int *warnings) const
+ {
+ DBUG_ASSERT(is_valid_datetime_slow());
+ return ::check_date(this, (year || month || day),
+ ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE),
+ warnings);
+ }
+ bool check_date(date_mode_t flags) const
+ {
+ int dummy; /* unused */
+ return check_date(flags, &dummy);
+ }
bool hhmmssff_is_zero() const
{
DBUG_ASSERT(is_valid_datetime_slow());
return hour == 0 && minute == 0 && second == 0 && second_part == 0;
}
+ ulong daynr() const
+ {
+ DBUG_ASSERT(is_valid_datetime_slow());
+ return Temporal_with_date::daynr();
+ }
+ longlong hhmmss_to_seconds_abs() const
+ {
+ DBUG_ASSERT(is_valid_datetime_slow());
+ return hour * 3600L + minute * 60 + second;
+ }
+ longlong hhmmss_to_seconds() const
+ {
+ return neg ? -hhmmss_to_seconds_abs() : hhmmss_to_seconds_abs();
+ }
+ longlong to_seconds() const
+ {
+ return hhmmss_to_seconds() + (longlong) daynr() * 24L * 3600L;
+ }
+
const MYSQL_TIME *get_mysql_time() const
{
DBUG_ASSERT(is_valid_datetime_slow());
@@ -1156,11 +1627,12 @@ public:
{
return is_valid_datetime() ? Temporal::to_packed() : 0;
}
- Datetime trunc(uint dec) const
+ Datetime &trunc(uint dec)
{
- Datetime tm(*this);
- my_time_trunc(&tm, dec);
- return tm;
+ if (is_valid_datetime())
+ my_time_trunc(this, dec);
+ DBUG_ASSERT(is_valid_value_slow());
+ return *this;
}
};
@@ -1968,8 +2440,8 @@ public:
virtual bool can_return_time() const { return true; }
virtual bool is_bool_type() const { return false; }
virtual bool is_general_purpose_string_type() const { return false; }
- virtual uint Item_time_precision(Item *item) const;
- virtual uint Item_datetime_precision(Item *item) const;
+ virtual uint Item_time_precision(THD *thd, Item *item) const;
+ virtual uint Item_datetime_precision(THD *thd, Item *item) const;
virtual uint Item_decimal_scale(const Item *item) const;
virtual uint Item_decimal_precision(const Item *item) const= 0;
/*
@@ -2092,7 +2564,7 @@ public:
virtual uint32 max_display_length(const Item *item) const= 0;
virtual uint32 calc_pack_length(uint32 length) const= 0;
virtual void Item_update_null_value(Item *item) const= 0;
- virtual bool Item_save_in_value(Item *item, st_value *value) const= 0;
+ virtual bool Item_save_in_value(THD *thd, Item *item, st_value *value) const= 0;
virtual void Item_param_setup_conversion(THD *thd, Item_param *) const {}
virtual void Item_param_set_param_func(Item_param *param,
uchar **pos, ulong len) const;
@@ -2227,8 +2699,11 @@ public:
bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const= 0;
virtual bool Item_val_bool(Item *item) const= 0;
- virtual bool Item_get_date(Item *item, MYSQL_TIME *ltime,
- ulonglong fuzzydate) const= 0;
+ virtual void Item_get_date(THD *thd, Item *item,
+ Temporal::Warn *buff, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const= 0;
+ bool Item_get_date_with_warn(THD *thd, Item *item, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const;
virtual longlong Item_val_int_signed_typecast(Item *item) const= 0;
virtual longlong Item_val_int_unsigned_typecast(Item *item) const= 0;
@@ -2249,9 +2724,15 @@ public:
Item_func_hybrid_field_type *,
my_decimal *) const= 0;
virtual
- bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+ void Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *,
+ Temporal::Warn *,
MYSQL_TIME *,
- ulonglong fuzzydate) const= 0;
+ date_mode_t fuzzydate) const= 0;
+ bool Item_func_hybrid_field_type_get_date_with_warn(THD *thd,
+ Item_func_hybrid_field_type *,
+ MYSQL_TIME *,
+ date_mode_t) const;
virtual
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const= 0;
virtual
@@ -2262,8 +2743,8 @@ public:
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
my_decimal *) const= 0;
virtual
- bool Item_func_min_max_get_date(Item_func_min_max*,
- MYSQL_TIME *, ulonglong fuzzydate) const= 0;
+ bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
+ MYSQL_TIME *, date_mode_t fuzzydate) const= 0;
virtual bool
Item_func_between_fix_length_and_dec(Item_func_between *func) const= 0;
virtual longlong
@@ -2451,7 +2932,7 @@ public:
DBUG_ASSERT(0);
return DECIMAL_MAX_PRECISION;
}
- bool Item_save_in_value(Item *item, st_value *value) const;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
@@ -2513,10 +2994,12 @@ public:
DBUG_ASSERT(0);
return false;
}
- bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const
+ void Item_get_date(THD *thd, Item *item,
+ Temporal::Warn *warn, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
{
DBUG_ASSERT(0);
- return true;
+ set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
}
longlong Item_val_int_signed_typecast(Item *item) const
{
@@ -2558,12 +3041,14 @@ public:
DBUG_ASSERT(0);
return NULL;
}
- bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
- MYSQL_TIME *,
- ulonglong fuzzydate) const
+ void Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *,
+ Temporal::Warn *,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
{
DBUG_ASSERT(0);
- return true;
+ set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
}
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const
@@ -2587,8 +3072,8 @@ public:
DBUG_ASSERT(0);
return NULL;
}
- bool Item_func_min_max_get_date(Item_func_min_max*,
- MYSQL_TIME *, ulonglong fuzzydate) const
+ bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
+ MYSQL_TIME *, date_mode_t fuzzydate) const
{
DBUG_ASSERT(0);
return true;
@@ -2672,8 +3157,8 @@ public:
longlong Item_func_min_max_val_int(Item_func_min_max *) const;
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
my_decimal *) const;
- bool Item_func_min_max_get_date(Item_func_min_max*,
- MYSQL_TIME *, ulonglong fuzzydate) const;
+ bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
+ MYSQL_TIME *, date_mode_t fuzzydate) const;
virtual ~Type_handler_numeric() { }
bool can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
@@ -2709,7 +3194,7 @@ public:
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
Item *a, Item *b) const;
uint Item_decimal_precision(const Item *item) const;
- bool Item_save_in_value(Item *item, st_value *value) const;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
@@ -2733,7 +3218,8 @@ public:
bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const;
bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const;
bool Item_val_bool(Item *item) const;
- bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const;
+ void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const;
longlong Item_val_int_signed_typecast(Item *item) const;
longlong Item_val_int_unsigned_typecast(Item *item) const;
String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const;
@@ -2746,9 +3232,11 @@ public:
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
my_decimal *) const;
- bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+ void Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *,
+ Temporal::Warn *,
MYSQL_TIME *,
- ulonglong fuzzydate) const;
+ date_mode_t fuzzydate) const;
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
longlong Item_func_between_val_int(Item_func_between *func) const;
cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
@@ -2800,7 +3288,7 @@ public:
return va.ptr() && vb.ptr() && !va.cmp(vb);
}
uint Item_decimal_precision(const Item *item) const;
- bool Item_save_in_value(Item *item, st_value *value) const;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
void Item_param_set_param_func(Item_param *param,
uchar **pos, ulong len) const;
bool Item_param_set_from_value(THD *thd,
@@ -2829,10 +3317,8 @@ public:
{
return VDec(item).to_bool();
}
- bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const
- {
- return VDec(item).to_datetime_with_warn(ltime, fuzzydate, item);
- }
+ void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const;
longlong Item_val_int_signed_typecast(Item *item) const;
longlong Item_val_int_unsigned_typecast(Item *item) const
{
@@ -2848,9 +3334,11 @@ public:
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
my_decimal *) const;
- bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+ void Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *,
+ Temporal::Warn *,
MYSQL_TIME *,
- ulonglong fuzzydate) const;
+ date_mode_t fuzzydate) const;
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
longlong Item_func_between_val_int(Item_func_between *func) const;
cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
@@ -3017,7 +3505,7 @@ public:
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
Item *a, Item *b) const;
uint Item_decimal_precision(const Item *item) const;
- bool Item_save_in_value(Item *item, st_value *value) const;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
@@ -3037,7 +3525,8 @@ public:
bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const;
bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const;
bool Item_val_bool(Item *item) const;
- bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const;
+ void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const;
longlong Item_val_int_signed_typecast(Item *item) const;
longlong Item_val_int_unsigned_typecast(Item *item) const;
String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const;
@@ -3050,9 +3539,11 @@ public:
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
my_decimal *) const;
- bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+ void Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *,
+ Temporal::Warn *,
MYSQL_TIME *,
- ulonglong fuzzydate) const;
+ date_mode_t fuzzydate) const;
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
longlong Item_func_between_val_int(Item_func_between *func) const;
cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
@@ -3110,12 +3601,15 @@ public:
Item *source_expr, Item *source_const) const;
bool subquery_type_allows_materialization(const Item *inner,
const Item *outer) const;
+ bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
+ Item **items, uint nitems) const;
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const;
bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const;
bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const;
bool Item_val_bool(Item *item) const;
- bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const;
+ void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const;
longlong Item_val_int_signed_typecast(Item *item) const;
longlong Item_val_int_unsigned_typecast(Item *item) const;
String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const;
@@ -3128,15 +3622,13 @@ public:
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
my_decimal *) const;
- bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+ void Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *,
+ Temporal::Warn *,
MYSQL_TIME *,
- ulonglong fuzzydate) const;
- double Item_func_min_max_val_real(Item_func_min_max *) const;
- longlong Item_func_min_max_val_int(Item_func_min_max *) const;
- my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
- my_decimal *) const;
- bool Item_func_min_max_get_date(Item_func_min_max*,
- MYSQL_TIME *, ulonglong fuzzydate) const;
+ date_mode_t fuzzydate) const;
+ bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
+ MYSQL_TIME *, date_mode_t fuzzydate) const;
bool Item_func_between_fix_length_and_dec(Item_func_between *func) const;
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
Item_func_in *) const;
@@ -3155,7 +3647,7 @@ public:
class Type_handler_string_result: public Type_handler
{
- uint Item_temporal_precision(Item *item, bool is_time) const;
+ uint Item_temporal_precision(THD *thd, Item *item, bool is_time) const;
public:
Item_result result_type() const { return STRING_RESULT; }
Item_result cmp_type() const { return STRING_RESULT; }
@@ -3186,17 +3678,17 @@ public:
bool binary_cmp) const;
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
Item *a, Item *b) const;
- uint Item_time_precision(Item *item) const
+ uint Item_time_precision(THD *thd, Item *item) const
{
- return Item_temporal_precision(item, true);
+ return Item_temporal_precision(thd, item, true);
}
- uint Item_datetime_precision(Item *item) const
+ uint Item_datetime_precision(THD *thd, Item *item) const
{
- return Item_temporal_precision(item, false);
+ return Item_temporal_precision(thd, item, false);
}
uint Item_decimal_precision(const Item *item) const;
void Item_update_null_value(Item *item) const;
- bool Item_save_in_value(Item *item, st_value *value) const;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
void Item_param_setup_conversion(THD *thd, Item_param *) const;
void Item_param_set_param_func(Item_param *param,
uchar **pos, ulong len) const;
@@ -3234,7 +3726,8 @@ public:
bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const;
bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const;
bool Item_val_bool(Item *item) const;
- bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const;
+ void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const;
longlong Item_val_int_signed_typecast(Item *item) const;
longlong Item_val_int_unsigned_typecast(Item *item) const;
String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const;
@@ -3247,16 +3740,18 @@ public:
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
my_decimal *) const;
- bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+ void Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *,
+ Temporal::Warn *,
MYSQL_TIME *,
- ulonglong fuzzydate) const;
+ date_mode_t fuzzydate) const;
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
double Item_func_min_max_val_real(Item_func_min_max *) const;
longlong Item_func_min_max_val_int(Item_func_min_max *) const;
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
my_decimal *) const;
- bool Item_func_min_max_get_date(Item_func_min_max*,
- MYSQL_TIME *, ulonglong fuzzydate) const;
+ bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
+ MYSQL_TIME *, date_mode_t fuzzydate) const;
bool Item_func_between_fix_length_and_dec(Item_func_between *func) const;
longlong Item_func_between_val_int(Item_func_between *func) const;
bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const;
@@ -3568,10 +4063,13 @@ public:
const Column_definition_attributes *attr,
uint32 flags) const;
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
- bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const;
- bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *item,
+ void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const;
+ void Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *item,
+ Temporal::Warn *,
MYSQL_TIME *to,
- ulonglong fuzzydate) const;
+ date_mode_t fuzzydate) const;
};
@@ -3730,7 +4228,7 @@ public:
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
void Column_definition_implicit_upgrade(Column_definition *c) const;
bool Column_definition_fix_attributes(Column_definition *c) const;
- bool Item_save_in_value(Item *item, st_value *value) const;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
{
return Item_send_time(item, protocol, buf);
@@ -3753,12 +4251,18 @@ public:
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
my_decimal *) const;
- bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+ void Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *,
+ Temporal::Warn *,
MYSQL_TIME *,
- ulonglong fuzzydate) const;
+ date_mode_t fuzzydate) const;
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
- bool Item_func_min_max_get_date(Item_func_min_max*,
- MYSQL_TIME *, ulonglong fuzzydate) const;
+ double Item_func_min_max_val_real(Item_func_min_max *) const;
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const;
+ my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
+ my_decimal *) const;
+ bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
+ MYSQL_TIME *, date_mode_t fuzzydate) const;
longlong Item_func_between_val_int(Item_func_between *func) const;
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
bool set_comparator_func(Arg_comparator *cmp) const;
@@ -3834,7 +4338,7 @@ public:
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
Item *a, Item *b) const;
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
- bool Item_save_in_value(Item *item, st_value *value) const;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
{
return Item_send_date(item, protocol, buf);
@@ -3874,6 +4378,10 @@ public:
String *print_item_value(THD *thd, Item *item, String *str) const;
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
+ double Item_func_min_max_val_real(Item_func_min_max *) const;
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const;
+ my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
+ my_decimal *) const;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
@@ -3970,6 +4478,10 @@ public:
String *print_item_value(THD *thd, Item *item, String *str) const;
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
+ double Item_func_min_max_val_real(Item_func_min_max *) const;
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const;
+ my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
+ my_decimal *) const;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
@@ -4070,6 +4582,10 @@ public:
String *print_item_value(THD *thd, Item *item, String *str) const;
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
+ double Item_func_min_max_val_real(Item_func_min_max *) const;
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const;
+ my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
+ my_decimal *) const;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
@@ -4221,7 +4737,7 @@ public:
uint32 calc_pack_length(uint32 length) const { return 0; }
bool Item_const_eq(const Item_const *a, const Item_const *b,
bool binary_cmp) const;
- bool Item_save_in_value(Item *item, st_value *value) const;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
bool Item_send(Item *item, Protocol *protocol, st_value *buf) const;
Field *make_conversion_table_field(TABLE *, uint metadata,
const Field *target) const;
diff --git a/sql/sql_type_int.h b/sql/sql_type_int.h
new file mode 100644
index 00000000000..1cc93415176
--- /dev/null
+++ b/sql/sql_type_int.h
@@ -0,0 +1,82 @@
+/* Copyright (c) 2018, 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
+ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#ifndef SQL_TYPE_INT_INCLUDED
+#define SQL_TYPE_INT_INCLUDED
+
+
+class Null_flag
+{
+protected:
+ bool m_is_null;
+public:
+ bool is_null() const { return m_is_null; }
+ Null_flag(bool is_null) :m_is_null(is_null) { }
+};
+
+
+class Longlong
+{
+protected:
+ longlong m_value;
+public:
+ longlong value() const { return m_value; }
+ Longlong(longlong nr) :m_value(nr) { }
+};
+
+
+class Longlong_null: public Longlong, public Null_flag
+{
+public:
+ Longlong_null(longlong nr, bool is_null)
+ :Longlong(nr), Null_flag(is_null)
+ { }
+};
+
+
+// A longlong/ulonglong hybrid. Good to store results of val_int().
+class Longlong_hybrid: public Longlong
+{
+protected:
+ bool m_unsigned;
+public:
+ Longlong_hybrid(longlong nr, bool unsigned_flag)
+ :Longlong(nr), m_unsigned(unsigned_flag)
+ { }
+ bool is_unsigned() const { return m_unsigned; }
+ bool neg() const { return m_value < 0 && !m_unsigned; }
+ ulonglong abs() const
+ {
+ if (m_unsigned)
+ return (ulonglong) m_value;
+ if (m_value == LONGLONG_MIN) // avoid undefined behavior
+ return ((ulonglong) LONGLONG_MAX) + 1;
+ return m_value < 0 ? -m_value : m_value;
+ }
+};
+
+
+class Longlong_hybrid_null: public Longlong_hybrid,
+ public Null_flag
+{
+public:
+ Longlong_hybrid_null(const Longlong_null &nr, bool unsigned_flag)
+ :Longlong_hybrid(nr.value(), unsigned_flag),
+ Null_flag(nr.is_null())
+ { }
+};
+
+
+#endif // SQL_TYPE_INT_INCLUDED
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index be987b82cba..1910ad0f83e 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -1321,6 +1321,8 @@ bool st_select_lex_unit::optimize()
thd->lex->current_select= lex_select_save;
DBUG_RETURN(TRUE);
}
+ if (derived)
+ sl->increase_derived_records(sl->tvc->get_records());
continue;
}
thd->lex->current_select= sl;
@@ -1726,6 +1728,7 @@ bool st_select_lex_unit::exec_recursive()
}
}
thd->lex->current_select= sl;
+ set_limit(sl);
if (sl->tvc)
sl->tvc->exec(sl);
else
@@ -1794,6 +1797,37 @@ bool st_select_lex_unit::cleanup()
{
DBUG_RETURN(FALSE);
}
+ /*
+ When processing a PS/SP or an EXPLAIN command cleanup of a unit can
+ be performed immediately when the unit is reached in the cleanup
+ traversal initiated by the cleanup of the main unit.
+ */
+ if (!thd->stmt_arena->is_stmt_prepare() && !thd->lex->describe &&
+ with_element && with_element->is_recursive && union_result)
+ {
+ select_union_recursive *result= with_element->rec_result;
+ if (++result->cleanup_count == with_element->rec_outer_references)
+ {
+ /*
+ Perform cleanup for with_element and for all with elements
+ mutually recursive with it.
+ */
+ cleaned= 1;
+ with_element->get_next_mutually_recursive()->spec->cleanup();
+ }
+ else
+ {
+ /*
+ Just increment by 1 cleanup_count for with_element and
+ for all with elements mutually recursive with it.
+ */
+ With_element *with_elem= with_element;
+ while ((with_elem= with_elem->get_next_mutually_recursive()) !=
+ with_element)
+ with_elem->rec_result->cleanup_count++;
+ DBUG_RETURN(FALSE);
+ }
+ }
cleaned= 1;
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
@@ -1824,7 +1858,7 @@ bool st_select_lex_unit::cleanup()
if (with_element && with_element->is_recursive)
{
- if (union_result )
+ if (union_result)
{
((select_union_recursive *) union_result)->cleanup();
delete union_result;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 6994ffa04a9..63240c1547d 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1255,7 +1255,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
table_list->register_want_access(SELECT_ACL);
#endif
- thd->lex->allow_sum_func= 0;
+ thd->lex->allow_sum_func.clear_all();
/*
We do not call DT_MERGE_FOR_INSERT because it has no sense for simple
@@ -2268,7 +2268,7 @@ multi_update::~multi_update()
TABLE_LIST *table;
for (table= update_tables ; table; table= table->next_local)
{
- table->table->no_keyread= table->table->no_cache= 0;
+ table->table->no_keyread= 0;
if (ignore)
table->table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
}
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index f2fc4b6bf75..e475a3d3719 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -711,9 +711,10 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
DBUG_RETURN(0);
#ifdef WITH_WSREP
- error:
- res= TRUE;
-#endif /* WITH_WSREP */
+wsrep_error_label:
+ res= true;
+#endif
+
err:
lex->link_first_table_back(view, link_to_local);
unit->cleanup();
@@ -1559,9 +1560,8 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
{
/* We have to keep the lock type for sequence tables */
if (!tbl->sequence)
- tbl->lock_type= table->lock_type;
- tbl->mdl_request.set_type((tbl->lock_type >= TL_WRITE_ALLOW_WRITE) ?
- MDL_SHARED_WRITE : MDL_SHARED_READ);
+ tbl->lock_type= table->lock_type;
+ tbl->mdl_request.set_type(table->mdl_request.type);
}
/*
If the view is mergeable, we might want to
diff --git a/sql/sql_window.cc b/sql/sql_window.cc
index 38fdd8ab80b..dcc6a7bac1c 100644
--- a/sql/sql_window.cc
+++ b/sql/sql_window.cc
@@ -82,19 +82,32 @@ void
Window_spec::print(String *str, enum_query_type query_type)
{
str->append('(');
+ print_partition(str, query_type);
+ print_order(str, query_type);
+
+ if (window_frame)
+ window_frame->print(str, query_type);
+ str->append(')');
+}
+
+void
+Window_spec::print_partition(String *str, enum_query_type query_type)
+{
if (partition_list->first)
{
str->append(STRING_WITH_LEN(" partition by "));
st_select_lex::print_order(str, partition_list->first, query_type);
}
+}
+
+void
+Window_spec::print_order(String *str, enum_query_type query_type)
+{
if (order_list->first)
{
str->append(STRING_WITH_LEN(" order by "));
st_select_lex::print_order(str, order_list->first, query_type);
}
- if (window_frame)
- window_frame->print(str, query_type);
- str->append(')');
}
bool
@@ -2928,7 +2941,7 @@ bool Window_func_runner::exec(THD *thd, TABLE *tbl, SORT_INFO *filesort_result)
}
-bool Window_funcs_sort::exec(JOIN *join)
+bool Window_funcs_sort::exec(JOIN *join, bool keep_filesort_result)
{
THD *thd= join->thd;
JOIN_TAB *join_tab= join->join_tab + join->total_join_tab_cnt();
@@ -2943,8 +2956,11 @@ bool Window_funcs_sort::exec(JOIN *join)
bool is_error= runner.exec(thd, tbl, filesort_result);
- delete join_tab->filesort_result;
- join_tab->filesort_result= NULL;
+ if (!keep_filesort_result)
+ {
+ delete join_tab->filesort_result;
+ join_tab->filesort_result= NULL;
+ }
return is_error;
}
@@ -3053,14 +3069,18 @@ bool Window_funcs_computation::setup(THD *thd,
}
-bool Window_funcs_computation::exec(JOIN *join)
+bool Window_funcs_computation::exec(JOIN *join, bool keep_last_filesort_result)
{
List_iterator<Window_funcs_sort> it(win_func_sorts);
Window_funcs_sort *srt;
+ uint counter= 0; /* Count how many sorts we've executed. */
/* Execute each sort */
while ((srt = it++))
{
- if (srt->exec(join))
+ counter++;
+ bool keep_filesort_result= keep_last_filesort_result &&
+ counter == win_func_sorts.elements;
+ if (srt->exec(join, keep_filesort_result))
return true;
}
return false;
diff --git a/sql/sql_window.h b/sql/sql_window.h
index 392f89e8f03..21f2c8af108 100644
--- a/sql/sql_window.h
+++ b/sql/sql_window.h
@@ -147,6 +147,8 @@ class Window_spec : public Sql_alloc
}
void print(String *str, enum_query_type query_type);
+ void print_order(String *str, enum_query_type query_type);
+ void print_partition(String *str, enum_query_type query_type);
};
@@ -211,7 +213,7 @@ class Window_funcs_sort : public Sql_alloc
public:
bool setup(THD *thd, SQL_SELECT *sel, List_iterator<Item_window_func> &it,
st_join_table *join_tab);
- bool exec(JOIN *join);
+ bool exec(JOIN *join, bool keep_filesort_result);
void cleanup() { delete filesort; }
friend class Window_funcs_computation;
@@ -241,7 +243,7 @@ class Window_funcs_computation : public Sql_alloc
List<Window_funcs_sort> win_func_sorts;
public:
bool setup(THD *thd, List<Item_window_func> *window_funcs, st_join_table *tab);
- bool exec(JOIN *join);
+ bool exec(JOIN *join, bool keep_last_filesort_result);
Explain_aggr_window_funcs *save_explain_plan(MEM_ROOT *mem_root, bool is_analyze);
void cleanup();
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index cf894325ba5..9a19a5b9c8c 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -817,10 +817,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%parse-param { THD *thd }
%lex-param { THD *thd }
/*
- Currently there are 58 shift/reduce conflicts.
+ Currently there are 52 shift/reduce conflicts.
We should not introduce new conflicts any more.
*/
-%expect 58
+%expect 52
/*
Comments for TOKENS.
@@ -1582,6 +1582,16 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%left JOIN_SYM INNER_SYM STRAIGHT_JOIN CROSS LEFT RIGHT
/* A dummy token to force the priority of table_ref production in a join. */
%left TABLE_REF_PRIORITY
+
+/*
+ Give ESCAPE (in LIKE) a very low precedence.
+ This allows the concatenation operator || to be used on the right
+ side of "LIKE" with sql_mode=PIPES_AS_CONCAT (without ORACLE):
+ SELECT 'ab' LIKE 'a'||'b'||'c';
+*/
+%left PREC_BELOW_ESCAPE
+%left ESCAPE_SYM
+
%left SET_VAR
%left OR_SYM OR2_SYM
%left XOR
@@ -1591,7 +1601,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%left NOT_SYM
%left BETWEEN_SYM CASE_SYM WHEN_SYM THEN_SYM ELSE
-%left '=' EQUAL_SYM GE '>' LE '<' NE IS LIKE REGEXP IN_SYM
+%left '=' EQUAL_SYM GE '>' LE '<' NE IS LIKE SOUNDS_SYM REGEXP IN_SYM
%left '|'
%left '&'
%left SHIFT_LEFT SHIFT_RIGHT
@@ -1623,6 +1633,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
SELECT system FROM t1;
ALTER TABLE DROP SYSTEM VERSIONIONG;
+ - USER: identifier, user:
+ SELECT user FROM t1;
+ KILL USER foo;
+
Note, we need here only tokens that cause shirt/reduce conflicts
with keyword identifiers. For example:
opt_clause1: %empty | KEYWORD ... ;
@@ -1661,7 +1675,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
and until NEXT_SYM / PREVIOUS_SYM.
*/
%left PREC_BELOW_IDENTIFIER_OPT_SPECIAL_CASE
-%left TRANSACTION_SYM TIMESTAMP PERIOD_SYM SYSTEM
+%left TRANSACTION_SYM TIMESTAMP PERIOD_SYM SYSTEM USER
/*
@@ -1747,7 +1761,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
optionally_qualified_column_ident
%type <simple_string>
- remember_name remember_end remember_tok_start
+ remember_name remember_end
+ remember_tok_start remember_tok_end
wild_and_where
%type <const_simple_string>
@@ -1996,6 +2011,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
preload_list preload_list_or_parts preload_keys preload_keys_parts
select_item_list select_item values_list no_braces
delete_limit_clause fields opt_values values
+ no_braces_with_names opt_values_with_names values_with_names
procedure_list procedure_list2 procedure_item
field_def handler opt_generated_always
opt_ignore opt_column opt_restrict
@@ -2874,8 +2890,8 @@ create:
{
Lex->pop_select(); //main select
}
- | create_or_replace USER_SYM opt_if_not_exists clear_privileges grant_list
- opt_require_clause opt_resource_options
+ | create_or_replace USER_SYM opt_if_not_exists clear_privileges
+ grant_list opt_require_clause opt_resource_options
{
if (unlikely(Lex->set_command_with_check(SQLCOM_CREATE_USER,
$1 | $3)))
@@ -5938,7 +5954,7 @@ opt_versioning_rotation:
| INTERVAL_SYM expr interval opt_versioning_interval_start
{
partition_info *part_info= Lex->part_info;
- if (unlikely(part_info->vers_set_interval($2, $3, $4)))
+ if (unlikely(part_info->vers_set_interval(thd, $2, $3, $4)))
{
my_error(ER_PART_WRONG_VALUE, MYF(0),
Lex->create_last_non_select_table->table_name.str,
@@ -9425,6 +9441,12 @@ remember_tok_start:
}
;
+remember_tok_end:
+ {
+ $$= (char*) YYLIP->get_tok_end();
+ }
+ ;
+
remember_name:
{
$$= (char*) YYLIP->get_cpp_tok_start();
@@ -9713,14 +9735,14 @@ predicate:
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bit_expr LIKE mysql_concatenation_expr opt_escape
+ | bit_expr LIKE bit_expr opt_escape
{
$$= new (thd->mem_root) Item_func_like(thd, $1, $3, $4,
Lex->escape_used);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bit_expr not LIKE mysql_concatenation_expr opt_escape
+ | bit_expr not LIKE bit_expr opt_escape
{
Item *item= new (thd->mem_root) Item_func_like(thd, $1, $4, $5,
Lex->escape_used);
@@ -12106,7 +12128,7 @@ opt_escape:
Lex->escape_used= TRUE;
$$= $2;
}
- | /* empty */
+ | /* empty */ %prec PREC_BELOW_ESCAPE
{
Lex->escape_used= FALSE;
$$= ((thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) ?
@@ -13156,7 +13178,7 @@ insert_values:
values_list:
values_list ',' no_braces
- | no_braces
+ | no_braces_with_names
;
ident_eq_list:
@@ -13209,11 +13231,31 @@ no_braces:
}
;
+no_braces_with_names:
+ '('
+ {
+ if (unlikely(!(Lex->insert_list= new (thd->mem_root) List_item)))
+ MYSQL_YYABORT;
+ }
+ opt_values_with_names ')'
+ {
+ LEX *lex=Lex;
+ if (unlikely(lex->many_values.push_back(lex->insert_list,
+ thd->mem_root)))
+ MYSQL_YYABORT;
+ }
+ ;
+
opt_values:
/* empty */ {}
| values
;
+opt_values_with_names:
+ /* empty */ {}
+ | values_with_names
+ ;
+
values:
values ',' expr_or_default
{
@@ -13227,6 +13269,25 @@ values:
}
;
+values_with_names:
+ values_with_names ',' remember_name expr_or_default remember_end
+ {
+ if (unlikely(Lex->insert_list->push_back($4, thd->mem_root)))
+ MYSQL_YYABORT;
+ // give some name in case of using in table value constuctor (TVC)
+ if (!$4->name.str || $4->name.str == item_empty_name)
+ $4->set_name(thd, $3, (uint) ($5 - $3), thd->charset());
+ }
+ | remember_name expr_or_default remember_end
+ {
+ if (unlikely(Lex->insert_list->push_back($2, thd->mem_root)))
+ MYSQL_YYABORT;
+ // give some name in case of using in table value constuctor (TVC)
+ if (!$2->name.str || $2->name.str == item_empty_name)
+ $2->set_name(thd, $1, (uint) ($3 - $1), thd->charset());
+ }
+ ;
+
expr_or_default:
expr { $$= $1;}
| DEFAULT
@@ -14257,9 +14318,18 @@ delete_domain_id_list:
;
delete_domain_id:
- ulong_num
+ ulonglong_num
{
- insert_dynamic(&Lex->delete_gtid_domain, (uchar*) &($1));
+ uint32 value= (uint32) $1;
+ if ($1 > UINT_MAX32)
+ {
+ my_printf_error(ER_BINLOG_CANT_DELETE_GTID_DOMAIN,
+ "The value of gtid domain being deleted ('%llu') "
+ "exceeds its maximum size "
+ "of 32 bit unsigned integer", MYF(0), $1);
+ MYSQL_YYABORT;
+ }
+ insert_dynamic(&Lex->delete_gtid_domain, (uchar*) &value);
}
;
@@ -14439,6 +14509,7 @@ load:
lex->field_list.empty();
lex->update_list.empty();
lex->value_list.empty();
+ lex->many_values.empty();
}
opt_load_data_charset
{ Lex->exchange->cs= $15; }
@@ -14877,12 +14948,17 @@ with_list_element:
MYSQL_YYABORT;
Lex->with_column_list.empty();
}
- AS '(' remember_name query_expression remember_end ')'
+ AS '(' remember_tok_start query_expression remember_tok_end ')'
{
+ LEX *lex= thd->lex;
+ const char *query_start= lex->sphead ? lex->sphead->m_tmp_query
+ : thd->query();
+ char *spec_start= $6 + 1;
With_element *elem= new With_element($1, *$2, $7);
if (elem == NULL || Lex->curr_with_clause->add_with_element(elem))
MYSQL_YYABORT;
- if (unlikely(elem->set_unparsed_spec(thd, $6+1, $8)))
+ if (elem->set_unparsed_spec(thd, spec_start, $8,
+ spec_start - query_start))
MYSQL_YYABORT;
}
;
@@ -15790,7 +15866,7 @@ keyword_sp_var_and_label:
| UNDOFILE_SYM
| UNKNOWN_SYM
| UNTIL_SYM
- | USER_SYM
+ | USER_SYM %prec PREC_BELOW_CONTRACTION_TOKEN2
| USE_FRM
| VARIABLES
| VERSIONING_SYM
@@ -16188,14 +16264,14 @@ opt_for_user:
;
text_or_password:
- TEXT_STRING { Lex->definer->pwhash= $1;}
+ TEXT_STRING { Lex->definer->auth= $1;}
| PASSWORD_SYM '(' TEXT_STRING ')' { Lex->definer->pwtext= $3; }
| OLD_PASSWORD_SYM '(' TEXT_STRING ')'
{
Lex->definer->pwtext= $3;
- Lex->definer->pwhash.str= Item_func_password::alloc(thd,
+ Lex->definer->auth.str= Item_func_password::alloc(thd,
$3.str, $3.length, Item_func_password::OLD);
- Lex->definer->pwhash.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
+ Lex->definer->auth.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
}
;
@@ -16753,13 +16829,11 @@ grant_user:
{
$$= $1;
$1->pwtext= $4;
- if (unlikely(Lex->sql_command == SQLCOM_REVOKE))
- MYSQL_YYABORT;
}
| user IDENTIFIED_SYM BY PASSWORD_SYM TEXT_STRING
{
$$= $1;
- $1->pwhash= $5;
+ $1->auth= $5;
}
| user IDENTIFIED_SYM via_or_with ident_or_text
{
@@ -16767,12 +16841,20 @@ grant_user:
$1->plugin= $4;
$1->auth= empty_clex_str;
}
- | user IDENTIFIED_SYM via_or_with ident_or_text using_or_as TEXT_STRING_sys
+ | user IDENTIFIED_SYM via_or_with ident_or_text using_or_as
+ TEXT_STRING_sys
{
$$= $1;
$1->plugin= $4;
$1->auth= $6;
}
+ | user IDENTIFIED_SYM via_or_with ident_or_text using_or_as
+ PASSWORD_SYM '(' TEXT_STRING ')'
+ {
+ $$= $1;
+ $1->plugin= $4;
+ $1->pwtext= $8;
+ }
| user_or_role
{ $$= $1; }
;
@@ -17424,12 +17506,15 @@ opt_migrate:
;
install:
- INSTALL_SYM PLUGIN_SYM ident SONAME_SYM TEXT_STRING_sys
+ INSTALL_SYM PLUGIN_SYM opt_if_not_exists ident SONAME_SYM TEXT_STRING_sys
{
LEX *lex= Lex;
+ lex->create_info.init();
+ if (lex->add_create_options_with_check($3))
+ MYSQL_YYABORT;
lex->sql_command= SQLCOM_INSTALL_PLUGIN;
- lex->comment= $3;
- lex->ident= $5;
+ lex->comment= $4;
+ lex->ident= $6;
}
| INSTALL_SYM SONAME_SYM TEXT_STRING_sys
{
@@ -17441,18 +17526,24 @@ install:
;
uninstall:
- UNINSTALL_SYM PLUGIN_SYM ident
+ UNINSTALL_SYM PLUGIN_SYM opt_if_exists ident
{
LEX *lex= Lex;
+ lex->check_opt.init();
+ if (lex->add_create_options_with_check($3))
+ MYSQL_YYABORT;
lex->sql_command= SQLCOM_UNINSTALL_PLUGIN;
- lex->comment= $3;
+ lex->comment= $4;
}
- | UNINSTALL_SYM SONAME_SYM TEXT_STRING_sys
+ | UNINSTALL_SYM SONAME_SYM opt_if_exists TEXT_STRING_sys
{
LEX *lex= Lex;
+ lex->check_opt.init();
+ if (lex->add_create_options_with_check($3))
+ MYSQL_YYABORT;
lex->sql_command= SQLCOM_UNINSTALL_PLUGIN;
lex->comment= null_clex_str;
- lex->ident= $3;
+ lex->ident= $4;
}
;
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index ef12b9c0c53..5a6914c89c7 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -296,10 +296,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%parse-param { THD *thd }
%lex-param { THD *thd }
/*
- Currently there are 59 shift/reduce conflicts.
+ Currently there are 53 shift/reduce conflicts.
We should not introduce new conflicts any more.
*/
-%expect 59
+%expect 53
/*
Comments for TOKENS.
@@ -1061,6 +1061,16 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%left JOIN_SYM INNER_SYM STRAIGHT_JOIN CROSS LEFT RIGHT
/* A dummy token to force the priority of table_ref production in a join. */
%left TABLE_REF_PRIORITY
+
+/*
+ Give ESCAPE (in LIKE) a very low precedence.
+ This allows the concatenation operator || to be used on the right
+ side of "LIKE" with sql_mode=PIPES_AS_CONCAT (without ORACLE):
+ SELECT 'ab' LIKE 'a'||'b'||'c';
+*/
+%left PREC_BELOW_ESCAPE
+%left ESCAPE_SYM
+
%left SET_VAR
%left OR_SYM OR2_SYM
%left XOR
@@ -1070,7 +1080,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%left NOT_SYM
%left BETWEEN_SYM CASE_SYM WHEN_SYM THEN_SYM ELSE
-%left '=' EQUAL_SYM GE '>' LE '<' NE IS LIKE REGEXP IN_SYM
+%left '=' EQUAL_SYM GE '>' LE '<' NE IS LIKE SOUNDS_SYM REGEXP IN_SYM
%left '|'
%left '&'
%left SHIFT_LEFT SHIFT_RIGHT
@@ -1102,6 +1112,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
SELECT system FROM t1;
ALTER TABLE DROP SYSTEM VERSIONIONG;
+ - USER: identifier, user:
+ SELECT user FROM t1;
+ KILL USER foo;
+
Note, we need here only tokens that cause shirt/reduce conflicts
with keyword identifiers. For example:
opt_clause1: %empty | KEYWORD ... ;
@@ -1140,7 +1154,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
and until NEXT_SYM / PREVIOUS_SYM.
*/
%left PREC_BELOW_IDENTIFIER_OPT_SPECIAL_CASE
-%left TRANSACTION_SYM TIMESTAMP PERIOD_SYM SYSTEM
+%left TRANSACTION_SYM TIMESTAMP PERIOD_SYM SYSTEM USER
/*
@@ -1230,7 +1244,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
optionally_qualified_column_ident
%type <simple_string>
- remember_name remember_end remember_end_opt remember_tok_start
+ remember_name remember_end remember_end_opt
+ remember_tok_start remember_tok_end
wild_and_where
colon_with_pos
@@ -1487,6 +1502,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
assign_to_keycache_parts
preload_list preload_list_or_parts preload_keys preload_keys_parts
select_item_list select_item values_list no_braces
+ no_braces_with_names opt_values_with_names values_with_names
delete_limit_clause fields opt_values values
procedure_list procedure_list2 procedure_item
field_def handler opt_generated_always
@@ -2373,8 +2389,8 @@ create:
{
Lex->pop_select(); //main select
}
- | create_or_replace USER_SYM opt_if_not_exists clear_privileges grant_list
- opt_require_clause opt_resource_options
+ | create_or_replace USER_SYM opt_if_not_exists clear_privileges
+ grant_list opt_require_clause opt_resource_options
{
if (unlikely(Lex->set_command_with_check(SQLCOM_CREATE_USER,
$1 | $3)))
@@ -5964,7 +5980,7 @@ opt_versioning_rotation:
| INTERVAL_SYM expr interval opt_versioning_interval_start
{
partition_info *part_info= Lex->part_info;
- if (unlikely(part_info->vers_set_interval($2, $3, $4)))
+ if (unlikely(part_info->vers_set_interval(thd, $2, $3, $4)))
{
my_error(ER_PART_WRONG_VALUE, MYF(0),
Lex->create_last_non_select_table->table_name.str,
@@ -9562,6 +9578,12 @@ remember_tok_start:
}
;
+remember_tok_end:
+ {
+ $$= (char*) YYLIP->get_tok_end();
+ }
+ ;
+
remember_name:
{
$$= (char*) YYLIP->get_cpp_tok_start();
@@ -9859,14 +9881,14 @@ predicate:
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bit_expr LIKE mysql_concatenation_expr opt_escape
+ | bit_expr LIKE bit_expr opt_escape
{
$$= new (thd->mem_root) Item_func_like(thd, $1, $3, $4,
Lex->escape_used);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | bit_expr not LIKE mysql_concatenation_expr opt_escape
+ | bit_expr not LIKE bit_expr opt_escape
{
Item *item= new (thd->mem_root) Item_func_like(thd, $1, $4, $5,
Lex->escape_used);
@@ -12318,7 +12340,7 @@ opt_escape:
Lex->escape_used= TRUE;
$$= $2;
}
- | /* empty */
+ | /* empty */ %prec PREC_BELOW_ESCAPE
{
Lex->escape_used= FALSE;
$$= ((thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) ?
@@ -13384,7 +13406,7 @@ insert_values:
values_list:
values_list ',' no_braces
- | no_braces
+ | no_braces_with_names
;
ident_eq_list:
@@ -13437,11 +13459,31 @@ no_braces:
}
;
+no_braces_with_names:
+ '('
+ {
+ if (unlikely(!(Lex->insert_list= new (thd->mem_root) List_item)))
+ MYSQL_YYABORT;
+ }
+ opt_values_with_names ')'
+ {
+ LEX *lex=Lex;
+ if (unlikely(lex->many_values.push_back(lex->insert_list,
+ thd->mem_root)))
+ MYSQL_YYABORT;
+ }
+ ;
+
opt_values:
/* empty */ {}
| values
;
+opt_values_with_names:
+ /* empty */ {}
+ | values_with_names
+ ;
+
values:
values ',' expr_or_default
{
@@ -13455,6 +13497,25 @@ values:
}
;
+values_with_names:
+ values_with_names ',' remember_name expr_or_default remember_end
+ {
+ if (unlikely(Lex->insert_list->push_back($4, thd->mem_root)))
+ MYSQL_YYABORT;
+ // give some name in case of using in table value constuctor (TVC)
+ if (!$4->name.str || $4->name.str == item_empty_name)
+ $4->set_name(thd, $3, (uint) ($5 - $3), thd->charset());
+ }
+ | remember_name expr_or_default remember_end
+ {
+ if (unlikely(Lex->insert_list->push_back($2, thd->mem_root)))
+ MYSQL_YYABORT;
+ // give some name in case of using in table value constuctor (TVC)
+ if (!$2->name.str || $2->name.str == item_empty_name)
+ $2->set_name(thd, $1, (uint) ($3 - $1), thd->charset());
+ }
+ ;
+
expr_or_default:
expr { $$= $1;}
| DEFAULT
@@ -14493,9 +14554,18 @@ delete_domain_id_list:
;
delete_domain_id:
- ulong_num
+ ulonglong_num
{
- insert_dynamic(&Lex->delete_gtid_domain, (uchar*) &($1));
+ uint32 value= (uint32) $1;
+ if ($1 > UINT_MAX32)
+ {
+ my_printf_error(ER_BINLOG_CANT_DELETE_GTID_DOMAIN,
+ "The value of gtid domain being deleted ('%llu') "
+ "exceeds its maximum size "
+ "of 32 bit unsigned integer", MYF(0), $1);
+ MYSQL_YYABORT;
+ }
+ insert_dynamic(&Lex->delete_gtid_domain, (uchar*) &value);
}
;
@@ -14672,6 +14742,7 @@ load:
lex->field_list.empty();
lex->update_list.empty();
lex->value_list.empty();
+ lex->many_values.empty();
}
opt_load_data_charset
{ Lex->exchange->cs= $15; }
@@ -15122,12 +15193,17 @@ with_list_element:
MYSQL_YYABORT;
Lex->with_column_list.empty();
}
- AS '(' remember_name query_expression remember_end ')'
+ AS '(' remember_tok_start query_expression remember_tok_end ')'
{
+ LEX *lex= thd->lex;
+ const char *query_start= lex->sphead ? lex->sphead->m_tmp_query
+ : thd->query();
+ char *spec_start= $6 + 1;
With_element *elem= new With_element($1, *$2, $7);
if (elem == NULL || Lex->curr_with_clause->add_with_element(elem))
MYSQL_YYABORT;
- if (unlikely(elem->set_unparsed_spec(thd, $6+1, $8)))
+ if (elem->set_unparsed_spec(thd, spec_start, $8,
+ spec_start - query_start))
MYSQL_YYABORT;
}
;
@@ -16069,7 +16145,7 @@ keyword_sp_var_and_label:
| UNDOFILE_SYM
| UNKNOWN_SYM
| UNTIL_SYM
- | USER_SYM
+ | USER_SYM %prec PREC_BELOW_CONTRACTION_TOKEN2
| USE_FRM
| VARIABLES
| VIEW_SYM
@@ -16515,14 +16591,14 @@ opt_for_user:
;
text_or_password:
- TEXT_STRING { Lex->definer->pwhash= $1;}
+ TEXT_STRING { Lex->definer->auth= $1;}
| PASSWORD_SYM '(' TEXT_STRING ')' { Lex->definer->pwtext= $3; }
| OLD_PASSWORD_SYM '(' TEXT_STRING ')'
{
Lex->definer->pwtext= $3;
- Lex->definer->pwhash.str= Item_func_password::alloc(thd,
+ Lex->definer->auth.str= Item_func_password::alloc(thd,
$3.str, $3.length, Item_func_password::OLD);
- Lex->definer->pwhash.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
+ Lex->definer->auth.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
}
;
@@ -17106,13 +17182,11 @@ grant_user:
{
$$= $1;
$1->pwtext= $4;
- if (unlikely(Lex->sql_command == SQLCOM_REVOKE))
- MYSQL_YYABORT;
}
| user IDENTIFIED_SYM BY PASSWORD_SYM TEXT_STRING
{
$$= $1;
- $1->pwhash= $5;
+ $1->auth= $5;
}
| user IDENTIFIED_SYM via_or_with ident_or_text
{
@@ -17120,12 +17194,20 @@ grant_user:
$1->plugin= $4;
$1->auth= empty_clex_str;
}
- | user IDENTIFIED_SYM via_or_with ident_or_text using_or_as TEXT_STRING_sys
+ | user IDENTIFIED_SYM via_or_with ident_or_text using_or_as
+ TEXT_STRING_sys
{
$$= $1;
$1->plugin= $4;
$1->auth= $6;
}
+ | user IDENTIFIED_SYM via_or_with ident_or_text using_or_as
+ PASSWORD_SYM '(' TEXT_STRING ')'
+ {
+ $$= $1;
+ $1->plugin= $4;
+ $1->pwtext= $8;
+ }
| user_or_role
{ $$= $1; }
;
diff --git a/sql/structs.h b/sql/structs.h
index 355d6e75e48..9ff52bccb40 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -227,12 +227,11 @@ struct AUTHID
struct LEX_USER: public AUTHID
{
- LEX_CSTRING plugin, auth;
- LEX_CSTRING pwtext, pwhash;
+ LEX_CSTRING plugin, auth, pwtext;
void reset_auth()
{
- pwtext.length= pwhash.length= plugin.length= auth.length= 0;
- pwtext.str= pwhash.str= 0;
+ pwtext.length= plugin.length= auth.length= 0;
+ pwtext.str= 0;
plugin.str= auth.str= "";
}
};
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index ba9b2c814ce..983d0490f2e 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -471,6 +471,10 @@ bool check_has_super(sys_var *self, THD *thd, set_var *var)
return false;
}
+static Sys_var_bit Sys_core_file("core_file", "write a core-file on crashes",
+ READ_ONLY GLOBAL_VAR(test_flags), NO_CMD_LINE,
+ TEST_CORE_ON_SIGNAL, DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ 0,0,0);
static bool binlog_format_check(sys_var *self, THD *thd, set_var *var)
{
@@ -2669,6 +2673,16 @@ static Sys_var_ulong Sys_div_precincrement(
SESSION_VAR(div_precincrement), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, DECIMAL_MAX_SCALE), DEFAULT(4), BLOCK_SIZE(1));
+static Sys_var_uint Sys_eq_range_index_dive_limit(
+ "eq_range_index_dive_limit",
+ "The optimizer will use existing index statistics instead of "
+ "doing index dives for equality ranges if the number of equality "
+ "ranges for the index is larger than or equal to this number. "
+ "If set to 0, index dives are always used.",
+ SESSION_VAR(eq_range_index_dive_limit), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, UINT_MAX32), DEFAULT(0),
+ BLOCK_SIZE(1));
+
static Sys_var_ulong Sys_range_alloc_block_size(
"range_alloc_block_size",
"Allocation block size for storing ranges during optimization",
@@ -2708,17 +2722,6 @@ static Sys_var_ulong Sys_query_prealloc_size(
BLOCK_SIZE(1024), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(fix_thd_mem_root));
-#ifdef HAVE_SMEM
-static Sys_var_mybool Sys_shared_memory(
- "shared_memory", "Enable the shared memory",
- READ_ONLY GLOBAL_VAR(opt_enable_shared_memory), CMD_LINE(OPT_ARG),
- DEFAULT(FALSE));
-
-static Sys_var_charptr Sys_shared_memory_base_name(
- "shared_memory_base_name", "Base name of shared memory",
- READ_ONLY GLOBAL_VAR(shared_memory_base_name), CMD_LINE(REQUIRED_ARG),
- IN_FS_CHARSET, DEFAULT(0));
-#endif
// this has to be NO_CMD_LINE as the command-line option has a different name
static Sys_var_mybool Sys_skip_external_locking(
@@ -4114,7 +4117,7 @@ static Sys_var_bit Sys_safe_updates(
"sql_safe_updates", "If set to 1, UPDATEs and DELETEs need either a key in "
"the WHERE clause, or a LIMIT clause, or else they will aborted. Prevents "
"the common mistake of accidentally deleting or updating every row in a table.",
- SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_SAFE_UPDATES,
+ SESSION_VAR(option_bits), CMD_LINE(OPT_ARG), OPTION_SAFE_UPDATES,
DEFAULT(FALSE));
static Sys_var_bit Sys_buffer_results(
diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic
index 373df354268..dbc3565e202 100644
--- a/sql/sys_vars.ic
+++ b/sql/sys_vars.ic
@@ -2659,7 +2659,7 @@ public:
if (!Sys_var_enum::do_check(thd, var))
return false;
MYSQL_TIME ltime;
- bool res= var->value->get_date(&ltime, 0);
+ bool res= var->value->get_date(thd, &ltime, date_mode_t(0));
if (!res)
{
var->save_result.ulonglong_value= SYSTEM_TIME_AS_OF;
@@ -2676,7 +2676,7 @@ private:
{
if (var->value)
{
- res= var->value->get_date(&out.ltime, 0);
+ res= var->value->get_date(current_thd, &out.ltime, date_mode_t(0));
}
else // set DEFAULT from global var
{
diff --git a/sql/table.cc b/sql/table.cc
index 2031d27b549..18be06c0b95 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -44,6 +44,7 @@
#include "sql_cte.h"
#include "ha_sequence.h"
#include "sql_show.h"
+#include <atomic>
/* For MySQL 5.7 virtual fields */
#define MYSQL57_GENERATED_FIELD 128
@@ -79,7 +80,7 @@ LEX_CSTRING MYSQL_PROC_NAME= {STRING_WITH_LEN("proc")};
*/
static LEX_CSTRING parse_vcol_keyword= { STRING_WITH_LEN("PARSE_VCOL_EXPR ") };
-static int64 last_table_id;
+static std::atomic<ulong> last_table_id;
/* Functions defined in this file */
@@ -324,7 +325,8 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name,
share->can_do_row_logging= 1;
if (share->table_category == TABLE_CATEGORY_LOG)
share->no_replicate= 1;
- if (my_strnncoll(table_alias_charset, (uchar*) db, 6,
+ if (key_length > 6 &&
+ my_strnncoll(table_alias_charset, (const uchar*) key, 6,
(const uchar*) "mysql", 6) == 0)
share->not_usable_by_query_cache= 1;
@@ -343,8 +345,8 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name,
*/
do
{
- share->table_map_id=(ulong) my_atomic_add64_explicit(&last_table_id, 1,
- MY_MEMORY_ORDER_RELAXED);
+ share->table_map_id=
+ last_table_id.fetch_add(1, std::memory_order_relaxed);
} while (unlikely(share->table_map_id == ~0UL));
}
DBUG_RETURN(share);
@@ -431,6 +433,7 @@ void TABLE_SHARE::destroy()
ha_share= NULL; // Safety
}
+ delete_stat_values_for_table_share(this);
delete sequence;
free_root(&stats_cb.mem_root, MYF(0));
stats_cb.stats_can_be_read= FALSE;
@@ -2183,7 +2186,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
keyinfo= share->key_info;
uint primary_key= my_strcasecmp(system_charset_info, share->keynames.type_names[0],
primary_key_name) ? MAX_KEY : 0;
- KEY* key_first_info;
+ KEY* key_first_info= NULL;
if (primary_key >= MAX_KEY && keyinfo->flags & HA_NOSAME)
{
@@ -2471,7 +2474,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
if (!(key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART |
HA_BIT_PART)) &&
key_part->type != HA_KEYTYPE_FLOAT &&
- key_part->type == HA_KEYTYPE_DOUBLE)
+ key_part->type != HA_KEYTYPE_DOUBLE)
key_part->key_part_flag|= HA_CAN_MEMCMP;
}
keyinfo->usable_key_parts= usable_parts; // Filesort
@@ -3162,10 +3165,12 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
{
enum open_frm_error error;
uint records, i, bitmap_size, bitmap_count;
+ const char *tmp_alias;
bool error_reported= FALSE;
uchar *record, *bitmaps;
Field **field_ptr;
uint8 save_context_analysis_only= thd->lex->context_analysis_only;
+ TABLE_SHARE::enum_v_keys check_set_initialized= share->check_set_initialized;
DBUG_ENTER("open_table_from_share");
DBUG_PRINT("enter",("name: '%s.%s' form: %p", share->db.str,
share->table_name.str, outparam));
@@ -3189,8 +3194,14 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
init_sql_alloc(&outparam->mem_root, "table", TABLE_ALLOC_BLOCK_SIZE, 0,
MYF(0));
- if (outparam->alias.copy(alias->str, alias->length, table_alias_charset))
+ /*
+ We have to store the original alias in mem_root as constraints and virtual
+ functions may store pointers to it
+ */
+ if (!(tmp_alias= strmake_root(&outparam->mem_root, alias->str, alias->length)))
goto err;
+
+ outparam->alias.set(tmp_alias, alias->length, table_alias_charset);
outparam->quick_keys.init();
outparam->covering_keys.init();
outparam->intersect_keys.init();
@@ -3279,6 +3290,8 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
}
(*field_ptr)= 0; // End marker
+ DEBUG_SYNC(thd, "TABLE_after_field_clone");
+
outparam->vers_write= share->versioned;
if (share->found_next_number_field)
@@ -3527,6 +3540,16 @@ partititon_err:
}
outparam->mark_columns_used_by_virtual_fields();
+ if (!check_set_initialized &&
+ share->check_set_initialized == TABLE_SHARE::V_KEYS)
+ {
+ // copy PART_INDIRECT_KEY_FLAG that was set meanwhile by *some* thread
+ for (uint i= 0 ; i < share->fields ; i++)
+ {
+ if (share->field[i]->flags & PART_INDIRECT_KEY_FLAG)
+ outparam->field[i]->flags|= PART_INDIRECT_KEY_FLAG;
+ }
+ }
if (db_stat)
{
@@ -4614,7 +4637,7 @@ void TABLE::init(THD *thd, TABLE_LIST *tl)
s->table_name.str,
tl->alias.str);
/* Fix alias if table name changes. */
- if (strcmp(alias.c_ptr(), tl->alias.str))
+ if (!alias.alloced_length() || strcmp(alias.c_ptr(), tl->alias.str))
alias.copy(tl->alias.str, tl->alias.length, alias.charset());
tablenr= thd->current_tablenr++;
@@ -6209,7 +6232,7 @@ Field_iterator_table_ref::get_or_create_column_ref(THD *thd, TABLE_LIST *parent_
nj_col= natural_join_it.column_ref();
DBUG_ASSERT(nj_col);
}
- DBUG_ASSERT(!nj_col->table_field ||
+ DBUG_ASSERT(!nj_col->table_field || !nj_col->table_field->field ||
nj_col->table_ref->table == nj_col->table_field->field->table);
/*
@@ -6258,7 +6281,7 @@ Field_iterator_table_ref::get_or_create_column_ref(THD *thd, TABLE_LIST *parent_
RETURN
# Pointer to a column of a natural join (or its operand)
- NULL No memory to allocate the column
+ NULL We didn't originally have memory to allocate the column
*/
Natural_join_column *
@@ -6274,7 +6297,7 @@ Field_iterator_table_ref::get_natural_column_ref()
*/
nj_col= natural_join_it.column_ref();
DBUG_ASSERT(nj_col &&
- (!nj_col->table_field ||
+ (!nj_col->table_field || !nj_col->table_field->field ||
nj_col->table_ref->table == nj_col->table_field->field->table));
return nj_col;
}
@@ -6848,6 +6871,7 @@ void TABLE::mark_columns_used_by_virtual_fields(void)
{
MY_BITMAP *save_read_set;
Field **vfield_ptr;
+ TABLE_SHARE::enum_v_keys v_keys= TABLE_SHARE::NO_V_KEYS;
/* If there is virtual fields are already initialized */
if (s->check_set_initialized)
@@ -6886,11 +6910,14 @@ void TABLE::mark_columns_used_by_virtual_fields(void)
for (uint i= 0 ; i < s->fields ; i++)
{
if (bitmap_is_set(&tmp_set, i))
- field[i]->flags|= PART_INDIRECT_KEY_FLAG;
+ {
+ s->field[i]->flags|= PART_INDIRECT_KEY_FLAG;
+ v_keys= TABLE_SHARE::V_KEYS;
+ }
}
bitmap_clear_all(&tmp_set);
}
- s->check_set_initialized= 1;
+ s->check_set_initialized= v_keys;
if (s->tmp_table == NO_TMP_TABLE)
mysql_mutex_unlock(&s->LOCK_share);
}
@@ -7098,6 +7125,14 @@ void TABLE::create_key_part_by_field(KEY_PART_INFO *key_part_info,
The function checks whether a possible key satisfies the constraints
imposed on the keys of any temporary table.
+ We need to filter out BLOB columns here, because ref access optimizer creates
+ KEYUSE objects for equalities for non-key columns for two puproses:
+ 1. To discover possible keys for derived_with_keys optimization
+ 2. To do hash joins
+ For the purpose of #1, KEYUSE objects are not created for "blob_column=..." .
+ However, they might be created for #2. In order to catch that case, we filter
+ them out here.
+
@return TRUE if the key is valid
@return FALSE otherwise
*/
@@ -7113,11 +7148,12 @@ bool TABLE::check_tmp_key(uint key, uint key_parts,
{
uint fld_idx= next_field_no(arg);
reg_field= field + fld_idx;
+ if ((*reg_field)->type() == MYSQL_TYPE_BLOB)
+ return FALSE;
uint fld_store_len= (uint16) (*reg_field)->key_length();
if ((*reg_field)->real_maybe_null())
fld_store_len+= HA_KEY_NULL_LENGTH;
- if ((*reg_field)->type() == MYSQL_TYPE_BLOB ||
- (*reg_field)->real_type() == MYSQL_TYPE_VARCHAR ||
+ if ((*reg_field)->real_type() == MYSQL_TYPE_VARCHAR ||
(*reg_field)->type() == MYSQL_TYPE_GEOMETRY)
fld_store_len+= HA_KEY_BLOB_LENGTH;
key_len+= fld_store_len;
@@ -8327,7 +8363,7 @@ int TABLE_LIST::fetch_number_of_rows()
}
if (is_materialized_derived() && !fill_me)
{
- table->file->stats.records= ((select_unit*)(get_unit()->result))->records;
+ table->file->stats.records= get_unit()->result->est_records;
set_if_bigger(table->file->stats.records, 2);
table->used_stat_records= table->file->stats.records;
}
@@ -8550,7 +8586,8 @@ bool TR_table::update(ulonglong start_id, ulonglong end_id)
return true;
store(FLD_BEGIN_TS, thd->transaction_time());
- timeval end_time= {thd->query_start(), long(thd->query_start_sec_part())};
+ thd->set_time();
+ timeval end_time= {thd->query_start(), int(thd->query_start_sec_part())};
store(FLD_TRX_ID, start_id);
store(FLD_COMMIT_ID, end_id);
store(FLD_COMMIT_TS, end_time);
@@ -8631,7 +8668,7 @@ bool TR_table::query(MYSQL_TIME &commit_time, bool backwards)
if (res > 0)
{
MYSQL_TIME commit_ts;
- if ((*this)[FLD_COMMIT_TS]->get_date(&commit_ts, 0))
+ if ((*this)[FLD_COMMIT_TS]->get_date(&commit_ts, date_mode_t(0)))
{
found= false;
break;
diff --git a/sql/table.h b/sql/table.h
index 14bc928bcb5..3c782c34bc3 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -721,6 +721,9 @@ struct TABLE_SHARE
uint column_bitmap_size;
uchar frm_version;
+ enum enum_v_keys { NOT_INITIALIZED=0, NO_V_KEYS, V_KEYS };
+ enum_v_keys check_set_initialized;
+
bool use_ext_keys; /* Extended keys can be used */
bool null_field_first;
bool system; /* Set if system table (one record) */
@@ -732,7 +735,6 @@ struct TABLE_SHARE
bool table_creation_was_logged;
bool non_determinstic_insert;
bool vcols_need_refixing;
- bool check_set_initialized;
bool has_update_default_function;
bool can_do_row_logging; /* 1 if table supports RBR */
@@ -1492,6 +1494,7 @@ public:
bool is_splittable() { return spl_opt_info != NULL; }
void set_spl_opt_info(SplM_opt_info *spl_info);
void deny_splitting();
+ double get_materialization_cost(); // Now used only if is_splittable()==true
void add_splitting_info_for_key_field(struct KEY_FIELD *key_field);
@@ -1944,6 +1947,14 @@ struct TABLE_LIST
const LEX_CSTRING *alias_arg,
enum thr_lock_type lock_type_arg)
{
+ enum enum_mdl_type mdl_type;
+ if (lock_type_arg >= TL_WRITE_ALLOW_WRITE)
+ mdl_type= MDL_SHARED_WRITE;
+ else if (lock_type_arg == TL_READ_NO_INSERT)
+ mdl_type= MDL_SHARED_NO_WRITE;
+ else
+ mdl_type= MDL_SHARED_READ;
+
bzero((char*) this, sizeof(*this));
DBUG_ASSERT(!db_arg->str || strlen(db_arg->str) == db_arg->length);
DBUG_ASSERT(!table_name_arg->str || strlen(table_name_arg->str) == table_name_arg->length);
@@ -1952,9 +1963,7 @@ struct TABLE_LIST
table_name= *table_name_arg;
alias= (alias_arg ? *alias_arg : *table_name_arg);
lock_type= lock_type_arg;
- mdl_request.init(MDL_key::TABLE, db.str, table_name.str,
- (lock_type >= TL_WRITE_ALLOW_WRITE) ?
- MDL_SHARED_WRITE : MDL_SHARED_READ,
+ mdl_request.init(MDL_key::TABLE, db.str, table_name.str, mdl_type,
MDL_TRANSACTION);
}
@@ -1990,6 +1999,7 @@ struct TABLE_LIST
*last_ptr= &next_global;
}
+
/*
List of tables local to a subquery (used by SQL_I_List). Considers
views as leaves (unlike 'next_leaf' below). Created at parse time
@@ -2602,6 +2612,16 @@ struct TABLE_LIST
}
void set_lock_type(THD* thd, enum thr_lock_type lock);
+ void remove_join_columns()
+ {
+ if (join_columns)
+ {
+ join_columns->empty();
+ join_columns= NULL;
+ is_join_columns_complete= FALSE;
+ }
+ }
+
private:
bool prep_check_option(THD *thd, uint8 check_opt_type);
bool prep_where(THD *thd, Item **conds, bool no_where_clause);
diff --git a/sql/table_cache.cc b/sql/table_cache.cc
index 2c5d25c0308..682f9455d26 100644
--- a/sql/table_cache.cc
+++ b/sql/table_cache.cc
@@ -463,6 +463,7 @@ void tc_release_table(TABLE *table)
DBUG_ENTER("tc_release_table");
DBUG_ASSERT(table->in_use);
DBUG_ASSERT(table->file);
+ DBUG_ASSERT(!table->pos_in_locked_tables);
mysql_mutex_lock(&tc[i].LOCK_table_cache);
if (table->needs_reopen() || table->s->tdc->flushed ||
@@ -644,7 +645,7 @@ bool tdc_init(void)
void tdc_start_shutdown(void)
{
- DBUG_ENTER("table_def_start_shutdown");
+ DBUG_ENTER("tdc_start_shutdown");
if (tdc_inited)
{
/*
@@ -1140,11 +1141,10 @@ bool tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
All_share_tables_list::Iterator it(element->all_tables);
while ((table= it++))
{
- my_refs++;
- DBUG_ASSERT(table->in_use == thd);
+ if (table->in_use == thd)
+ my_refs++;
}
}
- DBUG_ASSERT(element->all_tables.is_empty() || remove_type != TDC_RT_REMOVE_ALL);
mysql_mutex_unlock(&element->LOCK_table_share);
while ((table= purge_tables.pop_front()))
@@ -1176,6 +1176,17 @@ bool tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
mysql_mutex_lock(&element->LOCK_table_share);
while (element->ref_count > my_refs)
mysql_cond_wait(&element->COND_release, &element->LOCK_table_share);
+ DBUG_ASSERT(element->all_tables.is_empty() ||
+ remove_type != TDC_RT_REMOVE_ALL);
+#ifndef DBUG_OFF
+ if (remove_type == TDC_RT_REMOVE_NOT_OWN ||
+ remove_type == TDC_RT_REMOVE_NOT_OWN_KEEP_SHARE)
+ {
+ All_share_tables_list::Iterator it(element->all_tables);
+ while ((table= it++))
+ DBUG_ASSERT(table->in_use == thd);
+ }
+#endif
mysql_mutex_unlock(&element->LOCK_table_share);
}
diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc
index f23ec7a1acc..1c8af5eaf66 100644
--- a/sql/temporary_tables.cc
+++ b/sql/temporary_tables.cc
@@ -1540,3 +1540,33 @@ void THD::unlock_temporary_tables()
DBUG_VOID_RETURN;
}
+
+/**
+ Close unused TABLE instances for given temporary table.
+
+ @param tl [IN] TABLE_LIST
+
+ Initial use case was TRUNCATE, which expects only one instance (which is used
+ by TRUNCATE itself) to be open. Most probably some ALTER TABLE variants and
+ REPAIR may have similar expectations.
+*/
+
+void THD::close_unused_temporary_table_instances(const TABLE_LIST *tl)
+{
+ TMP_TABLE_SHARE *share= find_tmp_table_share(tl);
+
+ if (share)
+ {
+ All_share_tables_list::Iterator tables_it(share->all_tmp_tables);
+
+ while (TABLE *table= tables_it++)
+ {
+ if (table->query_id == 0)
+ {
+ /* Note: removing current list element doesn't invalidate iterator. */
+ share->all_tmp_tables.remove(table);
+ free_temporary_table(table);
+ }
+ }
+ }
+}
diff --git a/sql/threadpool_win.cc b/sql/threadpool_win.cc
index 0cc683c631d..67a8e783208 100644
--- a/sql/threadpool_win.cc
+++ b/sql/threadpool_win.cc
@@ -70,12 +70,16 @@ static DWORD fls;
static bool skip_completion_port_on_success = false;
+PTP_CALLBACK_ENVIRON get_threadpool_win_callback_environ()
+{
+ return pool? &callback_environ: 0;
+}
+
/*
Threadpool callbacks.
io_completion_callback - handle client request
timer_callback - handle wait timeout (kill connection)
- shm_read_callback, shm_close_callback - shared memory stuff
login_callback - user login (submitted as threadpool work)
*/
@@ -89,9 +93,6 @@ static void CALLBACK io_completion_callback(PTP_CALLBACK_INSTANCE instance,
static void CALLBACK work_callback(PTP_CALLBACK_INSTANCE instance, PVOID context, PTP_WORK work);
-static void CALLBACK shm_read_callback(PTP_CALLBACK_INSTANCE instance,
- PVOID Context, PTP_WAIT wait,TP_WAIT_RESULT wait_result);
-
static void pre_callback(PVOID context, PTP_CALLBACK_INSTANCE instance);
/* Get current time as Windows time */
@@ -120,7 +121,6 @@ public:
PTP_CALLBACK_INSTANCE callback_instance;
PTP_IO io;
PTP_TIMER timer;
- PTP_WAIT shm_read;
PTP_WORK work;
bool long_callback;
@@ -139,7 +139,15 @@ struct TP_connection *new_TP_connection(CONNECT *connect)
void TP_pool_win::add(TP_connection *c)
{
- SubmitThreadpoolWork(((TP_connection_win *)c)->work);
+ if(FlsGetValue(fls))
+ {
+ /* Inside threadpool(), execute callback directly. */
+ tp_callback(c);
+ }
+ else
+ {
+ SubmitThreadpoolWork(((TP_connection_win *)c)->work);
+ }
}
@@ -149,7 +157,6 @@ TP_connection_win::TP_connection_win(CONNECT *c) :
callback_instance(0),
io(0),
timer(0),
- shm_read(0),
work(0)
{
}
@@ -170,30 +177,20 @@ int TP_connection_win::init()
case VIO_TYPE_NAMEDPIPE:
handle= (HANDLE)vio->hPipe;
break;
- case VIO_TYPE_SHARED_MEMORY:
- handle= vio->event_server_wrote;
- break;
default:
abort();
}
- if (vio_type == VIO_TYPE_SHARED_MEMORY)
- {
- CHECK_ALLOC_ERROR(shm_read= CreateThreadpoolWait(shm_read_callback, this, &callback_environ));
- }
- else
+
+ /* Performance tweaks (s. MSDN documentation)*/
+ UCHAR flags= FILE_SKIP_SET_EVENT_ON_HANDLE;
+ if (skip_completion_port_on_success)
{
- /* Performance tweaks (s. MSDN documentation)*/
- UCHAR flags= FILE_SKIP_SET_EVENT_ON_HANDLE;
- if (skip_completion_port_on_success)
- {
- flags |= FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
- }
- (void)SetFileCompletionNotificationModes(handle, flags);
- /* Assign io completion callback */
- CHECK_ALLOC_ERROR(io= CreateThreadpoolIo(handle, io_completion_callback, this, &callback_environ));
+ flags |= FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
}
-
+ (void)SetFileCompletionNotificationModes(handle, flags);
+ /* Assign io completion callback */
+ CHECK_ALLOC_ERROR(io= CreateThreadpoolIo(handle, io_completion_callback, this, &callback_environ));
CHECK_ALLOC_ERROR(timer= CreateThreadpoolTimer(timer_callback, this, &callback_environ));
CHECK_ALLOC_ERROR(work= CreateThreadpoolWork(work_callback, this, &callback_environ));
return 0;
@@ -214,11 +211,6 @@ int TP_connection_win::start_io()
DWORD last_error= 0;
int retval;
- if (shm_read)
- {
- SetThreadpoolWait(shm_read, handle, NULL);
- return 0;
- }
StartThreadpoolIo(io);
if (vio_type == VIO_TYPE_TCPIP || vio_type == VIO_TYPE_SSL)
@@ -297,9 +289,6 @@ TP_connection_win::~TP_connection_win()
if (io)
CloseThreadpoolIo(io);
- if (shm_read)
- CloseThreadpoolWait(shm_read);
-
if (work)
CloseThreadpoolWork(work);
@@ -312,14 +301,13 @@ TP_connection_win::~TP_connection_win()
void TP_connection_win::wait_begin(int type)
{
-
/*
Signal to the threadpool whenever callback can run long. Currently, binlog
waits are a good candidate, its waits are really long
*/
if (type == THD_WAIT_BINLOG)
{
- if (!long_callback)
+ if (!long_callback && callback_instance)
{
CallbackMayRunLong(callback_instance);
long_callback= true;
@@ -332,12 +320,11 @@ void TP_connection_win::wait_end()
/* Do we need to do anything ? */
}
-/*
- This function should be called first whenever a callback is invoked in the
+/*
+ This function should be called first whenever a callback is invoked in the
threadpool, does my_thread_init() if not yet done
*/
-extern ulong thread_created;
-static void pre_callback(PVOID context, PTP_CALLBACK_INSTANCE instance)
+void tp_win_callback_prolog()
{
if (FlsGetValue(fls) == NULL)
{
@@ -347,6 +334,12 @@ static void pre_callback(PVOID context, PTP_CALLBACK_INSTANCE instance)
InterlockedIncrement((volatile long *)&tp_stats.num_worker_threads);
my_thread_init();
}
+}
+
+extern ulong thread_created;
+static void pre_callback(PVOID context, PTP_CALLBACK_INSTANCE instance)
+{
+ tp_win_callback_prolog();
TP_connection_win *c = (TP_connection_win *)context;
c->callback_instance = instance;
c->long_callback = false;
@@ -420,29 +413,6 @@ static VOID CALLBACK timer_callback(PTP_CALLBACK_INSTANCE instance,
}
}
-
-/*
- Shared memory read callback.
- Invoked when read event is set on connection.
-*/
-
-static void CALLBACK shm_read_callback(PTP_CALLBACK_INSTANCE instance,
- PVOID context, PTP_WAIT wait,TP_WAIT_RESULT wait_result)
-{
- TP_connection_win *c= (TP_connection_win *)context;
- /* Disarm wait. */
- SetThreadpoolWait(wait, NULL, NULL);
-
- /*
- This is an autoreset event, and one wakeup is eaten already by threadpool,
- and the current state is "not set". Thus we need to reset the event again,
- or vio_read will hang.
- */
- SetEvent(c->handle);
- tp_callback(instance, context);
-}
-
-
static void CALLBACK work_callback(PTP_CALLBACK_INSTANCE instance, PVOID context, PTP_WORK work)
{
tp_callback(instance, context);
diff --git a/sql/tztime.cc b/sql/tztime.cc
index 61fbee1731a..177521e5a55 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -1653,7 +1653,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
{
/* If we are in bootstrap mode we should not load time zone tables */
return_val= time_zone_tables_exist= 0;
- goto end_with_setting_default_tz;
+ goto end_with_cleanup;
}
/*
diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc
index f2d90def5ef..1f50ee55711 100644
--- a/sql/wsrep_applier.cc
+++ b/sql/wsrep_applier.cc
@@ -146,6 +146,7 @@ static wsrep_cb_status_t wsrep_apply_events(THD* thd,
/* Use the original server id for logging. */
thd->set_server_id(ev->server_id);
thd->set_time(); // time the query
+ thd->transaction.start_time.reset(thd);
wsrep_xid_init(&thd->transaction.xid_state.xid,
thd->wsrep_trx_meta.gtid.uuid,
thd->wsrep_trx_meta.gtid.seqno);
diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc
index cafd41b2653..0cbcdcd64aa 100644
--- a/sql/wsrep_binlog.cc
+++ b/sql/wsrep_binlog.cc
@@ -322,13 +322,28 @@ int wsrep_write_cache(wsrep_t* const wsrep,
void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len)
{
- char filename[PATH_MAX]= {0};
- int len= snprintf(filename, PATH_MAX, "%s/GRA_%lld_%lld.log",
+ int len= snprintf(NULL, 0, "%s/GRA_%lld_%lld.log",
wsrep_data_home_dir, (longlong) thd->thread_id,
(longlong) wsrep_thd_trx_seqno(thd));
- if (len >= PATH_MAX)
+ if (len < 0)
{
- WSREP_ERROR("RBR dump path too long: %d, skipping dump.", len);
+ WSREP_ERROR("snprintf error: %d, skipping dump.", len);
+ return;
+ }
+ /*
+ len doesn't count the \0 end-of-string. Use len+1 below
+ to alloc and pass as an argument to snprintf.
+ */
+
+ char *filename= (char *)malloc(len+1);
+ int len1= snprintf(filename, len+1, "%s/GRA_%lld_%lld.log",
+ wsrep_data_home_dir, (longlong) thd->thread_id,
+ (long long)wsrep_thd_trx_seqno(thd));
+
+ if (len > len1)
+ {
+ WSREP_ERROR("RBR dump path truncated: %d, skipping dump.", len);
+ free(filename);
return;
}
@@ -347,6 +362,7 @@ void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len)
WSREP_ERROR("Failed to open file '%s': %d (%s)",
filename, errno, strerror(errno));
}
+ free(filename);
}
/*
@@ -452,19 +468,34 @@ void wsrep_dump_rbr_buf_with_header(THD *thd, const void *rbr_buf,
{
DBUG_ENTER("wsrep_dump_rbr_buf_with_header");
- char filename[PATH_MAX]= {0};
File file;
IO_CACHE cache;
Log_event_writer writer(&cache, 0);
Format_description_log_event *ev= 0;
- int len= my_snprintf(filename, PATH_MAX, "%s/GRA_%lld_%lld_v2.log",
- wsrep_data_home_dir, (longlong) thd->thread_id,
- (long long) wsrep_thd_trx_seqno(thd));
+ longlong thd_trx_seqno= (long long)wsrep_thd_trx_seqno(thd);
+ int len= snprintf(NULL, 0, "%s/GRA_%lld_%lld_v2.log",
+ wsrep_data_home_dir, (longlong)thd->thread_id,
+ thd_trx_seqno);
+ /*
+ len doesn't count the \0 end-of-string. Use len+1 below
+ to alloc and pass as an argument to snprintf.
+ */
+ char *filename;
+ if (len < 0 || !(filename= (char*)malloc(len+1)))
+ {
+ WSREP_ERROR("snprintf error: %d, skipping dump.", len);
+ DBUG_VOID_RETURN;
+ }
+
+ int len1= snprintf(filename, len+1, "%s/GRA_%lld_%lld_v2.log",
+ wsrep_data_home_dir, (longlong) thd->thread_id,
+ thd_trx_seqno);
- if (len >= PATH_MAX)
+ if (len > len1)
{
- WSREP_ERROR("RBR dump path too long: %d, skipping dump.", len);
+ WSREP_ERROR("RBR dump path truncated: %d, skipping dump.", len);
+ free(filename);
DBUG_VOID_RETURN;
}
@@ -505,6 +536,7 @@ cleanup2:
end_io_cache(&cache);
cleanup1:
+ free(filename);
mysql_file_close(file, MYF(MY_WME));
if (!thd->wsrep_applier) delete ev;
diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc
index 0b6e7e0d5bb..9a4bbd01bcd 100644
--- a/sql/wsrep_dummy.cc
+++ b/sql/wsrep_dummy.cc
@@ -139,3 +139,6 @@ int wsrep_trx_is_aborting(THD *)
void wsrep_unlock_rollback()
{ }
+
+void wsrep_set_data_home_dir(const char *)
+{ }
diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc
index d4d35d752be..8110faf7d11 100644
--- a/sql/wsrep_hton.cc
+++ b/sql/wsrep_hton.cc
@@ -25,6 +25,8 @@
#include <cstdlib>
#include "debug_sync.h"
+extern handlerton *binlog_hton;
+extern int binlog_close_connection(handlerton *hton, THD *thd);
extern ulonglong thd_to_trx_id(THD *thd);
extern "C" int thd_binlog_format(const MYSQL_THD thd);
@@ -173,7 +175,10 @@ wsrep_close_connection(handlerton* hton, THD* thd)
{
DBUG_RETURN(0);
}
- DBUG_RETURN(wsrep_binlog_close_connection (thd));
+
+ if (wsrep_emulate_bin_log && thd_get_ha_data(thd, binlog_hton) != NULL)
+ binlog_hton->close_connection (binlog_hton, thd);
+ DBUG_RETURN(0);
}
/*
@@ -264,7 +269,7 @@ static int wsrep_rollback(handlerton *hton, THD *thd, bool all)
}
if ((all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
- (thd->variables.wsrep_on && thd->wsrep_conflict_state != MUST_REPLAY))
+ thd->variables.wsrep_on && thd->wsrep_conflict_state != MUST_REPLAY)
{
if (wsrep && wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle))
{
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index 0a2735fe0b7..bc52bff0de9 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -73,10 +73,7 @@ const char *wsrep_start_position;
const char *wsrep_data_home_dir;
const char *wsrep_dbug_option;
const char *wsrep_notify_cmd;
-const char *wsrep_sst_method;
-const char *wsrep_sst_receive_address;
-const char *wsrep_sst_donor;
-const char *wsrep_sst_auth;
+
my_bool wsrep_debug; // Enable debug level logging
my_bool wsrep_convert_LOCK_to_trx; // Convert locking sessions to trx
my_bool wsrep_auto_increment_control; // Control auto increment variables
@@ -88,7 +85,6 @@ my_bool wsrep_log_conflicts;
my_bool wsrep_load_data_splitting; // Commit load data every 10K intervals
my_bool wsrep_slave_UK_checks; // Slave thread does UK checks
my_bool wsrep_slave_FK_checks; // Slave thread does FK checks
-my_bool wsrep_sst_donor_rejects_queries;
my_bool wsrep_restart_slave; // Should mysql slave thread be
// restarted, when node joins back?
my_bool wsrep_desync; // De(re)synchronize the node from the
@@ -653,6 +649,9 @@ int wsrep_init()
wsrep->provider_vendor, sizeof(provider_vendor) - 1);
}
+ if (!wsrep_data_home_dir || strlen(wsrep_data_home_dir) == 0)
+ wsrep_data_home_dir = mysql_real_data_home;
+
/* Initialize node address */
char node_addr[512]= { 0, };
size_t const node_addr_max= sizeof(node_addr) - 1;
@@ -1078,114 +1077,151 @@ static bool wsrep_prepare_key_for_isolation(const char* db,
wsrep_buf_t* key,
size_t* key_len)
{
- if (*key_len < 2) return false;
+ if (*key_len < 2) return false;
- switch (wsrep_protocol_version)
- {
- case 0:
- *key_len= 0;
- break;
- case 1:
- case 2:
- case 3:
+ switch (wsrep_protocol_version)
+ {
+ case 0:
+ *key_len= 0;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ {
+ *key_len= 0;
+ if (db)
{
- *key_len= 0;
- if (db)
- {
- // sql_print_information("%s.%s", db, table);
- if (db)
- {
- key[*key_len].ptr= db;
- key[*key_len].len= strlen(db);
- ++(*key_len);
- if (table)
- {
- key[*key_len].ptr= table;
- key[*key_len].len= strlen(table);
- ++(*key_len);
- }
- }
- }
- break;
+ // sql_print_information("%s.%s", db, table);
+ key[*key_len].ptr= db;
+ key[*key_len].len= strlen(db);
+ ++(*key_len);
+ if (table)
+ {
+ key[*key_len].ptr= table;
+ key[*key_len].len= strlen(table);
+ ++(*key_len);
+ }
}
- default:
+ break;
+ }
+ default:
+ return false;
+ }
+ return true;
+}
+
+
+static bool wsrep_prepare_key_for_isolation(const char* db,
+ const char* table,
+ wsrep_key_arr_t* ka)
+{
+ wsrep_key_t* tmp;
+
+ if (!ka->keys)
+ tmp= (wsrep_key_t*)my_malloc((ka->keys_len + 1) * sizeof(wsrep_key_t),
+ MYF(0));
+ else
+ tmp= (wsrep_key_t*)my_realloc(ka->keys,
+ (ka->keys_len + 1) * sizeof(wsrep_key_t),
+ MYF(0));
+
+ if (!tmp)
+ {
+ WSREP_ERROR("Can't allocate memory for key_array");
+ return false;
+ }
+ ka->keys= tmp;
+ if (!(ka->keys[ka->keys_len].key_parts= (wsrep_buf_t*)
+ my_malloc(sizeof(wsrep_buf_t)*2, MYF(0))))
+ {
+ WSREP_ERROR("Can't allocate memory for key_parts");
+ return false;
+ }
+ ka->keys[ka->keys_len].key_parts_num= 2;
+ ++ka->keys_len;
+ if (!wsrep_prepare_key_for_isolation(db, table,
+ (wsrep_buf_t*)ka->keys[ka->keys_len - 1].key_parts,
+ &ka->keys[ka->keys_len - 1].key_parts_num))
+ {
+ WSREP_ERROR("Preparing keys for isolation failed");
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool wsrep_prepare_keys_for_alter_add_fk(const char* child_table_db,
+ Alter_info* alter_info,
+ wsrep_key_arr_t* ka)
+{
+ Key *key;
+ List_iterator<Key> key_iterator(alter_info->key_list);
+ while ((key= key_iterator++))
+ {
+ if (key->type == Key::FOREIGN_KEY)
+ {
+ Foreign_key *fk_key= (Foreign_key *)key;
+ const char *db_name= fk_key->ref_db.str;
+ const char *table_name= fk_key->ref_table.str;
+ if (!db_name)
+ {
+ db_name= child_table_db;
+ }
+ if (!wsrep_prepare_key_for_isolation(db_name, table_name, ka))
+ {
return false;
+ }
}
-
- return true;
+ }
+ return true;
}
-/* Prepare key list from db/table and table_list */
-bool wsrep_prepare_keys_for_isolation(THD* thd,
- const char* db,
- const char* table,
- const TABLE_LIST* table_list,
- wsrep_key_arr_t* ka)
+
+static bool wsrep_prepare_keys_for_isolation(THD* thd,
+ const char* db,
+ const char* table,
+ const TABLE_LIST* table_list,
+ Alter_info* alter_info,
+ wsrep_key_arr_t* ka)
{
ka->keys= 0;
ka->keys_len= 0;
if (db || table)
{
- if (!(ka->keys= (wsrep_key_t*)my_malloc(sizeof(wsrep_key_t), MYF(0))))
- {
- WSREP_ERROR("Can't allocate memory for key_array");
- goto err;
- }
- ka->keys_len= 1;
- if (!(ka->keys[0].key_parts= (wsrep_buf_t*)
- my_malloc(sizeof(wsrep_buf_t)*2, MYF(0))))
- {
- WSREP_ERROR("Can't allocate memory for key_parts");
+ if (!wsrep_prepare_key_for_isolation(db, table, ka))
goto err;
- }
- ka->keys[0].key_parts_num= 2;
- if (!wsrep_prepare_key_for_isolation(
- db, table,
- (wsrep_buf_t*)ka->keys[0].key_parts,
- &ka->keys[0].key_parts_num))
- {
- WSREP_ERROR("Preparing keys for isolation failed (1)");
- goto err;
- }
}
for (const TABLE_LIST* table= table_list; table; table= table->next_global)
{
- wsrep_key_t* tmp;
- if (ka->keys)
- tmp= (wsrep_key_t*)my_realloc(ka->keys,
- (ka->keys_len + 1) * sizeof(wsrep_key_t),
- MYF(0));
- else
- tmp= (wsrep_key_t*)my_malloc((ka->keys_len + 1) * sizeof(wsrep_key_t), MYF(0));
-
- if (!tmp)
- {
- WSREP_ERROR("Can't allocate memory for key_array");
+ if (!wsrep_prepare_key_for_isolation(table->db.str, table->table_name.str, ka))
goto err;
- }
- ka->keys= tmp;
- if (!(ka->keys[ka->keys_len].key_parts= (wsrep_buf_t*)
- my_malloc(sizeof(wsrep_buf_t)*2, MYF(0))))
- {
- WSREP_ERROR("Can't allocate memory for key_parts");
- goto err;
- }
- ka->keys[ka->keys_len].key_parts_num= 2;
- ++ka->keys_len;
- if (!wsrep_prepare_key_for_isolation(table->db.str, table->table_name.str,
- (wsrep_buf_t*)ka->keys[ka->keys_len - 1].key_parts,
- &ka->keys[ka->keys_len - 1].key_parts_num))
- {
- WSREP_ERROR("Preparing keys for isolation failed (2)");
+ }
+
+ if (alter_info && (alter_info->flags & (ALTER_ADD_FOREIGN_KEY)))
+ {
+ if (!wsrep_prepare_keys_for_alter_add_fk(table_list->db.str, alter_info, ka))
goto err;
- }
}
- return 0;
+
+ return false;
+
err:
- wsrep_keys_free(ka);
- return 1;
+ wsrep_keys_free(ka);
+ return true;
+}
+
+
+/* Prepare key list from db/table and table_list */
+bool wsrep_prepare_keys_for_isolation(THD* thd,
+ const char* db,
+ const char* table,
+ const TABLE_LIST* table_list,
+ wsrep_key_arr_t* ka)
+{
+ return wsrep_prepare_keys_for_isolation(thd, db, table, table_list, NULL, ka);
}
@@ -1398,6 +1434,67 @@ create_view_query(THD *thd, uchar** buf, size_t* buf_len)
return wsrep_to_buf_helper(thd, buff.ptr(), buff.length(), buf, buf_len);
}
+/*
+ Rewrite DROP TABLE for TOI. Temporary tables are eliminated from
+ the query as they are visible only to client connection.
+
+ TODO: See comments for sql_base.cc:drop_temporary_table() and refine
+ the function to deal with transactional locked tables.
+ */
+static int wsrep_drop_table_query(THD* thd, uchar** buf, size_t* buf_len)
+{
+
+ LEX* lex= thd->lex;
+ SELECT_LEX* select_lex= lex->first_select_lex();
+ TABLE_LIST* first_table= select_lex->table_list.first;
+ String buff;
+
+ DBUG_ASSERT(!lex->create_info.tmp_table());
+
+ bool found_temp_table= false;
+ for (TABLE_LIST* table= first_table; table; table= table->next_global)
+ {
+ if (thd->find_temporary_table(table->db.str, table->table_name.str))
+ {
+ found_temp_table= true;
+ break;
+ }
+ }
+
+ if (found_temp_table)
+ {
+ buff.append("DROP TABLE ");
+ if (lex->check_exists)
+ buff.append("IF EXISTS ");
+
+ for (TABLE_LIST* table= first_table; table; table= table->next_global)
+ {
+ if (!thd->find_temporary_table(table->db.str, table->table_name.str))
+ {
+ append_identifier(thd, &buff, table->db.str, table->db.length);
+ buff.append(".");
+ append_identifier(thd, &buff,
+ table->table_name.str, table->table_name.length);
+ buff.append(",");
+ }
+ }
+
+ /* Chop the last comma */
+ buff.chop();
+ buff.append(" /* generated by wsrep */");
+
+ WSREP_DEBUG("Rewrote '%s' as '%s'", thd->query(), buff.ptr());
+
+ return wsrep_to_buf_helper(thd, buff.ptr(), buff.length(), buf, buf_len);
+ }
+ else
+ {
+ return wsrep_to_buf_helper(thd, thd->query(), thd->query_length(),
+ buf, buf_len);
+ }
+}
+
+
/* Forward declarations. */
static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len);
static int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len);
@@ -1480,6 +1577,25 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
}
}
+static const char* wsrep_get_query_or_msg(const THD* thd)
+{
+ switch(thd->lex->sql_command)
+ {
+ case SQLCOM_CREATE_USER:
+ return "CREATE USER";
+ case SQLCOM_GRANT:
+ return "GRANT";
+ case SQLCOM_REVOKE:
+ return "REVOKE";
+ case SQLCOM_SET_OPTION:
+ if (thd->lex->definer)
+ return "SET PASSWORD";
+ /* fallthrough */
+ default:
+ return thd->query();
+ }
+}
+
/*
returns:
0: statement was replicated as TOI
@@ -1487,7 +1603,8 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
-1: TOI replication failed
*/
static int wsrep_TOI_begin(THD *thd, const char *db_, const char *table_,
- const TABLE_LIST* table_list)
+ const TABLE_LIST* table_list,
+ Alter_info* alter_info)
{
wsrep_status_t ret(WSREP_WARNING);
uchar* buf(0);
@@ -1502,7 +1619,8 @@ static int wsrep_TOI_begin(THD *thd, const char *db_, const char *table_,
}
WSREP_DEBUG("TO BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
- thd->wsrep_exec_mode, thd->query() );
+ thd->wsrep_exec_mode, wsrep_get_query_or_msg(thd));
+
switch (thd->lex->sql_command)
{
case SQLCOM_CREATE_VIEW:
@@ -1521,6 +1639,9 @@ static int wsrep_TOI_begin(THD *thd, const char *db_, const char *table_,
case SQLCOM_ALTER_EVENT:
buf_err= wsrep_alter_event_query(thd, &buf, &buf_len);
break;
+ case SQLCOM_DROP_TABLE:
+ buf_err= wsrep_drop_table_query(thd, &buf, &buf_len);
+ break;
case SQLCOM_CREATE_ROLE:
if (sp_process_definer(thd))
{
@@ -1536,7 +1657,8 @@ static int wsrep_TOI_begin(THD *thd, const char *db_, const char *table_,
wsrep_key_arr_t key_arr= {0, 0};
struct wsrep_buf buff = { buf, buf_len };
if (!buf_err &&
- !wsrep_prepare_keys_for_isolation(thd, db_, table_, table_list, &key_arr) &&
+ !wsrep_prepare_keys_for_isolation(thd, db_, table_,
+ table_list, alter_info, &key_arr) &&
key_arr.keys_len > 0 &&
WSREP_OK == (ret = wsrep->to_execute_start(wsrep, thd->thread_id,
key_arr.keys, key_arr.keys_len,
@@ -1576,8 +1698,8 @@ static void wsrep_TOI_end(THD *thd) {
wsrep_status_t ret;
wsrep_to_isolation--;
- WSREP_DEBUG("TO END: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
- thd->wsrep_exec_mode, (thd->query()) ? thd->query() : "void");
+ WSREP_DEBUG("TO END: %lld, %d: %s", (long long)wsrep_thd_trx_seqno(thd),
+ thd->wsrep_exec_mode, wsrep_get_query_or_msg(thd));
wsrep_set_SE_checkpoint(thd->wsrep_trx_meta.gtid.uuid,
thd->wsrep_trx_meta.gtid.seqno);
@@ -1676,7 +1798,8 @@ static void wsrep_RSU_end(THD *thd)
}
int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_,
- const TABLE_LIST* table_list)
+ const TABLE_LIST* table_list,
+ Alter_info* alter_info)
{
int ret= 0;
@@ -1730,10 +1853,10 @@ int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_,
{
switch (thd->variables.wsrep_OSU_method) {
case WSREP_OSU_TOI:
- ret = wsrep_TOI_begin(thd, db_, table_, table_list);
+ ret= wsrep_TOI_begin(thd, db_, table_, table_list, alter_info);
break;
case WSREP_OSU_RSU:
- ret = wsrep_RSU_begin(thd, db_, table_);
+ ret= wsrep_RSU_begin(thd, db_, table_);
break;
default:
WSREP_ERROR("Unsupported OSU method: %lu",
@@ -2607,10 +2730,11 @@ bool wsrep_create_like_table(THD* thd, TABLE_LIST* table,
}
return(false);
-
-error:
+#ifdef WITH_WSREP
+wsrep_error_label:
thd->wsrep_TOI_pre_query= NULL;
return (true);
+#endif
}
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
index 699a4daf27a..819a56b9f23 100644
--- a/sql/wsrep_mysqld.h
+++ b/sql/wsrep_mysqld.h
@@ -285,8 +285,10 @@ extern PSI_mutex_key key_LOCK_wsrep_desync;
extern PSI_file_key key_file_wsrep_gra_log;
#endif /* HAVE_PSI_INTERFACE */
struct TABLE_LIST;
+class Alter_info;
int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_,
- const TABLE_LIST* table_list);
+ const TABLE_LIST* table_list,
+ Alter_info* alter_info = NULL);
void wsrep_to_isolation_end(THD *thd);
void wsrep_cleanup_transaction(THD *thd);
int wsrep_to_buf_helper(
diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc
index d5b0344c456..e648a7f4c69 100644
--- a/sql/wsrep_sst.cc
+++ b/sql/wsrep_sst.cc
@@ -15,6 +15,7 @@
#include "mariadb.h"
#include "wsrep_sst.h"
+#include <inttypes.h>
#include <mysqld.h>
#include <m_ctype.h>
#include <strfunc.h>
@@ -36,8 +37,14 @@ static char wsrep_defaults_file[FN_REFLEN * 2 + 10 + 30 +
sizeof(WSREP_SST_OPT_CONF_SUFFIX) +
sizeof(WSREP_SST_OPT_CONF_EXTRA)] = {0};
+const char* wsrep_sst_method = WSREP_SST_DEFAULT;
+const char* wsrep_sst_receive_address = WSREP_SST_ADDRESS_AUTO;
+const char* wsrep_sst_donor = "";
+const char* wsrep_sst_auth = NULL;
+
// container for real auth string
static const char* sst_auth_real = NULL;
+my_bool wsrep_sst_donor_rejects_queries = FALSE;
bool wsrep_sst_method_check (sys_var *self, THD* thd, set_var* var)
{
@@ -58,6 +65,12 @@ bool wsrep_sst_method_update (sys_var *self, THD* thd, enum_var_type type)
return 0;
}
+static const char* data_home_dir = NULL;
+
+void wsrep_set_data_home_dir(const char *data_dir)
+{
+ data_home_dir= (data_dir && *data_dir) ? data_dir : NULL;
+}
static void make_wsrep_defaults_file()
{
@@ -149,7 +162,7 @@ void wsrep_sst_auth_free()
bool wsrep_sst_auth_update (sys_var *self, THD* thd, enum_var_type type)
{
- return sst_auth_real_set (wsrep_sst_auth);
+ return sst_auth_real_set (wsrep_sst_auth);
}
void wsrep_sst_auth_init ()
@@ -164,7 +177,7 @@ bool wsrep_sst_donor_check (sys_var *self, THD* thd, set_var* var)
bool wsrep_sst_donor_update (sys_var *self, THD* thd, enum_var_type type)
{
- return 0;
+ return 0;
}
bool wsrep_before_SE()
@@ -192,8 +205,7 @@ void wsrep_sst_grab ()
// Wait for end of SST
bool wsrep_sst_wait ()
{
- struct timespec wtime = {WSREP_TIMEDWAIT_SECONDS, 0};
- uint32 total_wtime = 0;
+ double total_wtime = 0;
if (mysql_mutex_lock (&LOCK_wsrep_sst))
abort();
@@ -202,14 +214,18 @@ bool wsrep_sst_wait ()
while (!sst_complete)
{
+ struct timespec wtime;
+ set_timespec(wtime, WSREP_TIMEDWAIT_SECONDS);
+ time_t start_time = time(NULL);
mysql_cond_timedwait (&COND_wsrep_sst, &LOCK_wsrep_sst, &wtime);
+ time_t end_time = time(NULL);
if (!sst_complete)
{
- total_wtime += wtime.tv_sec;
- WSREP_DEBUG("Waiting for SST to complete. waited %u secs.", total_wtime);
+ total_wtime += difftime(end_time, start_time);
+ WSREP_DEBUG("Waiting for SST to complete. current seqno: %" PRId64 " waited %f secs.", local_seqno, total_wtime);
service_manager_extend_timeout(WSREP_EXTEND_TIMEOUT_INTERVAL,
- "WSREP state transfer ongoing, current seqno: %ld", local_seqno);
+ "WSREP state transfer ongoing, current seqno: %ld waited %f secs", local_seqno, total_wtime);
}
}
@@ -293,7 +309,7 @@ bool wsrep_sst_received (wsrep_t* const wsrep,
}
if (memcmp(&local_uuid, &uuid, sizeof(wsrep_uuid_t)) ||
- local_seqno < seqno)
+ local_seqno < seqno || seqno < 0)
{
do_update= true;
}
@@ -444,6 +460,22 @@ static int generate_binlog_opt_val(char** ret)
return 0;
}
+static int generate_binlog_index_opt_val(char** ret)
+{
+ DBUG_ASSERT(ret);
+ *ret= NULL;
+ if (opt_binlog_index_name) {
+ *ret= strcmp(opt_binlog_index_name, "0") ?
+ my_strdup(opt_binlog_index_name, MYF(0)) : my_strdup("", MYF(0));
+ }
+ else
+ {
+ *ret= my_strdup("", MYF(0));
+ }
+ if (!*ret) return -ENOMEM;
+ return 0;
+}
+
static void* sst_joiner_thread (void* a)
{
sst_thread_arg* arg= (sst_thread_arg*) a;
@@ -592,6 +624,29 @@ static int sst_append_auth_env(wsp::env& env, const char* sst_auth)
return -env.error();
}
+#define DATA_HOME_DIR_ENV "INNODB_DATA_HOME_DIR"
+
+static int sst_append_data_dir(wsp::env& env, const char* data_dir)
+{
+ int const data_dir_size= strlen(DATA_HOME_DIR_ENV) + 1 /* = */
+ + (data_dir ? strlen(data_dir) : 0) + 1 /* \0 */;
+
+ wsp::string data_dir_str(data_dir_size); // for automatic cleanup on return
+ if (!data_dir_str()) return -ENOMEM;
+
+ int ret= snprintf(data_dir_str(), data_dir_size, "%s=%s",
+ DATA_HOME_DIR_ENV, data_dir ? data_dir : "");
+
+ if (ret < 0 || ret >= data_dir_size)
+ {
+ WSREP_ERROR("sst_append_data_dir(): snprintf() failed: %d", ret);
+ return (ret < 0 ? ret : -EMSGSIZE);
+ }
+
+ env.append(data_dir_str());
+ return -env.error();
+}
+
static ssize_t sst_prepare_other (const char* method,
const char* sst_auth,
const char* addr_in,
@@ -608,7 +663,9 @@ static ssize_t sst_prepare_other (const char* method,
}
const char* binlog_opt= "";
+ const char* binlog_index_opt= "";
char* binlog_opt_val= NULL;
+ char* binlog_index_opt_val= NULL;
int ret;
if ((ret= generate_binlog_opt_val(&binlog_opt_val)))
@@ -617,7 +674,15 @@ static ssize_t sst_prepare_other (const char* method,
ret);
return ret;
}
+
+ if ((ret= generate_binlog_index_opt_val(&binlog_index_opt_val)))
+ {
+ WSREP_ERROR("sst_prepare_other(): generate_binlog_index_opt_val() failed %d",
+ ret);
+ }
+
if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG;
+ if (strlen(binlog_index_opt_val)) binlog_index_opt= WSREP_SST_OPT_BINLOG_INDEX;
make_wsrep_defaults_file();
@@ -628,11 +693,14 @@ static ssize_t sst_prepare_other (const char* method,
WSREP_SST_OPT_DATA " '%s' "
" %s "
WSREP_SST_OPT_PARENT " '%d'"
- " %s '%s' ",
+ " %s '%s'"
+ " %s '%s'",
method, addr_in, mysql_real_data_home,
wsrep_defaults_file,
- (int)getpid(), binlog_opt, binlog_opt_val);
+ (int)getpid(), binlog_opt, binlog_opt_val,
+ binlog_index_opt, binlog_index_opt_val);
my_free(binlog_opt_val);
+ my_free(binlog_index_opt_val);
if (ret < 0 || ret >= cmd_len)
{
@@ -653,6 +721,16 @@ static ssize_t sst_prepare_other (const char* method,
return ret;
}
+ if (data_home_dir)
+ {
+ if ((ret= sst_append_data_dir(env, data_home_dir)))
+ {
+ WSREP_ERROR("sst_prepare_other(): appending data "
+ "directory failed: %d", ret);
+ return ret;
+ }
+ }
+
pthread_t tmp;
sst_thread_arg arg(cmd_str(), env());
mysql_mutex_lock (&arg.lock);
@@ -1344,6 +1422,16 @@ wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx,
return WSREP_CB_FAILURE;
}
+ if (data_home_dir)
+ {
+ if ((ret= sst_append_data_dir(env, data_home_dir)))
+ {
+ WSREP_ERROR("wsrep_sst_donate_cb(): appending data "
+ "directory failed: %d", ret);
+ return WSREP_CB_FAILURE;
+ }
+ }
+
if (!strcmp (WSREP_SST_MYSQLDUMP, method))
{
ret = sst_donate_mysqldump(data, &current_gtid->uuid, uuid_str,
@@ -1365,19 +1453,22 @@ void wsrep_SE_init_grab()
void wsrep_SE_init_wait()
{
- struct timespec wtime = {WSREP_TIMEDWAIT_SECONDS, 0};
- uint32 total_wtime=0;
+ double total_wtime=0;
while (SE_initialized == false)
{
+ struct timespec wtime;
+ set_timespec(wtime, WSREP_TIMEDWAIT_SECONDS);
+ time_t start_time = time(NULL);
mysql_cond_timedwait (&COND_wsrep_sst_init, &LOCK_wsrep_sst_init, &wtime);
+ time_t end_time = time(NULL);
if (!SE_initialized)
{
- total_wtime += wtime.tv_sec;
- WSREP_DEBUG("Waiting for SST to complete. waited %u secs.", total_wtime);
+ total_wtime += difftime(end_time, start_time);
+ WSREP_DEBUG("Waiting for SST to complete. current seqno: %" PRId64 " waited %f secs.", local_seqno, total_wtime);
service_manager_extend_timeout(WSREP_EXTEND_TIMEOUT_INTERVAL,
- "WSREP SE initialization ongoing.");
+ "WSREP state transfer ongoing, current seqno: %ld waited %f secs", local_seqno, total_wtime);
}
}
diff --git a/sql/wsrep_sst.h b/sql/wsrep_sst.h
index 8bf6dc31464..cc0f1f5389d 100644
--- a/sql/wsrep_sst.h
+++ b/sql/wsrep_sst.h
@@ -31,6 +31,7 @@
#define WSREP_SST_OPT_CONF_EXTRA "--defaults-extra-file"
#define WSREP_SST_OPT_PARENT "--parent"
#define WSREP_SST_OPT_BINLOG "--binlog"
+#define WSREP_SST_OPT_BINLOG_INDEX "--binlog-index"
// mysqldump-specific options
#define WSREP_SST_OPT_USER "--user"
diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc
index 7fe120beb8e..f8a494416e2 100644
--- a/sql/wsrep_var.cc
+++ b/sql/wsrep_var.cc
@@ -594,7 +594,9 @@ void wsrep_node_address_init (const char* value)
static void wsrep_slave_count_change_update ()
{
- wsrep_slave_count_change += (wsrep_slave_threads - wsrep_prev_slave_threads);
+ wsrep_slave_count_change = (wsrep_slave_threads - wsrep_prev_slave_threads);
+ WSREP_DEBUG("Change on slave threads: New %lu old %lu difference %d",
+ wsrep_slave_threads, wsrep_prev_slave_threads, wsrep_slave_count_change);
wsrep_prev_slave_threads = wsrep_slave_threads;
}
@@ -617,6 +619,12 @@ bool wsrep_desync_check (sys_var *self, THD* thd, set_var* var)
return true;
}
+ if (thd->global_read_lock.is_acquired())
+ {
+ my_message (ER_CANNOT_USER, "Global read lock acquired. Can't set 'wsrep_desync'", MYF(0));
+ return true;
+ }
+
bool new_wsrep_desync= (bool) var->save_result.ulonglong_value;
if (wsrep_desync == new_wsrep_desync) {
if (new_wsrep_desync) {
@@ -750,4 +758,3 @@ int wsrep_show_status (THD *thd, SHOW_VAR *var, char *buff,
v->name= 0; // terminator
return 0;
}
-
diff --git a/sql/wsrep_xid.cc b/sql/wsrep_xid.cc
index 618c98eade7..2834100568a 100644
--- a/sql/wsrep_xid.cc
+++ b/sql/wsrep_xid.cc
@@ -156,15 +156,14 @@ bool wsrep_get_SE_checkpoint(wsrep_uuid_t& uuid, wsrep_seqno_t& seqno)
seqno= WSREP_SEQNO_UNDEFINED;
XID xid;
- memset(&xid, 0, sizeof(xid));
- xid.formatID= -1;
+ xid.null();
if (wsrep_get_SE_checkpoint(xid))
{
return true;
}
- if (xid.formatID == -1) // nil XID
+ if (xid.is_null())
{
return false;
}