summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt93
-rw-r--r--sql/backup.cc5
-rw-r--r--sql/bounded_queue.h10
-rw-r--r--sql/create_options.cc48
-rw-r--r--sql/datadict.cc2
-rw-r--r--sql/debug_sync.cc66
-rw-r--r--sql/debug_sync.h6
-rw-r--r--sql/derror.cc8
-rw-r--r--sql/discover.cc14
-rw-r--r--sql/event_data_objects.cc51
-rw-r--r--sql/event_data_objects.h13
-rw-r--r--sql/event_db_repository.cc7
-rw-r--r--sql/event_queue.cc6
-rw-r--r--sql/event_scheduler.cc25
-rw-r--r--sql/events.cc37
-rw-r--r--sql/events.h2
-rw-r--r--sql/field.cc1446
-rw-r--r--sql/field.h2584
-rw-r--r--sql/field_conv.cc41
-rw-r--r--sql/filesort.cc1692
-rw-r--r--sql/filesort.h98
-rw-r--r--sql/filesort_utils.cc78
-rw-r--r--sql/filesort_utils.h218
-rw-r--r--sql/gcalc_slicescan.cc2
-rw-r--r--sql/gen_sql_yacc_ora_yy.cmake15
-rw-r--r--sql/grant.cc108
-rw-r--r--sql/grant.h99
-rw-r--r--sql/group_by_handler.cc13
-rw-r--r--sql/group_by_handler.h6
-rw-r--r--sql/gstream.cc8
-rw-r--r--sql/ha_partition.cc119
-rw-r--r--sql/ha_partition.h4
-rw-r--r--sql/ha_sequence.cc3
-rw-r--r--sql/handle_connections_win.cc11
-rw-r--r--sql/handler.cc700
-rw-r--r--sql/handler.h245
-rw-r--r--sql/hash_filo.h29
-rw-r--r--sql/hostname.cc13
-rw-r--r--sql/item.cc342
-rw-r--r--sql/item.h458
-rw-r--r--sql/item_cmpfunc.cc405
-rw-r--r--sql/item_cmpfunc.h74
-rw-r--r--sql/item_create.cc2105
-rw-r--r--sql/item_create.h130
-rw-r--r--sql/item_func.cc181
-rw-r--r--sql/item_func.h297
-rw-r--r--sql/item_geofunc.cc1308
-rw-r--r--sql/item_geofunc.h167
-rw-r--r--sql/item_inetfunc.cc967
-rw-r--r--sql/item_inetfunc.h226
-rw-r--r--sql/item_jsonfunc.cc267
-rw-r--r--sql/item_jsonfunc.h203
-rw-r--r--sql/item_row.cc19
-rw-r--r--sql/item_row.h3
-rw-r--r--sql/item_strfunc.cc352
-rw-r--r--sql/item_strfunc.h13
-rw-r--r--sql/item_subselect.cc76
-rw-r--r--sql/item_sum.cc47
-rw-r--r--sql/item_sum.h63
-rw-r--r--sql/item_timefunc.cc128
-rw-r--r--sql/item_timefunc.h38
-rw-r--r--sql/item_windowfunc.cc3
-rw-r--r--sql/item_windowfunc.h13
-rw-r--r--sql/item_xmlfunc.cc272
-rw-r--r--sql/item_xmlfunc.h40
-rw-r--r--sql/key.cc41
-rw-r--r--sql/keycaches.cc10
-rw-r--r--sql/lex.h16
-rw-r--r--sql/lex_string.h42
-rw-r--r--sql/lock.cc31
-rw-r--r--sql/log.cc567
-rw-r--r--sql/log.h49
-rw-r--r--sql/log_event.cc11667
-rw-r--r--sql/log_event.h547
-rw-r--r--sql/log_event_client.cc3928
-rw-r--r--sql/log_event_old.cc18
-rw-r--r--sql/log_event_server.cc8471
-rw-r--r--sql/mdl.cc79
-rw-r--r--sql/mdl.h36
-rw-r--r--sql/multi_range_read.cc2
-rw-r--r--sql/mysql_install_db.cc4
-rw-r--r--sql/mysql_upgrade_service.cc6
-rw-r--r--sql/mysqld.cc993
-rw-r--r--sql/mysqld.h163
-rw-r--r--sql/net_serv.cc30
-rw-r--r--sql/opt_range.cc104
-rw-r--r--sql/opt_range.h1
-rw-r--r--sql/opt_split.cc12
-rw-r--r--sql/opt_subselect.cc64
-rw-r--r--sql/opt_subselect.h1
-rw-r--r--sql/opt_trace.cc25
-rw-r--r--sql/partition_info.cc259
-rw-r--r--sql/partition_info.h87
-rw-r--r--sql/privilege.h738
-rw-r--r--sql/procedure.h22
-rw-r--r--sql/protocol.cc65
-rw-r--r--sql/protocol.h6
-rw-r--r--sql/proxy_protocol.cc3
-rw-r--r--sql/records.cc169
-rw-r--r--sql/records.h14
-rw-r--r--sql/repl_failsafe.cc10
-rw-r--r--sql/rpl_filter.cc34
-rw-r--r--sql/rpl_gtid.cc62
-rw-r--r--sql/rpl_gtid.h2
-rw-r--r--sql/rpl_injector.cc3
-rw-r--r--sql/rpl_mi.cc16
-rw-r--r--sql/rpl_parallel.cc50
-rw-r--r--sql/rpl_parallel.h3
-rw-r--r--sql/rpl_rli.cc31
-rw-r--r--sql/rpl_tblmap.cc13
-rw-r--r--sql/rpl_utility.cc989
-rw-r--r--sql/rpl_utility.h4
-rw-r--r--sql/rpl_utility_server.cc1185
-rw-r--r--sql/scheduler.cc25
-rw-r--r--sql/scheduler.h20
-rw-r--r--sql/select_handler.cc29
-rw-r--r--sql/semisync_master.cc4
-rw-r--r--sql/semisync_master.h2
-rw-r--r--sql/semisync_master_ack_receiver.cc2
-rw-r--r--sql/service_wsrep.cc57
-rw-r--r--sql/session_tracker.cc62
-rw-r--r--sql/session_tracker.h73
-rw-r--r--sql/set_var.cc102
-rw-r--r--sql/set_var.h23
-rw-r--r--sql/share/errmsg-utf8.txt33
-rw-r--r--sql/signal_handler.cc18
-rw-r--r--sql/slave.cc60
-rw-r--r--sql/sp.cc96
-rw-r--r--sql/sp.h52
-rw-r--r--sql/sp_cache.cc20
-rw-r--r--sql/sp_head.cc240
-rw-r--r--sql/sp_head.h98
-rw-r--r--sql/sp_pcontext.cc17
-rw-r--r--sql/sp_pcontext.h6
-rw-r--r--sql/sp_rcontext.cc1
-rw-r--r--sql/spatial.cc49
-rw-r--r--sql/spatial.h1
-rw-r--r--sql/sql_acl.cc925
-rw-r--r--sql/sql_acl.h259
-rw-r--r--sql/sql_admin.cc19
-rw-r--r--sql/sql_alter.cc31
-rw-r--r--sql/sql_alter.h7
-rw-r--r--sql/sql_analyze_stmt.cc40
-rw-r--r--sql/sql_analyze_stmt.h170
-rw-r--r--sql/sql_array.h35
-rw-r--r--sql/sql_audit.cc2
-rw-r--r--sql/sql_base.cc169
-rw-r--r--sql/sql_base.h9
-rw-r--r--sql/sql_basic_types.h2
-rw-r--r--sql/sql_binlog.cc7
-rw-r--r--sql/sql_bitmap.h380
-rw-r--r--sql/sql_builtin.cc.in6
-rw-r--r--sql/sql_cache.cc16
-rw-r--r--sql/sql_class.cc342
-rw-r--r--sql/sql_class.h556
-rw-r--r--sql/sql_cmd.h22
-rw-r--r--sql/sql_connect.cc146
-rw-r--r--sql/sql_connect.h28
-rw-r--r--sql/sql_const.h2
-rw-r--r--sql/sql_cte.cc142
-rw-r--r--sql/sql_cte.h15
-rw-r--r--sql/sql_cursor.cc7
-rw-r--r--sql/sql_db.cc110
-rw-r--r--sql/sql_delete.cc71
-rw-r--r--sql/sql_delete.h3
-rw-r--r--sql/sql_derived.cc7
-rw-r--r--sql/sql_digest.cc2
-rw-r--r--sql/sql_error.cc121
-rw-r--r--sql/sql_error.h21
-rw-r--r--sql/sql_explain.cc5
-rw-r--r--sql/sql_explain.h4
-rw-r--r--sql/sql_expression_cache.h2
-rw-r--r--sql/sql_get_diagnostics.cc4
-rw-r--r--sql/sql_handler.cc17
-rw-r--r--sql/sql_help.cc12
-rw-r--r--sql/sql_hset.h23
-rw-r--r--sql/sql_i_s.h360
-rw-r--r--sql/sql_insert.cc261
-rw-r--r--sql/sql_insert.h5
-rw-r--r--sql/sql_join_cache.cc20
-rw-r--r--sql/sql_lex.cc1255
-rw-r--r--sql/sql_lex.h304
-rw-r--r--sql/sql_limit.h72
-rw-r--r--sql/sql_list.h3
-rw-r--r--sql/sql_load.cc16
-rw-r--r--sql/sql_manager.cc3
-rw-r--r--sql/sql_parse.cc990
-rw-r--r--sql/sql_parse.h26
-rw-r--r--sql/sql_partition.cc171
-rw-r--r--sql/sql_partition.h7
-rw-r--r--sql/sql_partition_admin.cc4
-rw-r--r--sql/sql_plugin.cc146
-rw-r--r--sql/sql_plugin_services.ic16
-rw-r--r--sql/sql_prepare.cc98
-rw-r--r--sql/sql_priv.h4
-rw-r--r--sql/sql_profile.cc69
-rw-r--r--sql/sql_profile.h9
-rw-r--r--sql/sql_reload.cc4
-rw-r--r--sql/sql_rename.cc9
-rw-r--r--sql/sql_repl.cc46
-rw-r--r--sql/sql_select.cc1624
-rw-r--r--sql/sql_select.h28
-rw-r--r--sql/sql_sequence.cc25
-rw-r--r--sql/sql_servers.cc16
-rw-r--r--sql/sql_show.cc1992
-rw-r--r--sql/sql_show.h12
-rw-r--r--sql/sql_signal.cc11
-rw-r--r--sql/sql_sort.h607
-rw-r--r--sql/sql_statistics.cc2
-rw-r--r--sql/sql_string.cc66
-rw-r--r--sql/sql_string.h92
-rw-r--r--sql/sql_table.cc700
-rw-r--r--sql/sql_table.h4
-rw-r--r--sql/sql_tablespace.cc2
-rw-r--r--sql/sql_test.cc8
-rw-r--r--sql/sql_time.cc19
-rw-r--r--sql/sql_trigger.cc36
-rw-r--r--sql/sql_truncate.cc22
-rw-r--r--sql/sql_tvc.cc10
-rw-r--r--sql/sql_type.cc2567
-rw-r--r--sql/sql_type.h3358
-rw-r--r--sql/sql_type_geom.cc965
-rw-r--r--sql/sql_type_geom.h435
-rw-r--r--sql/sql_type_json.cc6
-rw-r--r--sql/sql_type_string.cc104
-rw-r--r--sql/sql_type_string.h48
-rw-r--r--sql/sql_udf.cc15
-rw-r--r--sql/sql_union.cc1007
-rw-r--r--sql/sql_update.cc16
-rw-r--r--sql/sql_view.cc41
-rw-r--r--sql/sql_window.cc6
-rw-r--r--sql/sql_yacc.yy4907
-rw-r--r--sql/sql_yacc_ora.yy18369
-rw-r--r--sql/strfunc.cc18
-rw-r--r--sql/strfunc.h3
-rw-r--r--sql/structs.h2
-rw-r--r--sql/sys_vars.cc1025
-rw-r--r--sql/sys_vars.ic118
-rw-r--r--sql/table.cc314
-rw-r--r--sql/table.h180
-rw-r--r--sql/table_cache.cc87
-rw-r--r--sql/table_cache.h13
-rw-r--r--sql/temporary_tables.cc9
-rw-r--r--sql/thr_malloc.cc7
-rw-r--r--sql/thr_malloc.h4
-rw-r--r--sql/thread_pool_info.cc357
-rw-r--r--sql/threadpool.h9
-rw-r--r--sql/threadpool_common.cc51
-rw-r--r--sql/threadpool_generic.cc231
-rw-r--r--sql/threadpool_generic.h150
-rw-r--r--sql/threadpool_win.cc50
-rw-r--r--sql/transaction.cc53
-rw-r--r--sql/tztime.cc33
-rw-r--r--sql/uniques.cc90
-rw-r--r--sql/uniques.h2
-rw-r--r--sql/unireg.cc145
-rw-r--r--sql/unireg.h3
-rw-r--r--sql/upgrade_conf_file.cc7
-rw-r--r--sql/vers_string.h34
-rw-r--r--sql/vers_utils.h8
-rw-r--r--sql/wsrep_applier.cc82
-rw-r--r--sql/wsrep_applier.h37
-rw-r--r--sql/wsrep_binlog.cc6
-rw-r--r--sql/wsrep_client_service.cc1
-rw-r--r--sql/wsrep_dummy.cc8
-rw-r--r--sql/wsrep_high_priority_service.cc76
-rw-r--r--sql/wsrep_high_priority_service.h5
-rw-r--r--sql/wsrep_mysqld.cc420
-rw-r--r--sql/wsrep_mysqld.h159
-rw-r--r--sql/wsrep_schema.cc14
-rw-r--r--sql/wsrep_server_service.cc12
-rw-r--r--sql/wsrep_sst.cc32
-rw-r--r--sql/wsrep_trans_observer.h84
-rw-r--r--sql/wsrep_utils.cc2
-rw-r--r--sql/wsrep_var.cc81
-rw-r--r--sql/wsrep_var.h9
-rw-r--r--sql/wsrep_xid.cc66
-rw-r--r--sql/wsrep_xid.h7
-rw-r--r--sql/xa.cc294
-rw-r--r--sql/xa.h14
280 files changed, 46523 insertions, 50530 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index bab8e67fdac..d0a3e8a437a 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -36,31 +36,39 @@ IF(WITH_WSREP AND NOT EMBEDDED_LIBRARY)
wsrep_plugin.cc
service_wsrep.cc
)
- SET(WSREP_LIB wsrep-lib wsrep_api_v26)
+ MYSQL_ADD_PLUGIN(wsrep ${WSREP_SOURCES} MANDATORY NOT_EMBEDDED EXPORT_SYMBOLS LINK_LIBRARIES wsrep-lib wsrep_api_v26)
ELSE()
- SET(WSREP_SOURCES wsrep_dummy.cc)
+ ADD_LIBRARY(wsrep STATIC wsrep_dummy.cc)
+ ADD_DEPENDENCIES(wsrep GenError)
ENDIF()
INCLUDE_DIRECTORIES(
${CMAKE_SOURCE_DIR}/include
-${CMAKE_SOURCE_DIR}/sql
+${CMAKE_SOURCE_DIR}/sql
${PCRE_INCLUDES}
${ZLIB_INCLUDE_DIR}
${SSL_INCLUDE_DIRS}
${CMAKE_BINARY_DIR}/sql
+${CMAKE_SOURCE_DIR}/tpool
)
-
-
-
-
-
ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lex_token.h
COMMAND gen_lex_token > lex_token.h
DEPENDS gen_lex_token
)
+ADD_CUSTOM_COMMAND(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc_ora.yy
+ COMMAND ${CMAKE_COMMAND}
+ "-DIN=${CMAKE_CURRENT_SOURCE_DIR}/sql_yacc.yy"
+ "-DOUT=${CMAKE_CURRENT_BINARY_DIR}/sql_yacc_ora.yy"
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/gen_sql_yacc_ora_yy.cmake
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/sql_yacc.yy
+)
+
+ADD_CUSTOM_TARGET(gen_sql_yacc_ora_yy DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc_ora.yy)
+
ADD_DEFINITIONS(-DMYSQL_SERVER -DHAVE_EVENT_SCHEDULER)
IF(SSL_DEFINES)
@@ -79,7 +87,8 @@ SET (SQL_SOURCE
item_create.cc item_func.cc item_geofunc.cc item_row.cc
item_strfunc.cc item_subselect.cc item_sum.cc item_timefunc.cc
key.cc log.cc lock.cc
- log_event.cc rpl_record.cc rpl_reporting.cc
+ log_event.cc log_event_server.cc
+ rpl_record.cc rpl_reporting.cc
log_event_old.cc rpl_record_old.cc
mf_iocache.cc my_decimal.cc
mysqld.cc net_serv.cc keycaches.cc
@@ -110,15 +119,17 @@ SET (SQL_SOURCE
rpl_tblmap.cc sql_binlog.cc event_scheduler.cc event_data_objects.cc
event_queue.cc event_db_repository.cc
sql_tablespace.cc events.cc ../sql-common/my_user.c
- partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc
+ partition_info.cc rpl_utility.cc rpl_utility_server.cc
+ rpl_injector.cc sql_locale.cc
rpl_rli.cc rpl_mi.cc sql_servers.cc sql_audit.cc
sql_connect.cc scheduler.cc sql_partition_admin.cc
sql_profile.cc event_parse_data.cc sql_alter.cc
sql_signal.cc mdl.cc sql_admin.cc
transaction.cc sys_vars.cc sql_truncate.cc datadict.cc
- sql_reload.cc item_inetfunc.cc
+ sql_reload.cc
# added in MariaDB:
+ grant.cc
sql_explain.cc
sql_analyze_stmt.cc
sql_join_cache.cc
@@ -133,6 +144,8 @@ SET (SQL_SOURCE
semisync.cc semisync_master.cc semisync_slave.cc
semisync_master_ack_receiver.cc
sql_type.cc sql_mode.cc sql_type_json.cc
+ sql_type_string.cc
+ sql_type_geom.cc
item_windowfunc.cc sql_window.cc
sql_cte.cc
item_vers.cc
@@ -141,14 +154,13 @@ SET (SQL_SOURCE
opt_split.cc
rowid_filter.cc rowid_filter.h
opt_trace.cc
- ${WSREP_SOURCES}
table_cache.cc encryption.cc temporary_tables.cc
proxy_protocol.cc backup.cc xa.cc
- ${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc
${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.cc
${CMAKE_CURRENT_BINARY_DIR}/sql_yacc_ora.cc
${CMAKE_CURRENT_BINARY_DIR}/lex_hash.h
${CMAKE_CURRENT_BINARY_DIR}/lex_token.h
+ ${GEN_SOURCES}
${MYSYS_LIBWRAP_SOURCE}
)
@@ -163,6 +175,7 @@ IF ((CMAKE_SYSTEM_NAME MATCHES "Linux" OR
ENDIF()
SET(SQL_SOURCE ${SQL_SOURCE} threadpool_generic.cc)
SET(SQL_SOURCE ${SQL_SOURCE} threadpool_common.cc)
+ MYSQL_ADD_PLUGIN(thread_pool_info thread_pool_info.cc DEFAULT STATIC_ONLY NOT_EMBEDDED)
ENDIF()
IF(WIN32)
@@ -176,13 +189,24 @@ RECOMPILE_FOR_EMBEDDED)
ADD_LIBRARY(sql STATIC ${SQL_SOURCE})
DTRACE_INSTRUMENT(sql)
-TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATIC_PLUGIN_LIBS}
- mysys mysys_ssl dbug strings vio pcre
+TARGET_LINK_LIBRARIES(sql
+ mysys mysys_ssl dbug strings vio pcre2-8
+ tpool
${LIBWRAP} ${LIBCRYPT} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT}
- ${WSREP_LIB}
${SSL_LIBRARIES}
${LIBSYSTEMD})
+IF(TARGET pcre2)
+ ADD_DEPENDENCIES(sql pcre2)
+ENDIF()
+
+FOREACH(se aria partition perfschema sql_sequence wsrep)
+ # These engines are used directly in sql sources.
+ IF(TARGET ${se})
+ TARGET_LINK_LIBRARIES(sql ${se})
+ ENDIF()
+ENDFOREACH()
+
IF(WIN32)
SET(MYSQLD_SOURCE main.cc nt_servc.cc message.rc)
TARGET_LINK_LIBRARIES(sql psapi)
@@ -266,6 +290,9 @@ IF(MSVC AND NOT WITHOUT_DYNAMIC_PLUGINS)
SET_TARGET_PROPERTIES(mysqld_import_lib PROPERTIES IMPORTED_LOCATION ${MYSQLD_LIB})
ENDIF()
+ADD_LIBRARY(sql_builtins STATIC ${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc)
+TARGET_LINK_LIBRARIES(sql_builtins ${MYSQLD_STATIC_PLUGIN_LIBS})
+
MYSQL_ADD_EXECUTABLE(mysqld ${MYSQLD_SOURCE} DESTINATION ${INSTALL_SBINDIR} COMPONENT Server)
IF(APPLE)
@@ -293,7 +320,8 @@ IF(NOT WITHOUT_DYNAMIC_PLUGINS)
ENDIF()
ENDIF(NOT WITHOUT_DYNAMIC_PLUGINS)
-TARGET_LINK_LIBRARIES(mysqld LINK_PRIVATE sql)
+TARGET_LINK_LIBRARIES(mysqld LINK_PRIVATE sql sql_builtins)
+
# Provide plugins with minimal set of libraries
SET(INTERFACE_LIBS ${LIBRT})
@@ -352,8 +380,7 @@ IF (NOT BISON_FOUND)
ELSE()
BISON_TARGET(gen_sql_yacc ${CMAKE_CURRENT_SOURCE_DIR}/sql_yacc.yy ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.cc
COMPILE_FLAGS "-p MYSQL")
-
- BISON_TARGET(gen_sql_yacc_ora ${CMAKE_CURRENT_SOURCE_DIR}/sql_yacc_ora.yy ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc_ora.cc
+ BISON_TARGET(gen_sql_yacc_ora ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc_ora.yy ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc_ora.cc
COMPILE_FLAGS "-p ORA")
ENDIF()
@@ -381,6 +408,8 @@ ADD_CUSTOM_TARGET(
${CMAKE_CURRENT_BINARY_DIR}/sql_yacc_ora.cc
)
+ADD_DEPENDENCIES(GenServerSource gen_sql_yacc_ora_yy)
+
IF(WIN32 OR HAVE_DLOPEN AND NOT DISABLE_SHARED)
ADD_LIBRARY(udf_example MODULE udf_example.c udf_example.def)
SET_TARGET_PROPERTIES(udf_example PROPERTIES PREFIX "")
@@ -404,16 +433,9 @@ ADD_CUSTOM_TARGET(distclean
VERBATIM
)
-IF(INSTALL_LAYOUT STREQUAL "STANDALONE")
-
-# Copy db.opt into data/test/
-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(WIN32 AND TARGET mysqld AND NOT CMAKE_CROSSCOMPILING)
-
- IF(MSVC_IDE OR CMAKE_GENERATOR MATCHES "Xcode")
+# Install initial database (default on windows, optional target elsewhere)
+IF(TARGET mysqld AND NOT CMAKE_CROSSCOMPILING)
+ IF(GENERATOR_IS_MULTI_CONFIG)
SET (CONFIG_PARAM -DCONFIG=${CMAKE_CFG_INTDIR})
ENDIF()
MAKE_DIRECTORY(${CMAKE_CURRENT_BINARY_DIR}/data)
@@ -432,15 +454,16 @@ IF(WIN32 AND TARGET mysqld AND NOT CMAKE_CROSSCOMPILING)
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/
DEPENDS mysqld
)
+ IF(WIN32)
+ SET(ALL_ON_WINDOWS ALL)
+ ELSE()
+ SET(ALL_ON_WINDOWS)
+ ENDIF()
ADD_CUSTOM_TARGET(initial_database
- ALL
+ ${ALL_ON_WINDOWS}
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/initdb.dep
)
-ELSE()
- # Not windows or cross compiling, just install an empty directory
- INSTALL(FILES ${DUMMY_FILE} DESTINATION data/mysql COMPONENT DataFiles)
-ENDIF(WIN32 AND TARGET mysqld AND NOT CMAKE_CROSSCOMPILING)
-ENDIF(INSTALL_LAYOUT STREQUAL "STANDALONE")
+ENDIF()
IF(WIN32)
SET(my_bootstrap_sql ${CMAKE_CURRENT_BINARY_DIR}/my_bootstrap.sql)
diff --git a/sql/backup.cc b/sql/backup.cc
index 5976506cf92..40791e27416 100644
--- a/sql/backup.cc
+++ b/sql/backup.cc
@@ -161,7 +161,8 @@ static bool backup_start(THD *thd)
DBUG_RETURN(1);
}
- mdl_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_START, MDL_EXPLICIT);
+ MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_START,
+ MDL_EXPLICIT);
if (thd->mdl_context.acquire_lock(&mdl_request,
thd->variables.lock_wait_timeout))
DBUG_RETURN(1);
@@ -204,7 +205,7 @@ static bool backup_flush(THD *thd)
Free unused tables and table shares so that mariabackup knows what
is safe to copy
*/
- tc_purge(false);
+ tc_purge();
tdc_purge(true);
DBUG_RETURN(0);
diff --git a/sql/bounded_queue.h b/sql/bounded_queue.h
index fd733caa019..07ab6dbaab9 100644
--- a/sql/bounded_queue.h
+++ b/sql/bounded_queue.h
@@ -57,9 +57,10 @@ public:
@param to Where to put the key.
@param from The input data.
*/
- typedef void (*keymaker_function)(Sort_param *param,
+ typedef uint (*keymaker_function)(Sort_param *param,
Key_type *to,
- Element_type *from);
+ Element_type *from,
+ bool packing_keys);
/**
Function for comparing two keys.
@@ -181,11 +182,12 @@ void Bounded_queue<Element_type, Key_type>::push(Element_type *element)
{
// Replace top element with new key, and re-order the queue.
Key_type **pq_top= reinterpret_cast<Key_type **>(queue_top(&m_queue));
- (*m_keymaker)(m_sort_param, *pq_top, element);
+ (void)(*m_keymaker)(m_sort_param, *pq_top, element, false);
queue_replace_top(&m_queue);
} else {
// Insert new key into the queue.
- (*m_keymaker)(m_sort_param, m_sort_keys[m_queue.elements], element);
+ (*m_keymaker)(m_sort_param, m_sort_keys[m_queue.elements],
+ element, false);
queue_insert(&m_queue,
reinterpret_cast<uchar*>(&m_sort_keys[m_queue.elements]));
}
diff --git a/sql/create_options.cc b/sql/create_options.cc
index a8d997efaf4..04469120db1 100644
--- a/sql/create_options.cc
+++ b/sql/create_options.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010, 2019, MariaDB Corporation.
+/* Copyright (C) 2010, 2020, 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
@@ -44,9 +44,8 @@ void engine_option_value::link(engine_option_value **start,
/* check duplicates to avoid writing them to frm*/
for(opt= *start;
opt && ((opt->parsed && !opt->value.str) ||
- my_strnncoll(system_charset_info,
- (uchar *)name.str, name.length,
- (uchar*)opt->name.str, opt->name.length));
+ system_charset_info->strnncoll(name.str, name.length,
+ opt->name.str, opt->name.length));
opt= opt->next) /* no-op */;
if (opt)
{
@@ -187,9 +186,8 @@ static bool set_one_value(ha_create_table_option *opt,
for (end=start;
*end && *end != ',';
end++) /* no-op */;
- if (!my_strnncoll(system_charset_info,
- (uchar*)start, end-start,
- (uchar*)value->str, value->length))
+ if (!system_charset_info->strnncoll(start, end-start,
+ value->str, value->length))
{
*val= num;
DBUG_RETURN(0);
@@ -211,29 +209,17 @@ static bool set_one_value(ha_create_table_option *opt,
if (!value->str)
DBUG_RETURN(0);
- if (!my_strnncoll(system_charset_info,
- (const uchar*)"NO", 2,
- (uchar *)value->str, value->length) ||
- !my_strnncoll(system_charset_info,
- (const uchar*)"OFF", 3,
- (uchar *)value->str, value->length) ||
- !my_strnncoll(system_charset_info,
- (const uchar*)"0", 1,
- (uchar *)value->str, value->length))
+ if (!system_charset_info->strnncoll("NO", 2, value->str, value->length) ||
+ !system_charset_info->strnncoll("OFF", 3, value->str, value->length) ||
+ !system_charset_info->strnncoll("0", 1, value->str, value->length))
{
*val= FALSE;
DBUG_RETURN(FALSE);
}
- if (!my_strnncoll(system_charset_info,
- (const uchar*)"YES", 3,
- (uchar *)value->str, value->length) ||
- !my_strnncoll(system_charset_info,
- (const uchar*)"ON", 2,
- (uchar *)value->str, value->length) ||
- !my_strnncoll(system_charset_info,
- (const uchar*)"1", 1,
- (uchar *)value->str, value->length))
+ if (!system_charset_info->strnncoll("YES", 3, value->str, value->length) ||
+ !system_charset_info->strnncoll("ON", 2, value->str, value->length) ||
+ !system_charset_info->strnncoll("1", 1, value->str, value->length))
{
*val= TRUE;
DBUG_RETURN(FALSE);
@@ -295,9 +281,8 @@ bool parse_option_list(THD* thd, handlerton *hton, void *option_struct_arg,
for (val= *option_list; val; val= val->next)
{
last= val;
- if (my_strnncoll(system_charset_info,
- (uchar*)opt->name, opt->name_length,
- (uchar*)val->name.str, val->name.length))
+ if (system_charset_info->strnncoll(opt->name, opt->name_length,
+ val->name.str, val->name.length))
continue;
/* skip duplicates (see engine_option_value constructor above) */
@@ -422,7 +407,7 @@ static bool resolve_sysvars(handlerton *hton, ha_create_table_option *rules)
return 1;
}
DBUG_ASSERT(str.length());
- opt->values= my_strndup(str.ptr(), str.length()-1, MYF(MY_WME));
+ opt->values= my_strndup(PSI_INSTRUMENT_ME, str.ptr(), str.length()-1, MYF(MY_WME));
if (!opt->values)
return 1;
break;
@@ -809,9 +794,8 @@ bool is_engine_option_known(engine_option_value *opt,
for (; rules->name; rules++)
{
- if (!my_strnncoll(system_charset_info,
- (uchar*)rules->name, rules->name_length,
- (uchar*)opt->name.str, opt->name.length))
+ if (!system_charset_info->strnncoll(rules->name, rules->name_length,
+ opt->name.str, opt->name.length))
return true;
}
return false;
diff --git a/sql/datadict.cc b/sql/datadict.cc
index da8376d8b1a..5cfda166b2b 100644
--- a/sql/datadict.cc
+++ b/sql/datadict.cc
@@ -25,7 +25,7 @@ static int read_string(File file, uchar**to, size_t length)
DBUG_ENTER("read_string");
/* This can't use MY_THREAD_SPECIFIC as it's used on server start */
- if (!(*to= (uchar*) my_malloc(length+1,MYF(MY_WME))) ||
+ if (!(*to= (uchar*) my_malloc(PSI_INSTRUMENT_ME, length+1,MYF(MY_WME))) ||
mysql_file_read(file, *to, length, MYF(MY_NABP)))
{
my_free(*to);
diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc
index bf721bddb85..2fc2e00d043 100644
--- a/sql/debug_sync.cc
+++ b/sql/debug_sync.cc
@@ -1,4 +1,5 @@
/* Copyright (c) 2009, 2013, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2020, 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
@@ -121,6 +122,25 @@ static void init_debug_sync_psi_keys(void)
/**
+ Set the THD::proc_info without instrumentation.
+ This method is private to DEBUG_SYNC,
+ and on purpose avoid any use of:
+ - the SHOW PROFILE instrumentation
+ - the PERFORMANCE_SCHEMA instrumentation
+ so that using DEBUG_SYNC() in the server code
+ does not cause the instrumentations to record
+ spurious data.
+*/
+static const char*
+debug_sync_thd_proc_info(THD *thd, const char* info)
+{
+ const char* old_proc_info= thd->proc_info;
+ thd->proc_info= info;
+ return old_proc_info;
+}
+
+
+/**
Initialize the debug sync facility at server start.
@return status
@@ -235,7 +255,8 @@ void debug_sync_init_thread(THD *thd)
if (opt_debug_sync_timeout)
{
thd->debug_sync_control= (st_debug_sync_control*)
- my_malloc(sizeof(st_debug_sync_control),
+ my_malloc(PSI_NOT_INSTRUMENTED,
+ sizeof(st_debug_sync_control),
MYF(MY_WME | MY_ZEROFILL | MY_THREAD_SPECIFIC));
if (!thd->debug_sync_control)
{
@@ -266,12 +287,6 @@ void debug_sync_end_thread(THD *thd)
{
st_debug_sync_control *ds_control= thd->debug_sync_control;
- /*
- This synchronization point can be used to synchronize on thread end.
- This is the latest point in a THD's life, where this can be done.
- */
- DEBUG_SYNC(thd, "thread_end");
-
if (ds_control->ds_action)
{
st_debug_sync_action *action= ds_control->ds_action;
@@ -301,6 +316,20 @@ void debug_sync_end_thread(THD *thd)
}
+void debug_sync_reset_thread(THD *thd)
+{
+ if (thd->debug_sync_control)
+ {
+ /*
+ This synchronization point can be used to synchronize on thread end.
+ This is the latest point in a THD's life, where this can be done.
+ */
+ DEBUG_SYNC(thd, "thread_end");
+ thd->debug_sync_control->ds_active= 0;
+ }
+}
+
+
/**
Move a string by length.
@@ -656,7 +685,7 @@ static st_debug_sync_action *debug_sync_get_action(THD *thd,
if (ds_control->ds_active > ds_control->ds_allocated)
{
uint new_alloc= ds_control->ds_active + 3;
- void *new_action= my_realloc(ds_control->ds_action,
+ void *new_action= my_realloc(PSI_NOT_INSTRUMENTED, ds_control->ds_action,
new_alloc * sizeof(st_debug_sync_action),
MYF(MY_WME | MY_ALLOW_ZERO_PTR));
if (!new_action)
@@ -855,8 +884,7 @@ static char *debug_sync_token(char **token_p, uint *token_length_p,
DBUG_ASSERT(ptr);
/* Skip leading space */
- ptr+= system_charset_info->cset->scan(system_charset_info,
- ptr, ptrend, MY_SEQ_SPACES);
+ ptr+= system_charset_info->scan(ptr, ptrend, MY_SEQ_SPACES);
if (!*ptr)
{
ptr= NULL;
@@ -867,8 +895,7 @@ static char *debug_sync_token(char **token_p, uint *token_length_p,
*token_p= ptr;
/* Find token end. */
- ptr+= system_charset_info->cset->scan(system_charset_info,
- ptr, ptrend, MY_SEQ_NONSPACES);
+ ptr+= system_charset_info->scan(ptr, ptrend, MY_SEQ_NONSPACES);
/* Get token length. */
*token_length_p= (uint)(ptr - *token_p);
@@ -878,7 +905,7 @@ static char *debug_sync_token(char **token_p, uint *token_length_p,
{
DBUG_ASSERT(ptr < ptrend);
/* Get terminator character length. */
- uint mbspacelen= my_charlen_fix(system_charset_info, ptr, ptrend);
+ uint mbspacelen= system_charset_info->charlen_fix(ptr, ptrend);
/* Terminate token. */
*ptr= '\0';
@@ -887,8 +914,7 @@ static char *debug_sync_token(char **token_p, uint *token_length_p,
ptr+= mbspacelen;
/* Skip trailing space */
- ptr+= system_charset_info->cset->scan(system_charset_info,
- ptr, ptrend, MY_SEQ_SPACES);
+ ptr+= system_charset_info->scan(ptr, ptrend, MY_SEQ_SPACES);
}
end:
@@ -1366,7 +1392,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
strxnmov(ds_control->ds_proc_info, sizeof(ds_control->ds_proc_info)-1,
"debug sync point: ", action->sync_point.c_ptr(), NullS);
old_proc_info= thd->proc_info;
- thd_proc_info(thd, ds_control->ds_proc_info);
+ debug_sync_thd_proc_info(thd, ds_control->ds_proc_info);
}
/*
@@ -1451,12 +1477,10 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
if (unlikely(error == ETIMEDOUT || error == ETIME))
{
// We should not make the statement fail, even if in strict mode.
- const bool save_abort_on_warning= thd->abort_on_warning;
- thd->abort_on_warning= false;
+ Abort_on_warning_instant_set aws(thd, false);
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
ER_DEBUG_SYNC_TIMEOUT,
ER_THD(thd, ER_DEBUG_SYNC_TIMEOUT));
- thd->abort_on_warning= save_abort_on_warning;
DBUG_EXECUTE_IF("debug_sync_abort_on_timeout", DBUG_ASSERT(0););
break;
}
@@ -1486,11 +1510,11 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
mysql_mutex_lock(&thd->mysys_var->mutex);
thd->mysys_var->current_mutex= old_mutex;
thd->mysys_var->current_cond= old_cond;
- thd_proc_info(thd, old_proc_info);
+ debug_sync_thd_proc_info(thd, old_proc_info);
mysql_mutex_unlock(&thd->mysys_var->mutex);
}
else
- thd_proc_info(thd, old_proc_info);
+ debug_sync_thd_proc_info(thd, old_proc_info);
}
else
{
diff --git a/sql/debug_sync.h b/sql/debug_sync.h
index 7a63a52959c..d92dc48cb0a 100644
--- a/sql/debug_sync.h
+++ b/sql/debug_sync.h
@@ -41,10 +41,14 @@ extern int debug_sync_init(void);
extern void debug_sync_end(void);
extern void debug_sync_init_thread(THD *thd);
extern void debug_sync_end_thread(THD *thd);
+void debug_sync_reset_thread(THD *thd);
extern bool debug_sync_set_action(THD *thd, const char *action_str, size_t len);
extern bool debug_sync_update(THD *thd, char *val_str, size_t len);
extern uchar *debug_sync_value_ptr(THD *thd);
-
+#else
+static inline void debug_sync_init_thread(THD *thd) {}
+static inline void debug_sync_end_thread(THD *thd) {}
+static inline void debug_sync_reset_thread(THD *thd) {}
#endif /* defined(ENABLED_DEBUG_SYNC) */
#endif /* DEBUG_SYNC_INCLUDED */
diff --git a/sql/derror.cc b/sql/derror.cc
index 7a79833c26c..1c10bdfdd92 100644
--- a/sql/derror.cc
+++ b/sql/derror.cc
@@ -120,8 +120,9 @@ bool init_errmessage(void)
all_errors+= errors_per_range[i];
if (!(original_error_messages= (const char***)
- my_malloc((all_errors + MAX_ERROR_RANGES)* sizeof(void*),
- MYF(MY_ZEROFILL))))
+ my_malloc(PSI_NOT_INSTRUMENTED,
+ (all_errors + MAX_ERROR_RANGES)*sizeof(void*),
+ MYF(MY_ZEROFILL))))
DBUG_RETURN(TRUE);
errmsgs= (const char**)(original_error_messages + MAX_ERROR_RANGES);
@@ -315,7 +316,8 @@ bool read_texts(const char *file_name, const char *language,
DBUG_RETURN(1);
if (!(*data= (const char***)
- my_malloc((size_t) ((MAX_ERROR_RANGES+1) * sizeof(char**) +
+ my_malloc(key_memory_errmsgs,
+ (size_t) ((MAX_ERROR_RANGES+1) * sizeof(char**) +
MY_MAX(msg_file.text_length, msg_file.errors * 2)+
msg_file.errors * sizeof(char*)),
MYF(MY_WME))))
diff --git a/sql/discover.cc b/sql/discover.cc
index 3df777c19ba..e49a2a3b0c0 100644
--- a/sql/discover.cc
+++ b/sql/discover.cc
@@ -1,4 +1,5 @@
/* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2009, 2020, 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
@@ -75,7 +76,8 @@ int readfrm(const char *name, const uchar **frmdata, size_t *len)
// Read whole frm file
error= 3;
- if (!(read_data= (uchar*)my_malloc(read_len, MYF(MY_WME))))
+ if (!(read_data= (uchar*)my_malloc(key_memory_frm_string, read_len,
+ MYF(MY_WME))))
goto err;
if (mysql_file_read(file, read_data, read_len, MYF(MY_NABP)))
{
@@ -206,12 +208,12 @@ int extension_based_table_discovery(MY_DIR *dirp, const char *ext_meta,
size_t len= (octothorp ? octothorp : ext) - cur->name;
if (from != cur &&
(strlen(from->name) <= len ||
- my_strnncoll(cs, (uchar*)from->name, len, (uchar*)cur->name, len) ||
+ cs->strnncoll(from->name, len, cur->name, len) ||
(from->name[len] != FN_EXTCHAR && from->name[len] != '#')))
advance(from, to, cur, skip);
- if (my_strnncoll(cs, (uchar*)ext, strlen(ext),
- (uchar*)ext_meta, ext_meta_len) == 0)
+ if (cs->strnncoll(ext, strlen(ext),
+ ext_meta, ext_meta_len) == 0)
{
*ext = 0;
if (result->add_file(cur->name))
@@ -255,8 +257,8 @@ int ext_table_discovery_simple(MY_DIR *dirp,
if (ext)
{
- if (my_strnncoll(cs, (uchar*)ext, strlen(ext),
- (uchar*)reg_ext, reg_ext_length) == 0)
+ if (cs->strnncoll(ext, strlen(ext),
+ reg_ext, reg_ext_length) == 0)
{
*ext = 0;
if (result->add_file(cur->name))
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index d9ed0b633e4..bd457fba4fa 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -25,13 +25,13 @@
// date_add_interval,
// calc_time_diff
#include "tztime.h" // my_tz_find, my_tz_OFFSET0, struct Time_zone
-#include "sql_acl.h" // EVENT_ACL, SUPER_ACL
#include "sp.h" // load_charset, load_collation
#include "events.h"
#include "event_data_objects.h"
#include "event_db_repository.h"
#include "sp_head.h"
#include "sql_show.h" // append_definer, append_identifier
+#include "mysql/psi/mysql_sp.h"
#ifdef WITH_WSREP
#include "wsrep_trans_observer.h"
#endif /* WITH_WSREP */
@@ -40,6 +40,18 @@
@{
*/
+#ifdef HAVE_PSI_INTERFACE
+void init_scheduler_psi_keys()
+{
+ const char *category= "scheduler";
+
+ PSI_server->register_statement(category, & Event_queue_element_for_exec::psi_info, 1);
+}
+
+PSI_statement_info Event_queue_element_for_exec::psi_info=
+{ 0, "event", 0};
+#endif
+
/*************************************************************************/
/**
@@ -173,11 +185,13 @@ Event_creation_ctx::load_from_db(THD *thd,
*/
bool
-Event_queue_element_for_exec::init(const LEX_CSTRING *db, const LEX_CSTRING *n)
+Event_queue_element_for_exec::init(const LEX_CSTRING &db, const LEX_CSTRING &n)
{
- if (!(dbname.str= my_strndup(db->str, dbname.length= db->length, MYF(MY_WME))))
+ if (!(dbname.str= my_strndup(key_memory_Event_queue_element_for_exec_names,
+ db.str, dbname.length= db.length, MYF(MY_WME))))
return TRUE;
- if (!(name.str= my_strndup(n->str, name.length= n->length, MYF(MY_WME))))
+ if (!(name.str= my_strndup(key_memory_Event_queue_element_for_exec_names,
+ n.str, name.length= n.length, MYF(MY_WME))))
{
my_free(const_cast<char*>(dbname.str));
return TRUE;
@@ -211,7 +225,7 @@ Event_basic::Event_basic()
{
DBUG_ENTER("Event_basic::Event_basic");
/* init memory root */
- init_sql_alloc(&mem_root, "Event_basic", 256, 512, MYF(0));
+ init_sql_alloc(key_memory_event_basic_root, &mem_root, 256, 512, MYF(0));
dbname.str= name.str= NULL;
dbname.length= name.length= 0;
time_zone= NULL;
@@ -1425,15 +1439,23 @@ Event_job_data::execute(THD *thd, bool drop)
{
Parser_state parser_state;
+ sql_digest_state *parent_digest= thd->m_digest;
+ PSI_statement_locker *parent_locker= thd->m_statement_psi;
+ bool res;
+
if (parser_state.init(thd, thd->query(), thd->query_length()))
goto end;
- if (parse_sql(thd, & parser_state, creation_ctx))
+ thd->m_digest= NULL;
+ thd->m_statement_psi= NULL;
+ res= parse_sql(thd, & parser_state, creation_ctx);
+ thd->m_digest= parent_digest;
+ thd->m_statement_psi= parent_locker;
+
+ if (res)
{
- sql_print_error("Event Scheduler: "
- "%serror during compilation of %s.%s",
- thd->is_fatal_error ? "fatal " : "",
- (const char *) dbname.str, (const char *) name.str);
+ sql_print_error("Event Scheduler: %serror during compilation of %s.%s",
+ thd->is_fatal_error ? "fatal " : "", dbname.str, name.str);
goto end;
}
}
@@ -1456,6 +1478,9 @@ Event_job_data::execute(THD *thd, bool drop)
sphead->set_creation_ctx(creation_ctx);
sphead->optimize();
+ sphead->m_sp_share= MYSQL_GET_SP_SHARE(SP_TYPE_EVENT,
+ dbname.str, static_cast<uint>(dbname.length),
+ name.str, static_cast<uint>(name.length));
ret= sphead->execute_procedure(thd, &empty_item_list);
/*
There is no pre-locking and therefore there should be no
@@ -1480,8 +1505,6 @@ end:
ret= 1;
else
{
- ulong saved_master_access;
-
thd->set_query(sp_sql.c_ptr_safe(), sp_sql.length());
/*
@@ -1493,8 +1516,8 @@ end:
Temporarily reset it to read-write.
*/
- saved_master_access= thd->security_ctx->master_access;
- thd->security_ctx->master_access |= SUPER_ACL;
+ privilege_t saved_master_access(thd->security_ctx->master_access);
+ thd->security_ctx->master_access |= PRIV_IGNORE_READ_ONLY;
bool save_tx_read_only= thd->tx_read_only;
thd->tx_read_only= false;
diff --git a/sql/event_data_objects.h b/sql/event_data_objects.h
index e5e3e4eb087..c20a8c31425 100644
--- a/sql/event_data_objects.h
+++ b/sql/event_data_objects.h
@@ -30,6 +30,8 @@ class THD;
class Time_zone;
struct TABLE;
+void init_scheduler_psi_keys(void);
+
class Event_queue_element_for_exec
{
public:
@@ -37,7 +39,7 @@ public:
~Event_queue_element_for_exec();
bool
- init(const LEX_CSTRING *dbname, const LEX_CSTRING *name);
+ init(const LEX_CSTRING &dbname, const LEX_CSTRING &name);
LEX_CSTRING dbname;
LEX_CSTRING name;
@@ -48,6 +50,15 @@ private:
/* Prevent use of these */
Event_queue_element_for_exec(const Event_queue_element_for_exec &);
void operator=(Event_queue_element_for_exec &);
+#ifdef HAVE_PSI_INTERFACE
+public:
+ PSI_statement_info* get_psi_info()
+ {
+ return & psi_info;
+ }
+
+ static PSI_statement_info psi_info;
+#endif
};
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc
index dc47ed0b2e1..af43d92dea7 100644
--- a/sql/event_db_repository.cc
+++ b/sql/event_db_repository.cc
@@ -24,7 +24,6 @@
#include "sql_db.h" // get_default_db_collation
#include "sql_time.h" // interval_type_to_name
#include "tztime.h" // struct Time_zone
-#include "sql_acl.h" // SUPER_ACL, MYSQL_DB_FIELD_COUNT, mysql_db_table_fields
#include "records.h" // init_read_record, end_read_record
#include "sp_head.h"
#include "event_data_objects.h"
@@ -1061,7 +1060,6 @@ Event_db_repository::load_named_event(THD *thd, const LEX_CSTRING *dbname,
Event_basic *etn)
{
bool ret;
- ulonglong saved_mode= thd->variables.sql_mode;
Open_tables_backup open_tables_backup;
TABLE_LIST event_table;
@@ -1072,7 +1070,7 @@ Event_db_repository::load_named_event(THD *thd, const LEX_CSTRING *dbname,
event_table.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_EVENT_NAME, 0, TL_READ);
/* Reset sql_mode during data dictionary operations. */
- thd->variables.sql_mode= 0;
+ Sql_mode_instant_set sms(thd, 0);
/*
We don't use open_event_table() here to make sure that SHOW
@@ -1097,7 +1095,6 @@ Event_db_repository::load_named_event(THD *thd, const LEX_CSTRING *dbname,
close_system_tables(thd, &open_tables_backup);
}
- thd->variables.sql_mode= saved_mode;
DBUG_RETURN(ret);
}
@@ -1130,7 +1127,7 @@ update_timing_fields_for_event(THD *thd,
*/
save_binlog_format= thd->set_current_stmt_binlog_format_stmt();
- DBUG_ASSERT(thd->security_ctx->master_access & SUPER_ACL);
+ DBUG_ASSERT(thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY);
if (open_event_table(thd, TL_WRITE, &table))
goto end;
diff --git a/sql/event_queue.cc b/sql/event_queue.cc
index 6b3f5777df3..71d1d2c68ee 100644
--- a/sql/event_queue.cc
+++ b/sql/event_queue.cc
@@ -24,6 +24,7 @@
#include "tztime.h" // my_tz_find, my_tz_OFFSET0, struct Time_zone
#include "log.h" // sql_print_error
#include "sql_class.h" // struct THD
+#include "mysql/psi/mysql_sp.h"
/**
@addtogroup Event_Scheduler
@@ -351,6 +352,9 @@ Event_queue::drop_matching_events(THD *thd, const LEX_CSTRING *pattern,
is ok.
*/
queue_remove(&queue, i);
+ /* Drop statistics for this stored program from performance schema. */
+ MYSQL_DROP_SP(SP_TYPE_EVENT, et->dbname.str, static_cast<uint>(et->dbname.length),
+ et->name.str, static_cast<uint>(et->name.length));
delete et;
}
else
@@ -637,7 +641,7 @@ Event_queue::get_top_for_execution_if_time(THD *thd,
}
if (!(*event_name= new Event_queue_element_for_exec()) ||
- (*event_name)->init(&top->dbname, &top->name))
+ (*event_name)->init(top->dbname, top->name))
{
ret= TRUE;
break;
diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc
index 8d90e8aed70..0e8e4826939 100644
--- a/sql/event_scheduler.cc
+++ b/sql/event_scheduler.cc
@@ -22,7 +22,7 @@
#include "event_queue.h"
#include "event_db_repository.h"
#include "sql_connect.h" // init_new_connection_handler_thread
-#include "sql_acl.h" // SUPER_ACL
+#include "sql_class.h"
/**
@addtogroup Event_Scheduler
@@ -177,8 +177,8 @@ pre_init_event_thread(THD* thd)
set_current_thd(thd);
thd->client_capabilities= 0;
- thd->security_ctx->master_access= 0;
- thd->security_ctx->db_access= 0;
+ thd->security_ctx->master_access= NO_ACL;
+ thd->security_ctx->db_access= NO_ACL;
thd->security_ctx->host_or_ip= (char*)my_localhost;
my_net_init(&thd->net, NULL, thd, MYF(MY_THREAD_SPECIFIC));
thd->security_ctx->set_user((char*)"event_scheduler");
@@ -291,6 +291,15 @@ Event_worker_thread::run(THD *thd, Event_queue_element_for_exec *event)
DBUG_ASSERT(thd->m_digest == NULL);
DBUG_ASSERT(thd->m_statement_psi == NULL);
+#ifdef HAVE_PSI_STATEMENT_INTERFACE
+ PSI_statement_locker_state state;
+ thd->m_statement_psi= MYSQL_START_STATEMENT(& state,
+ event->get_psi_info()->m_key,
+ event->dbname.str,
+ event->dbname.length,
+ thd->charset(), NULL);
+#endif
+
thd->thread_stack= &my_stack; // remember where our stack is
res= post_init_event_thread(thd);
@@ -319,7 +328,10 @@ Event_worker_thread::run(THD *thd, Event_queue_element_for_exec *event)
job_data.definer.str,
job_data.dbname.str, job_data.name.str);
end:
- DBUG_ASSERT(thd->m_statement_psi == NULL);
+#ifdef HAVE_PSI_STATEMENT_INTERFACE
+ MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
+ thd->m_statement_psi= NULL;
+#endif
DBUG_ASSERT(thd->m_digest == NULL);
DBUG_PRINT("info", ("Done with Event %s.%s", event->dbname.str,
event->name.str));
@@ -405,13 +417,14 @@ Event_scheduler::start(int *err_no)
Same goes for transaction access mode. Set it to read-write for this thd.
*/
- new_thd->security_ctx->master_access |= SUPER_ACL;
+ new_thd->security_ctx->master_access |= PRIV_IGNORE_READ_ONLY;
new_thd->variables.tx_read_only= false;
new_thd->tx_read_only= false;
/* This should not be marked with MY_THREAD_SPECIFIC */
scheduler_param_value=
- (struct scheduler_param *)my_malloc(sizeof(struct scheduler_param), MYF(0));
+ (struct scheduler_param *)my_malloc(key_memory_Event_scheduler_scheduler_param,
+ sizeof(struct scheduler_param), MYF(0));
scheduler_param_value->thd= new_thd;
scheduler_param_value->scheduler= this;
diff --git a/sql/events.cc b/sql/events.cc
index 3e731cc23c4..91adc0c23ba 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2005, 2013, Oracle and/or its affiliates.
- Copyright (c) 2017, MariaDB Corporation.
+ Copyright (c) 2017, 2020, 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
@@ -34,6 +34,7 @@
#include "sp_head.h" // for Stored_program_creation_ctx
#include "set_var.h"
#include "lock.h" // lock_object_name
+#include "mysql/psi/mysql_sp.h"
/**
@addtogroup Event_Scheduler
@@ -103,8 +104,8 @@ ulong Events::inited;
int sortcmp_lex_string(const LEX_CSTRING *s, const LEX_CSTRING *t,
const CHARSET_INFO *cs)
{
- return cs->coll->strnncollsp(cs, (uchar *) s->str, s->length,
- (uchar *) t->str, t->length);
+ return cs->strnncollsp(s->str, s->length,
+ t->str, t->length);
}
@@ -620,6 +621,9 @@ Events::drop_event(THD *thd, const LEX_CSTRING *dbname,
/* Binlog the drop event. */
DBUG_ASSERT(thd->query() && thd->query_length());
ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ /* Drop statistics for this stored program from performance schema. */
+ MYSQL_DROP_SP(SP_TYPE_EVENT,
+ dbname->str, static_cast<uint>(dbname->length), name->str, static_cast<uint>(name->length));
}
thd->restore_stmt_binlog_format(save_binlog_format);
@@ -832,13 +836,12 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
*/
if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS)
{
- DBUG_ASSERT(thd->lex->first_select_lex()->db.str);
- if (!is_infoschema_db(&thd->lex->first_select_lex()->db) && // There is no events in I_S
- check_access(thd, EVENT_ACL, thd->lex->first_select_lex()->db.str,
- NULL, NULL, 0, 0))
+ LEX_CSTRING *lexdb= &thd->lex->first_select_lex()->db;
+ DBUG_ASSERT(lexdb);
+ if (!is_infoschema_db(lexdb) && !is_perfschema_db(lexdb) &&
+ check_access(thd, EVENT_ACL, lexdb->str, NULL, NULL, 0, 0))
DBUG_RETURN(1);
- db= normalize_db_name(thd->lex->first_select_lex()->db.str,
- db_tmp, sizeof(db_tmp));
+ db= normalize_db_name(lexdb->str, db_tmp, sizeof(db_tmp));
}
ret= db_repository->fill_schema_events(thd, tables, db);
@@ -1028,6 +1031,8 @@ PSI_stage_info stage_waiting_on_empty_queue= { 0, "Waiting on empty queue", 0};
PSI_stage_info stage_waiting_for_next_activation= { 0, "Waiting for next activation", 0};
PSI_stage_info stage_waiting_for_scheduler_to_stop= { 0, "Waiting for the scheduler to stop", 0};
+PSI_memory_key key_memory_event_basic_root;
+
#ifdef HAVE_PSI_INTERFACE
PSI_stage_info *all_events_stages[]=
{
@@ -1036,6 +1041,11 @@ PSI_stage_info *all_events_stages[]=
& stage_waiting_for_scheduler_to_stop
};
+static PSI_memory_info all_events_memory[]=
+{
+ { &key_memory_event_basic_root, "Event_basic::mem_root", PSI_FLAG_GLOBAL}
+};
+
static void init_events_psi_keys(void)
{
const char* category= "sql";
@@ -1053,6 +1063,10 @@ static void init_events_psi_keys(void)
count= array_elements(all_events_stages);
mysql_stage_register(category, all_events_stages, count);
+ count= array_elements(all_events_memory);
+ mysql_memory_register(category, all_events_memory, count);
+
+ init_scheduler_psi_keys();
}
#endif /* HAVE_PSI_INTERFACE */
@@ -1145,7 +1159,6 @@ Events::load_events_from_db(THD *thd)
READ_RECORD read_record_info;
bool ret= TRUE;
uint count= 0;
- ulong saved_master_access;
DBUG_ENTER("Events::load_events_from_db");
DBUG_PRINT("enter", ("thd: %p", thd));
@@ -1158,8 +1171,8 @@ Events::load_events_from_db(THD *thd)
Temporarily reset it to read-write.
*/
- saved_master_access= thd->security_ctx->master_access;
- thd->security_ctx->master_access |= SUPER_ACL;
+ privilege_t saved_master_access(thd->security_ctx->master_access);
+ thd->security_ctx->master_access |= PRIV_IGNORE_READ_ONLY;
bool save_tx_read_only= thd->tx_read_only;
thd->tx_read_only= false;
diff --git a/sql/events.h b/sql/events.h
index 9e1651c767a..2fb13d7c807 100644
--- a/sql/events.h
+++ b/sql/events.h
@@ -31,6 +31,8 @@ extern PSI_cond_key key_event_scheduler_COND_state;
extern PSI_thread_key key_thread_event_scheduler, key_thread_event_worker;
#endif /* HAVE_PSI_INTERFACE */
+extern PSI_memory_key key_memory_event_basic_root;
+
/* Always defined, for SHOW PROCESSLIST. */
extern PSI_stage_info stage_waiting_on_empty_queue;
extern PSI_stage_info stage_waiting_for_next_activation;
diff --git a/sql/field.cc b/sql/field.cc
index ace70c178bc..460c26fbfd2 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -58,7 +58,7 @@ const char field_separator=',';
((ulong) ((1LL << MY_MIN(arg, 4) * 8) - 1))
// Column marked for read or the field set to read out or record[0] or [1]
-inline bool Field::marked_for_read() const
+bool Field::marked_for_read() const
{
return !table ||
(!table->read_set ||
@@ -73,7 +73,7 @@ inline bool Field::marked_for_read() const
changed fields with DBUG_FIX_WRITE_SET() in table.cc
*/
-inline bool Field::marked_for_write_or_computed() const
+bool Field::marked_for_write_or_computed() const
{
return (!table ||
(!table->write_set ||
@@ -984,7 +984,7 @@ static bool
test_if_important_data(CHARSET_INFO *cs, const char *str, const char *strend)
{
if (cs != &my_charset_bin)
- str+= cs->cset->scan(cs, str, strend, MY_SEQ_SPACES);
+ str+= cs->scan(str, strend, MY_SEQ_SPACES);
return (str < strend);
}
@@ -1013,8 +1013,15 @@ CPP_UNNAMED_NS_END
Static help functions
*****************************************************************************/
+/*
+ @brief
+ Create a fixed size sort key part
+
+ @param buff buffer where values are written
+ @param length fixed size of the sort column
+*/
-void Field::make_sort_key(uchar *buff,uint length)
+void Field::make_sort_key_part(uchar *buff,uint length)
{
if (maybe_null())
{
@@ -1029,6 +1036,62 @@ void Field::make_sort_key(uchar *buff,uint length)
}
+/*
+ @brief
+ Create a packed sort key part
+
+ @param buff buffer where values are written
+ @param sort_field sort column structure
+
+ @retval
+ length of the bytes written, does not include the NULL bytes
+*/
+uint
+Field::make_packed_sort_key_part(uchar *buff,
+ const SORT_FIELD_ATTR *sort_field)
+{
+ if (maybe_null())
+ {
+ if (is_null())
+ {
+ *buff++= 0;
+ return 0; // For NULL values don't write any data
+ }
+ *buff++=1;
+ }
+ sort_string(buff, sort_field->original_length);
+ return sort_field->original_length;
+}
+
+
+uint
+Field_longstr::make_packed_sort_key_part(uchar *buff,
+ const SORT_FIELD_ATTR *sort_field)
+{
+ if (maybe_null())
+ {
+ if (is_null())
+ {
+ *buff++= 0;
+ return 0; // For NULL values don't write any data
+ }
+ *buff++=1;
+ }
+ uchar *end= pack_sort_string(buff, sort_field);
+ return static_cast<int>(end-buff);
+}
+
+
+uchar*
+Field_longstr::pack_sort_string(uchar *to, const SORT_FIELD_ATTR *sort_field)
+{
+ String buf;
+ val_str(&buf, &buf);
+ return to + sort_field->pack_sort_string(to, buf.lex_cstring(),
+ field_charset());
+}
+
+
/**
@brief
Determine the relative position of the field value in a numeric interval
@@ -1120,15 +1183,15 @@ double Field::pos_in_interval_val_str(Field *min, Field *max, uint data_offset)
uchar minp_prefix[sizeof(ulonglong)];
uchar maxp_prefix[sizeof(ulonglong)];
ulonglong mp, minp, maxp;
- my_strnxfrm(charset(), mp_prefix, sizeof(mp),
- ptr + data_offset,
- data_length());
- my_strnxfrm(charset(), minp_prefix, sizeof(minp),
- min->ptr + data_offset,
- min->data_length());
- my_strnxfrm(charset(), maxp_prefix, sizeof(maxp),
- max->ptr + data_offset,
- max->data_length());
+ charset()->strnxfrm(mp_prefix, sizeof(mp),
+ ptr + data_offset,
+ data_length());
+ charset()->strnxfrm(minp_prefix, sizeof(minp),
+ min->ptr + data_offset,
+ min->data_length());
+ charset()->strnxfrm(maxp_prefix, sizeof(maxp),
+ max->ptr + data_offset,
+ max->data_length());
mp= char_prefix_to_ulonglong(mp_prefix);
minp= char_prefix_to_ulonglong(minp_prefix);
maxp= char_prefix_to_ulonglong(maxp_prefix);
@@ -1582,7 +1645,7 @@ Value_source::Converter_string_to_number::check_edom_and_truncation(THD *thd,
@note
This is called after one has called one of the following functions:
- strntoull10rnd()
- - my_strntod()
+ - strntod()
- str2my_decimal()
@retval
@@ -1662,9 +1725,9 @@ bool Field_num::get_int(CHARSET_INFO *cs, const char *from, size_t len,
char *end;
int error;
- *rnd= (longlong) cs->cset->strntoull10rnd(cs, from, len,
- unsigned_flag, &end,
- &error);
+ *rnd= (longlong) cs->strntoull10rnd(from, len,
+ unsigned_flag, &end,
+ &error);
if (unsigned_flag)
{
@@ -1703,7 +1766,7 @@ double Field_real::get_double(const char *str, size_t length, CHARSET_INFO *cs,
int *error)
{
char *end;
- double nr= my_strntod(cs,(char*) str, length, &end, error);
+ double nr= cs->strntod((char*) str, length, &end, error);
if (unlikely(*error))
{
set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
@@ -1760,10 +1823,10 @@ String *Field::val_int_as_str(String *val_buffer, bool unsigned_val)
if (val_buffer->alloc(MY_INT64_NUM_DECIMAL_DIGITS))
return 0;
- length= (uint) (*cs->cset->longlong10_to_str)(cs, (char*) val_buffer->ptr(),
- MY_INT64_NUM_DECIMAL_DIGITS,
- unsigned_val ? 10 : -10,
- value);
+ length= (uint) (cs->longlong10_to_str)((char*) val_buffer->ptr(),
+ MY_INT64_NUM_DECIMAL_DIGITS,
+ unsigned_val ? 10 : -10,
+ value);
val_buffer->length(length);
return val_buffer;
}
@@ -1801,8 +1864,7 @@ void Field::hash(ulong *nr, ulong *nr2)
else
{
uint len= pack_length();
- CHARSET_INFO *cs= sort_charset();
- cs->coll->hash_sort(cs, ptr, len, nr, nr2);
+ sort_charset()->hash_sort(ptr, len, nr, nr2);
}
}
@@ -1871,9 +1933,9 @@ bool Field::send_binary(Protocol *protocol)
master's field size, @c false otherwise.
*/
bool Field::compatible_field_size(uint field_metadata,
- Relay_log_info *rli_arg __attribute__((unused)),
+ const Relay_log_info *rli_arg __attribute__((unused)),
uint16 mflags __attribute__((unused)),
- int *order_var)
+ int *order_var) const
{
uint const source_size= pack_length_from_metadata(field_metadata);
uint const destination_size= row_pack_length();
@@ -1887,13 +1949,16 @@ bool Field::compatible_field_size(uint field_metadata,
int Field::store(const char *to, size_t length, CHARSET_INFO *cs,
enum_check_fields check_level)
{
- int res;
- THD *thd= get_thd();
- enum_check_fields old_check_level= thd->count_cuted_fields;
- thd->count_cuted_fields= check_level;
- res= store(to, length, cs);
- thd->count_cuted_fields= old_check_level;
- return res;
+ Check_level_instant_set tmp_level(get_thd(), check_level);
+ return store(to, length, cs);
+}
+
+
+int Field::store_text(const char *to, size_t length, CHARSET_INFO *cs,
+ enum_check_fields check_level)
+{
+ Check_level_instant_set tmp_level(get_thd(), check_level);
+ return store_text(to, length, cs);
}
@@ -2012,24 +2077,24 @@ void Field::make_send_field(Send_field *field)
{
if (orig_table && orig_table->s->db.str && *orig_table->s->db.str)
{
- field->db_name= orig_table->s->db.str;
+ field->db_name= orig_table->s->db;
if (orig_table->pos_in_table_list &&
orig_table->pos_in_table_list->schema_table)
- field->org_table_name= (orig_table->pos_in_table_list->
- schema_table->table_name);
+ field->org_table_name= Lex_cstring_strlen(orig_table->pos_in_table_list->
+ schema_table->table_name);
else
- field->org_table_name= orig_table->s->table_name.str;
+ field->org_table_name= orig_table->s->table_name;
}
else
- field->org_table_name= field->db_name= "";
+ field->org_table_name= field->db_name= empty_clex_str;
if (orig_table && orig_table->alias.ptr())
{
- field->table_name= orig_table->alias.ptr();
+ field->table_name= orig_table->alias.lex_cstring();
field->org_col_name= field_name;
}
else
{
- field->table_name= "";
+ field->table_name= empty_clex_str;
field->org_col_name= empty_clex_str;
}
field->col_name= field_name;
@@ -2188,11 +2253,9 @@ Field_str::Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
:Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg)
{
- field_charset= collation.collation;
+ m_collation= collation;
if (collation.collation->state & MY_CS_BINSORT)
flags|=BINARY_FLAG;
- field_derivation= collation.derivation;
- field_repertoire= collation.repertoire;
}
@@ -2206,7 +2269,7 @@ bool Field_str::test_if_equality_guarantees_uniqueness(const Item *item) const
SELECT * FROM t1 WHERE varchar_column=DATE'2001-01-01'
return non-unuque values, e.g. '2001-01-01' and '2001-01-01x'.
*/
- if (!field_charset->coll->propagate(field_charset, 0, 0) ||
+ if (!field_charset()->propagate(0, 0) ||
item->cmp_type() != STRING_RESULT)
return false;
/*
@@ -2217,8 +2280,8 @@ bool Field_str::test_if_equality_guarantees_uniqueness(const Item *item) const
WHERE latin1_bin_column = _latin1'A' COLLATE latin1_swedish_ci
return non-unique values 'a' and 'A'.
*/
- DTCollation tmp(field_charset, field_derivation, repertoire());
- return !tmp.aggregate(item->collation) && tmp.collation == field_charset;
+ DTCollation tmp(dtcollation());
+ return !tmp.aggregate(item->collation) && tmp.collation == field_charset();
}
@@ -2488,7 +2551,7 @@ bool Field_null::is_equal(const Column_definition &new_field) const
{
DBUG_ASSERT(!compression_method());
return new_field.type_handler() == type_handler() &&
- new_field.charset == field_charset &&
+ new_field.charset == field_charset() &&
new_field.length == max_display_length();
}
@@ -3034,8 +3097,7 @@ double Field_decimal::val_real(void)
DBUG_ASSERT(marked_for_read());
int not_used;
char *end_not_used;
- return my_strntod(&my_charset_bin, (char*) ptr, field_length, &end_not_used,
- &not_used);
+ return my_charset_bin.strntod((char*) ptr, field_length, &end_not_used, &not_used);
}
longlong Field_decimal::val_int(void)
@@ -3043,10 +3105,8 @@ longlong Field_decimal::val_int(void)
DBUG_ASSERT(marked_for_read());
int not_used;
if (unsigned_flag)
- return my_strntoull(&my_charset_bin, (char*) ptr, field_length, 10, NULL,
- &not_used);
- return my_strntoll(&my_charset_bin, (char*) ptr, field_length, 10, NULL,
- &not_used);
+ return my_charset_bin.strntoull((char*) ptr, field_length, 10, NULL, &not_used);
+ return my_charset_bin.strntoll((char*) ptr, field_length, 10, NULL, &not_used);
}
@@ -3072,7 +3132,7 @@ String *Field_decimal::val_str(String *val_buffer __attribute__((unused)),
5.00 , -1.0, 05, -05, +5 with optional pre/end space
*/
-int Field_decimal::cmp(const uchar *a_ptr,const uchar *b_ptr)
+int Field_decimal::cmp(const uchar *a_ptr,const uchar *b_ptr) const
{
const uchar *end;
int swap=0;
@@ -3451,7 +3511,7 @@ my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value)
}
-int Field_new_decimal::cmp(const uchar *a,const uchar*b)
+int Field_new_decimal::cmp(const uchar *a,const uchar*b) const
{
return memcmp(a, b, bin_size);
}
@@ -3484,11 +3544,12 @@ void Field_new_decimal::sql_type(String &str) const
@returns number of bytes written to metadata_ptr
*/
-int Field_new_decimal::save_field_metadata(uchar *metadata_ptr)
+
+Binlog_type_info Field_new_decimal::binlog_type_info() const
{
- *metadata_ptr= precision;
- *(metadata_ptr + 1)= decimals();
- return 2;
+ DBUG_ASSERT(Field_new_decimal::type() == binlog_type());
+ return Binlog_type_info(Field_new_decimal::type(), precision +
+ (decimals() << 8), 2, binlog_signedness());
}
@@ -3504,7 +3565,7 @@ int Field_new_decimal::save_field_metadata(uchar *metadata_ptr)
@returns The size of the field based on the field metadata.
*/
-uint Field_new_decimal::pack_length_from_metadata(uint field_metadata)
+uint Field_new_decimal::pack_length_from_metadata(uint field_metadata) const
{
uint const source_precision= (field_metadata >> 8U) & 0x00ff;
uint const source_decimal= field_metadata & 0x00ff;
@@ -3515,9 +3576,9 @@ uint Field_new_decimal::pack_length_from_metadata(uint field_metadata)
bool Field_new_decimal::compatible_field_size(uint field_metadata,
- Relay_log_info * __attribute__((unused)),
+ const Relay_log_info * __attribute__((unused)),
uint16 mflags __attribute__((unused)),
- int *order_var)
+ int *order_var) const
{
uint const source_precision= (field_metadata >> 8U) & 0x00ff;
uint const source_decimal= field_metadata & 0x00ff;
@@ -3638,6 +3699,17 @@ int Field_int::store_time_dec(const MYSQL_TIME *ltime, uint dec_arg)
}
+void Field_int::sql_type(String &res) const
+{
+ CHARSET_INFO *cs=res.charset();
+ Name name= type_handler()->type_handler_signed()->name();
+ res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "%.*s(%d)", (int) name.length(), name.ptr(),
+ (int) field_length));
+ add_zerofill_and_unsigned(res);
+}
+
+
/****************************************************************************
** tiny int
****************************************************************************/
@@ -3773,7 +3845,7 @@ bool Field_tiny::send_binary(Protocol *protocol)
return protocol->store_tiny((longlong) (int8) ptr[0]);
}
-int Field_tiny::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_tiny::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
signed char a,b;
a=(signed char) a_ptr[0]; b= (signed char) b_ptr[0];
@@ -3790,14 +3862,6 @@ void Field_tiny::sort_string(uchar *to,uint length __attribute__((unused)))
to[0] = (char) (ptr[0] ^ (uchar) 128); /* Revers signbit */
}
-void Field_tiny::sql_type(String &res) const
-{
- CHARSET_INFO *cs=res.charset();
- res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
- "tinyint(%d)",(int) field_length));
- add_zerofill_and_unsigned(res);
-}
-
/****************************************************************************
Field type short int (2 byte)
****************************************************************************/
@@ -3942,7 +4006,7 @@ bool Field_short::send_binary(Protocol *protocol)
}
-int Field_short::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_short::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
short a,b;
a=sint2korr(a_ptr);
@@ -3963,15 +4027,6 @@ void Field_short::sort_string(uchar *to,uint length __attribute__((unused)))
to[1] = ptr[0];
}
-void Field_short::sql_type(String &res) const
-{
- CHARSET_INFO *cs=res.charset();
- res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
- "smallint(%d)",(int) field_length));
- add_zerofill_and_unsigned(res);
-}
-
-
/****************************************************************************
Field type medium int (3 byte)
****************************************************************************/
@@ -4119,7 +4174,7 @@ String *Field_int::val_str_from_long(String *val_buffer,
uint mlength= MY_MAX(field_length + 1, max_char_length * cs->mbmaxlen);
val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
- length= (uint) cs->cset->long10_to_str(cs, to, mlength, radix, nr);
+ length= (uint) cs->long10_to_str(to, mlength, radix, nr);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer); /* purecov: inspected */
@@ -4135,7 +4190,7 @@ bool Field_medium::send_binary(Protocol *protocol)
}
-int Field_medium::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_medium::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
long a,b;
if (unsigned_flag)
@@ -4162,14 +4217,6 @@ void Field_medium::sort_string(uchar *to,uint length __attribute__((unused)))
}
-void Field_medium::sql_type(String &res) const
-{
- CHARSET_INFO *cs=res.charset();
- res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
- "mediumint(%d)",(int) field_length));
- add_zerofill_and_unsigned(res);
-}
-
/****************************************************************************
** long int
****************************************************************************/
@@ -4313,7 +4360,7 @@ bool Field_long::send_binary(Protocol *protocol)
return protocol->store_long(Field_long::val_int());
}
-int Field_long::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_long::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
int32 a,b;
a=sint4korr(a_ptr);
@@ -4335,14 +4382,6 @@ void Field_long::sort_string(uchar *to,uint length __attribute__((unused)))
}
-void Field_long::sql_type(String &res) const
-{
- CHARSET_INFO *cs=res.charset();
- res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
- "int(%d)",(int) field_length));
- add_zerofill_and_unsigned(res);
-}
-
/****************************************************************************
Field type longlong int (8 bytes)
****************************************************************************/
@@ -4354,7 +4393,7 @@ int Field_longlong::store(const char *from,size_t len,CHARSET_INFO *cs)
char *end;
ulonglong tmp;
- tmp= cs->cset->strntoull10rnd(cs,from,len,unsigned_flag,&end,&error);
+ tmp= cs->strntoull10rnd(from, len, unsigned_flag, &end, &error);
if (unlikely(error == MY_ERRNO_ERANGE))
{
set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
@@ -4442,8 +4481,8 @@ String *Field_longlong::val_str(String *val_buffer,
longlong j;
j=sint8korr(ptr);
- length=(uint) (cs->cset->longlong10_to_str)(cs,to,mlength,
- unsigned_flag ? 10 : -10, j);
+ length=(uint) (cs->longlong10_to_str)(to, mlength,
+ unsigned_flag ? 10 : -10, j);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
@@ -4459,7 +4498,7 @@ bool Field_longlong::send_binary(Protocol *protocol)
}
-int Field_longlong::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_longlong::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
longlong a,b;
a=sint8korr(a_ptr);
@@ -4486,14 +4525,6 @@ void Field_longlong::sort_string(uchar *to,uint length __attribute__((unused)))
}
-void Field_longlong::sql_type(String &res) const
-{
- CHARSET_INFO *cs=res.charset();
- res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
- "bigint(%d)",(int) field_length));
- add_zerofill_and_unsigned(res);
-}
-
void Field_longlong::set_max()
{
DBUG_ASSERT(marked_for_write_or_computed());
@@ -4594,7 +4625,7 @@ String *Field_float::val_str(String *val_buffer,
}
-int Field_float::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_float::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
float a,b;
float4get(a,a_ptr);
@@ -4656,26 +4687,11 @@ bool Field_float::send_binary(Protocol *protocol)
@returns number of bytes written to metadata_ptr
*/
-int Field_float::save_field_metadata(uchar *metadata_ptr)
+Binlog_type_info Field_float::binlog_type_info() const
{
- *metadata_ptr= pack_length();
- return 1;
-}
-
-
-void Field_float::sql_type(String &res) const
-{
- if (dec >= FLOATING_POINT_DECIMALS)
- {
- res.set_ascii(STRING_WITH_LEN("float"));
- }
- else
- {
- CHARSET_INFO *cs= res.charset();
- res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
- "float(%d,%d)",(int) field_length,dec));
- }
- add_zerofill_and_unsigned(res);
+ DBUG_ASSERT(Field_float::type() == binlog_type());
+ return Binlog_type_info(Field_float::type(), pack_length(), 1,
+ binlog_signedness());
}
@@ -4900,6 +4916,24 @@ Item *Field_real::get_equal_const_item(THD *thd, const Context &ctx,
}
+void Field_real::sql_type(String &res) const
+{
+ const Name name= type_handler()->name();
+ if (dec >= FLOATING_POINT_DECIMALS)
+ {
+ res.set_ascii(name.ptr(), name.length());
+ }
+ else
+ {
+ CHARSET_INFO *cs= res.charset();
+ res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "%.*s(%d,%d)", (int) name.length(), name.ptr(),
+ (int) field_length,dec));
+ }
+ add_zerofill_and_unsigned(res);
+}
+
+
String *Field_double::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
@@ -4936,7 +4970,7 @@ bool Field_double::send_binary(Protocol *protocol)
}
-int Field_double::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_double::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
double a,b;
float8get(a,a_ptr);
@@ -4967,26 +5001,11 @@ void Field_double::sort_string(uchar *to,uint length __attribute__((unused)))
@returns number of bytes written to metadata_ptr
*/
-int Field_double::save_field_metadata(uchar *metadata_ptr)
+Binlog_type_info Field_double::binlog_type_info() const
{
- *metadata_ptr= pack_length();
- return 1;
-}
-
-
-void Field_double::sql_type(String &res) const
-{
- CHARSET_INFO *cs=res.charset();
- if (dec >= FLOATING_POINT_DECIMALS)
- {
- res.set_ascii(STRING_WITH_LEN("double"));
- }
- else
- {
- res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
- "double(%d,%d)",(int) field_length,dec));
- }
- add_zerofill_and_unsigned(res);
+ DBUG_ASSERT(Field_double::type() == binlog_type());
+ return Binlog_type_info(Field_double::type(), pack_length(), 1,
+ binlog_signedness());
}
@@ -5066,8 +5085,8 @@ int Field_timestamp::save_in_field(Field *to)
return to->store_timestamp_dec(Timeval(ts, sec_part), decimals());
}
-my_time_t Field_timestamp::get_timestamp(const uchar *pos,
- ulong *sec_part) const
+my_time_t Field_timestamp0::get_timestamp(const uchar *pos,
+ ulong *sec_part) const
{
DBUG_ASSERT(marked_for_read());
*sec_part= 0;
@@ -5075,7 +5094,7 @@ my_time_t Field_timestamp::get_timestamp(const uchar *pos,
}
-bool Field_timestamp::val_native(Native *to)
+bool Field_timestamp0::val_native(Native *to)
{
DBUG_ASSERT(marked_for_read());
my_time_t sec= (my_time_t) sint4korr(ptr);
@@ -5240,12 +5259,6 @@ int Field_timestamp::store_native(const Native &value)
}
-double Field_timestamp::val_real(void)
-{
- return (double) Field_timestamp::val_int();
-}
-
-
longlong Field_timestamp::val_int(void)
{
MYSQL_TIME ltime;
@@ -5349,15 +5362,15 @@ bool Field_timestamp::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
}
-bool Field_timestamp::send_binary(Protocol *protocol)
+bool Field_timestamp0::send_binary(Protocol *protocol)
{
MYSQL_TIME ltime;
- Field_timestamp::get_date(&ltime, date_mode_t(0));
+ Field_timestamp0::get_date(&ltime, date_mode_t(0));
return protocol->store(&ltime, 0);
}
-int Field_timestamp::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_timestamp0::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
int32 a,b;
a=sint4korr(a_ptr);
@@ -5366,7 +5379,7 @@ int Field_timestamp::cmp(const uchar *a_ptr, const uchar *b_ptr)
}
-void Field_timestamp::sort_string(uchar *to,uint length __attribute__((unused)))
+void Field_timestamp0::sort_string(uchar *to,uint length __attribute__((unused)))
{
to[0] = ptr[3];
to[1] = ptr[2];
@@ -5375,20 +5388,7 @@ void Field_timestamp::sort_string(uchar *to,uint length __attribute__((unused)))
}
-void Field_timestamp::sql_type(String &res) const
-{
- if (!decimals())
- {
- res.set_ascii(STRING_WITH_LEN("timestamp"));
- return;
- }
- CHARSET_INFO *cs=res.charset();
- res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
- "timestamp(%u)", decimals()));
-}
-
-
-int Field_timestamp::set_time()
+int Field_timestamp0::set_time()
{
set_notnull();
store_TIMESTAMP(Timestamp(get_thd()->query_start(), 0));
@@ -5458,29 +5458,6 @@ static longlong read_native(const uchar *from, uint bytes)
}
#endif
-static void store_lowendian(ulonglong num, uchar *to, uint bytes)
-{
- switch(bytes) {
- case 1: *to= (uchar)num; break;
- case 2: int2store(to, num); break;
- case 3: int3store(to, num); break;
- case 4: int4store(to, num); break;
- case 8: int8store(to, num); break;
- default: DBUG_ASSERT(0);
- }
-}
-
-static longlong read_lowendian(const uchar *from, uint bytes)
-{
- switch(bytes) {
- case 1: return from[0];
- case 2: return uint2korr(from);
- case 3: return uint3korr(from);
- case 4: return uint4korr(from);
- case 8: return sint8korr(from);
- default: DBUG_ASSERT(0); return 0;
- }
-}
void Field_timestamp_hires::store_TIMEVAL(const timeval &tv)
{
@@ -5553,7 +5530,7 @@ bool Field_timestamp_with_dec::send_binary(Protocol *protocol)
}
-int Field_timestamp_hires::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_timestamp_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
int32 a,b;
ulong a_sec_part, b_sec_part;
@@ -5626,6 +5603,11 @@ bool Field_timestampf::val_native(Native *to)
return Field::val_native(to);
}
+Binlog_type_info Field_timestampf::binlog_type_info() const
+{
+ return Binlog_type_info(Field_timestampf::binlog_type(), decimals(), 1);
+}
+
/*************************************************************/
sql_mode_t Field_temporal::can_handle_sql_mode_dependency_on_store() const
@@ -5662,6 +5644,44 @@ void Field_temporal::set_warnings(Sql_condition::enum_warning_level trunc_level,
}
+void Field_temporal::sql_type_dec_comment(String &res,
+ const Name &name,
+ uint dec,
+ const Name &comment) const
+{
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
+ "%.*s(%u)%s%.*s%s",
+ (uint) name.length(), name.ptr(),
+ dec,
+ comment.length() ? " /* " : "",
+ (uint) comment.length(), comment.ptr(),
+ comment.length() ? " */" : ""));
+}
+
+
+void Field_temporal::sql_type_comment(String &res,
+ const Name &name,
+ const Name &comment) const
+{
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
+ "%.*s%s%.*s%s",
+ (uint) name.length(), name.ptr(),
+ comment.length() ? " /* " : "",
+ (uint) comment.length(), comment.ptr(),
+ comment.length() ? " */" : ""));
+}
+
+
+const Name & Field_temporal::type_version_mysql56()
+{
+ DBUG_EXECUTE_IF("sql_type", return Type_handler::version_mysql56(); );
+ static Name none(NULL, 0);
+ return none;
+}
+
+
/*
Store string into a date/time field
@@ -5843,7 +5863,7 @@ int Field_time::store_TIME_with_warning(const Time *t,
}
-void Field_time::store_TIME(const MYSQL_TIME *ltime)
+void Field_time0::store_TIME(const MYSQL_TIME *ltime)
{
DBUG_ASSERT(ltime->year == 0);
DBUG_ASSERT(ltime->month == 0);
@@ -5931,14 +5951,14 @@ Field *Field_time::new_key_field(MEM_ROOT *root, TABLE *new_table,
}
-double Field_time::val_real(void)
+double Field_time0::val_real(void)
{
DBUG_ASSERT(marked_for_read());
uint32 j= (uint32) uint3korr(ptr);
return (double) j;
}
-longlong Field_time::val_int(void)
+longlong Field_time0::val_int(void)
{
DBUG_ASSERT(marked_for_read());
return (longlong) sint3korr(ptr);
@@ -5987,7 +6007,7 @@ bool Field_time::check_zero_in_date_with_warn(date_mode_t fuzzydate)
DATE_FORMAT(time, "%l.%i %p")
*/
-bool Field_time::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
+bool Field_time0::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
if (check_zero_in_date_with_warn(fuzzydate))
return true;
@@ -6017,7 +6037,7 @@ bool Field_time::send_binary(Protocol *protocol)
}
-int Field_time::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_time0::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
int32 a,b;
a=(int32) sint3korr(a_ptr);
@@ -6025,24 +6045,13 @@ int Field_time::cmp(const uchar *a_ptr, const uchar *b_ptr)
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
-void Field_time::sort_string(uchar *to,uint length __attribute__((unused)))
+void Field_time0::sort_string(uchar *to,uint length __attribute__((unused)))
{
to[0] = (uchar) (ptr[2] ^ 128);
to[1] = ptr[1];
to[2] = ptr[0];
}
-void Field_time::sql_type(String &res) const
-{
- if (decimals() == 0)
- {
- res.set_ascii(STRING_WITH_LEN("time"));
- return;
- }
- CHARSET_INFO *cs= res.charset();
- res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
- "time(%d)", decimals()));
-}
int Field_time_hires::reset()
{
@@ -6205,7 +6214,7 @@ bool Field_time_hires::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
}
-int Field_time_hires::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_time_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
ulonglong a=read_bigendian(a_ptr, Field_time_hires::pack_length());
ulonglong b=read_bigendian(b_ptr, Field_time_hires::pack_length());
@@ -6251,6 +6260,10 @@ bool Field_timef::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
TIME_from_longlong_time_packed(ltime, tmp);
return false;
}
+Binlog_type_info Field_timef::binlog_type_info() const
+{
+ return Binlog_type_info(Field_timef::binlog_type(), decimals(), 1);
+}
/****************************************************************************
** year type
@@ -6263,7 +6276,7 @@ int Field_year::store(const char *from, size_t len,CHARSET_INFO *cs)
DBUG_ASSERT(marked_for_write_or_computed());
char *end;
int error;
- longlong nr= cs->cset->strntoull10rnd(cs, from, len, 0, &end, &error);
+ longlong nr= cs->strntoull10rnd(from, len, 0, &end, &error);
if (nr < 0 || (nr >= 100 && nr <= 1900) || nr > 2155 ||
error == MY_ERRNO_ERANGE)
@@ -6533,7 +6546,7 @@ String *Field_date::val_str(String *val_buffer,
}
-int Field_date::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_date::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
int32 a,b;
a=sint4korr(a_ptr);
@@ -6637,7 +6650,7 @@ bool Field_newdate::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
}
-int Field_newdate::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_newdate::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
uint32 a,b;
a=(uint32) uint3korr(a_ptr);
@@ -6726,7 +6739,7 @@ Item *Field_newdate::get_equal_const_item(THD *thd, const Context &ctx,
** Stored as a 8 byte unsigned int. Should sometimes be change to a 6 byte int.
****************************************************************************/
-void Field_datetime::store_TIME(const MYSQL_TIME *ltime)
+void Field_datetime0::store_TIME(const MYSQL_TIME *ltime)
{
ulonglong tmp= TIME_to_ulonglong_datetime(ltime);
int8store(ptr,tmp);
@@ -6741,20 +6754,15 @@ Field_datetime::conversion_depends_on_sql_mode(THD *thd, Item *expr) const
}
-bool Field_datetime::send_binary(Protocol *protocol)
+bool Field_datetime0::send_binary(Protocol *protocol)
{
MYSQL_TIME tm;
- Field_datetime::get_date(&tm, date_mode_t(0));
+ Field_datetime0::get_date(&tm, date_mode_t(0));
return protocol->store(&tm, 0);
}
-double Field_datetime::val_real(void)
-{
- return (double) Field_datetime::val_int();
-}
-
-longlong Field_datetime::val_int(void)
+longlong Field_datetime0::val_int(void)
{
DBUG_ASSERT(marked_for_read());
longlong j;
@@ -6763,8 +6771,8 @@ longlong Field_datetime::val_int(void)
}
-String *Field_datetime::val_str(String *val_buffer,
- String *val_ptr __attribute__((unused)))
+String *Field_datetime0::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
{
val_buffer->alloc(field_length);
val_buffer->length(field_length);
@@ -6775,7 +6783,7 @@ String *Field_datetime::val_str(String *val_buffer,
char *pos;
int part3;
- tmp= Field_datetime::val_int();
+ tmp= Field_datetime0::val_int();
/*
Avoid problem with slow longlong arithmetic and sprintf
@@ -6809,8 +6817,8 @@ String *Field_datetime::val_str(String *val_buffer,
return val_buffer;
}
-bool Field_datetime::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
- date_mode_t fuzzydate) const
+bool Field_datetime0::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
+ date_mode_t fuzzydate) const
{
DBUG_ASSERT(marked_for_read());
longlong tmp= sint8korr(pos);
@@ -6831,7 +6839,7 @@ bool Field_datetime::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
}
-int Field_datetime::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_datetime0::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
longlong a,b;
a=sint8korr(a_ptr);
@@ -6840,7 +6848,7 @@ int Field_datetime::cmp(const uchar *a_ptr, const uchar *b_ptr)
((ulonglong) a > (ulonglong) b) ? 1 : 0;
}
-void Field_datetime::sort_string(uchar *to,uint length __attribute__((unused)))
+void Field_datetime0::sort_string(uchar *to,uint length __attribute__((unused)))
{
to[0] = ptr[7];
to[1] = ptr[6];
@@ -6853,19 +6861,6 @@ void Field_datetime::sort_string(uchar *to,uint length __attribute__((unused)))
}
-void Field_datetime::sql_type(String &res) const
-{
- if (decimals() == 0)
- {
- res.set_ascii(STRING_WITH_LEN("datetime"));
- return;
- }
- CHARSET_INFO *cs= res.charset();
- res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
- "datetime(%u)", decimals()));
-}
-
-
int Field_datetime::set_time()
{
THD *thd= table->in_use;
@@ -6933,7 +6928,7 @@ bool Field_datetime_hires::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
}
-int Field_datetime_hires::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_datetime_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
ulonglong a=read_bigendian(a_ptr, Field_datetime_hires::pack_length());
ulonglong b=read_bigendian(b_ptr, Field_datetime_hires::pack_length());
@@ -6971,6 +6966,10 @@ bool Field_datetimef::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
TIME_from_longlong_datetime_packed(ltime, tmp);
return validate_MMDD(tmp, ltime->month, ltime->day, fuzzydate);
}
+Binlog_type_info Field_datetimef::binlog_type_info() const
+{
+ return Binlog_type_info(Field_datetimef::binlog_type(), decimals(), 1);
+}
/****************************************************************************
** string type
@@ -7052,7 +7051,7 @@ Field_longstr::report_if_important_data(const char *pstr, const char *end,
if ((pstr < end) &&
(thd= get_thd())->count_cuted_fields > CHECK_FIELD_EXPRESSION)
{
- if (test_if_important_data(field_charset, pstr, end))
+ if (test_if_important_data(field_charset(), pstr, end))
{
if (thd->abort_on_warning)
set_warning(ER_DATA_TOO_LONG, 1);
@@ -7071,6 +7070,27 @@ Field_longstr::report_if_important_data(const char *pstr, const char *end,
}
+/*
+ This is JSON specific.
+ We should eventually add Field_json_varchar and Field_json_blob
+ and move make_send_field() to the new classes.
+*/
+void Field_longstr::make_send_field(Send_field *field)
+{
+ Field_str::make_send_field(field);
+ if (check_constraint)
+ {
+ /*
+ Append the format that is implicitly implied by the CHECK CONSTRAINT.
+ For example:
+ CREATE TABLE t1 (js longtext DEFAULT NULL CHECK (json_valid(a)));
+ SELECT j FROM t1;
+ will add "format=json" to the extended type info metadata for t1.js.
+ */
+ check_constraint->expr->set_format_by_check_constraint(field);
+ }
+}
+
/* Copy a string and fill with space */
int Field_string::store(const char *from, size_t length,CHARSET_INFO *cs)
@@ -7084,14 +7104,14 @@ int Field_string::store(const char *from, size_t length,CHARSET_INFO *cs)
rc= well_formed_copy_with_check((char*) ptr, field_length,
cs, from, length,
- field_length / field_charset->mbmaxlen,
+ Field_string::char_length(),
false, &copy_length);
/* Append spaces if the string was shorter than the field. */
if (copy_length < field_length)
- field_charset->cset->fill(field_charset,(char*) ptr+copy_length,
- field_length-copy_length,
- field_charset->pad_char);
+ field_charset()->fill((char*) ptr + copy_length,
+ field_length - copy_length,
+ field_charset()->pad_char);
return rc;
}
@@ -7101,13 +7121,10 @@ int Field_str::store(longlong nr, bool unsigned_val)
{
char buff[64];
uint length;
- length= (uint) (field_charset->cset->longlong10_to_str)(field_charset,
- buff,
- sizeof(buff),
- (unsigned_val ? 10:
- -10),
- nr);
- return store(buff, length, field_charset);
+ length= (uint) (field_charset()->longlong10_to_str)(buff, sizeof(buff),
+ (unsigned_val ? 10: -10),
+ nr);
+ return store(buff, length, field_charset());
}
@@ -7123,8 +7140,7 @@ int Field_str::store(double nr)
{
DBUG_ASSERT(marked_for_write_or_computed());
char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
- uint local_char_length= MY_MIN(sizeof(buff),
- field_length / field_charset->mbmaxlen);
+ uint local_char_length= MY_MIN(sizeof(buff), Field_str::char_length());
size_t length= 0;
my_bool error= (local_char_length == 0);
@@ -7147,7 +7163,7 @@ bool Field_string::is_equal(const Column_definition &new_field) const
DBUG_ASSERT(!compression_method());
return new_field.type_handler() == type_handler() &&
new_field.char_length == char_length() &&
- new_field.charset == field_charset &&
+ new_field.charset == field_charset() &&
new_field.length == max_display_length();
}
@@ -7233,7 +7249,7 @@ Field_string::Warn_filter_string::Warn_filter_string(const THD *thd,
const Field_string *field)
:Warn_filter(!thd->no_errors,
!thd->no_errors &&
- field->Field_string::charset() == &my_charset_bin)
+ field->field_charset() == &my_charset_bin)
{ }
@@ -7281,12 +7297,11 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)),
size_t length;
if (get_thd()->variables.sql_mode &
MODE_PAD_CHAR_TO_FULL_LENGTH)
- length= my_charpos(field_charset, ptr, ptr + field_length,
- field_length / field_charset->mbmaxlen);
+ length= field_charset()->charpos(ptr, ptr + field_length,
+ Field_string::char_length());
else
- length= field_charset->cset->lengthsp(field_charset, (const char*) ptr,
- field_length);
- val_ptr->set((const char*) ptr, length, field_charset);
+ length= field_charset()->lengthsp((const char*) ptr, field_length);
+ val_ptr->set((const char*) ptr, length, field_charset());
return val_ptr;
}
@@ -7306,7 +7321,7 @@ my_decimal *Field_string::val_decimal(my_decimal *decimal_value)
struct Check_field_param {
- Field *field;
+ const Field *field;
};
#ifdef HAVE_REPLICATION
@@ -7325,9 +7340,9 @@ check_field_for_37426(const void *param_arg)
bool
Field_string::compatible_field_size(uint field_metadata,
- Relay_log_info *rli_arg,
+ const Relay_log_info *rli_arg,
uint16 mflags __attribute__((unused)),
- int *order_var)
+ int *order_var) const
{
#ifdef HAVE_REPLICATION
const Check_field_param check_param = { this };
@@ -7339,15 +7354,15 @@ Field_string::compatible_field_size(uint field_metadata,
}
-int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
size_t a_len, b_len;
- if (field_charset->mbmaxlen != 1)
+ if (mbmaxlen() != 1)
{
- size_t char_len= field_length/field_charset->mbmaxlen;
- a_len= my_charpos(field_charset, a_ptr, a_ptr + field_length, char_len);
- b_len= my_charpos(field_charset, b_ptr, b_ptr + field_length, char_len);
+ size_t char_len= Field_string::char_length();
+ a_len= field_charset()->charpos(a_ptr, a_ptr + field_length, char_len);
+ b_len= field_charset()->charpos(b_ptr, b_ptr + field_length, char_len);
}
else
a_len= b_len= field_length;
@@ -7355,9 +7370,8 @@ int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr)
We have to remove end space to be able to compare multi-byte-characters
like in latin_de 'ae' and 0xe4
*/
- return field_charset->coll->strnncollsp(field_charset,
- a_ptr, a_len,
- b_ptr, b_len);
+ return field_charset()->strnncollsp(a_ptr, a_len,
+ b_ptr, b_len);
}
@@ -7366,13 +7380,11 @@ void Field_string::sort_string(uchar *to,uint length)
#ifdef DBUG_ASSERT_EXISTS
size_t tmp=
#endif
- field_charset->coll->strnxfrm(field_charset,
- to, length,
- char_length() *
- field_charset->strxfrm_multiply,
- ptr, field_length,
- MY_STRXFRM_PAD_WITH_SPACE |
- MY_STRXFRM_PAD_TO_MAXLEN);
+ field_charset()->strnxfrm(to, length,
+ char_length() * field_charset()->strxfrm_multiply,
+ ptr, field_length,
+ MY_STRXFRM_PAD_WITH_SPACE |
+ MY_STRXFRM_PAD_TO_MAXLEN);
DBUG_ASSERT(tmp == length);
}
@@ -7421,38 +7433,8 @@ void Field_string::sql_rpl_type(String *res) const
uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length)
{
- size_t length= MY_MIN(field_length,max_length);
- size_t local_char_length= max_length/field_charset->mbmaxlen;
- DBUG_PRINT("debug", ("Packing field '%s' - length: %zu ", field_name.str,
- length));
-
- if (length > local_char_length)
- local_char_length= my_charpos(field_charset, from, from+length,
- local_char_length);
- set_if_smaller(length, local_char_length);
-
- /*
- TODO: change charset interface to add a new function that does
- the following or add a flag to lengthsp to do it itself
- (this is for not packing padding adding bytes in BINARY
- fields).
- */
- if (field_charset->mbmaxlen == 1)
- {
- while (length && from[length-1] == field_charset->pad_char)
- length --;
- }
- else
- length= field_charset->cset->lengthsp(field_charset, (const char*) from, length);
-
- // Length always stored little-endian
- *to++= (uchar) length;
- if (field_length > 255)
- *to++= (uchar) (length >> 8);
-
- // Store the actual bytes of the string
- memcpy(to, from, length);
- return to+length;
+ DBUG_PRINT("debug", ("Packing field '%s'", field_name.str));
+ return StringPack(field_charset(), field_length).pack(to, from, max_length);
}
@@ -7479,44 +7461,8 @@ const uchar *
Field_string::unpack(uchar *to, const uchar *from, const uchar *from_end,
uint param_data)
{
- uint from_length, length;
-
- /*
- Compute the declared length of the field on the master. This is
- used to decide if one or two bytes should be read as length.
- */
- if (param_data)
- from_length= (((param_data >> 4) & 0x300) ^ 0x300) + (param_data & 0x00ff);
- else
- from_length= field_length;
-
- DBUG_PRINT("debug",
- ("param_data: 0x%x, field_length: %u, from_length: %u",
- param_data, field_length, from_length));
- /*
- Compute the actual length of the data by reading one or two bits
- (depending on the declared field length on the master).
- */
- if (from_length > 255)
- {
- if (from + 2 > from_end)
- return 0;
- length= uint2korr(from);
- from+= 2;
- }
- else
- {
- if (from + 1 > from_end)
- return 0;
- length= (uint) *from++;
- }
- if (from + length > from_end || length > field_length)
- return 0;
-
- memcpy(to, from, length);
- // Pad the string with the pad character of the fields charset
- field_charset->cset->fill(field_charset, (char*) to + length, field_length - length, field_charset->pad_char);
- return from+length;
+ return StringPack(field_charset(), field_length).unpack(to, from, from_end,
+ param_data);
}
@@ -7550,41 +7496,50 @@ Field_string::unpack(uchar *to, const uchar *from, const uchar *from_end,
@returns number of bytes written to metadata_ptr
*/
-int Field_string::save_field_metadata(uchar *metadata_ptr)
+
+Binlog_type_info_fixed_string::Binlog_type_info_fixed_string(uchar type_code,
+ uint32 octets,
+ CHARSET_INFO *cs)
+ :Binlog_type_info(type_code, 0, 2, cs)
+{
+ DBUG_ASSERT(octets < 1024);
+ DBUG_ASSERT((type_code & 0xF0) == 0xF0);
+ DBUG_PRINT("debug", ("octets: %u, type_code: %u", octets, type_code));
+ m_metadata= (type_code ^ ((octets & 0x300) >> 4)) +
+ (((uint)(octets & 0xFF)) << 8);
+}
+
+
+Binlog_type_info Field_string::binlog_type_info() const
{
- DBUG_ASSERT(field_length < 1024);
- DBUG_ASSERT((real_type() & 0xF0) == 0xF0);
- DBUG_PRINT("debug", ("field_length: %u, real_type: %u",
- field_length, real_type()));
- *metadata_ptr= (real_type() ^ ((field_length & 0x300) >> 4));
- *(metadata_ptr + 1)= field_length & 0xFF;
- return 2;
+ DBUG_ASSERT(Field_string::type() == binlog_type());
+ return Binlog_type_info_fixed_string(Field_string::binlog_type(),
+ field_length, charset());
}
uint Field_string::packed_col_length(const uchar *data_ptr, uint length)
{
- if (length > 255)
- return uint2korr(data_ptr)+2;
- return (uint) *data_ptr + 1;
+ return StringPack::packed_col_length(data_ptr, length);
}
uint Field_string::max_packed_col_length(uint max_length)
{
- return (max_length > 255 ? 2 : 1)+max_length;
+ return StringPack::max_packed_col_length(max_length);
}
uint Field_string::get_key_image(uchar *buff, uint length, imagetype type_arg)
{
- size_t bytes = my_charpos(field_charset, (char*) ptr,
- (char*) ptr + field_length,
- length / field_charset->mbmaxlen);
+ size_t bytes= field_charset()->charpos((char*) ptr,
+ (char*) ptr + field_length,
+ length / mbmaxlen());
memcpy(buff, ptr, bytes);
if (bytes < length)
- field_charset->cset->fill(field_charset, (char*) buff + bytes,
- length - bytes, field_charset->pad_char);
+ field_charset()->fill((char*) buff + bytes,
+ length - bytes,
+ field_charset()->pad_char);
return (uint)bytes;
}
@@ -7610,6 +7565,12 @@ Field *Field_string::make_new_field(MEM_ROOT *root, TABLE *new_table,
}
+en_fieldtype Field_string::tmp_engine_column_type(bool use_packed_rows) const
+{
+ return field_length >= MIN_STRING_LENGTH_TO_PACK_ROWS ? FIELD_SKIP_ENDSPACE :
+ FIELD_NORMAL;
+}
+
/****************************************************************************
VARCHAR type
Data in field->ptr is stored as:
@@ -7639,13 +7600,23 @@ const uint Field_varstring::MAX_SIZE= UINT_MAX16;
@returns number of bytes written to metadata_ptr
*/
-int Field_varstring::save_field_metadata(uchar *metadata_ptr)
+Binlog_type_info Field_varstring::binlog_type_info() const
+{
+ DBUG_ASSERT(Field_varstring::type() == binlog_type());
+ return Binlog_type_info(Field_varstring::type(), field_length, 2, charset());
+}
+
+
+bool Field_varstring::memcpy_field_possible(const Field *from) const
{
- DBUG_ASSERT(field_length <= 65535);
- int2store((char*)metadata_ptr, field_length);
- return 2;
+ return (Field_str::memcpy_field_possible(from) &&
+ !compression_method() == !from->compression_method() &&
+ length_bytes == ((Field_varstring*) from)->length_bytes &&
+ (table->file && !(table->file->ha_table_flags() &
+ HA_RECORD_MUST_BE_CLEAN_ON_WRITE)));
}
+
int Field_varstring::store(const char *from,size_t length,CHARSET_INFO *cs)
{
DBUG_ASSERT(marked_for_write_or_computed());
@@ -7654,7 +7625,7 @@ int Field_varstring::store(const char *from,size_t length,CHARSET_INFO *cs)
rc= well_formed_copy_with_check((char*) get_data(), field_length,
cs, from, length,
- field_length / field_charset->mbmaxlen,
+ Field_varstring::char_length(),
true, &copy_length);
store_length(copy_length);
@@ -7689,7 +7660,7 @@ String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
DBUG_ASSERT(marked_for_read());
- val_ptr->set((const char*) get_data(), get_length(), field_charset);
+ val_ptr->set((const char*) get_data(), get_length(), field_charset());
return val_ptr;
}
@@ -7709,7 +7680,7 @@ my_decimal *Field_varstring::val_decimal(my_decimal *decimal_value)
int Field_varstring::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
- uint max_len)
+ uint max_len) const
{
uint a_length, b_length;
int diff;
@@ -7726,13 +7697,8 @@ int Field_varstring::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
}
set_if_smaller(a_length, max_len);
set_if_smaller(b_length, max_len);
- diff= field_charset->coll->strnncollsp(field_charset,
- a_ptr+
- length_bytes,
- a_length,
- b_ptr+
- length_bytes,
- b_length);
+ diff= field_charset()->strnncollsp(a_ptr + length_bytes, a_length,
+ b_ptr + length_bytes, b_length);
return diff;
}
@@ -7742,20 +7708,19 @@ int Field_varstring::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
varstring and blob keys are ALWAYS stored with a 2 byte length prefix
*/
-int Field_varstring::key_cmp(const uchar *key_ptr, uint max_key_length)
+int Field_varstring::key_cmp(const uchar *key_ptr, uint max_key_length) const
{
size_t length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
- size_t local_char_length= max_key_length / field_charset->mbmaxlen;
+ size_t local_char_length= max_key_length / mbmaxlen();
- local_char_length= my_charpos(field_charset, ptr + length_bytes,
- ptr + length_bytes + length, local_char_length);
+ local_char_length= field_charset()->charpos(ptr + length_bytes,
+ ptr + length_bytes + length,
+ local_char_length);
set_if_smaller(length, local_char_length);
- return field_charset->coll->strnncollsp(field_charset,
- ptr + length_bytes,
- length,
- key_ptr+
- HA_KEY_BLOB_LENGTH,
- uint2korr(key_ptr));
+ return field_charset()->strnncollsp(ptr + length_bytes,
+ length,
+ key_ptr + HA_KEY_BLOB_LENGTH,
+ uint2korr(key_ptr));
}
@@ -7767,13 +7732,10 @@ int Field_varstring::key_cmp(const uchar *key_ptr, uint max_key_length)
(keys are created and compared in key.cc)
*/
-int Field_varstring::key_cmp(const uchar *a,const uchar *b)
+int Field_varstring::key_cmp(const uchar *a,const uchar *b) const
{
- return field_charset->coll->strnncollsp(field_charset,
- a + HA_KEY_BLOB_LENGTH,
- uint2korr(a),
- b + HA_KEY_BLOB_LENGTH,
- uint2korr(b));
+ return field_charset()->strnncollsp(a + HA_KEY_BLOB_LENGTH, uint2korr(a),
+ b + HA_KEY_BLOB_LENGTH, uint2korr(b));
}
@@ -7783,7 +7745,7 @@ void Field_varstring::sort_string(uchar *to,uint length)
val_str(&buf, &buf);
- if (field_charset == &my_charset_bin)
+ if (field_charset() == &my_charset_bin)
{
/* Store length last in high-byte order to sort longer strings first */
if (length_bytes == 1)
@@ -7796,11 +7758,11 @@ void Field_varstring::sort_string(uchar *to,uint length)
#ifdef DBUG_ASSERT_EXISTS
size_t rc=
#endif
- field_charset->coll->strnxfrm(field_charset, to, length,
- char_length() * field_charset->strxfrm_multiply,
- (const uchar*) buf.ptr(), buf.length(),
- MY_STRXFRM_PAD_WITH_SPACE |
- MY_STRXFRM_PAD_TO_MAXLEN);
+ field_charset()->strnxfrm(to, length,
+ char_length() * field_charset()->strxfrm_multiply,
+ (const uchar *) buf.ptr(), buf.length(),
+ MY_STRXFRM_PAD_WITH_SPACE |
+ MY_STRXFRM_PAD_TO_MAXLEN);
DBUG_ASSERT(rc == length);
}
@@ -7964,7 +7926,7 @@ uint Field_varstring::get_key_image(uchar *buff, uint length,
val_str(&val, &val);
dbug_tmp_restore_column_map(table->read_set, old_map);
- local_char_length= val.charpos(length / field_charset->mbmaxlen);
+ local_char_length= val.charpos(length / mbmaxlen());
if (local_char_length < val.length())
val.length(local_char_length);
/* Key is always stored with 2 bytes */
@@ -7985,12 +7947,12 @@ uint Field_varstring::get_key_image(uchar *buff, uint length,
void Field_varstring::set_key_image(const uchar *buff,uint length)
{
length= uint2korr(buff); // Real length is here
- (void) store((const char*) buff + HA_KEY_BLOB_LENGTH, length, field_charset);
+ (void) store((const char*) buff + HA_KEY_BLOB_LENGTH, length, field_charset());
}
int Field_varstring::cmp_binary(const uchar *a_ptr, const uchar *b_ptr,
- uint32 max_length)
+ uint32 max_length) const
{
uint32 a_length,b_length;
@@ -8045,7 +8007,7 @@ bool Field_varstring::is_equal(const Column_definition &new_field) const
new_field.length == field_length &&
new_field.char_length == char_length() &&
!new_field.compression_method() == !compression_method() &&
- new_field.charset == field_charset;
+ new_field.charset == field_charset();
}
@@ -8058,8 +8020,7 @@ void Field_varstring::hash(ulong *nr, ulong *nr2)
else
{
uint len= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
- CHARSET_INFO *cs= charset();
- cs->coll->hash_sort(cs, ptr + length_bytes, len, nr, nr2);
+ charset()->hash_sort(ptr + length_bytes, len, nr, nr2);
}
}
@@ -8109,11 +8070,11 @@ int Field_longstr::compress(char *to, uint to_length,
uint buf_length;
int rc= 0;
- if (String::needs_conversion_on_storage(length, cs, field_charset) ||
+ if (String::needs_conversion_on_storage(length, cs, field_charset()) ||
max_length < length)
{
- set_if_smaller(max_length, static_cast<ulonglong>(field_charset->mbmaxlen) * length + 1);
- if (!(buf= (char*) my_malloc(max_length, MYF(MY_WME))))
+ set_if_smaller(max_length, static_cast<ulonglong>(mbmaxlen()) * length + 1);
+ if (!(buf= (char*) my_malloc(PSI_INSTRUMENT_ME, max_length, MYF(MY_WME))))
{
*out_length= 0;
return -1;
@@ -8163,7 +8124,7 @@ int Field_longstr::compress(char *to, uint to_length,
*/
String *Field_longstr::uncompress(String *val_buffer, String *val_ptr,
- const uchar *from, uint from_length)
+ const uchar *from, uint from_length) const
{
if (from_length)
{
@@ -8172,7 +8133,7 @@ String *Field_longstr::uncompress(String *val_buffer, String *val_ptr,
/* Uncompressed data */
if (!method)
{
- val_ptr->set((const char*) from + 1, from_length - 1, field_charset);
+ val_ptr->set((const char*) from + 1, from_length - 1, field_charset());
return val_ptr;
}
@@ -8181,7 +8142,7 @@ String *Field_longstr::uncompress(String *val_buffer, String *val_ptr,
if (!compression_methods[method].uncompress(val_buffer, from, from_length,
field_length))
{
- val_buffer->set_charset(field_charset);
+ val_buffer->set_charset(field_charset());
status_var_increment(get_thd()->status_var.column_decompressions);
return val_buffer;
}
@@ -8193,7 +8154,7 @@ String *Field_longstr::uncompress(String *val_buffer, String *val_ptr,
safer route, let's return a zero string and let the general
handler catch the error.
*/
- val_ptr->set("", 0, field_charset);
+ val_ptr->set("", 0, field_charset());
return val_ptr;
}
@@ -8225,7 +8186,7 @@ double Field_varstring_compressed::val_real(void)
THD *thd= get_thd();
String buf;
val_str(&buf, &buf);
- return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset,
+ return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset(),
buf.ptr(), buf.length()).result();
}
@@ -8236,13 +8197,13 @@ longlong Field_varstring_compressed::val_int(void)
THD *thd= get_thd();
String buf;
val_str(&buf, &buf);
- return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset,
+ return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset(),
buf.ptr(), buf.length()).result();
}
int Field_varstring_compressed::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
- uint max_len)
+ uint max_len) const
{
String a, b;
uint a_length, b_length;
@@ -8266,7 +8227,12 @@ int Field_varstring_compressed::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
if (b.length() > max_len)
b.length(max_len);
- return sortcmp(&a, &b, field_charset);
+ return sortcmp(&a, &b, field_charset());
+}
+Binlog_type_info Field_varstring_compressed::binlog_type_info() const
+{
+ return Binlog_type_info(Field_varstring_compressed::binlog_type(),
+ field_length, 2, charset());
}
@@ -8311,7 +8277,7 @@ uint32 Field_blob::get_length(const uchar *pos, uint packlength_arg) const
*/
int Field_blob::copy_value(Field_blob *from)
{
- DBUG_ASSERT(field_charset == from->charset());
+ DBUG_ASSERT(field_charset() == from->charset());
DBUG_ASSERT(!compression_method() == !from->compression_method());
int rc= 0;
uint32 length= from->get_length();
@@ -8319,7 +8285,7 @@ int Field_blob::copy_value(Field_blob *from)
if (packlength < from->packlength)
{
set_if_smaller(length, Field_blob::max_data_length());
- length= (uint32) Well_formed_prefix(field_charset,
+ length= (uint32) Well_formed_prefix(field_charset(),
(const char *) data, length).length();
rc= report_if_important_data((const char *) data + length,
(const char *) data + from->get_length(),
@@ -8356,7 +8322,7 @@ int Field_blob::store(const char *from,size_t length,CHARSET_INFO *cs)
if (table && table->blob_storage) // GROUP_CONCAT with ORDER BY | DISTINCT
{
DBUG_ASSERT(!f_is_hex_escape(flags));
- DBUG_ASSERT(field_charset == cs);
+ DBUG_ASSERT(field_charset() == cs);
DBUG_ASSERT(length <= max_data_length());
new_length= length;
@@ -8387,7 +8353,7 @@ int Field_blob::store(const char *from,size_t length,CHARSET_INFO *cs)
If content of the 'from'-address is cached in the 'value'-object
it is possible that the content needs a character conversion.
*/
- if (!String::needs_conversion_on_storage(length, cs, field_charset))
+ if (!String::needs_conversion_on_storage(length, cs, field_charset()))
{
Field_blob::store_length(length);
bmove(ptr + packlength, &from, sizeof(char*));
@@ -8398,14 +8364,14 @@ int Field_blob::store(const char *from,size_t length,CHARSET_INFO *cs)
from= tmpstr.ptr();
}
- new_length= MY_MIN(max_data_length(), field_charset->mbmaxlen * length);
+ new_length= MY_MIN(max_data_length(), mbmaxlen() * length);
if (value.alloc(new_length))
goto oom_error;
tmp= const_cast<char*>(value.ptr());
if (f_is_hex_escape(flags))
{
- copy_length= my_copy_with_hex_escaping(field_charset,
+ copy_length= my_copy_with_hex_escaping(field_charset(),
tmp, new_length,
from, length);
Field_blob::store_length(copy_length);
@@ -8493,15 +8459,14 @@ my_decimal *Field_blob::val_decimal(my_decimal *decimal_value)
int Field_blob::cmp(const uchar *a,uint32 a_length, const uchar *b,
- uint32 b_length)
+ uint32 b_length) const
{
- return field_charset->coll->strnncollsp(field_charset,
- a, a_length, b, b_length);
+ return field_charset()->strnncollsp(a, a_length, b, b_length);
}
int Field_blob::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
- uint max_length)
+ uint max_length) const
{
uchar *blob1,*blob2;
memcpy(&blob1, a_ptr+packlength, sizeof(char*));
@@ -8514,7 +8479,7 @@ int Field_blob::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
int Field_blob::cmp_binary(const uchar *a_ptr, const uchar *b_ptr,
- uint32 max_length)
+ uint32 max_length) const
{
char *a,*b;
uint diff;
@@ -8534,44 +8499,13 @@ int Field_blob::cmp_binary(const uchar *a_ptr, const uchar *b_ptr,
/* The following is used only when comparing a key */
-uint Field_blob::get_key_image(uchar *buff,uint length, imagetype type_arg)
+uint Field_blob::get_key_image_itRAW(uchar *buff, uint length)
{
size_t blob_length= get_length(ptr);
- uchar *blob;
-
-#ifdef HAVE_SPATIAL
- if (type_arg == itMBR)
- {
- const char *dummy;
- MBR mbr;
- Geometry_buffer buffer;
- Geometry *gobj;
- const uint image_length= SIZEOF_STORED_DOUBLE*4;
-
- if (blob_length < SRID_SIZE)
- {
- bzero(buff, image_length);
- return image_length;
- }
- blob= get_ptr();
- gobj= Geometry::construct(&buffer, (char*) blob, (uint32)blob_length);
- if (!gobj || gobj->get_mbr(&mbr, &dummy))
- bzero(buff, image_length);
- else
- {
- float8store(buff, mbr.xmin);
- float8store(buff+8, mbr.xmax);
- float8store(buff+16, mbr.ymin);
- float8store(buff+24, mbr.ymax);
- }
- return image_length;
- }
-#endif /*HAVE_SPATIAL*/
-
- blob= get_ptr();
- size_t local_char_length= length / field_charset->mbmaxlen;
- local_char_length= my_charpos(field_charset, blob, blob + blob_length,
- local_char_length);
+ uchar *blob= get_ptr();
+ size_t local_char_length= length / mbmaxlen();
+ local_char_length= field_charset()->charpos(blob, blob + blob_length,
+ local_char_length);
set_if_smaller(blob_length, local_char_length);
if (length > blob_length)
@@ -8593,26 +8527,26 @@ void Field_blob::set_key_image(const uchar *buff,uint length)
{
length= uint2korr(buff);
(void) Field_blob::store((const char*) buff+HA_KEY_BLOB_LENGTH, length,
- field_charset);
+ field_charset());
}
-int Field_blob::key_cmp(const uchar *key_ptr, uint max_key_length)
+int Field_blob::key_cmp(const uchar *key_ptr, uint max_key_length) const
{
uchar *blob1;
size_t blob_length=get_length(ptr);
memcpy(&blob1, ptr+packlength, sizeof(char*));
CHARSET_INFO *cs= charset();
size_t local_char_length= max_key_length / cs->mbmaxlen;
- local_char_length= my_charpos(cs, blob1, blob1+blob_length,
- local_char_length);
+ local_char_length= cs->charpos(blob1, blob1+blob_length,
+ local_char_length);
set_if_smaller(blob_length, local_char_length);
return Field_blob::cmp(blob1, (uint32)blob_length,
key_ptr+HA_KEY_BLOB_LENGTH,
uint2korr(key_ptr));
}
-int Field_blob::key_cmp(const uchar *a,const uchar *b)
+int Field_blob::key_cmp(const uchar *a,const uchar *b) const
{
return Field_blob::cmp(a+HA_KEY_BLOB_LENGTH, uint2korr(a),
b+HA_KEY_BLOB_LENGTH, uint2korr(b));
@@ -8643,19 +8577,25 @@ Field *Field_blob::new_key_field(MEM_ROOT *root, TABLE *new_table,
@returns number of bytes written to metadata_ptr
*/
-int Field_blob::save_field_metadata(uchar *metadata_ptr)
+Binlog_type_info Field_blob::binlog_type_info() const
{
- DBUG_ENTER("Field_blob::save_field_metadata");
- *metadata_ptr= pack_length_no_ptr();
- DBUG_PRINT("debug", ("metadata: %u (pack_length_no_ptr)", *metadata_ptr));
- DBUG_RETURN(1);
+ DBUG_ASSERT(Field_blob::type() == binlog_type());
+ return Binlog_type_info(Field_blob::type(), pack_length_no_ptr(), 1,
+ charset());
}
uint32 Field_blob::sort_length() const
{
- return (uint32) (get_thd()->variables.max_sort_length +
- (field_charset == &my_charset_bin ? 0 : packlength));
+ return packlength == 4 ?
+ UINT_MAX32 :
+ (uint32) field_length + sort_suffix_length();
+}
+
+
+uint32 Field_blob::sort_suffix_length() const
+{
+ return field_charset() == &my_charset_bin ? packlength : 0;
}
@@ -8664,11 +8604,11 @@ void Field_blob::sort_string(uchar *to,uint length)
String buf;
val_str(&buf, &buf);
- if (!buf.length() && field_charset->pad_char == 0)
+ if (!buf.length() && field_charset()->pad_char == 0)
bzero(to,length);
else
{
- if (field_charset == &my_charset_bin)
+ if (field_charset() == &my_charset_bin)
{
/*
Store length of blob last in blob to shorter blobs before longer blobs
@@ -8680,10 +8620,10 @@ void Field_blob::sort_string(uchar *to,uint length)
#ifdef DBUG_ASSERT_EXISTS
size_t rc=
#endif
- field_charset->coll->strnxfrm(field_charset, to, length, length,
- (const uchar*) buf.ptr(), buf.length(),
- MY_STRXFRM_PAD_WITH_SPACE |
- MY_STRXFRM_PAD_TO_MAXLEN);
+ field_charset()->strnxfrm(to, length, length,
+ (const uchar *) buf.ptr(), buf.length(),
+ MY_STRXFRM_PAD_WITH_SPACE |
+ MY_STRXFRM_PAD_TO_MAXLEN);
DBUG_ASSERT(rc == length);
}
}
@@ -8818,7 +8758,7 @@ bool Field_blob::is_equal(const Column_definition &new_field) const
return new_field.type_handler() == type_handler() &&
!new_field.compression_method() == !compression_method() &&
new_field.pack_length == pack_length() &&
- new_field.charset == field_charset;
+ new_field.charset == field_charset();
}
@@ -8854,8 +8794,7 @@ int Field_blob_compressed::store(const char *from, size_t length,
DBUG_ASSERT(marked_for_write_or_computed());
uint compressed_length;
uint max_length= max_data_length();
- uint to_length= (uint) MY_MIN(max_length,
- field_charset->mbmaxlen * length + 1);
+ uint to_length= (uint) MY_MIN(max_length, mbmaxlen() * length + 1);
String tmp(from, length, cs);
int rc;
@@ -8889,7 +8828,7 @@ double Field_blob_compressed::val_real(void)
THD *thd= get_thd();
String buf;
val_str(&buf, &buf);
- return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset,
+ return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset(),
buf.ptr(), buf.length()).result();
}
@@ -8900,285 +8839,16 @@ longlong Field_blob_compressed::val_int(void)
THD *thd= get_thd();
String buf;
val_str(&buf, &buf);
- return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset,
+ return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset(),
buf.ptr(), buf.length()).result();
}
-
-#ifdef HAVE_SPATIAL
-/* Values 1-40 reserved for 1-byte options,
- 41-80 for 2-byte options,
- 81-120 for 4-byte options,
- 121-160 for 8-byte options,
- other - varied length in next 1-3 bytes.
-*/
-enum extra2_gis_field_options {
- FIELDGEOM_END=0,
- FIELDGEOM_STORAGE_MODEL=1,
- FIELDGEOM_PRECISION=2,
- FIELDGEOM_SCALE=3,
- FIELDGEOM_SRID=81,
-};
-
-
-uint gis_field_options_image(uchar *buff, List<Create_field> &create_fields)
+Binlog_type_info Field_blob_compressed::binlog_type_info() const
{
- uint image_size= 0;
- List_iterator<Create_field> it(create_fields);
- Create_field *field;
- while ((field= it++))
- {
- if (field->real_field_type() != MYSQL_TYPE_GEOMETRY)
- continue;
- if (buff)
- {
- uchar *cbuf= buff + image_size;
-
- cbuf[0]= FIELDGEOM_STORAGE_MODEL;
- cbuf[1]= (uchar) Field_geom::GEOM_STORAGE_WKB;
-
- cbuf[2]= FIELDGEOM_PRECISION;
- cbuf[3]= (uchar) field->length;
-
- cbuf[4]= FIELDGEOM_SCALE;
- cbuf[5]= (uchar) field->decimals;
-
- cbuf[6]= FIELDGEOM_SRID;
- int4store(cbuf + 7, ((uint32) field->srid));
-
- cbuf[11]= FIELDGEOM_END;
- }
- image_size+= 12;
- }
-
- return image_size;
+ return Binlog_type_info(Field_blob_compressed::binlog_type(),
+ pack_length_no_ptr(), 1, charset());
}
-
-uint gis_field_options_read(const uchar *buf, size_t buf_len,
- Field_geom::storage_type *st_type,uint *precision, uint *scale, uint *srid)
-{
- const uchar *buf_end= buf + buf_len;
- const uchar *cbuf= buf;
- int option_id;
-
- *precision= *scale= *srid= 0;
- *st_type= Field_geom::GEOM_STORAGE_WKB;
-
- if (!buf) /* can only happen with the old FRM file */
- goto end_of_record;
-
- while (cbuf < buf_end)
- {
- switch ((option_id= *(cbuf++)))
- {
- case FIELDGEOM_STORAGE_MODEL:
- *st_type= (Field_geom::storage_type) cbuf[0];
- break;
- case FIELDGEOM_PRECISION:
- *precision= cbuf[0];
- break;
- case FIELDGEOM_SCALE:
- *scale= cbuf[0];
- break;
- case FIELDGEOM_SRID:
- *srid= uint4korr(cbuf);
- break;
- case FIELDGEOM_END:
- goto end_of_record;
- }
- if (option_id > 0 && option_id <= 40)
- cbuf+= 1;
- else if (option_id > 40 && option_id <= 80)
- cbuf+= 2;
- else if (option_id > 80 && option_id <= 120)
- cbuf+= 4;
- else if (option_id > 120 && option_id <= 160)
- cbuf+= 8;
- else /* > 160 and <=255 */
- cbuf+= cbuf[0] ? 1 + cbuf[0] : 3 + uint2korr(cbuf+1);
- }
-
-end_of_record:
- return (uint)(cbuf - buf);
-}
-
-
-
-void Field_geom::sql_type(String &res) const
-{
- CHARSET_INFO *cs= &my_charset_latin1;
- switch (geom_type)
- {
- case GEOM_POINT:
- res.set(STRING_WITH_LEN("point"), cs);
- break;
- case GEOM_LINESTRING:
- res.set(STRING_WITH_LEN("linestring"), cs);
- break;
- case GEOM_POLYGON:
- res.set(STRING_WITH_LEN("polygon"), cs);
- break;
- case GEOM_MULTIPOINT:
- res.set(STRING_WITH_LEN("multipoint"), cs);
- break;
- case GEOM_MULTILINESTRING:
- res.set(STRING_WITH_LEN("multilinestring"), cs);
- break;
- case GEOM_MULTIPOLYGON:
- res.set(STRING_WITH_LEN("multipolygon"), cs);
- break;
- case GEOM_GEOMETRYCOLLECTION:
- res.set(STRING_WITH_LEN("geometrycollection"), cs);
- break;
- default:
- res.set(STRING_WITH_LEN("geometry"), cs);
- }
-}
-
-
-int Field_geom::store(double nr)
-{
- my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
- ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
- return -1;
-}
-
-
-int Field_geom::store(longlong nr, bool unsigned_val)
-{
- my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
- ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
- return -1;
-}
-
-
-int Field_geom::store_decimal(const my_decimal *)
-{
- my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
- ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
- return -1;
-}
-
-
-int Field_geom::store(const char *from, size_t length, CHARSET_INFO *cs)
-{
- if (!length)
- bzero(ptr, Field_blob::pack_length());
- else
- {
- if (from == Geometry::bad_geometry_data.ptr())
- goto err;
- // Check given WKB
- uint32 wkb_type;
- if (length < SRID_SIZE + WKB_HEADER_SIZE + 4)
- goto err;
- wkb_type= uint4korr(from + SRID_SIZE + 1);
- if (wkb_type < (uint32) Geometry::wkb_point ||
- wkb_type > (uint32) Geometry::wkb_last)
- goto err;
-
- if (geom_type != Field::GEOM_GEOMETRY &&
- geom_type != Field::GEOM_GEOMETRYCOLLECTION &&
- (uint32) geom_type != wkb_type)
- {
- const char *db= table->s->db.str;
- const char *tab_name= table->s->table_name.str;
- Geometry_buffer buffer;
- Geometry *geom= NULL;
- String wkt;
- const char *dummy;
-
- if (!db)
- db= "";
- if (!tab_name)
- tab_name= "";
- wkt.set_charset(&my_charset_latin1);
- if (!(geom= Geometry::construct(&buffer, from, uint32(length))) ||
- geom->as_wkt(&wkt, &dummy))
- goto err;
-
- my_error(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, MYF(0),
- Geometry::ci_collection[geom_type]->m_name.str,
- wkt.c_ptr(), db, tab_name, field_name.str,
- (ulong) table->in_use->get_stmt_da()->
- current_row_for_warning());
-
- goto err_exit;
- }
-
- Field_blob::store_length(length);
- if ((table->copy_blobs || length <= MAX_FIELD_WIDTH) &&
- from != value.ptr())
- { // Must make a copy
- value.copy(from, length, cs);
- from= value.ptr();
- }
- bmove(ptr + packlength, &from, sizeof(char*));
- }
- return 0;
-
-err:
- my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
- ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
-err_exit:
- bzero(ptr, Field_blob::pack_length());
- return -1;
-}
-
-Field::geometry_type Field_geom::geometry_type_merge(geometry_type a,
- geometry_type b)
-{
- if (a == b)
- return a;
- return Field::GEOM_GEOMETRY;
-}
-
-
-bool Field_geom::is_equal(const Column_definition &new_field) const
-{
- return new_field.type_handler() == type_handler() &&
- /*
- - Allow ALTER..INPLACE to supertype (GEOMETRY),
- e.g. POINT to GEOMETRY or POLYGON to GEOMETRY.
- - Allow ALTER..INPLACE to the same geometry type: POINT -> POINT
- */
- (new_field.geom_type == geom_type ||
- new_field.geom_type == GEOM_GEOMETRY);
-}
-
-
-bool Field_geom::can_optimize_range(const Item_bool_func *cond,
- const Item *item,
- bool is_eq_func) const
-{
- return item->cmp_type() == STRING_RESULT;
-}
-
-
-bool Field_geom::load_data_set_no_data(THD *thd, bool fixed_format)
-{
- return Field_geom::load_data_set_null(thd);
-}
-
-
-bool Field_geom::load_data_set_null(THD *thd)
-{
- Field_blob::reset();
- if (!maybe_null())
- {
- my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field_name.str,
- thd->get_stmt_da()->current_row_for_warning());
- return true;
- }
- set_null();
- set_has_explicit_value(); // Do not auto-update this field
- return false;
-}
-
-
-#endif /*HAVE_SPATIAL*/
-
/****************************************************************************
** enum type.
** This is a string which only can have a selection of different values.
@@ -9222,24 +8892,24 @@ int Field_enum::store(const char *from,size_t length,CHARSET_INFO *cs)
String tmpstr(buff,sizeof(buff), &my_charset_bin);
/* Convert character set if necessary */
- if (String::needs_conversion_on_storage(length, cs, field_charset))
+ if (String::needs_conversion_on_storage(length, cs, field_charset()))
{
uint dummy_errors;
- tmpstr.copy(from, length, cs, field_charset, &dummy_errors);
+ tmpstr.copy(from, length, cs, field_charset(), &dummy_errors);
from= tmpstr.ptr();
length= tmpstr.length();
}
/* Remove end space */
- length= (uint)field_charset->cset->lengthsp(field_charset, from, length);
- uint tmp=find_type2(typelib, from, length, field_charset);
+ length= (uint) field_charset()->lengthsp(from, length);
+ uint tmp=find_type2(typelib, from, length, field_charset());
if (!tmp)
{
if (length < 6) // Can't be more than 99999 enums
{
/* This is for reading numbers with LOAD DATA INFILE */
char *end;
- tmp=(uint) my_strntoul(cs,from,length,10,&end,&err);
+ tmp=(uint) cs->strntoul(from,length,10,&end,&err);
if (err || end != from+length || tmp > typelib->count)
{
tmp=0;
@@ -9293,9 +8963,13 @@ double Field_enum::val_real(void)
longlong Field_enum::val_int(void)
{
DBUG_ASSERT(marked_for_read());
- return read_lowendian(ptr, packlength);
+ return val_int(ptr);
}
+longlong Field_enum::val_int(const uchar *real_ptr) const
+{
+ return read_lowendian(real_ptr, packlength);
+}
/**
Save the field metadata for enum fields.
@@ -9308,11 +8982,11 @@ longlong Field_enum::val_int(void)
@returns number of bytes written to metadata_ptr
*/
-int Field_enum::save_field_metadata(uchar *metadata_ptr)
+Binlog_type_info Field_enum::binlog_type_info() const
{
- *metadata_ptr= real_type();
- *(metadata_ptr + 1)= pack_length();
- return 2;
+ DBUG_ASSERT(Field_enum::type() == binlog_type());
+ return Binlog_type_info(Field_enum::type(), real_type() + (pack_length() << 8),
+ 2, charset(), (TYPELIB *)get_typelib(), NULL);
}
@@ -9321,22 +8995,18 @@ String *Field_enum::val_str(String *val_buffer __attribute__((unused)),
{
uint tmp=(uint) Field_enum::val_int();
if (!tmp || tmp > typelib->count)
- val_ptr->set("", 0, field_charset);
+ val_ptr->set("", 0, field_charset());
else
val_ptr->set((const char*) typelib->type_names[tmp-1],
typelib->type_lengths[tmp-1],
- field_charset);
+ field_charset());
return val_ptr;
}
-int Field_enum::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_enum::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
- uchar *old= ptr;
- ptr= (uchar*) a_ptr;
- ulonglong a=Field_enum::val_int();
- ptr= (uchar*) b_ptr;
- ulonglong b=Field_enum::val_int();
- ptr= old;
+ ulonglong a=Field_enum::val_int(a_ptr);
+ ulonglong b=Field_enum::val_int(b_ptr);
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
@@ -9408,20 +9078,20 @@ int Field_set::store(const char *from,size_t length,CHARSET_INFO *cs)
String tmpstr(buff,sizeof(buff), &my_charset_bin);
/* Convert character set if necessary */
- if (String::needs_conversion_on_storage(length, cs, field_charset))
+ if (String::needs_conversion_on_storage(length, cs, field_charset()))
{
uint dummy_errors;
- tmpstr.copy(from, length, cs, field_charset, &dummy_errors);
+ tmpstr.copy(from, length, cs, field_charset(), &dummy_errors);
from= tmpstr.ptr();
length= tmpstr.length();
}
- ulonglong tmp= find_set(typelib, from, length, field_charset,
+ ulonglong tmp= find_set(typelib, from, length, field_charset(),
&not_used, &not_used2, &got_warning);
if (!tmp && length && length < 22)
{
/* This is for reading numbers with LOAD DATA INFILE */
char *end;
- tmp=my_strntoull(cs,from,length,10,&end,&err);
+ tmp= cs->strntoull(from,length,10,&end,&err);
if (err || end != from+length ||
tmp > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1))
{
@@ -9475,7 +9145,7 @@ String *Field_set::val_str(String *val_buffer,
return val_buffer;
}
- val_buffer->set_charset(field_charset);
+ val_buffer->set_charset(field_charset());
val_buffer->length(0);
while (tmp && bitnr < (uint) typelib->count)
@@ -9486,7 +9156,7 @@ String *Field_set::val_str(String *val_buffer,
val_buffer->append(&field_separator, 1, &my_charset_latin1);
String str(typelib->type_names[bitnr],
typelib->type_lengths[bitnr],
- field_charset);
+ field_charset());
val_buffer->append(str);
}
tmp>>=1;
@@ -9519,6 +9189,13 @@ void Field_set::sql_type(String &res) const
res.append(')');
}
+Binlog_type_info Field_set::binlog_type_info() const
+{
+ DBUG_ASSERT(Field_set::type() == binlog_type());
+ return Binlog_type_info(Field_set::type(), real_type()
+ + (pack_length() << 8), 2, charset(), NULL, (TYPELIB *)get_typelib());
+}
+
/**
@retval
1 if the fields are equally defined
@@ -9541,14 +9218,12 @@ bool Field::eq_def(const Field *field) const
@return TRUE if the type names of t1 match those of t2. FALSE otherwise.
*/
-static bool compare_type_names(CHARSET_INFO *charset, TYPELIB *t1, TYPELIB *t2)
+static bool compare_type_names(CHARSET_INFO *charset, const TYPELIB *t1,
+ const TYPELIB *t2)
{
for (uint i= 0; i < t1->count; i++)
- if (my_strnncoll(charset,
- (const uchar*) t1->type_names[i],
- t1->type_lengths[i],
- (const uchar*) t2->type_names[i],
- t2->type_lengths[i]))
+ if (charset->strnncoll(t1->type_names[i], t1->type_lengths[i],
+ t2->type_names[i], t2->type_lengths[i]))
return FALSE;
return TRUE;
}
@@ -9560,7 +9235,7 @@ static bool compare_type_names(CHARSET_INFO *charset, TYPELIB *t1, TYPELIB *t2)
bool Field_enum::eq_def(const Field *field) const
{
- TYPELIB *values;
+ const TYPELIB *values;
if (!Field::eq_def(field))
return FALSE;
@@ -9571,7 +9246,7 @@ bool Field_enum::eq_def(const Field *field) const
if (typelib->count != values->count)
return FALSE;
- return compare_type_names(field_charset, typelib, values);
+ return compare_type_names(field_charset(), typelib, values);
}
@@ -9586,14 +9261,14 @@ bool Field_enum::eq_def(const Field *field) const
bool Field_enum::is_equal(const Column_definition &new_field) const
{
- TYPELIB *values= new_field.interval;
+ const TYPELIB *values= new_field.interval;
/*
The fields are compatible if they have the same flags,
type, charset and have the same underlying length.
*/
if (new_field.type_handler() != type_handler() ||
- new_field.charset != field_charset ||
+ new_field.charset != field_charset() ||
new_field.pack_length != pack_length())
return false;
@@ -9606,7 +9281,7 @@ bool Field_enum::is_equal(const Column_definition &new_field) const
return false;
/* Check whether there are modification before the end. */
- if (! compare_type_names(field_charset, typelib, new_field.interval))
+ if (! compare_type_names(field_charset(), typelib, new_field.interval))
return false;
return true;
@@ -9768,6 +9443,14 @@ Field_bit::Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
}
+const DTCollation & Field_bit::dtcollation() const
+{
+ static DTCollation tmp(&my_charset_bin,
+ DERIVATION_IMPLICIT, MY_REPERTOIRE_UNICODE30);
+ return tmp;
+}
+
+
void Field_bit::hash(ulong *nr, ulong *nr2)
{
if (is_null())
@@ -9780,7 +9463,7 @@ void Field_bit::hash(ulong *nr, ulong *nr2)
longlong value= Field_bit::val_int();
uchar tmp[8];
mi_int8store(tmp,value);
- cs->coll->hash_sort(cs, tmp, 8, nr, nr2);
+ cs->hash_sort(tmp, 8, nr, nr2);
}
}
@@ -9976,7 +9659,7 @@ my_decimal *Field_bit::val_decimal(my_decimal *deciaml_value)
The a and b pointer must be pointers to the field in a record
(not the table->record[0] necessarily)
*/
-int Field_bit::cmp_max(const uchar *a, const uchar *b, uint max_len)
+int Field_bit::cmp_max(const uchar *a, const uchar *b, uint max_len) const
{
my_ptrdiff_t a_diff= a - ptr;
my_ptrdiff_t b_diff= b - ptr;
@@ -9994,7 +9677,7 @@ int Field_bit::cmp_max(const uchar *a, const uchar *b, uint max_len)
}
-int Field_bit::key_cmp(const uchar *str, uint length)
+int Field_bit::key_cmp(const uchar *str, uint length) const
{
if (bit_len)
{
@@ -10038,33 +9721,6 @@ uint Field_bit::get_key_image(uchar *buff, uint length, imagetype type_arg)
/**
- Save the field metadata for bit fields.
-
- Saves the bit length in the first byte and bytes in record in the
- second byte of the field metadata array at index of *metadata_ptr and
- *(metadata_ptr + 1).
-
- @param metadata_ptr First byte of field metadata
-
- @returns number of bytes written to metadata_ptr
-*/
-int Field_bit::save_field_metadata(uchar *metadata_ptr)
-{
- DBUG_ENTER("Field_bit::save_field_metadata");
- DBUG_PRINT("debug", ("bit_len: %d, bytes_in_rec: %d",
- bit_len, bytes_in_rec));
- /*
- Since this class and Field_bit_as_char have different ideas of
- what should be stored here, we compute the values of the metadata
- explicitly using the field_length.
- */
- metadata_ptr[0]= field_length % 8;
- metadata_ptr[1]= field_length / 8;
- DBUG_RETURN(2);
-}
-
-
-/**
Returns the number of bytes field uses in row-based replication
row packed size.
@@ -10076,7 +9732,7 @@ int Field_bit::save_field_metadata(uchar *metadata_ptr)
@returns The size of the field based on the field metadata.
*/
-uint Field_bit::pack_length_from_metadata(uint field_metadata)
+uint Field_bit::pack_length_from_metadata(uint field_metadata) const
{
uint const from_len= (field_metadata >> 8U) & 0x00ff;
uint const from_bit_len= field_metadata & 0x00ff;
@@ -10087,9 +9743,9 @@ uint Field_bit::pack_length_from_metadata(uint field_metadata)
bool
Field_bit::compatible_field_size(uint field_metadata,
- Relay_log_info * __attribute__((unused)),
+ const Relay_log_info * __attribute__((unused)),
uint16 mflags,
- int *order_var)
+ int *order_var) const
{
DBUG_ENTER("Field_bit::compatible_field_size");
DBUG_ASSERT((field_metadata >> 16) == 0);
@@ -10319,31 +9975,31 @@ bool Column_definition::create_interval_from_interval_list(MEM_ROOT *mem_root,
{
DBUG_ENTER("Column_definition::create_interval_from_interval_list");
DBUG_ASSERT(!interval);
- if (!(interval= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB))))
+ TYPELIB *tmpint;
+ if (!(interval= tmpint= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB))))
DBUG_RETURN(true); // EOM
List_iterator<String> it(interval_list);
StringBuffer<64> conv;
char comma_buf[5]; /* 5 bytes for 'filename' charset */
DBUG_ASSERT(sizeof(comma_buf) >= charset->mbmaxlen);
- int comma_length= charset->cset->wc_mb(charset, ',',
- (uchar*) comma_buf,
- (uchar*) comma_buf +
- sizeof(comma_buf));
+ int comma_length= charset->wc_mb(',',
+ (uchar*) comma_buf,
+ (uchar*) comma_buf + sizeof(comma_buf));
DBUG_ASSERT(comma_length >= 0 && comma_length <= (int) sizeof(comma_buf));
if (!multi_alloc_root(mem_root,
- &interval->type_names,
+ &tmpint->type_names,
sizeof(char*) * (interval_list.elements + 1),
- &interval->type_lengths,
+ &tmpint->type_lengths,
sizeof(uint) * (interval_list.elements + 1),
NullS))
goto err; // EOM
- interval->name= "";
- interval->count= interval_list.elements;
+ tmpint->name= "";
+ tmpint->count= interval_list.elements;
- for (uint i= 0; i < interval->count; i++)
+ for (uint i= 0; i < interval_list.elements; i++)
{
uint32 dummy;
String *tmp= it++;
@@ -10368,24 +10024,24 @@ bool Column_definition::create_interval_from_interval_list(MEM_ROOT *mem_root,
goto err; // EOM
// Strip trailing spaces.
- value.length= charset->cset->lengthsp(charset, value.str, value.length);
+ value.length= charset->lengthsp(value.str, value.length);
((char*) value.str)[value.length]= '\0';
if (real_field_type() == MYSQL_TYPE_SET)
{
- if (charset->coll->instr(charset, value.str, value.length,
- comma_buf, comma_length, NULL, 0))
+ if (charset->instr(value.str, value.length,
+ comma_buf, comma_length, NULL, 0))
{
ErrConvString err(tmp);
my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "set", err.ptr());
goto err;
}
}
- interval->type_names[i]= value.str;
- interval->type_lengths[i]= (uint)value.length;
+ tmpint->type_names[i]= value.str;
+ tmpint->type_lengths[i]= (uint)value.length;
}
- interval->type_names[interval->count]= 0; // End marker
- interval->type_lengths[interval->count]= 0;
+ tmpint->type_names[interval_list.elements]= 0; // End marker
+ tmpint->type_lengths[interval_list.elements]= 0;
interval_list.empty(); // Don't need interval_list anymore
DBUG_RETURN(false);
err:
@@ -10449,17 +10105,26 @@ bool Column_definition::prepare_interval_field(MEM_ROOT *mem_root,
}
-void Column_definition::set_attributes(const Lex_field_type_st &type,
- CHARSET_INFO *cs)
+bool Column_definition::set_attributes(THD *thd,
+ const Lex_field_type_st &def,
+ CHARSET_INFO *cs,
+ column_definition_type_t type)
{
DBUG_ASSERT(type_handler() == &type_handler_null);
DBUG_ASSERT(charset == &my_charset_bin || charset == NULL);
DBUG_ASSERT(length == 0);
DBUG_ASSERT(decimals == 0);
- set_handler(type.type_handler());
- charset= cs;
+ set_handler(def.type_handler());
+ return type_handler()->Column_definition_set_attributes(thd, this,
+ def, cs, type);
+}
+
+void
+Column_definition_attributes::set_length_and_dec(const Lex_length_and_dec_st
+ &type)
+{
if (type.length())
{
int err;
@@ -10477,13 +10142,11 @@ void Column_definition::create_length_to_internal_length_bit()
{
if (f_bit_as_char(pack_flag))
{
- key_length= pack_length= ((length + 7) & ~7) / 8;
+ pack_length= ((length + 7) & ~7) / 8;
}
else
{
pack_length= (uint) length / 8;
- /* We need one extra byte to store the bits we save among the null bits */
- key_length= pack_length + MY_TEST(length & 7);
}
}
@@ -10492,11 +10155,11 @@ void Column_definition::create_length_to_internal_length_newdecimal()
{
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);
+ pack_length= my_decimal_get_binary_size(prec, decimals);
}
-bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *name,
+bool check_expression(Virtual_column_info *vcol, const LEX_CSTRING *name,
enum_vcol_info_type type)
{
@@ -10621,6 +10284,7 @@ bool Column_definition::fix_attributes_temporal_with_time(uint int_part_length)
MAX_DATETIME_PRECISION);
return true;
}
+ decimals= (uint) length;
length+= int_part_length + (length ? 1 : 0);
return false;
}
@@ -10826,15 +10490,27 @@ bool Field_vers_trx_id::test_if_equality_guarantees_uniqueness(const Item* item)
Column_definition_attributes::Column_definition_attributes(const Field *field)
:length(field->character_octet_length() / field->charset()->mbmaxlen),
+ decimals(field->decimals()),
unireg_check(field->unireg_check),
interval(NULL),
charset(field->charset()), // May be NULL ptr
srid(0),
- geom_type(Field::GEOM_GEOMETRY),
pack_flag(0)
{}
+Column_definition_attributes::
+ Column_definition_attributes(const Type_all_attributes &attr)
+ :length(attr.max_length),
+ decimals(attr.decimals),
+ unireg_check(Field::NONE),
+ interval(attr.get_typelib()),
+ charset(attr.collation.collation),
+ srid(0),
+ pack_flag(attr.unsigned_flag ? 0 : FIELDFLAG_DECIMAL)
+{}
+
+
/** Create a field suitable for create of table. */
Column_definition::Column_definition(THD *thd, Field *old_field,
@@ -10845,10 +10521,8 @@ Column_definition::Column_definition(THD *thd, Field *old_field,
field_name= old_field->field_name;
flags= old_field->flags;
pack_length=old_field->pack_length();
- key_length= old_field->key_length();
set_handler(old_field->type_handler());
comment= old_field->comment;
- decimals= old_field->decimals();
vcol_info= old_field->vcol_info;
option_list= old_field->option_list;
compression_method_ptr= 0;
@@ -10930,7 +10604,6 @@ Column_definition::redefine_stage1_common(const Column_definition *dup_field,
schema->default_table_charset;
length= dup_field->char_length;
pack_length= dup_field->pack_length;
- key_length= dup_field->key_length;
decimals= dup_field->decimals;
unireg_check= dup_field->unireg_check;
flags= dup_field->flags;
@@ -11062,6 +10735,19 @@ Column_definition::set_compressed_deprecated_column_attribute(THD *thd,
}
+bool Column_definition::check_vcol_for_key(THD *thd) const
+{
+ if (vcol_info && (vcol_info->flags & VCOL_NOT_STRICTLY_DETERMINISTIC))
+ {
+ /* use check_expression() to report an error */
+ check_expression(vcol_info, &field_name, VCOL_GENERATED_STORED);
+ DBUG_ASSERT(thd->is_error());
+ return true;
+ }
+ return false;
+}
+
+
Send_field::Send_field(THD *thd, Item *item)
{
item->make_send_field(thd, this);
@@ -11081,11 +10767,11 @@ uint32 Field_blob::max_display_length() const
switch (packlength)
{
case 1:
- return 255 * field_charset->mbmaxlen;
+ return 255 * mbmaxlen();
case 2:
- return 65535 * field_charset->mbmaxlen;
+ return 65535 * mbmaxlen();
case 3:
- return 16777215 * field_charset->mbmaxlen;
+ return 16777215 * mbmaxlen();
case 4:
return (uint32) UINT_MAX32;
default:
@@ -11320,8 +11006,7 @@ bool Field::val_str_nopad(MEM_ROOT *mem_root, LEX_CSTRING *to)
StringBuffer<MAX_FIELD_WIDTH> str;
bool rc= false;
THD *thd= get_thd();
- sql_mode_t sql_mode_backup= thd->variables.sql_mode;
- thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
+ Sql_mode_instant_remove sms(thd, MODE_PAD_CHAR_TO_FULL_LENGTH);
val_str(&str);
if (!(to->length= str.length()))
@@ -11329,7 +11014,6 @@ bool Field::val_str_nopad(MEM_ROOT *mem_root, LEX_CSTRING *to)
else if ((rc= !(to->str= strmake_root(mem_root, str.ptr(), str.length()))))
to->length= 0;
- thd->variables.sql_mode= sql_mode_backup;
return rc;
}
@@ -11347,7 +11031,7 @@ void Field_string::print_key_value(String *out, uint32 length)
{
if (charset() == &my_charset_bin)
{
- size_t len= field_charset->cset->lengthsp(field_charset, (const char*) ptr, length);
+ size_t len= field_charset()->lengthsp((const char*) ptr, length);
print_key_value_binary(out, ptr, static_cast<uint32>(len));
}
else
diff --git a/sql/field.h b/sql/field.h
index 5fe3a9ed106..49e82766af3 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1,7 +1,7 @@
#ifndef FIELD_INCLUDED
#define FIELD_INCLUDED
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2008, 2019, MariaDB Corporation.
+ Copyright (c) 2008, 2020, 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
@@ -51,6 +51,8 @@ class Table_ident;
class SEL_ARG;
class RANGE_OPT_PARAM;
struct KEY_PART;
+struct SORT_FIELD;
+struct SORT_FIELD_ATTR;
enum enum_check_fields
{
@@ -60,6 +62,45 @@ enum enum_check_fields
CHECK_FIELD_ERROR_FOR_NULL,
};
+
+enum enum_conv_type
+{
+ CONV_TYPE_PRECISE,
+ CONV_TYPE_VARIANT,
+ CONV_TYPE_SUBSET_TO_SUPERSET,
+ CONV_TYPE_SUPERSET_TO_SUBSET,
+ CONV_TYPE_IMPOSSIBLE
+};
+
+
+class Conv_param
+{
+ uint16 m_table_def_flags;
+public:
+ Conv_param(uint16 table_def_flags)
+ :m_table_def_flags(table_def_flags)
+ { }
+ uint16 table_def_flags() const { return m_table_def_flags; }
+};
+
+
+class Conv_source: public Type_handler_hybrid_field_type
+{
+ uint16 m_metadata;
+ CHARSET_INFO *m_cs;
+public:
+ Conv_source(const Type_handler *h, uint16 metadata, CHARSET_INFO *cs)
+ :Type_handler_hybrid_field_type(h),
+ m_metadata(metadata),
+ m_cs(cs)
+ {
+ DBUG_ASSERT(cs);
+ }
+ uint16 metadata() const { return m_metadata; }
+ uint mbmaxlen() const { return m_cs->mbmaxlen; }
+};
+
+
/*
Common declarations for Field and Item
*/
@@ -165,7 +206,7 @@ protected:
public:
Converter_strntod(CHARSET_INFO *cs, const char *str, size_t length)
{
- m_result= my_strntod(cs, (char *) str, length, &m_end_of_num, &m_error);
+ m_result= cs->strntod((char *) str, length, &m_end_of_num, &m_error);
// strntod() does not set an error if the input string was empty
m_edom= m_error !=0 || str == m_end_of_num;
}
@@ -185,7 +226,7 @@ protected:
public:
Converter_strntoll(CHARSET_INFO *cs, const char *str, size_t length)
{
- m_result= my_strntoll(cs, str, length, 10, &m_end_of_num, &m_error);
+ m_result= cs->strntoll(str, length, 10, &m_end_of_num, &m_error);
/*
All non-zero errors means EDOM error.
strntoll() does not set an error if the input string was empty.
@@ -202,7 +243,7 @@ protected:
Converter_strtoll10(CHARSET_INFO *cs, const char *str, size_t length)
{
m_end_of_num= (char *) str + length;
- m_result= (*(cs->cset->strtoll10))(cs, str, &m_end_of_num, &m_error);
+ m_result= cs->strtoll10(str, &m_end_of_num, &m_error);
/*
Negative error means "good negative number".
Only a positive m_error value means a real error.
@@ -410,7 +451,7 @@ public:
{ // Use this when an item is [a part of] a boolean expression
public:
Context_boolean()
- :Context(ANY_SUBST, &type_handler_longlong, &my_charset_bin) { }
+ :Context(ANY_SUBST, &type_handler_slonglong, &my_charset_bin) { }
};
};
@@ -595,6 +636,101 @@ public:
inline void print(String*);
};
+class Binlog_type_info
+{
+public:
+ enum binlog_sign_t
+ {
+ SIGN_SIGNED,
+ SIGN_UNSIGNED,
+ SIGN_NOT_APPLICABLE // for non-numeric types
+ };
+ uchar m_type_code; // according to Field::binlog_type()
+ /**
+ Retrieve the field metadata for fields.
+ */
+ uint16 m_metadata;
+ uint8 m_metadata_size;
+ binlog_sign_t m_signedness;
+ CHARSET_INFO *m_cs; // NULL if not relevant
+ TYPELIB *m_enum_typelib; // NULL if not relevant
+ TYPELIB *m_set_typelib; // NULL if not relevant
+ uchar m_geom_type; // Non-geometry fields can return 0
+ Binlog_type_info(uchar type_code,
+ uint16 metadata,
+ uint8 metadata_size)
+ :m_type_code(type_code),
+ m_metadata(metadata),
+ m_metadata_size(metadata_size),
+ m_signedness(SIGN_NOT_APPLICABLE),
+ m_cs(NULL),
+ m_enum_typelib(NULL),
+ m_set_typelib(NULL),
+ m_geom_type(0)
+ {};
+ Binlog_type_info(uchar type_code, uint16 metadata,
+ uint8 metadata_size,
+ binlog_sign_t signedness)
+ :m_type_code(type_code),
+ m_metadata(metadata),
+ m_metadata_size(metadata_size),
+ m_signedness(signedness),
+ m_cs(NULL),
+ m_enum_typelib(NULL),
+ m_set_typelib(NULL),
+ m_geom_type(0)
+ {};
+ Binlog_type_info(uchar type_code, uint16 metadata,
+ uint8 metadata_size,
+ CHARSET_INFO *cs)
+ :m_type_code(type_code),
+ m_metadata(metadata),
+ m_metadata_size(metadata_size),
+ m_signedness(SIGN_NOT_APPLICABLE),
+ m_cs(cs),
+ m_enum_typelib(NULL),
+ m_set_typelib(NULL),
+ m_geom_type(0)
+ {};
+ Binlog_type_info(uchar type_code, uint16 metadata,
+ uint8 metadata_size,
+ CHARSET_INFO *cs,
+ TYPELIB *t_enum, TYPELIB *t_set)
+ :m_type_code(type_code),
+ m_metadata(metadata),
+ m_metadata_size(metadata_size),
+ m_signedness(SIGN_NOT_APPLICABLE),
+ m_cs(cs),
+ m_enum_typelib(t_enum),
+ m_set_typelib(t_set),
+ m_geom_type(0)
+ {};
+ Binlog_type_info(uchar type_code, uint16 metadata,
+ uint8 metadata_size, CHARSET_INFO *cs,
+ uchar geom_type)
+ :m_type_code(type_code),
+ m_metadata(metadata),
+ m_metadata_size(metadata_size),
+ m_signedness(SIGN_NOT_APPLICABLE),
+ m_cs(cs),
+ m_enum_typelib(NULL),
+ m_set_typelib(NULL),
+ m_geom_type(geom_type)
+ {};
+ static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
+ { return alloc_root(mem_root, size); }
+};
+
+
+class Binlog_type_info_fixed_string: public Binlog_type_info
+{
+public:
+ Binlog_type_info_fixed_string(uchar type_code,
+ uint32 octet_length,
+ CHARSET_INFO *cs);
+};
+
+
class Field: public Value_source
{
Field(const Item &); /* Prevent use of these */
@@ -608,6 +744,7 @@ protected:
}
void error_generated_column_function_is_not_allowed(THD *thd, bool error)
const;
+ static void do_field_eq(Copy_field *copy);
static void do_field_int(Copy_field *copy);
static void do_field_real(Copy_field *copy);
static void do_field_string(Copy_field *copy);
@@ -685,16 +822,10 @@ public:
TIMESTAMP_DNUN_FIELD=23, // TIMESTAMP DEFAULT NOW() ON UPDATE NOW()
TMYSQL_COMPRESSED= 24, // Compatibility with TMySQL
};
- enum geometry_type
- {
- GEOM_GEOMETRY = 0, GEOM_POINT = 1, GEOM_LINESTRING = 2, GEOM_POLYGON = 3,
- GEOM_MULTIPOINT = 4, GEOM_MULTILINESTRING = 5, GEOM_MULTIPOLYGON = 6,
- GEOM_GEOMETRYCOLLECTION = 7
- };
enum imagetype { itRAW, itMBR};
utype unireg_check;
- const uint32 field_length; // Length of field
+ uint32 field_length; // Length of field
uint32 flags;
uint16 field_index; // field number in fields array
uchar null_bit; // Bit used to test null bit
@@ -748,15 +879,13 @@ public:
const LEX_CSTRING *field_name_arg);
virtual ~Field() {}
- DTCollation dtcollation() const
+ virtual Type_numeric_attributes type_numeric_attributes() const
{
- return DTCollation(charset(), derivation(), repertoire());
+ return Type_numeric_attributes(field_length, decimals(), is_unsigned());
}
- virtual Type_std_attributes type_std_attributes() const
+ Type_std_attributes type_std_attributes() const
{
- return Type_std_attributes(field_length, decimals(),
- MY_TEST(flags & UNSIGNED_FLAG),
- dtcollation());
+ return Type_std_attributes(type_numeric_attributes(), dtcollation());
}
bool is_unsigned() const { return flags & UNSIGNED_FLAG; }
@@ -767,6 +896,10 @@ public:
*/
typedef void Copy_func(Copy_field*);
virtual Copy_func *get_copy_func(const Field *from) const= 0;
+ virtual Copy_func *get_copy_func_to(const Field *to) const
+ {
+ return to->get_copy_func(this);
+ }
/* Store functions returns 1 on overflow and -1 on fatal error */
virtual int store_field(Field *from) { return from->save_in_field(this); }
virtual int save_in_field(Field *to)= 0;
@@ -785,6 +918,23 @@ public:
reset();
}
virtual int store(const char *to, size_t length,CHARSET_INFO *cs)=0;
+ /*
+ This is used by engines like CSV and Federated to signal the field
+ that the data is going to be in text (rather than binary) representation,
+ even if cs points to &my_charset_bin.
+
+ If a Field distinguishes between text and binary formats (e.g. INET6),
+ we cannot call store(str,length,&my_charset_bin),
+ to avoid "field" mis-interpreting the data format as binary.
+ */
+ virtual int store_text(const char *to, size_t length, CHARSET_INFO *cs)
+ {
+ return store(to, length, cs);
+ }
+ virtual int store_binary(const char *to, size_t length)
+ {
+ return store(to, length, &my_charset_bin);
+ }
virtual int store_hex_hybrid(const char *str, size_t length);
virtual int store(double nr)=0;
virtual int store(longlong nr, bool unsigned_val)=0;
@@ -809,6 +959,8 @@ public:
{ return store_time_dec(ltime, TIME_SECOND_PART_DIGITS); }
int store(const char *to, size_t length, CHARSET_INFO *cs,
enum_check_fields check_level);
+ int store_text(const char *to, size_t length, CHARSET_INFO *cs,
+ enum_check_fields check_level);
int store(const LEX_STRING *ls, CHARSET_INFO *cs)
{
DBUG_ASSERT(ls->length < UINT_MAX32);
@@ -824,8 +976,8 @@ public:
DBUG_ASSERT(ls.length < UINT_MAX32);
return store(ls.str, (uint) ls.length, cs);
}
- virtual double val_real(void)=0;
- virtual longlong val_int(void)=0;
+ virtual double val_real()=0;
+ virtual longlong val_int()=0;
/*
Get ulonglong representation.
Negative values are truncated to 0.
@@ -835,7 +987,7 @@ public:
longlong nr= val_int();
return nr < 0 ? 0 : (ulonglong) nr;
}
- virtual bool val_bool(void)= 0;
+ virtual bool val_bool()= 0;
virtual my_decimal *val_decimal(my_decimal *)=0;
inline String *val_str(String *str) { return val_str(str, str); }
/*
@@ -877,7 +1029,7 @@ public:
str_needs_quotes() returns TRUE if the value returned by val_str() needs
to be quoted when used in constructing an SQL query.
*/
- virtual bool str_needs_quotes() { return FALSE; }
+ virtual bool str_needs_quotes() const { return false; }
const Type_handler *type_handler_for_comparison() const
{
return type_handler()->type_handler_for_comparison();
@@ -910,36 +1062,27 @@ public:
table, which is located on disk).
*/
virtual uint32 pack_length_in_rec() const { return pack_length(); }
- virtual bool compatible_field_size(uint metadata, Relay_log_info *rli,
- uint16 mflags, int *order);
- virtual uint pack_length_from_metadata(uint field_metadata)
+ virtual bool compatible_field_size(uint metadata, const Relay_log_info *rli,
+ uint16 mflags, int *order) const;
+ virtual uint pack_length_from_metadata(uint field_metadata) const
{
DBUG_ENTER("Field::pack_length_from_metadata");
DBUG_RETURN(field_metadata);
}
virtual uint row_pack_length() const { return 0; }
-
- /**
- Retrieve the field metadata for fields.
-
- This default implementation returns 0 and saves 0 in the first_byte value.
-
- @param first_byte First byte of field metadata
-
- @returns 0 no bytes written.
- */
-
- virtual int save_field_metadata(uchar *first_byte)
- { return 0; }
-
-
/*
data_length() return the "real size" of the data in memory.
*/
virtual uint32 data_length() { return pack_length(); }
virtual uint32 sort_length() const { return pack_length(); }
+ /*
+ sort_suffix_length() return the length bytes needed to store the length
+ for binary charset
+ */
+ virtual uint32 sort_suffix_length() const { return 0; }
+
/*
Get the number bytes occupied by the value in the field.
CHAR values are stripped of trailing spaces.
@@ -970,7 +1113,7 @@ public:
return pack_length();
};
- virtual int reset(void) { bzero(ptr,pack_length()); return 0; }
+ virtual int reset() { bzero(ptr,pack_length()); return 0; }
virtual void reset_fields() {}
const uchar *ptr_in_record(const uchar *record) const
{
@@ -1016,6 +1159,8 @@ public:
virtual bool binary() const { return 1; }
virtual bool zero_pack() const { return 1; }
virtual enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
+ virtual uint16 key_part_flag() const { return 0; }
+ virtual uint16 key_part_length_bytes() const { return 0; }
virtual uint32 key_length() const { return pack_length(); }
virtual const Type_handler *type_handler() const= 0;
virtual enum_field_types type() const
@@ -1074,19 +1219,39 @@ public:
*/
return type();
}
+ virtual Binlog_type_info binlog_type_info() const
+ {
+ DBUG_ASSERT(Field::type() == binlog_type());
+ return Binlog_type_info(Field::type(), 0, 0);
+ }
+ virtual en_fieldtype tmp_engine_column_type(bool use_packed_rows) const
+ {
+ return FIELD_NORMAL;
+ }
+ /*
+ Conversion type for from the source to the current field.
+ */
+ virtual enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param)
+ const= 0;
+ enum_conv_type rpl_conv_type_from_same_data_type(uint16 metadata,
+ const Relay_log_info *rli,
+ const Conv_param &param)
+ const;
inline int cmp(const uchar *str) { return cmp(ptr,str); }
- virtual int cmp_max(const uchar *a, const uchar *b, uint max_len)
+ virtual int cmp_max(const uchar *a, const uchar *b, uint max_len) const
{ return cmp(a, b); }
- virtual int cmp(const uchar *,const uchar *)=0;
- virtual int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U)
+ virtual int cmp(const uchar *,const uchar *) const=0;
+ virtual int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U) const
{ return memcmp(a,b,pack_length()); }
virtual int cmp_offset(my_ptrdiff_t row_offset)
{ return cmp(ptr,ptr+row_offset); }
virtual int cmp_binary_offset(uint row_offset)
{ return cmp_binary(ptr, ptr+row_offset); };
- virtual int key_cmp(const uchar *a,const uchar *b)
+ virtual int key_cmp(const uchar *a,const uchar *b) const
{ return cmp(a, b); }
- virtual int key_cmp(const uchar *str, uint length)
+ virtual int key_cmp(const uchar *str, uint length) const
{ return cmp(ptr,str); }
/*
Update the value m of the 'min_val' field with the current value v
@@ -1133,6 +1298,8 @@ public:
{
return Information_schema_character_attributes();
}
+ virtual void update_data_type_statistics(Data_type_statistics *st) const
+ { }
/*
Caller beware: sql_type can change str.Ptr, so check
ptr() to see if it changed if you are using your own buffer
@@ -1184,7 +1351,7 @@ public:
void load_data_set_value(const char *pos, uint length, CHARSET_INFO *cs);
/* @return true if this field is NULL-able (even if temporarily) */
- inline bool real_maybe_null(void) const { return null_ptr != 0; }
+ inline bool real_maybe_null() const { return null_ptr != 0; }
uint null_offset(const uchar *record) const
{ return (uint) (null_ptr - record); }
/*
@@ -1202,7 +1369,7 @@ public:
void set_null_ptr(uchar *p_null_ptr, uint p_null_bit)
{
null_ptr= p_null_ptr;
- null_bit= p_null_bit;
+ null_bit= static_cast<uchar>(p_null_bit);
}
bool stored_in_db() const { return !vcol_info || vcol_info->stored_in_db; }
@@ -1251,7 +1418,18 @@ public:
return bytes;
}
- void make_sort_key(uchar *buff, uint length);
+ /*
+ Create mem-comparable sort key part for a sort key
+ */
+ void make_sort_key_part(uchar *buff, uint length);
+
+ /*
+ create a compact sort key which can be compared with a comparison
+ function. They are called packed sort keys
+ */
+ virtual uint make_packed_sort_key_part(uchar *buff,
+ const SORT_FIELD_ATTR *sort_field);
+
virtual void make_send_field(Send_field *);
virtual void sort_string(uchar *buff,uint length)=0;
virtual bool optimize_range(uint idx, uint part) const;
@@ -1368,6 +1546,7 @@ public:
{ return length;}
virtual uint max_packed_col_length(uint max_length)
{ return max_length;}
+ virtual bool is_packable() const { return false; }
uint offset(const uchar *record) const
{
@@ -1376,15 +1555,13 @@ public:
void copy_from_tmp(int offset);
uint fill_cache_field(struct st_cache_field *copy);
virtual bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
- virtual TYPELIB *get_typelib() const { return NULL; }
- virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; }
+ virtual const TYPELIB *get_typelib() const { return NULL; }
+ virtual CHARSET_INFO *charset() const= 0;
+ virtual const DTCollation &dtcollation() const= 0;
virtual CHARSET_INFO *charset_for_protocol(void) const
{ return binary() ? &my_charset_bin : charset(); }
virtual CHARSET_INFO *sort_charset(void) const { return charset(); }
virtual bool has_charset(void) const { return FALSE; }
- virtual enum Derivation derivation(void) const
- { return DERIVATION_IMPLICIT; }
- virtual uint repertoire(void) const { return MY_REPERTOIRE_UNICODE30; }
virtual int set_time() { return 1; }
bool set_warning(Sql_condition::enum_warning_level, unsigned int code,
int cuted_increment, ulong current_row=0) const;
@@ -1536,12 +1713,6 @@ public:
{
return field_length / charset()->mbmaxlen;
}
- virtual geometry_type get_geometry_type() const
- {
- /* shouldn't get here. */
- DBUG_ASSERT(0);
- return GEOM_GEOMETRY;
- }
ha_storage_media field_storage_type() const
{
@@ -1778,6 +1949,11 @@ protected:
void prepend_zeros(String *value) const;
Item *get_equal_zerofill_const_item(THD *thd, const Context &ctx,
Item *const_item);
+ Binlog_type_info::binlog_sign_t binlog_signedness() const
+ {
+ return (flags & UNSIGNED_FLAG) ? Binlog_type_info::SIGN_UNSIGNED :
+ Binlog_type_info::SIGN_SIGNED;
+ }
public:
const uint8 dec;
bool zerofill,unsigned_flag; // Purify cannot handle bit fields
@@ -1785,11 +1961,17 @@ public:
uchar null_bit_arg, utype unireg_check_arg,
const LEX_CSTRING *field_name_arg,
uint8 dec_arg, bool zero_arg, bool unsigned_arg);
- enum Derivation derivation(void) const { return DERIVATION_NUMERIC; }
- uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; }
- CHARSET_INFO *charset(void) const { return &my_charset_numeric; }
- sql_mode_t can_handle_sql_mode_dependency_on_store() const;
+ CHARSET_INFO *charset() const override
+ {
+ return DTCollation_numeric::singleton().collation;
+ }
+ const DTCollation &dtcollation() const override
+ {
+ return DTCollation_numeric::singleton();
+ }
+ sql_mode_t can_handle_sql_mode_dependency_on_store() const override;
Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item)
+ override
{
return (flags & ZEROFILL_FLAG) ?
get_equal_zerofill_const_item(thd, ctx, const_item) :
@@ -1797,94 +1979,111 @@ public:
}
void add_zerofill_and_unsigned(String &res) const;
friend class Create_field;
- void make_send_field(Send_field *);
- uint decimals() const { return (uint) dec; }
- uint size_of() const { return sizeof(*this); }
- bool eq_def(const Field *field) const;
- Copy_func *get_copy_func(const Field *from) const
+ void make_send_field(Send_field *) override;
+ uint decimals() const override { return (uint) dec; }
+ uint size_of() const override { return sizeof(*this); }
+ bool eq_def(const Field *field) const override;
+ Copy_func *get_copy_func(const Field *from) const override
{
if (unsigned_flag && from->cmp_type() == DECIMAL_RESULT)
return do_field_decimal;
return do_field_int;
}
- int save_in_field(Field *to)
+ int save_in_field(Field *to) override
{
return to->store(val_int(), MY_TEST(flags & UNSIGNED_FLAG));
}
- bool is_equal(const Column_definition &new_field) const;
- uint row_pack_length() const { return pack_length(); }
- uint32 pack_length_from_metadata(uint field_metadata) {
+ bool is_equal(const Column_definition &new_field) const override;
+ uint row_pack_length() const override { return pack_length(); }
+ uint32 pack_length_from_metadata(uint field_metadata) const override
+ {
uint32 length= pack_length();
DBUG_PRINT("result", ("pack_length_from_metadata(%d): %u",
field_metadata, length));
return length;
}
- double pos_in_interval(Field *min, Field *max)
+ double pos_in_interval(Field *min, Field *max) override
{
return pos_in_interval_val_real(min, max);
}
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
const Item_bool_func *cond,
- scalar_comparison_op op, Item *value);
+ scalar_comparison_op op, Item *value) override;
+ Binlog_type_info binlog_type_info() const override
+ {
+ DBUG_ASSERT(Field_num::type() == binlog_type());
+ return Binlog_type_info(Field_num::type(), 0, 0, binlog_signedness());
+ }
};
class Field_str :public Field {
protected:
- // TODO-10.2: Reuse DTCollation instead of these three members
- CHARSET_INFO *field_charset;
- enum Derivation field_derivation;
- uint field_repertoire;
+ DTCollation m_collation;
+ // A short alias for m_collation.collation with non-virtual linkage
+ const CHARSET_INFO *field_charset() const { return m_collation.collation; }
+ uint mbmaxlen() const { return m_collation.collation->mbmaxlen; }
public:
bool can_be_substituted_to_equal_item(const Context &ctx,
- const Item_equal *item_equal);
+ const Item_equal *item_equal) override;
Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
const LEX_CSTRING *field_name_arg,
const DTCollation &collation);
- uint decimals() const { return NOT_FIXED_DEC; }
- int save_in_field(Field *to) { return save_in_field_str(to); }
- bool memcpy_field_possible(const Field *from) const
+ uint decimals() const override { return NOT_FIXED_DEC; }
+ int save_in_field(Field *to) override { return save_in_field_str(to); }
+ bool memcpy_field_possible(const Field *from) const override
{
return real_type() == from->real_type() &&
pack_length() == from->pack_length() &&
charset() == from->charset();
}
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- int store_decimal(const my_decimal *);
- int store(const char *to,size_t length,CHARSET_INFO *cs)=0;
- int store_hex_hybrid(const char *str, size_t length)
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ int store_decimal(const my_decimal *) override;
+ int store(const char *to,size_t length,CHARSET_INFO *cs) override=0;
+ int store_hex_hybrid(const char *str, size_t length) override
{
return store(str, length, &my_charset_bin);
}
- uint repertoire(void) const { return field_repertoire; }
- CHARSET_INFO *charset(void) const { return field_charset; }
- enum Derivation derivation(void) const { return field_derivation; }
- bool binary() const { return field_charset == &my_charset_bin; }
- uint32 max_display_length() const { return field_length; }
- uint32 character_octet_length() const { return field_length; }
- uint32 char_length() const { return field_length / field_charset->mbmaxlen; }
+ CHARSET_INFO *charset() const override { return m_collation.collation; }
+ const DTCollation &dtcollation() const override
+ {
+ return m_collation;
+ }
+ bool binary() const override { return field_charset() == &my_charset_bin; }
+ uint32 max_display_length() const override { return field_length; }
+ uint32 character_octet_length() const override { return field_length; }
+ uint32 char_length() const override
+ {
+ return field_length / mbmaxlen();
+ }
Information_schema_character_attributes
- information_schema_character_attributes() const
+ information_schema_character_attributes() const override
{
return Information_schema_character_attributes(max_display_length(),
char_length());
}
friend class Create_field;
- my_decimal *val_decimal(my_decimal *);
- bool val_bool() { return val_real() != 0e0; }
- virtual bool str_needs_quotes() { return TRUE; }
- bool eq_cmp_as_binary() { return MY_TEST(flags & BINARY_FLAG); }
+ my_decimal *val_decimal(my_decimal *) override;
+ bool val_bool() override { return val_real() != 0e0; }
+ bool str_needs_quotes() const override { return true; }
+ bool eq_cmp_as_binary() override { return MY_TEST(flags & BINARY_FLAG); }
virtual uint length_size() const { return 0; }
- double pos_in_interval(Field *min, Field *max)
+ double pos_in_interval(Field *min, Field *max) override
{
return pos_in_interval_val_str(min, max, length_size());
}
- bool test_if_equality_guarantees_uniqueness(const Item *const_item) const;
+ bool test_if_equality_guarantees_uniqueness(const Item *const_item) const
+ override;
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
const Item_bool_func *cond,
- scalar_comparison_op op, Item *value);
+ scalar_comparison_op op, Item *value) override;
+ Binlog_type_info binlog_type_info() const override
+ {
+ DBUG_ASSERT(Field_str::type() == binlog_type());
+ return Binlog_type_info(Field_str::type(), 0, 0, charset());
+ }
};
/* base class for Field_string, Field_varstring and Field_blob */
@@ -1913,7 +2112,7 @@ protected:
{
String_copier copier;
- *copy_length= copier.well_formed_copy(field_charset, to, to_length,
+ *copy_length= copier.well_formed_copy(field_charset(), to, to_length,
from_cs, from, from_length,
nchars);
@@ -1929,7 +2128,7 @@ protected:
uint *out_length,
CHARSET_INFO *cs, size_t nchars);
String *uncompress(String *val_buffer, String *val_ptr,
- const uchar *from, uint from_length);
+ const uchar *from, uint from_length) const;
public:
Field_longstr(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
@@ -1938,11 +2137,14 @@ public:
:Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
field_name_arg, collation)
{}
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
+ int store_decimal(const my_decimal *d) override;
+ uint32 max_data_length() const override;
+ void make_send_field(Send_field *) override;
- int store_decimal(const my_decimal *d);
- uint32 max_data_length() const;
-
- bool is_varchar_and_in_write_set() const
+ bool is_varchar_and_in_write_set() const override
{
DBUG_ASSERT(table && table->write_set);
return bitmap_is_set(table->write_set, field_index);
@@ -1950,14 +2152,18 @@ public:
bool match_collation_to_optimize_range() const { return true; }
bool can_optimize_keypart_ref(const Item_bool_func *cond,
- const Item *item) const;
+ const Item *item) const override;
bool can_optimize_hash_join(const Item_bool_func *cond,
- const Item *item) const;
+ const Item *item) const override;
bool can_optimize_group_min_max(const Item_bool_func *cond,
- const Item *const_item) const;
+ const Item *const_item) const override;
bool can_optimize_range(const Item_bool_func *cond,
const Item *item,
- bool is_eq_func) const;
+ bool is_eq_func) const override;
+ bool is_packable() const override { return true; }
+ uint make_packed_sort_key_part(uchar *buff,
+ const SORT_FIELD_ATTR *sort_field)override;
+ uchar* pack_sort_string(uchar *to, const SORT_FIELD_ATTR *sort_field);
};
/* base class for float and double and decimal (old one) */
@@ -1975,19 +2181,23 @@ public:
field_name_arg, dec_arg, zero_arg, unsigned_arg),
not_fixed(dec_arg >= FLOATING_POINT_DECIMALS)
{}
- Copy_func *get_copy_func(const Field *from) const
+ Copy_func *get_copy_func(const Field *from) const override
{
return do_field_real;
}
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
Information_schema_numeric_attributes
- information_schema_numeric_attributes() const
+ information_schema_numeric_attributes() const override
{
return dec == NOT_FIXED_DEC ?
Information_schema_numeric_attributes(field_length) :
Information_schema_numeric_attributes(field_length, dec);
}
- int save_in_field(Field *to) { return to->store(val_real()); }
- bool memcpy_field_possible(const Field *from) const
+ void sql_type(String &str) const override;
+ int save_in_field(Field *to) override { return to->store(val_real()); }
+ bool memcpy_field_possible(const Field *from) const override
{
/*
Cannot do memcpy from a longer field to a shorter field,
@@ -2000,14 +2210,16 @@ public:
decimals() == from->decimals() &&
field_length >= from->field_length;
}
- 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, 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; }
- uint size_of() const { return sizeof(*this); }
- Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item);
+ int store_decimal(const my_decimal *dec) override
+ { return store(dec->to_double()); }
+ int store_time_dec(const MYSQL_TIME *ltime, uint dec) override;
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override;
+ my_decimal *val_decimal(my_decimal *) override;
+ bool val_bool() override { return val_real() != 0e0; }
+ uint32 max_display_length() const override { return field_length; }
+ uint size_of() const override { return sizeof *this; }
+ Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item)
+ override;
};
@@ -2021,33 +2233,35 @@ public:
unireg_check_arg, field_name_arg,
dec_arg, zero_arg, unsigned_arg)
{}
- Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type);
- const Type_handler *type_handler() const { return &type_handler_olddecimal; }
- enum ha_base_keytype key_type() const
+ Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type)
+ override;
+ const Type_handler *type_handler() const override
+ { return &type_handler_olddecimal; }
+ enum ha_base_keytype key_type() const override
{ return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; }
Information_schema_numeric_attributes
- information_schema_numeric_attributes() const
+ information_schema_numeric_attributes() const override
{
uint tmp= dec ? 2 : 1; // The sign and the decimal point
return Information_schema_numeric_attributes(field_length - tmp, dec);
}
- Copy_func *get_copy_func(const Field *from) const
+ Copy_func *get_copy_func(const Field *from) const override
{
return eq_def(from) ? get_identical_copy_func() : do_field_string;
}
- int reset(void);
- int store(const char *to,size_t length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
+ int reset() override;
+ int store(const char *to,size_t length,CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ double val_real() override;
+ longlong val_int() override;
+ String *val_str(String *, String *) override;
+ int cmp(const uchar *,const uchar *) const override;
+ void sort_string(uchar *buff,uint length) override;
void overflow(bool negative);
- bool zero_pack() const { return 0; }
- void sql_type(String &str) const;
- virtual uchar *pack(uchar* to, const uchar *from, uint max_length)
+ bool zero_pack() const override { return false; }
+ void sql_type(String &str) const override;
+ uchar *pack(uchar* to, const uchar *from, uint max_length) override
{
return Field::pack(to, from, max_length);
}
@@ -2056,8 +2270,6 @@ public:
/* New decimal/numeric field which use fixed point arithmetic */
class Field_new_decimal :public Field_num {
-private:
- int save_field_metadata(uchar *first_byte);
public:
/* The maximum number of decimal digits can be stored */
uint precision;
@@ -2073,20 +2285,21 @@ public:
enum utype unireg_check_arg,
const LEX_CSTRING *field_name_arg,
uint8 dec_arg, bool zero_arg, bool unsigned_arg);
- const Type_handler *type_handler() const { return &type_handler_newdecimal; }
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
- Copy_func *get_copy_func(const Field *from) const
+ const Type_handler *type_handler() const override
+ { return &type_handler_newdecimal; }
+ enum ha_base_keytype key_type() const override { return HA_KEYTYPE_BINARY; }
+ Copy_func *get_copy_func(const Field *from) const override
{
// if (from->real_type() == MYSQL_TYPE_BIT) // QQ: why?
// return do_field_int;
return do_field_decimal;
}
- int save_in_field(Field *to)
+ int save_in_field(Field *to) override
{
my_decimal tmp(ptr, precision, dec);
return to->store_decimal(&tmp);
}
- bool memcpy_field_possible(const Field *from) const
+ bool memcpy_field_possible(const Field *from) const override
{
return real_type() == from->real_type() &&
pack_length() == from->pack_length() &&
@@ -2094,63 +2307,69 @@ public:
decimals() == from->decimals() &&
field_length == from->field_length;
}
- int reset(void);
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
+ int reset() override;
bool store_value(const my_decimal *decimal_value);
bool store_value(const my_decimal *decimal_value, int *native_error);
void set_value_on_overflow(my_decimal *decimal_value, bool sign);
- 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)
+ int store(const char *to, size_t length, CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ int store_time_dec(const MYSQL_TIME *ltime, uint dec) override;
+ int store_decimal(const my_decimal *) override;
+ double val_real() override
{
return my_decimal(ptr, precision, dec).to_double();
}
- longlong val_int(void)
+ longlong val_int() override
{
return my_decimal(ptr, precision, dec).to_longlong(unsigned_flag);
}
- ulonglong val_uint(void)
+ ulonglong val_uint() override
{
return (ulonglong) my_decimal(ptr, precision, dec).to_longlong(true);
}
- my_decimal *val_decimal(my_decimal *);
- String *val_str(String *val_buffer, String *val_ptr __attribute__((unused)))
+ my_decimal *val_decimal(my_decimal *) override;
+ String *val_str(String *val_buffer, String *) override
{
uint fixed_precision= zerofill ? precision : 0;
return my_decimal(ptr, precision, dec).
to_string(val_buffer, fixed_precision, dec, '0');
}
- bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override
{
my_decimal nr(ptr, precision, dec);
return decimal_to_datetime_with_warn(get_thd(), &nr, ltime,
fuzzydate, table->s, field_name.str);
}
- bool val_bool()
+ bool val_bool() override
{
return my_decimal(ptr, precision, dec).to_bool();
}
- int cmp(const uchar *, const uchar *);
- void sort_string(uchar *buff, uint length);
- bool zero_pack() const { return 0; }
- void sql_type(String &str) const;
- uint32 max_display_length() const { return field_length; }
+ int cmp(const uchar *, const uchar *) const override;
+ void sort_string(uchar *buff, uint length) override;
+ bool zero_pack() const override { return false; }
+ void sql_type(String &str) const override;
+ uint32 max_display_length() const override { return field_length; }
Information_schema_numeric_attributes
- information_schema_numeric_attributes() const
+ information_schema_numeric_attributes() const override
{
return Information_schema_numeric_attributes(precision, dec);
}
- uint size_of() const { return sizeof(*this); }
- uint32 pack_length() const { return (uint32) bin_size; }
- uint pack_length_from_metadata(uint field_metadata);
- uint row_pack_length() const { return pack_length(); }
- bool compatible_field_size(uint field_metadata, Relay_log_info *rli,
- uint16 mflags, int *order_var);
- bool is_equal(const Column_definition &new_field) const;
- virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data);
- Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item);
+ uint size_of() const override { return sizeof *this; }
+ uint32 pack_length() const override { return (uint32) bin_size; }
+ uint pack_length_from_metadata(uint field_metadata) const override;
+ uint row_pack_length() const override { return pack_length(); }
+ bool compatible_field_size(uint field_metadata, const Relay_log_info *rli,
+ uint16 mflags, int *order_var) const override;
+ bool is_equal(const Column_definition &new_field) const override;
+ const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
+ uint param_data) override;
+ Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item)
+ override;
+ Binlog_type_info binlog_type_info() const override;
};
@@ -2166,28 +2385,31 @@ public:
:Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, 0, zero_arg, unsigned_arg)
{}
- bool memcpy_field_possible(const Field *from) const
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
+ bool memcpy_field_possible(const Field *from) const override
{
return real_type() == from->real_type() &&
pack_length() == from->pack_length() &&
is_unsigned() == from->is_unsigned();
}
- int store_decimal(const my_decimal *);
- my_decimal *val_decimal(my_decimal *);
- bool val_bool() { return val_int() != 0; }
- ulonglong val_uint()
+ int store_decimal(const my_decimal *) override;
+ my_decimal *val_decimal(my_decimal *) override;
+ bool val_bool() override { return val_int() != 0; }
+ ulonglong val_uint() override
{
longlong nr= val_int();
return nr < 0 && !unsigned_flag ? 0 : (ulonglong) nr;
}
- int store_time_dec(const MYSQL_TIME *ltime, uint dec);
- bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ int store_time_dec(const MYSQL_TIME *ltime, uint dec) override;
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override;
virtual const Type_limits_int *type_limits_int() const= 0;
- uint32 max_display_length() const
+ uint32 max_display_length() const override
{
return type_limits_int()->char_length();
}
- Type_std_attributes type_std_attributes() const
+ Type_numeric_attributes type_numeric_attributes() const override
{
/*
For integer data types, the user-specified length does not constrain the
@@ -2201,19 +2423,19 @@ public:
*/
uint32 length1= max_display_length();
uint32 length2= field_length;
- return Type_std_attributes(MY_MAX(length1, length2), decimals(),
- MY_TEST(flags & UNSIGNED_FLAG),
- dtcollation());
+ return Type_numeric_attributes(MY_MAX(length1, length2),
+ decimals(), is_unsigned());
}
Information_schema_numeric_attributes
- information_schema_numeric_attributes() const
+ information_schema_numeric_attributes() const override
{
uint32 prec= type_limits_int()->precision();
return Information_schema_numeric_attributes(prec, 0);
}
+ void sql_type(String &str) const override;
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
const Item_bool_func *cond,
- scalar_comparison_op op, Item *value)
+ scalar_comparison_op op, Item *value) override
{
return get_mm_leaf_int(param, key_part, cond, op, value, unsigned_flag);
}
@@ -2222,6 +2444,12 @@ public:
class Field_tiny :public Field_int
{
+ const Type_handler_general_purpose_int *type_handler_priv() const
+ {
+ if (is_unsigned())
+ return &type_handler_utiny;
+ return &type_handler_stiny;
+ }
public:
Field_tiny(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
@@ -2230,41 +2458,41 @@ public:
:Field_int(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, zero_arg, unsigned_arg)
{}
- const Type_handler *type_handler() const { return &type_handler_tiny; }
- enum ha_base_keytype key_type() const
+ const Type_handler *type_handler() const override
+ { return type_handler_priv(); }
+ enum ha_base_keytype key_type() const override
{ return unsigned_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_INT8; }
- int store(const char *to,size_t length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- int reset(void) { ptr[0]=0; return 0; }
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return 1; }
- void sql_type(String &str) const;
- const Type_limits_int *type_limits_int() const
+ int store(const char *to,size_t length,CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ int reset() override { ptr[0]=0; return 0; }
+ double val_real() override;
+ longlong val_int() override;
+ String *val_str(String *, String *) override;
+ bool send_binary(Protocol *protocol) override;
+ int cmp(const uchar *,const uchar *) const override;
+ void sort_string(uchar *buff,uint length) override;
+ uint32 pack_length() const override { return 1; }
+ const Type_limits_int *type_limits_int() const override
{
- return type_handler_tiny.type_limits_int_by_unsigned_flag(is_unsigned());
+ return type_handler_priv()->type_limits_int();
}
- virtual uchar *pack(uchar* to, const uchar *from, uint max_length)
+ uchar *pack(uchar* to, const uchar *from, uint max_length) override
{
*to= *from;
return to + 1;
}
- virtual const uchar *unpack(uchar* to, const uchar *from,
- const uchar *from_end, uint param_data)
+ const uchar *unpack(uchar* to, const uchar *from,
+ const uchar *from_end, uint param_data) override
{
if (from == from_end)
return 0;
*to= *from;
return from + 1;
}
- virtual ulonglong get_max_int_value() const
+ ulonglong get_max_int_value() const override
{
return unsigned_flag ? 0xFFULL : 0x7FULL;
}
@@ -2273,6 +2501,12 @@ public:
class Field_short :public Field_int
{
+ const Type_handler_general_purpose_int *type_handler_priv() const
+ {
+ if (is_unsigned())
+ return &type_handler_ushort;
+ return &type_handler_sshort;
+ }
public:
Field_short(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
@@ -2287,32 +2521,32 @@ public:
:Field_int((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg, 0, unsigned_arg)
{}
- const Type_handler *type_handler() const { return &type_handler_short; }
- enum ha_base_keytype key_type() const
+ const Type_handler *type_handler() const override
+ { return type_handler_priv(); }
+ enum ha_base_keytype key_type() const override
{ return unsigned_flag ? HA_KEYTYPE_USHORT_INT : HA_KEYTYPE_SHORT_INT;}
- int store(const char *to,size_t length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- int reset(void) { ptr[0]=ptr[1]=0; return 0; }
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return 2; }
- void sql_type(String &str) const;
- const Type_limits_int *type_limits_int() const
- {
- return type_handler_short.type_limits_int_by_unsigned_flag(is_unsigned());
- }
- virtual uchar *pack(uchar* to, const uchar *from, uint max_length)
+ int store(const char *to,size_t length,CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ int reset() override { ptr[0]=ptr[1]=0; return 0; }
+ double val_real() override;
+ longlong val_int() override;
+ String *val_str(String *, String *) override;
+ bool send_binary(Protocol *protocol) override;
+ int cmp(const uchar *,const uchar *) const override;
+ void sort_string(uchar *buff,uint length) override;
+ uint32 pack_length() const override { return 2; }
+ const Type_limits_int *type_limits_int() const override
+ {
+ return type_handler_priv()->type_limits_int();
+ }
+ uchar *pack(uchar* to, const uchar *from, uint) override
{ return pack_int16(to, from); }
- virtual const uchar *unpack(uchar* to, const uchar *from,
- const uchar *from_end, uint param_data)
+ const uchar *unpack(uchar* to, const uchar *from,
+ const uchar *from_end, uint) override
{ return unpack_int16(to, from, from_end); }
- virtual ulonglong get_max_int_value() const
+ ulonglong get_max_int_value() const override
{
return unsigned_flag ? 0xFFFFULL : 0x7FFFULL;
}
@@ -2320,6 +2554,12 @@ public:
class Field_medium :public Field_int
{
+ const Type_handler_general_purpose_int *type_handler_priv() const
+ {
+ if (is_unsigned())
+ return &type_handler_uint24;
+ return &type_handler_sint24;
+ }
public:
Field_medium(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
@@ -2328,30 +2568,30 @@ public:
:Field_int(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, zero_arg, unsigned_arg)
{}
- const Type_handler *type_handler() const { return &type_handler_int24; }
- enum ha_base_keytype key_type() const
+ const Type_handler *type_handler() const override
+ { return type_handler_priv(); }
+ enum ha_base_keytype key_type() const override
{ return unsigned_flag ? HA_KEYTYPE_UINT24 : HA_KEYTYPE_INT24; }
- int store(const char *to,size_t length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; }
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return 3; }
- void sql_type(String &str) const;
- const Type_limits_int *type_limits_int() const
- {
- return type_handler_int24.type_limits_int_by_unsigned_flag(is_unsigned());
- }
- virtual uchar *pack(uchar* to, const uchar *from, uint max_length)
+ int store(const char *to,size_t length,CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ int reset() override { ptr[0]=ptr[1]=ptr[2]=0; return 0; }
+ double val_real() override;
+ longlong val_int() override;
+ String *val_str(String *, String *) override;
+ bool send_binary(Protocol *protocol) override;
+ int cmp(const uchar *,const uchar *) const override;
+ void sort_string(uchar *buff,uint length) override;
+ uint32 pack_length() const override { return 3; }
+ const Type_limits_int *type_limits_int() const override
+ {
+ return type_handler_priv()->type_limits_int();
+ }
+ uchar *pack(uchar* to, const uchar *from, uint max_length) override
{
return Field::pack(to, from, max_length);
}
- virtual ulonglong get_max_int_value() const
+ ulonglong get_max_int_value() const override
{
return unsigned_flag ? 0xFFFFFFULL : 0x7FFFFFULL;
}
@@ -2360,6 +2600,12 @@ public:
class Field_long :public Field_int
{
+ const Type_handler_general_purpose_int *type_handler_priv() const
+ {
+ if (is_unsigned())
+ return &type_handler_ulong;
+ return &type_handler_slong;
+ }
public:
Field_long(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
@@ -2374,37 +2620,35 @@ public:
:Field_int((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg, 0, unsigned_arg)
{}
- const Type_handler *type_handler() const { return &type_handler_long; }
- enum ha_base_keytype key_type() const
+ const Type_handler *type_handler() const override
+ { return type_handler_priv(); }
+ enum ha_base_keytype key_type() const override
{ return unsigned_flag ? HA_KEYTYPE_ULONG_INT : HA_KEYTYPE_LONG_INT; }
- int store(const char *to,size_t length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; }
- double val_real(void);
- longlong val_int(void);
- bool send_binary(Protocol *protocol);
- String *val_str(String*,String *);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return 4; }
- void sql_type(String &str) const;
- const Type_limits_int *type_limits_int() const
- {
- return type_handler_long.type_limits_int_by_unsigned_flag(is_unsigned());
- }
- virtual uchar *pack(uchar* to, const uchar *from,
- uint max_length __attribute__((unused)))
+ int store(const char *to,size_t length,CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ int reset() override { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; }
+ double val_real() override;
+ longlong val_int() override;
+ bool send_binary(Protocol *protocol) override;
+ String *val_str(String *, String *) override;
+ int cmp(const uchar *,const uchar *) const override;
+ void sort_string(uchar *buff,uint length) override;
+ uint32 pack_length() const override { return 4; }
+ const Type_limits_int *type_limits_int() const override
+ {
+ return type_handler_priv()->type_limits_int();
+ }
+ uchar *pack(uchar* to, const uchar *from, uint) override
{
return pack_int32(to, from);
}
- virtual const uchar *unpack(uchar* to, const uchar *from,
- const uchar *from_end,
- uint param_data __attribute__((unused)))
+ const uchar *unpack(uchar* to, const uchar *from,
+ const uchar *from_end, uint) override
{
return unpack_int32(to, from, from_end);
}
- virtual ulonglong get_max_int_value() const
+ ulonglong get_max_int_value() const override
{
return unsigned_flag ? 0xFFFFFFFFULL : 0x7FFFFFFFULL;
}
@@ -2413,6 +2657,12 @@ public:
class Field_longlong :public Field_int
{
+ const Type_handler_general_purpose_int *type_handler_priv() const
+ {
+ if (is_unsigned())
+ return &type_handler_ulonglong;
+ return &type_handler_slonglong;
+ }
public:
Field_longlong(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
@@ -2427,42 +2677,41 @@ public:
:Field_int((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg, 0, unsigned_arg)
{}
- const Type_handler *type_handler() const { return &type_handler_longlong; }
- enum ha_base_keytype key_type() const
- { return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; }
- int store(const char *to,size_t length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- int reset(void)
+ const Type_handler *type_handler() const override
+ { return type_handler_priv(); }
+ enum ha_base_keytype key_type() const override
+ { return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; }
+ int store(const char *to,size_t length,CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ int reset() override
{
ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0;
return 0;
}
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return 8; }
- void sql_type(String &str) const;
- const Type_limits_int *type_limits_int() const
+ double val_real() override;
+ longlong val_int() override;
+ String *val_str(String *, String *) override;
+ bool send_binary(Protocol *protocol) override;
+ int cmp(const uchar *,const uchar *) const override;
+ void sort_string(uchar *buff,uint length) override;
+ uint32 pack_length() const override { return 8; }
+ const Type_limits_int *type_limits_int() const override
{
- return type_handler_longlong.type_limits_int_by_unsigned_flag(is_unsigned());
+ return type_handler_priv()->type_limits_int();
}
- virtual uchar *pack(uchar* to, const uchar *from,
- uint max_length __attribute__((unused)))
+ uchar *pack(uchar* to, const uchar *from, uint) override
{
return pack_int64(to, from);
}
const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
- uint param_data __attribute__((unused)))
+ uint) override
{
return unpack_int64(to, from, from_end);
}
- void set_max();
- bool is_max();
- virtual ulonglong get_max_int_value() const
+ void set_max() override;
+ bool is_max() override;
+ ulonglong get_max_int_value() const override
{
return unsigned_flag ? 0xFFFFFFFFFFFFFFFFULL : 0x7FFFFFFFFFFFFFFFULL;
}
@@ -2482,28 +2731,28 @@ public:
unsigned_arg),
cached(0)
{}
- const Type_handler *type_handler() const { return &type_handler_vers_trx_id; }
- uint size_of() const { return sizeof(*this); }
+ const Type_handler *type_handler() const override
+ { return &type_handler_vers_trx_id; }
+ uint size_of() const override { return sizeof *this; }
bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate, ulonglong trx_id);
- bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override
{
return get_date(ltime, fuzzydate, (ulonglong) val_int());
}
- bool test_if_equality_guarantees_uniqueness(const Item *item) const;
- bool can_optimize_keypart_ref(const Item_bool_func *cond,
- const Item *item) const
+ bool test_if_equality_guarantees_uniqueness(const Item *item) const override;
+ bool can_optimize_keypart_ref(const Item_bool_func *, const Item *)
+ const override
{
return true;
}
- bool can_optimize_group_min_max(const Item_bool_func *cond,
- const Item *const_item) const
+ bool can_optimize_group_min_max(const Item_bool_func *, const Item *)
+ const override
{
return true;
}
- bool can_optimize_range(const Item_bool_func *cond,
- const Item *item,
- bool is_eq_func) const
+ bool can_optimize_range(const Item_bool_func *, const Item *, bool)
+ const override
{
return true;
}
@@ -2533,30 +2782,29 @@ public:
if (dec_arg >= FLOATING_POINT_DECIMALS)
dec_arg= NOT_FIXED_DEC;
}
- const Type_handler *type_handler() const { return &type_handler_float; }
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; }
- int store(const char *to,size_t length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- int reset(void) { bzero(ptr,sizeof(float)); return 0; }
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return sizeof(float); }
- uint row_pack_length() const { return pack_length(); }
- void sql_type(String &str) const;
- virtual ulonglong get_max_int_value() const
+ const Type_handler *type_handler() const override
+ { return &type_handler_float; }
+ enum ha_base_keytype key_type() const override { return HA_KEYTYPE_FLOAT; }
+ int store(const char *to,size_t length,CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ int reset() override { bzero(ptr,sizeof(float)); return 0; }
+ double val_real() override;
+ longlong val_int() override;
+ String *val_str(String *, String *) override;
+ bool send_binary(Protocol *protocol) override;
+ int cmp(const uchar *,const uchar *) const override;
+ void sort_string(uchar *buff, uint length) override;
+ uint32 pack_length() const override { return sizeof(float); }
+ uint row_pack_length() const override { return pack_length(); }
+ ulonglong get_max_int_value() const override
{
/*
We use the maximum as per IEEE754-2008 standard, 2^24
*/
return 0x1000000ULL;
}
-private:
- int save_field_metadata(uchar *first_byte);
+ Binlog_type_info binlog_type_info() const override;
};
@@ -2592,36 +2840,35 @@ public:
if (dec_arg >= FLOATING_POINT_DECIMALS)
dec_arg= NOT_FIXED_DEC;
}
- void init_for_tmp_table(Field *org_field, TABLE *new_table)
+ void init_for_tmp_table(Field *org_field, TABLE *new_table) override
{
Field::init_for_tmp_table(org_field, new_table);
not_fixed= true;
}
- const Type_handler *type_handler() const { return &type_handler_double; }
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; }
- int store(const char *to,size_t length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- int reset(void) { bzero(ptr,sizeof(double)); return 0; }
- double val_real(void);
- longlong val_int(void) { return val_int_from_real(false); }
- ulonglong val_uint(void) { return (ulonglong) val_int_from_real(true); }
- String *val_str(String*,String *);
- bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return sizeof(double); }
- uint row_pack_length() const { return pack_length(); }
- void sql_type(String &str) const;
- virtual ulonglong get_max_int_value() const
+ const Type_handler *type_handler() const override
+ { return &type_handler_double; }
+ enum ha_base_keytype key_type() const override { return HA_KEYTYPE_DOUBLE; }
+ int store(const char *to,size_t length,CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ int reset() override { bzero(ptr,sizeof(double)); return 0; }
+ double val_real() override;
+ longlong val_int() override { return val_int_from_real(false); }
+ ulonglong val_uint() override { return (ulonglong) val_int_from_real(true); }
+ String *val_str(String *, String *) override;
+ bool send_binary(Protocol *protocol) override;
+ int cmp(const uchar *,const uchar *) const override;
+ void sort_string(uchar *buff, uint length) override;
+ uint32 pack_length() const override { return sizeof(double); }
+ uint row_pack_length() const override { return pack_length(); }
+ ulonglong get_max_int_value() const override
{
/*
We use the maximum as per IEEE754-2008 standard, 2^53
*/
return 0x20000000000000ULL;
}
-private:
- int save_field_metadata(uchar *first_byte);
+ Binlog_type_info binlog_type_info() const override;
};
@@ -2636,43 +2883,47 @@ public:
:Field_str(ptr_arg, len_arg, null, 1,
unireg_check_arg, field_name_arg, collation)
{}
- const Type_handler *type_handler() const { return &type_handler_null; }
+ const Type_handler *type_handler() const override
+ { return &type_handler_null; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
Information_schema_character_attributes
- information_schema_character_attributes() const
+ information_schema_character_attributes() const override
{
return Information_schema_character_attributes();
}
- Copy_func *get_copy_func(const Field *from) const
+ Copy_func *get_copy_func(const Field *from) const override
{
return do_field_string;
}
- int store(const char *to, size_t length, CHARSET_INFO *cs)
+ int store(const char *to, size_t length, CHARSET_INFO *cs) override
{ null[0]=1; return 0; }
- int store(double nr) { null[0]=1; return 0; }
- int store(longlong nr, bool unsigned_val) { null[0]=1; return 0; }
- int store_decimal(const my_decimal *d) { null[0]=1; return 0; }
- int reset(void) { return 0; }
- double val_real(void) { return 0.0;}
- longlong val_int(void) { return 0;}
- bool val_bool(void) { return false; }
- my_decimal *val_decimal(my_decimal *) { return 0; }
- String *val_str(String *value,String *value2)
+ int store(double nr) override { null[0]=1; return 0; }
+ int store(longlong nr, bool unsigned_val) override { null[0]=1; return 0; }
+ int store_decimal(const my_decimal *d) override { null[0]=1; return 0; }
+ int reset() override { return 0; }
+ double val_real() override { return 0.0;}
+ longlong val_int() override { return 0;}
+ bool val_bool() override { return false; }
+ my_decimal *val_decimal(my_decimal *) override { return 0; }
+ String *val_str(String *value,String *value2) override
{ value2->length(0); return value2;}
- bool is_equal(const Column_definition &new_field) const;
- int cmp(const uchar *a, const uchar *b) { return 0;}
- void sort_string(uchar *buff, uint length) {}
- uint32 pack_length() const { return 0; }
- void sql_type(String &str) const;
- uint size_of() const { return sizeof(*this); }
- uint32 max_display_length() const { return 4; }
- void move_field_offset(my_ptrdiff_t ptr_diff) {}
+ bool is_equal(const Column_definition &new_field) const override;
+ int cmp(const uchar *a, const uchar *b) const override { return 0;}
+ void sort_string(uchar *buff, uint length) override {}
+ uint32 pack_length() const override { return 0; }
+ void sql_type(String &str) const override;
+ uint size_of() const override { return sizeof *this; }
+ uint32 max_display_length() const override { return 4; }
+ void move_field_offset(my_ptrdiff_t ptr_diff) override {}
bool can_optimize_keypart_ref(const Item_bool_func *cond,
- const Item *item) const
+ const Item *item) const override
{
return false;
}
bool can_optimize_group_min_max(const Item_bool_func *cond,
- const Item *const_item) const
+ const Item *const_item) const override
{
return false;
}
@@ -2712,6 +2963,22 @@ protected:
set_warnings(level, str, MYSQL_TIME_WARN_TRUNCATED, typestr);
return 1;
}
+ void sql_type_comment(String &str,
+ const Name &name,
+ const Name &comment) const;
+ void sql_type_dec_comment(String &str,
+ const Name &name, uint dec,
+ const Name &comment) const;
+ void sql_type_opt_dec_comment(String &str,
+ const Name &name, uint dec,
+ const Name &comment) const
+ {
+ if (dec)
+ sql_type_dec_comment(str, name, dec, comment);
+ else
+ sql_type_comment(str, name, comment);
+ }
+ static const Name &type_version_mysql56();
public:
Field_temporal(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
@@ -2719,13 +2986,13 @@ public:
:Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
field_name_arg)
{ flags|= BINARY_FLAG; }
- int store_hex_hybrid(const char *str, size_t length)
+ int store_hex_hybrid(const char *str, size_t length) override
{
return store(str, length, &my_charset_bin);
}
- sql_mode_t can_handle_sql_mode_dependency_on_store() const;
- Copy_func *get_copy_func(const Field *from) const;
- int save_in_field(Field *to)
+ sql_mode_t can_handle_sql_mode_dependency_on_store() const override;
+ Copy_func *get_copy_func(const Field *from) const override;
+ int save_in_field(Field *to) override
{
MYSQL_TIME ltime;
// For temporal types no truncation needed. Rounding mode is not important.
@@ -2733,38 +3000,43 @@ public:
return to->reset();
return to->store_time_dec(&ltime, decimals());
}
- bool memcpy_field_possible(const Field *from) const;
- uint32 max_display_length() const { return field_length; }
- bool str_needs_quotes() { return TRUE; }
- enum Derivation derivation(void) const { return DERIVATION_NUMERIC; }
- uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; }
- CHARSET_INFO *charset(void) const { return &my_charset_numeric; }
- CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; }
- bool binary() const { return true; }
- bool val_bool() { return val_real() != 0e0; }
- bool is_equal(const Column_definition &new_field) const;
- bool eq_def(const Field *field) const
+ bool memcpy_field_possible(const Field *from) const override;
+ uint32 max_display_length() const override { return field_length; }
+ bool str_needs_quotes() const override { return true; }
+ CHARSET_INFO *charset() const override
+ {
+ return DTCollation_numeric::singleton().collation;
+ }
+ const DTCollation &dtcollation() const override
+ {
+ return DTCollation_numeric::singleton();
+ }
+ CHARSET_INFO *sort_charset() const override { return &my_charset_bin; }
+ bool binary() const override { return true; }
+ bool val_bool() override { return val_real() != 0e0; }
+ bool is_equal(const Column_definition &new_field) const override;
+ bool eq_def(const Field *field) const override
{
return (Field::eq_def(field) && decimals() == field->decimals());
}
- my_decimal *val_decimal(my_decimal*);
- double pos_in_interval(Field *min, Field *max)
+ my_decimal *val_decimal(my_decimal*) override;
+ double pos_in_interval(Field *min, Field *max) override
{
return pos_in_interval_val_real(min, max);
}
bool can_optimize_keypart_ref(const Item_bool_func *cond,
- const Item *item) const;
+ const Item *item) const override;
bool can_optimize_group_min_max(const Item_bool_func *cond,
- const Item *const_item) const;
+ const Item *const_item) const override;
bool can_optimize_range(const Item_bool_func *cond,
const Item *item,
- bool is_eq_func) const
+ bool is_eq_func) const override
{
return true;
}
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
const Item_bool_func *cond,
- scalar_comparison_op op, Item *value);
+ scalar_comparison_op op, Item *value) override;
};
@@ -2809,10 +3081,7 @@ class Field_timestamp :public Field_temporal {
protected:
int store_TIME_with_warning(THD *, const Datetime *,
const ErrConv *, int warn);
- virtual void store_TIMEVAL(const timeval &tv)
- {
- int4store(ptr, tv.tv_sec);
- }
+ virtual void store_TIMEVAL(const timeval &tv)= 0;
void store_TIMESTAMP(const Timestamp &ts)
{
store_TIMEVAL(ts.tv());
@@ -2824,33 +3093,23 @@ public:
enum utype unireg_check_arg,
const LEX_CSTRING *field_name_arg,
TABLE_SHARE *share);
- const Type_handler *type_handler() const { return &type_handler_timestamp; }
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
- Copy_func *get_copy_func(const Field *from) const;
- sql_mode_t conversion_depends_on_sql_mode(THD *, Item *) const;
- 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 *);
- int store_timestamp_dec(const timeval &ts, uint dec);
- int save_in_field(Field *to);
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return 4; }
- void sql_type(String &str) const;
- bool zero_pack() const { return 0; }
- int set_time();
- /* Get TIMESTAMP field value as seconds since begging of Unix Epoch */
- my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const;
- my_time_t get_timestamp(ulong *sec_part) const
- {
- return get_timestamp(ptr, sec_part);
- }
+ const Type_handler *type_handler() const override
+ { return &type_handler_timestamp; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
+ Copy_func *get_copy_func(const Field *from) const override;
+ sql_mode_t conversion_depends_on_sql_mode(THD *, Item *) const override;
+ int store(const char *to,size_t length,CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ int store_time_dec(const MYSQL_TIME *ltime, uint dec) override;
+ int store_decimal(const my_decimal *) override;
+ int store_timestamp_dec(const timeval &ts, uint dec) override;
+ int save_in_field(Field *to) override;
+ longlong val_int() override;
+ String *val_str(String *, String *) override;
+ bool zero_pack() const override { return false; }
/*
This method is used by storage/perfschema and
Item_func_now_local::save_in_field().
@@ -2861,27 +3120,63 @@ public:
time_round_mode_t mode= Datetime::default_round_mode(get_thd());
store_TIMESTAMP(Timestamp(ts, sec_part).round(decimals(), mode, &warn));
}
- bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
- int store_native(const Native &value);
- bool val_native(Native *to);
- uchar *pack(uchar *to, const uchar *from,
- uint max_length __attribute__((unused)))
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override;
+ int store_native(const Native &value) override;
+ bool validate_value_in_record(THD *thd, const uchar *record) const override;
+ Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item)
+ override
+ {
+ return get_equal_const_item_datetime(thd, ctx, const_item);
+ }
+ bool load_data_set_null(THD *thd) override;
+ bool load_data_set_no_data(THD *thd, bool fixed_format) override;
+};
+
+
+class Field_timestamp0 :public Field_timestamp
+{
+ void store_TIMEVAL(const timeval &tv) override
+ {
+ int4store(ptr, tv.tv_sec);
+ }
+public:
+ Field_timestamp0(uchar *ptr_arg, uint32 len_arg,
+ uchar *null_ptr_arg, uchar null_bit_arg,
+ enum utype unireg_check_arg,
+ const LEX_CSTRING *field_name_arg,
+ TABLE_SHARE *share)
+ :Field_timestamp(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, share)
+ { }
+ enum ha_base_keytype key_type() const override
+ { return HA_KEYTYPE_ULONG_INT; }
+ void sql_type(String &str) const override
+ {
+ sql_type_comment(str, Field_timestamp0::type_handler()->name(),
+ Type_handler::version_mariadb53());
+ }
+ double val_real() override
+ {
+ return (double) Field_timestamp0::val_int();
+ }
+ bool send_binary(Protocol *protocol) override;
+ int cmp(const uchar *,const uchar *) const override;
+ void sort_string(uchar *buff,uint length) override;
+ uint32 pack_length() const override { return 4; }
+ int set_time() override;
+ /* Get TIMESTAMP field value as seconds since begging of Unix Epoch */
+ my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const override;
+ bool val_native(Native *to) override;
+ uchar *pack(uchar *to, const uchar *from, uint) override
{
return pack_int32(to, from);
}
const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
- uint param_data __attribute__((unused)))
+ uint) override
{
return unpack_int32(to, from, from_end);
}
- bool validate_value_in_record(THD *thd, const uchar *record) const;
- Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item)
- {
- return get_equal_const_item_datetime(thd, ctx, const_item);
- }
- bool load_data_set_null(THD *thd);
- bool load_data_set_no_data(THD *thd, bool fixed_format);
- uint size_of() const { return sizeof(*this); }
+ uint size_of() const override { return sizeof *this; }
};
@@ -2906,23 +3201,23 @@ public:
{
DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
}
- uint decimals() const { return dec; }
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
- uchar *pack(uchar *to, const uchar *from, uint max_length)
+ uint decimals() const override { return dec; }
+ enum ha_base_keytype key_type() const override { return HA_KEYTYPE_BINARY; }
+ uchar *pack(uchar *to, const uchar *from, uint max_length) override
{ return Field::pack(to, from, max_length); }
const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
- uint param_data)
+ uint param_data) override
{ return Field::unpack(to, from, from_end, param_data); }
- void make_send_field(Send_field *field);
- void sort_string(uchar *to, uint length)
+ void make_send_field(Send_field *field) override;
+ void sort_string(uchar *to, uint length) override
{
DBUG_ASSERT(length == pack_length());
memcpy(to, ptr, length);
}
- bool send_binary(Protocol *protocol);
- double val_real(void);
- my_decimal* val_decimal(my_decimal*);
- int set_time();
+ bool send_binary(Protocol *protocol) override;
+ double val_real() override;
+ my_decimal* val_decimal(my_decimal*) override;
+ int set_time() override;
};
@@ -2931,7 +3226,7 @@ class Field_timestamp_hires :public Field_timestamp_with_dec {
{
return Type_handler_timestamp::sec_part_bytes(dec);
}
- void store_TIMEVAL(const timeval &tv);
+ void store_TIMEVAL(const timeval &tv) override;
public:
Field_timestamp_hires(uchar *ptr_arg,
uchar *null_ptr_arg, uchar null_bit_arg,
@@ -2943,11 +3238,16 @@ public:
{
DBUG_ASSERT(dec);
}
- bool val_native(Native *to);
- my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const;
- int cmp(const uchar *,const uchar *);
- uint32 pack_length() const { return 4 + sec_part_bytes(dec); }
- uint size_of() const { return sizeof(*this); }
+ void sql_type(String &str) const override
+ {
+ sql_type_dec_comment(str, Field_timestamp_hires::type_handler()->name(),
+ dec, Type_handler::version_mariadb53());
+ }
+ bool val_native(Native *to) override;
+ my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const override;
+ int cmp(const uchar *,const uchar *) const override;
+ uint32 pack_length() const override { return 4 + sec_part_bytes(dec); }
+ uint size_of() const override { return sizeof *this; }
};
@@ -2955,12 +3255,7 @@ public:
TIMESTAMP(0..6) - MySQL56 version
*/
class Field_timestampf :public Field_timestamp_with_dec {
- int save_field_metadata(uchar *metadata_ptr)
- {
- *metadata_ptr= (uchar) decimals();
- return 1;
- }
- void store_TIMEVAL(const timeval &tv);
+ void store_TIMEVAL(const timeval &tv) override;
public:
Field_timestampf(uchar *ptr_arg,
uchar *null_ptr_arg, uchar null_bit_arg,
@@ -2970,32 +3265,40 @@ public:
Field_timestamp_with_dec(ptr_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, share, dec_arg)
{}
- const Type_handler *type_handler() const { return &type_handler_timestamp2; }
- enum_field_types binlog_type() const { return MYSQL_TYPE_TIMESTAMP2; }
- uint32 pack_length() const
+ const Type_handler *type_handler() const override
+ { return &type_handler_timestamp2; }
+ enum_field_types binlog_type() const override
+ { return MYSQL_TYPE_TIMESTAMP2; }
+ void sql_type(String &str) const override
+ {
+ sql_type_opt_dec_comment(str, Field_timestampf::type_handler()->name(),
+ dec, type_version_mysql56());
+
+ }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
+ uint32 pack_length() const override
{
return my_timestamp_binary_length(dec);
}
- uint row_pack_length() const { return pack_length(); }
- uint pack_length_from_metadata(uint field_metadata)
+ uint row_pack_length() const override { return pack_length(); }
+ uint pack_length_from_metadata(uint field_metadata) const override
{
DBUG_ENTER("Field_timestampf::pack_length_from_metadata");
uint tmp= my_timestamp_binary_length(field_metadata);
DBUG_RETURN(tmp);
}
- int cmp(const uchar *a_ptr,const uchar *b_ptr)
+ int cmp(const uchar *a_ptr,const uchar *b_ptr) const override
{
return memcmp(a_ptr, b_ptr, pack_length());
}
- void set_max();
- bool is_max();
- my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const;
- my_time_t get_timestamp(ulong *sec_part) const
- {
- return get_timestamp(ptr, sec_part);
- }
- bool val_native(Native *to);
- uint size_of() const { return sizeof(*this); }
+ void set_max() override;
+ bool is_max() override;
+ my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const override;
+ bool val_native(Native *to) override;
+ uint size_of() const override { return sizeof *this; }
+ Binlog_type_info binlog_type_info() const override;
};
@@ -3007,11 +3310,14 @@ public:
:Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, 1, 1)
{}
- const Type_handler *type_handler() const
+ const Type_handler *type_handler() const override
{
return field_length == 2 ? &type_handler_year2 : &type_handler_year;
}
- Copy_func *get_copy_func(const Field *from) const
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
+ Copy_func *get_copy_func(const Field *from) const override
{
if (eq_def(from))
return get_identical_copy_func();
@@ -3038,22 +3344,22 @@ public:
}
return do_field_int;
}
- 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);
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
- bool send_binary(Protocol *protocol);
+ int store(const char *to,size_t length,CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ int store_time_dec(const MYSQL_TIME *ltime, uint dec) override;
+ double val_real() override;
+ longlong val_int() override;
+ String *val_str(String *, String *) override;
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override;
+ bool send_binary(Protocol *protocol) override;
Information_schema_numeric_attributes
- information_schema_numeric_attributes() const
+ information_schema_numeric_attributes() const override
{
return Information_schema_numeric_attributes();
}
- uint32 max_display_length() const { return field_length; }
- void sql_type(String &str) const;
+ uint32 max_display_length() const override { return field_length; }
+ void sql_type(String &str) const override;
};
@@ -3070,79 +3376,90 @@ public:
null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg)
{}
- Copy_func *get_copy_func(const Field *from) const;
+ Copy_func *get_copy_func(const Field *from) const override;
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 *);
+ scalar_comparison_op op, Item *value) override;
+ int store(const char *to, size_t length, CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ int store_time_dec(const MYSQL_TIME *ltime, uint dec) override;
+ int store_decimal(const my_decimal *) override;
};
class Field_date :public Field_date_common
{
- void store_TIME(const MYSQL_TIME *ltime);
- bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate) const;
+ void store_TIME(const MYSQL_TIME *ltime) override;
+ bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate)
+ const override;
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)
:Field_date_common(ptr_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg) {}
- 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, date_mode_t fuzzydate)
+ const Type_handler *type_handler() const override
+ { return &type_handler_date; }
+ enum ha_base_keytype key_type() const override
+ { return HA_KEYTYPE_ULONG_INT; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
+ int reset() override { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; }
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override
{ return Field_date::get_TIME(ltime, ptr, fuzzydate); }
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return 4; }
- void sql_type(String &str) const;
- uchar *pack(uchar* to, const uchar *from,
- uint max_length __attribute__((unused)))
+ double val_real() override;
+ longlong val_int() override;
+ String *val_str(String *, String *) override;
+ bool send_binary(Protocol *protocol) override;
+ int cmp(const uchar *,const uchar *) const override;
+ void sort_string(uchar *buff,uint length) override;
+ uint32 pack_length() const override { return 4; }
+ void sql_type(String &str) const override;
+ uchar *pack(uchar* to, const uchar *from, uint) override
{
return pack_int32(to, from);
}
const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
- uint param_data __attribute__((unused)))
+ uint) override
{
return unpack_int32(to, from, from_end);
}
- uint size_of() const { return sizeof(*this); }
+ uint size_of() const override { return sizeof *this; }
};
class Field_newdate :public Field_date_common
{
- void store_TIME(const MYSQL_TIME *ltime);
- bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate) const;
+ void store_TIME(const MYSQL_TIME *ltime) override;
+ bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate)
+ const override;
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)
:Field_date_common(ptr_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg)
{}
- const Type_handler *type_handler() const { return &type_handler_newdate; }
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; }
- int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; }
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- 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, date_mode_t fuzzydate)
+ const Type_handler *type_handler() const override
+ { return &type_handler_newdate; }
+ enum ha_base_keytype key_type() const override { return HA_KEYTYPE_UINT24; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
+ int reset() override { ptr[0]=ptr[1]=ptr[2]=0; return 0; }
+ double val_real() override;
+ longlong val_int() override;
+ String *val_str(String *, String *) override;
+ bool send_binary(Protocol *protocol) override;
+ int cmp(const uchar *,const uchar *) const override;
+ void sort_string(uchar *buff,uint length) override;
+ uint32 pack_length() const override { return 3; }
+ void sql_type(String &str) const override;
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override
{ 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);
+ uint size_of() const override { return sizeof *this; }
+ Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item)
+ override;
};
@@ -3154,11 +3471,8 @@ class Field_time :public Field_temporal {
*/
long curdays;
protected:
- virtual void store_TIME(const MYSQL_TIME *ltime);
- void store_TIME(const Time &t)
- {
- return store_TIME(t.get_mysql_time());
- }
+ virtual void store_TIME(const MYSQL_TIME *ltime)= 0;
+ void store_TIME(const Time &t) { return store_TIME(t.get_mysql_time()); }
int store_TIME_with_warning(const Time *ltime, const ErrConv *str, int warn);
bool check_zero_in_date_with_warn(date_mode_t fuzzydate);
static void do_field_time(Copy_field *copy);
@@ -3170,10 +3484,13 @@ public:
unireg_check_arg, field_name_arg), curdays(0)
{}
bool can_be_substituted_to_equal_item(const Context &ctx,
- const Item_equal *item_equal);
- const Type_handler *type_handler() const { return &type_handler_time; }
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; }
- Copy_func *get_copy_func(const Field *from) const
+ const Item_equal *item_equal) override;
+ const Type_handler *type_handler() const override
+ { return &type_handler_time; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
+ Copy_func *get_copy_func(const Field *from) const override
{
return from->cmp_type() == REAL_RESULT ? do_field_string : // MDEV-9344
from->type() == MYSQL_TYPE_YEAR ? do_field_int :
@@ -3181,32 +3498,52 @@ public:
eq_def(from) ? get_identical_copy_func() :
do_field_time;
}
- bool memcpy_field_possible(const Field *from) const
+ bool memcpy_field_possible(const Field *from) const override
{
return real_type() == from->real_type() &&
decimals() == from->decimals();
}
- sql_mode_t conversion_depends_on_sql_mode(THD *, Item *) const;
- int store_time_dec(const MYSQL_TIME *ltime, uint dec);
- int store(const char *to,size_t length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- int store_decimal(const my_decimal *);
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- 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);
- uint32 pack_length() const { return 3; }
- void sql_type(String &str) const;
- uint size_of() const { return sizeof(*this); }
+ sql_mode_t conversion_depends_on_sql_mode(THD *, Item *) const override;
+ int store_time_dec(const MYSQL_TIME *ltime, uint dec) override;
+ int store(const char *to,size_t length,CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ int store_decimal(const my_decimal *) override;
+ String *val_str(String *, String *) override;
+ bool send_binary(Protocol *protocol) override;
void set_curdays(THD *thd);
Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
uchar *new_ptr, uint32 length,
- uchar *new_null_ptr, uint new_null_bit);
- Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item);
+ uchar *new_null_ptr, uint new_null_bit) override;
+ Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item)
+ override;
+};
+
+
+class Field_time0: public Field_time
+{
+protected:
+ void store_TIME(const MYSQL_TIME *ltime) override;
+public:
+ Field_time0(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, enum utype unireg_check_arg,
+ const LEX_CSTRING *field_name_arg)
+ :Field_time(ptr_arg, length_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg)
+ { }
+ enum ha_base_keytype key_type() const override { return HA_KEYTYPE_INT24; }
+ void sql_type(String &str) const override
+ {
+ sql_type_comment(str, Field_time0::type_handler()->name(),
+ Type_handler::version_mariadb53());
+ }
+ double val_real() override;
+ longlong val_int() override;
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override;
+ int cmp(const uchar *,const uchar *) const override;
+ void sort_string(uchar *buff,uint length) override;
+ uint32 pack_length() const override { return 3; }
+ uint size_of() const override { return sizeof *this; }
};
@@ -3229,11 +3566,11 @@ public:
{
DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
}
- uint decimals() const { return dec; }
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
- longlong val_int(void);
- double val_real(void);
- void make_send_field(Send_field *);
+ uint decimals() const override { return dec; }
+ enum ha_base_keytype key_type() const override { return HA_KEYTYPE_BINARY; }
+ longlong val_int() override;
+ double val_real() override;
+ void make_send_field(Send_field *) override;
};
@@ -3242,7 +3579,7 @@ public:
*/
class Field_time_hires :public Field_time_with_dec {
longlong zero_point;
- void store_TIME(const MYSQL_TIME *);
+ void store_TIME(const MYSQL_TIME *) override;
public:
Field_time_hires(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
@@ -3255,12 +3592,18 @@ public:
zero_point= sec_part_shift(
((TIME_MAX_VALUE_SECONDS+1LL)*TIME_SECOND_PART_FACTOR), dec);
}
- int reset(void);
- 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); }
- uint size_of() const { return sizeof(*this); }
+ void sql_type(String &str) const override
+ {
+ sql_type_dec_comment(str, Field_time_hires::type_handler()->name(),
+ dec, Type_handler::version_mariadb53());
+ }
+ int reset() override;
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override;
+ int cmp(const uchar *,const uchar *) const override;
+ void sort_string(uchar *buff,uint length) override;
+ uint32 pack_length() const override
+ { return Type_handler_time::hires_bytes(dec); }
+ uint size_of() const override { return sizeof *this; }
};
@@ -3268,12 +3611,7 @@ public:
TIME(0..6) - MySQL56 version
*/
class Field_timef :public Field_time_with_dec {
- void store_TIME(const MYSQL_TIME *ltime);
- int save_field_metadata(uchar *metadata_ptr)
- {
- *metadata_ptr= (uchar) decimals();
- return 1;
- }
+ void store_TIME(const MYSQL_TIME *ltime) override;
public:
Field_timef(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
@@ -3284,37 +3622,45 @@ public:
{
DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
}
- const Type_handler *type_handler() const { return &type_handler_time2; }
- enum_field_types binlog_type() const { return MYSQL_TYPE_TIME2; }
- uint32 pack_length() const
+ const Type_handler *type_handler() const override
+ { return &type_handler_time2; }
+ enum_field_types binlog_type() const override { return MYSQL_TYPE_TIME2; }
+ void sql_type(String &str) const override
+ {
+ sql_type_opt_dec_comment(str, Field_timef::type_handler()->name(),
+ dec, type_version_mysql56());
+ }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
+ uint32 pack_length() const override
{
return my_time_binary_length(dec);
}
- uint row_pack_length() const { return pack_length(); }
- uint pack_length_from_metadata(uint field_metadata)
+ uint row_pack_length() const override { return pack_length(); }
+ uint pack_length_from_metadata(uint field_metadata) const override
{
DBUG_ENTER("Field_timef::pack_length_from_metadata");
uint tmp= my_time_binary_length(field_metadata);
DBUG_RETURN(tmp);
}
- void sort_string(uchar *to, uint length)
+ void sort_string(uchar *to, uint length) override
{
DBUG_ASSERT(length == Field_timef::pack_length());
memcpy(to, ptr, length);
}
- int cmp(const uchar *a_ptr, const uchar *b_ptr)
+ int cmp(const uchar *a_ptr, const uchar *b_ptr) const override
{
return memcmp(a_ptr, b_ptr, pack_length());
}
- int reset();
- bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
- uint size_of() const { return sizeof(*this); }
+ int reset() override;
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override;
+ uint size_of() const override { return sizeof *this; }
+ Binlog_type_info binlog_type_info() const override;
};
class Field_datetime :public Field_temporal_with_date {
- void store_TIME(const MYSQL_TIME *ltime);
- 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);
@@ -3329,40 +3675,67 @@ public:
unireg_check == TIMESTAMP_DNUN_FIELD)
flags|= ON_UPDATE_NOW_FLAG;
}
- const Type_handler *type_handler() const { return &type_handler_datetime; }
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; }
- sql_mode_t conversion_depends_on_sql_mode(THD *, Item *) const;
- 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 *);
- bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
- 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, date_mode_t fuzzydate)
- { return Field_datetime::get_TIME(ltime, ptr, fuzzydate); }
- int set_time();
- uchar *pack(uchar* to, const uchar *from,
- uint max_length __attribute__((unused)))
+ const Type_handler *type_handler() const override
+ { return &type_handler_datetime; }
+ sql_mode_t conversion_depends_on_sql_mode(THD *, Item *) const override;
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
+ int store(const char *to, size_t length, CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ int store_time_dec(const MYSQL_TIME *ltime, uint dec) override;
+ int store_decimal(const my_decimal *) override;
+ int set_time() override;
+ Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item)
+ override
+ {
+ return get_equal_const_item_datetime(thd, ctx, const_item);
+ }
+};
+
+
+class Field_datetime0 :public Field_datetime
+{
+ void store_TIME(const MYSQL_TIME *ltime) override;
+ bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate)
+ const override;
+public:
+ Field_datetime0(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, enum utype unireg_check_arg,
+ const LEX_CSTRING *field_name_arg)
+ :Field_datetime(ptr_arg, length_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg)
+ {}
+ enum ha_base_keytype key_type() const override
+ { return HA_KEYTYPE_ULONGLONG; }
+ void sql_type(String &str) const override
+ {
+ sql_type_comment(str, Field_datetime0::type_handler()->name(),
+ Type_handler::version_mariadb53());
+ }
+ double val_real() override
+ {
+ return (double) Field_datetime0::val_int();
+ }
+ longlong val_int() override;
+ String *val_str(String *, String *) override;
+ bool send_binary(Protocol *protocol) override;
+ int cmp(const uchar *,const uchar *) const override;
+ void sort_string(uchar *buff,uint length) override;
+ uint32 pack_length() const override { return 8; }
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override
+ { return Field_datetime0::get_TIME(ltime, ptr, fuzzydate); }
+ uchar *pack(uchar* to, const uchar *from, uint) override
{
return pack_int64(to, from);
}
const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
- uint param_data __attribute__((unused)))
+ uint) override
{
return unpack_int64(to, from, from_end);
}
- Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item)
- {
- return get_equal_const_item_datetime(thd, ctx, const_item);
- }
- uint size_of() const { return sizeof(*this); }
+ uint size_of() const override { return sizeof *this; }
};
@@ -3384,23 +3757,23 @@ public:
{
DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
}
- uint decimals() const { return dec; }
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
- void make_send_field(Send_field *field);
- bool send_binary(Protocol *protocol);
- uchar *pack(uchar *to, const uchar *from, uint max_length)
+ uint decimals() const override { return dec; }
+ enum ha_base_keytype key_type() const override { return HA_KEYTYPE_BINARY; }
+ void make_send_field(Send_field *field) override;
+ bool send_binary(Protocol *protocol) override;
+ uchar *pack(uchar *to, const uchar *from, uint max_length) override
{ return Field::pack(to, from, max_length); }
const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
- uint param_data)
+ uint param_data) override
{ return Field::unpack(to, from, from_end, param_data); }
- void sort_string(uchar *to, uint length)
+ void sort_string(uchar *to, uint length) override
{
DBUG_ASSERT(length == pack_length());
memcpy(to, ptr, length);
}
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
+ double val_real() override;
+ longlong val_int() override;
+ String *val_str(String *, String *) override;
};
@@ -3408,8 +3781,9 @@ public:
DATETIME(1..6)
*/
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, date_mode_t fuzzydate) const;
+ void store_TIME(const MYSQL_TIME *ltime) override;
+ bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate)
+ const override;
public:
Field_datetime_hires(uchar *ptr_arg, uchar *null_ptr_arg,
uchar null_bit_arg, enum utype unireg_check_arg,
@@ -3419,11 +3793,17 @@ public:
{
DBUG_ASSERT(dec);
}
- int cmp(const uchar *,const uchar *);
- uint32 pack_length() const { return Type_handler_datetime::hires_bytes(dec); }
- bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ void sql_type(String &str) const override
+ {
+ sql_type_dec_comment(str, Field_datetime_hires::type_handler()->name(),
+ dec, Type_handler::version_mariadb53());
+ }
+ int cmp(const uchar *,const uchar *) const override;
+ uint32 pack_length() const override
+ { return Type_handler_datetime::hires_bytes(dec); }
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override
{ return Field_datetime_hires::get_TIME(ltime, ptr, fuzzydate); }
- uint size_of() const { return sizeof(*this); }
+ uint size_of() const override { return sizeof *this; }
};
@@ -3431,13 +3811,9 @@ public:
DATETIME(0..6) - MySQL56 version
*/
class Field_datetimef :public Field_datetime_with_dec {
- void store_TIME(const MYSQL_TIME *ltime);
- 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();
- return 1;
- }
+ void store_TIME(const MYSQL_TIME *ltime) override;
+ bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate)
+ const override;
public:
Field_datetimef(uchar *ptr_arg, uchar *null_ptr_arg,
uchar null_bit_arg, enum utype unireg_check_arg,
@@ -3445,27 +3821,38 @@ public:
:Field_datetime_with_dec(ptr_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, dec_arg)
{}
- const Type_handler *type_handler() const { return &type_handler_datetime2; }
- enum_field_types binlog_type() const { return MYSQL_TYPE_DATETIME2; }
- uint32 pack_length() const
+ const Type_handler *type_handler() const override
+ { return &type_handler_datetime2; }
+ enum_field_types binlog_type() const override
+ { return MYSQL_TYPE_DATETIME2; }
+ void sql_type(String &str) const override
+ {
+ sql_type_opt_dec_comment(str, Field_datetimef::type_handler()->name(),
+ dec, type_version_mysql56());
+ }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
+ uint32 pack_length() const override
{
return my_datetime_binary_length(dec);
}
- uint row_pack_length() const { return pack_length(); }
- uint pack_length_from_metadata(uint field_metadata)
+ uint row_pack_length() const override { return pack_length(); }
+ uint pack_length_from_metadata(uint field_metadata) const override
{
DBUG_ENTER("Field_datetimef::pack_length_from_metadata");
uint tmp= my_datetime_binary_length(field_metadata);
DBUG_RETURN(tmp);
}
- int cmp(const uchar *a_ptr, const uchar *b_ptr)
+ int cmp(const uchar *a_ptr, const uchar *b_ptr) const override
{
return memcmp(a_ptr, b_ptr, pack_length());
}
- int reset();
- bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ int reset() override;
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override
{ return Field_datetimef::get_TIME(ltime, ptr, fuzzydate); }
- uint size_of() const { return sizeof(*this); }
+ uint size_of() const override { return sizeof *this; }
+ Binlog_type_info binlog_type_info() const override;
};
@@ -3477,8 +3864,8 @@ new_Field_timestamp(MEM_ROOT *root,uchar *ptr, uchar *null_ptr, uchar null_bit,
{
if (dec==0)
return new (root)
- Field_timestamp(ptr, MAX_DATETIME_WIDTH, null_ptr,
- null_bit, unireg_check, field_name, share);
+ Field_timestamp0(ptr, MAX_DATETIME_WIDTH, null_ptr,
+ null_bit, unireg_check, field_name, share);
if (dec >= FLOATING_POINT_DECIMALS)
dec= MAX_DATETIME_PRECISION;
return new (root)
@@ -3493,8 +3880,8 @@ new_Field_time(MEM_ROOT *root, uchar *ptr, uchar *null_ptr, uchar null_bit,
{
if (dec == 0)
return new (root)
- Field_time(ptr, MIN_TIME_WIDTH, null_ptr, null_bit, unireg_check,
- field_name);
+ Field_time0(ptr, MIN_TIME_WIDTH, null_ptr, null_bit, unireg_check,
+ field_name);
if (dec >= FLOATING_POINT_DECIMALS)
dec= MAX_DATETIME_PRECISION;
return new (root)
@@ -3508,8 +3895,8 @@ new_Field_datetime(MEM_ROOT *root, uchar *ptr, uchar *null_ptr, uchar null_bit,
{
if (dec == 0)
return new (root)
- Field_datetime(ptr, MAX_DATETIME_WIDTH, null_ptr, null_bit,
- unireg_check, field_name);
+ Field_datetime0(ptr, MAX_DATETIME_WIDTH, null_ptr, null_bit,
+ unireg_check, field_name);
if (dec >= FLOATING_POINT_DECIMALS)
dec= MAX_DATETIME_PRECISION;
return new (root)
@@ -3547,66 +3934,70 @@ public:
NONE, field_name_arg, collation),
can_alter_field_type(1) {};
- const Type_handler *type_handler() const
+ const Type_handler *type_handler() const override
{
if (is_var_string())
return &type_handler_var_string;
return &type_handler_string;
}
- enum ha_base_keytype key_type() const
+ enum ha_base_keytype key_type() const override
{ return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; }
- bool zero_pack() const { return 0; }
- Copy_func *get_copy_func(const Field *from) const;
- int reset(void)
+ en_fieldtype tmp_engine_column_type(bool use_packed_rows) const override;
+ bool zero_pack() const override { return false; }
+ Copy_func *get_copy_func(const Field *from) const override;
+ int reset() override
{
- charset()->cset->fill(charset(),(char*) ptr, field_length,
- (has_charset() ? ' ' : 0));
+ charset()->fill((char*) ptr, field_length, (has_charset() ? ' ' : 0));
return 0;
}
- int store(const char *to,size_t length,CHARSET_INFO *charset);
+ int store(const char *to,size_t length,CHARSET_INFO *charset) override;
using Field_str::store;
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- my_decimal *val_decimal(my_decimal *);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- void sql_type(String &str) const;
- void sql_rpl_type(String*) const;
- bool is_equal(const Column_definition &new_field) const;
+ double val_real() override;
+ longlong val_int() override;
+ String *val_str(String *, String *) override;
+ my_decimal *val_decimal(my_decimal *) override;
+ int cmp(const uchar *,const uchar *) const override;
+ void sort_string(uchar *buff,uint length) override;
+ void update_data_type_statistics(Data_type_statistics *st) const override
+ {
+ st->m_fixed_string_count++;
+ st->m_fixed_string_total_length+= pack_length();
+ }
+ void sql_type(String &str) const override;
+ void sql_rpl_type(String*) const override;
+ bool is_equal(const Column_definition &new_field) const override;
bool can_be_converted_by_engine(const Column_definition &new_type) const
+ override
{
return table->file->can_convert_string(this, new_type);
}
- virtual uchar *pack(uchar *to, const uchar *from,
- uint max_length);
- virtual const uchar *unpack(uchar* to, const uchar *from,
- const uchar *from_end,uint param_data);
- uint pack_length_from_metadata(uint field_metadata)
+ uchar *pack(uchar *to, const uchar *from, uint max_length) override;
+ const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
+ uint param_data) override;
+ uint pack_length_from_metadata(uint field_metadata) const override
{
DBUG_PRINT("debug", ("field_metadata: 0x%04x", field_metadata));
if (field_metadata == 0)
return row_pack_length();
return (((field_metadata >> 4) & 0x300) ^ 0x300) + (field_metadata & 0x00ff);
}
- bool compatible_field_size(uint field_metadata, Relay_log_info *rli,
- uint16 mflags, int *order_var);
- uint row_pack_length() const { return field_length; }
+ bool compatible_field_size(uint field_metadata, const Relay_log_info *rli,
+ uint16 mflags, int *order_var) const override;
+ uint row_pack_length() const override { return field_length; }
int pack_cmp(const uchar *a,const uchar *b,uint key_length,
bool insert_or_update);
int pack_cmp(const uchar *b,uint key_length,bool insert_or_update);
- uint packed_col_length(const uchar *to, uint length);
- uint max_packed_col_length(uint max_length);
- uint size_of() const { return sizeof(*this); }
- bool has_charset(void) const
- { return charset() == &my_charset_bin ? FALSE : TRUE; }
- Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type);
- virtual uint get_key_image(uchar *buff,uint length, imagetype type);
- sql_mode_t value_depends_on_sql_mode() const;
- sql_mode_t can_handle_sql_mode_dependency_on_store() const;
- void print_key_value(String *out, uint32 length);
-private:
- int save_field_metadata(uchar *first_byte);
+ uint packed_col_length(const uchar *to, uint length) override;
+ uint max_packed_col_length(uint max_length) override;
+ uint size_of() const override { return sizeof *this; }
+ bool has_charset() const override { return charset() != &my_charset_bin; }
+ Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type)
+ override;
+ uint get_key_image(uchar *buff,uint length, imagetype type) override;
+ sql_mode_t value_depends_on_sql_mode() const override;
+ sql_mode_t can_handle_sql_mode_dependency_on_store() const override;
+ void print_key_value(String *out, uint32 length) override;
+ Binlog_type_info binlog_type_info() const override;
};
@@ -3657,67 +4048,80 @@ public:
share->varchar_fields++;
}
- const Type_handler *type_handler() const { return &type_handler_varchar; }
- enum ha_base_keytype key_type() const;
- uint row_pack_length() const { return field_length; }
- bool zero_pack() const { return 0; }
- int reset(void) { bzero(ptr,field_length+length_bytes); return 0; }
- uint32 pack_length() const { return (uint32) field_length+length_bytes; }
- uint32 key_length() const { return (uint32) field_length; }
- uint32 sort_length() const
+ const Type_handler *type_handler() const override
+ { return &type_handler_varchar; }
+ en_fieldtype tmp_engine_column_type(bool use_packed_rows) const override
{
- return (uint32) field_length + (field_charset == &my_charset_bin ?
- length_bytes : 0);
+ return FIELD_VARCHAR;
}
- Copy_func *get_copy_func(const Field *from) const;
- bool memcpy_field_possible(const Field *from) const
+ enum ha_base_keytype key_type() const override;
+ uint16 key_part_flag() const override { return HA_VAR_LENGTH_PART; }
+ uint16 key_part_length_bytes() const override { return HA_KEY_BLOB_LENGTH; }
+ uint row_pack_length() const override { return field_length; }
+ bool zero_pack() const override { return false; }
+ int reset() override { bzero(ptr,field_length+length_bytes); return 0; }
+ uint32 pack_length() const override
+ { return (uint32) field_length+length_bytes; }
+ uint32 key_length() const override { return (uint32) field_length; }
+ uint32 sort_length() const override
{
- return Field_str::memcpy_field_possible(from) &&
- !compression_method() == !from->compression_method() &&
- length_bytes == ((Field_varstring*) from)->length_bytes;
+ return (uint32) field_length + sort_suffix_length();
+ }
+ virtual uint32 sort_suffix_length() const override
+ {
+ return (field_charset() == &my_charset_bin ? length_bytes : 0);
+ }
+ Copy_func *get_copy_func(const Field *from) const override;
+ bool memcpy_field_possible(const Field *from) const override;
+ void update_data_type_statistics(Data_type_statistics *st) const override
+ {
+ st->m_variable_string_count++;
+ st->m_variable_string_total_length+= pack_length();
}
- int store(const char *to,size_t length,CHARSET_INFO *charset);
+ int store(const char *to,size_t length,CHARSET_INFO *charset) override;
using Field_str::store;
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- my_decimal *val_decimal(my_decimal *);
- int cmp_max(const uchar *, const uchar *, uint max_length);
- int cmp(const uchar *a,const uchar *b)
+ double val_real() override;
+ longlong val_int() override;
+ String *val_str(String *, String *) override;
+ my_decimal *val_decimal(my_decimal *) override;
+ int cmp_max(const uchar *, const uchar *, uint max_length) const override;
+ int cmp(const uchar *a,const uchar *b) const override
{
return cmp_max(a, b, ~0U);
}
- void sort_string(uchar *buff,uint length);
- uint get_key_image(uchar *buff,uint length, imagetype type);
- void set_key_image(const uchar *buff,uint length);
- void sql_type(String &str) const;
- void sql_rpl_type(String*) const;
- virtual uchar *pack(uchar *to, const uchar *from, uint max_length);
- virtual const uchar *unpack(uchar* to, const uchar *from,
- const uchar *from_end, uint param_data);
- int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U);
- int key_cmp(const uchar *,const uchar*);
- int key_cmp(const uchar *str, uint length);
- uint packed_col_length(const uchar *to, uint length);
- uint max_packed_col_length(uint max_length);
- uint32 data_length();
- uint size_of() const { return sizeof(*this); }
- bool has_charset(void) const
+ void sort_string(uchar *buff,uint length) override;
+ uint get_key_image(uchar *buff,uint length, imagetype type) override;
+ void set_key_image(const uchar *buff,uint length) override;
+ void sql_type(String &str) const override;
+ void sql_rpl_type(String*) const override;
+ uchar *pack(uchar *to, const uchar *from, uint max_length) override;
+ const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
+ uint param_data) override;
+ int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U) const
+ override;
+ int key_cmp(const uchar *,const uchar*) const override;
+ int key_cmp(const uchar *str, uint length) const override;
+ uint packed_col_length(const uchar *to, uint length) override;
+ uint max_packed_col_length(uint max_length) override;
+ uint32 data_length() override;
+ uint size_of() const override { return sizeof *this; }
+ bool has_charset() const override
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
- Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type);
+ Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type)
+ override;
Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
uchar *new_ptr, uint32 length,
- uchar *new_null_ptr, uint new_null_bit);
- bool is_equal(const Column_definition &new_field) const;
+ uchar *new_null_ptr, uint new_null_bit) override;
+ bool is_equal(const Column_definition &new_field) const override;
bool can_be_converted_by_engine(const Column_definition &new_type) const
+ override
{
return table->file->can_convert_varstring(this, new_type);
}
- void hash(ulong *nr, ulong *nr2);
- uint length_size() const { return length_bytes; }
- void print_key_value(String *out, uint32 length);
-private:
- int save_field_metadata(uchar *first_byte);
+ void hash(ulong *nr, ulong *nr2) override;
+ uint length_size() const override { return length_bytes; }
+ void print_key_value(String *out, uint32 length) override;
+ Binlog_type_info binlog_type_info() const override;
};
@@ -3734,38 +4138,41 @@ public:
null_bit_arg, unireg_check_arg, field_name_arg,
share, collation),
compression_method_ptr(compression_method_arg) { DBUG_ASSERT(len_arg > 0); }
- Compression_method *compression_method() const
+ Compression_method *compression_method() const override
{ return compression_method_ptr; }
private:
Compression_method *compression_method_ptr;
- int store(const char *to, size_t length, CHARSET_INFO *charset);
+ int store(const char *to, size_t length, CHARSET_INFO *charset) override;
using Field_str::store;
- String *val_str(String *, String *);
- double val_real(void);
- longlong val_int(void);
- uint size_of() const { return sizeof(*this); }
- enum_field_types binlog_type() const { return MYSQL_TYPE_VARCHAR_COMPRESSED; }
- void sql_type(String &str) const
+ String *val_str(String *, String *) override;
+ double val_real() override;
+ longlong val_int() override;
+ uint size_of() const override { return sizeof *this; }
+ enum_field_types binlog_type() const override
+ { return MYSQL_TYPE_VARCHAR_COMPRESSED; }
+ void sql_type(String &str) const override
{
Field_varstring::sql_type(str);
str.append(STRING_WITH_LEN(" /*!100301 COMPRESSED*/"));
}
- uint32 max_display_length() const { return field_length - 1; }
- uint32 character_octet_length() const { return field_length - 1; }
- uint32 char_length() const
+ uint32 max_display_length() const override { return field_length - 1; }
+ uint32 character_octet_length() const override { return field_length - 1; }
+ uint32 char_length() const override
{
- return (field_length - 1) / field_charset->mbmaxlen;
+ return (field_length - 1) / mbmaxlen();
}
- int cmp_max(const uchar *a_ptr, const uchar *b_ptr, uint max_len);
+ int cmp_max(const uchar *a_ptr, const uchar *b_ptr, uint max_len) const
+ override;
/*
Compressed fields can't have keys as two rows may have different
compression methods or compression levels.
*/
- int key_cmp(const uchar *str, uint length)
+ int key_cmp(const uchar *str, uint length) const override
{ DBUG_ASSERT(0); return 0; }
using Field_varstring::key_cmp;
+ Binlog_type_info binlog_type_info() const override;
};
@@ -3806,6 +4213,30 @@ static inline longlong read_bigendian(const uchar *from, uint bytes)
}
}
+static inline void store_lowendian(ulonglong num, uchar *to, uint bytes)
+{
+ switch(bytes) {
+ case 1: *to= (uchar)num; break;
+ case 2: int2store(to, num); break;
+ case 3: int3store(to, num); break;
+ case 4: int4store(to, num); break;
+ case 8: int8store(to, num); break;
+ default: DBUG_ASSERT(0);
+ }
+}
+
+static inline longlong read_lowendian(const uchar *from, uint bytes)
+{
+ switch(bytes) {
+ case 1: return from[0];
+ case 2: return uint2korr(from);
+ case 3: return uint3korr(from);
+ case 4: return uint4korr(from);
+ case 8: return sint8korr(from);
+ default: DBUG_ASSERT(0); return 0;
+ }
+}
+
extern LEX_CSTRING temp_lex_str;
@@ -3829,6 +4260,7 @@ protected:
static void do_copy_blob(Copy_field *copy);
static void do_conv_blob(Copy_field *copy);
+ uint get_key_image_itRAW(uchar *buff, uint length);
public:
Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
@@ -3855,9 +4287,9 @@ public:
:Field_longstr((uchar*) 0, 0, (uchar*) "", 0, NONE, &temp_lex_str,
system_charset_info),
packlength(packlength_arg) {}
- const Type_handler *type_handler() const;
+ const Type_handler *type_handler() const override;
/* Note that the default copy constructor is used, in clone() */
- enum_field_types type() const
+ enum_field_types type() const override
{
/*
We cannot return type_handler()->field_type() here.
@@ -3869,27 +4301,36 @@ public:
*/
return MYSQL_TYPE_BLOB;
}
- enum_field_types real_type() const
+ enum_field_types real_type() const override
{
return MYSQL_TYPE_BLOB;
}
- enum ha_base_keytype key_type() const
+ enum ha_base_keytype key_type() const override
{ return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; }
- Type_std_attributes type_std_attributes() const
+ uint16 key_part_flag() const override { return HA_BLOB_PART; }
+ uint16 key_part_length_bytes() const override { return HA_KEY_BLOB_LENGTH; }
+ en_fieldtype tmp_engine_column_type(bool use_packed_rows) const override
+ {
+ return FIELD_BLOB;
+ }
+ Type_numeric_attributes type_numeric_attributes() const override
{
- return Type_std_attributes(Field_blob::max_display_length(), decimals(),
- MY_TEST(flags & UNSIGNED_FLAG),
- dtcollation());
+ return Type_numeric_attributes(Field_blob::max_display_length(),
+ decimals(), is_unsigned());
}
Information_schema_character_attributes
- information_schema_character_attributes() const
+ information_schema_character_attributes() const override
{
uint32 octets= Field_blob::character_octet_length();
- uint32 chars= octets / field_charset->mbminlen;
+ uint32 chars= octets / field_charset()->mbminlen;
return Information_schema_character_attributes(octets, chars);
}
- void make_send_field(Send_field *);
- Copy_func *get_copy_func(const Field *from) const
+ void update_data_type_statistics(Data_type_statistics *st) const override
+ {
+ st->m_blob_count++;
+ }
+ void make_send_field(Send_field *) override;
+ Copy_func *get_copy_func(const Field *from) const override
{
/*
TODO: MDEV-9331
@@ -3903,41 +4344,51 @@ public:
return do_copy_blob;
return get_identical_copy_func();
}
- int store_field(Field *from)
+ int store_field(Field *from) override
{ // Be sure the value is stored
+ if (field_charset() == &my_charset_bin &&
+ from->type_handler()->convert_to_binary_using_val_native())
+ {
+ NativeBuffer<64> tmp;
+ from->val_native(&tmp);
+ value.copy(tmp.ptr(), tmp.length(), &my_charset_bin);
+ return store(value.ptr(), value.length(), &my_charset_bin);
+ }
from->val_str(&value);
if (table->copy_blobs ||
(!value.is_alloced() && from->is_varchar_and_in_write_set()))
value.copy();
return store(value.ptr(), value.length(), from->charset());
}
- bool memcpy_field_possible(const Field *from) const
+ bool memcpy_field_possible(const Field *from) const override
{
return Field_str::memcpy_field_possible(from) &&
!compression_method() == !from->compression_method() &&
!table->copy_blobs;
}
- bool make_empty_rec_store_default_value(THD *thd, Item *item);
- int store(const char *to, size_t length, CHARSET_INFO *charset);
+ bool make_empty_rec_store_default_value(THD *thd, Item *item) override;
+ int store(const char *to, size_t length, CHARSET_INFO *charset) override;
using Field_str::store;
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- my_decimal *val_decimal(my_decimal *);
- int cmp_max(const uchar *, const uchar *, uint max_length);
- int cmp(const uchar *a,const uchar *b)
+ double val_real() override;
+ longlong val_int() override;
+ String *val_str(String *, String *) override;
+ my_decimal *val_decimal(my_decimal *) override;
+ int cmp_max(const uchar *, const uchar *, uint max_length) const override;
+ int cmp(const uchar *a,const uchar *b) const override
{ return cmp_max(a, b, ~0U); }
- int cmp(const uchar *a, uint32 a_length, const uchar *b, uint32 b_length);
- int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U);
- int key_cmp(const uchar *,const uchar*);
- int key_cmp(const uchar *str, uint length);
+ int cmp(const uchar *a, uint32 a_length, const uchar *b, uint32 b_length)
+ const;
+ int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U) const
+ override;
+ int key_cmp(const uchar *,const uchar*) const override;
+ int key_cmp(const uchar *str, uint length) const override;
/* Never update the value of min_val for a blob field */
- bool update_min(Field *min_val, bool force_update) { return FALSE; }
+ bool update_min(Field *min_val, bool force_update) override { return false; }
/* Never update the value of max_val for a blob field */
- bool update_max(Field *max_val, bool force_update) { return FALSE; }
- uint32 key_length() const { return 0; }
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const
+ bool update_max(Field *max_val, bool force_update) override { return false; }
+ uint32 key_length() const override { return 0; }
+ void sort_string(uchar *buff,uint length) override;
+ uint32 pack_length() const override
{ return (uint32) (packlength + portable_sizeof_char_ptr); }
/**
@@ -3950,18 +4401,23 @@ public:
*/
uint32 pack_length_no_ptr() const
{ return (uint32) (packlength); }
- uint row_pack_length() const { return pack_length_no_ptr(); }
- uint32 sort_length() const;
- uint32 value_length() { return get_length(); }
- virtual uint32 max_data_length() const
+ uint row_pack_length() const override { return pack_length_no_ptr(); }
+ uint32 sort_length() const override;
+ uint32 sort_suffix_length() const override;
+ uint32 value_length() override { return get_length(); }
+ virtual uint32 max_data_length() const override
{
return (uint32) (((ulonglong) 1 << (packlength*8)) -1);
}
- int reset(void) { bzero(ptr, packlength+sizeof(uchar*)); return 0; }
- void reset_fields() { bzero((uchar*) &value,sizeof(value)); bzero((uchar*) &read_value,sizeof(read_value)); }
- uint32 get_field_buffer_size(void) { return value.alloced_length(); }
+ int reset() override { bzero(ptr, packlength+sizeof(uchar*)); return 0; }
+ void reset_fields() override
+ {
+ bzero((uchar*) &value, sizeof value);
+ bzero((uchar*) &read_value, sizeof read_value);
+ }
+ uint32 get_field_buffer_size() { return value.alloced_length(); }
void store_length(uchar *i_ptr, uint i_packlength, uint32 i_number);
- inline void store_length(size_t number)
+ void store_length(size_t number)
{
DBUG_ASSERT(number < UINT_MAX32);
store_length(ptr, packlength, (uint32)number);
@@ -3994,12 +4450,16 @@ public:
set_ptr_offset(0, length, data);
}
int copy_value(Field_blob *from);
- uint get_key_image(uchar *buff,uint length, imagetype type);
- void set_key_image(const uchar *buff,uint length);
+ uint get_key_image(uchar *buff, uint length, imagetype type) override
+ {
+ DBUG_ASSERT(type == itRAW);
+ return get_key_image_itRAW(buff, length);
+ }
+ void set_key_image(const uchar *buff,uint length) override;
Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
uchar *new_ptr, uint32 length,
- uchar *new_null_ptr, uint new_null_bit);
- void sql_type(String &str) const;
+ uchar *new_null_ptr, uint new_null_bit) override;
+ void sql_type(String &str) const override;
inline bool copy()
{
uchar *tmp= get_ptr();
@@ -4022,12 +4482,12 @@ public:
/* Set value pointer. Lengths are not important */
value.reset((char*) data, 1, 1, &my_charset_bin);
}
- virtual uchar *pack(uchar *to, const uchar *from, uint max_length);
- virtual const uchar *unpack(uchar *to, const uchar *from,
- const uchar *from_end, uint param_data);
- uint packed_col_length(const uchar *col_ptr, uint length);
- uint max_packed_col_length(uint max_length);
- void free()
+ uchar *pack(uchar *to, const uchar *from, uint max_length) override;
+ const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end,
+ uint param_data) override;
+ uint packed_col_length(const uchar *col_ptr, uint length) override;
+ uint max_packed_col_length(uint max_length) override;
+ void free() override
{
value.free();
read_value.free();
@@ -4047,24 +4507,22 @@ public:
bzero((uchar*) &read_value, sizeof(read_value));
}
}
- uint size_of() const { return sizeof(*this); }
- bool has_charset(void) const
- { return charset() == &my_charset_bin ? FALSE : TRUE; }
- uint32 max_display_length() const;
- uint32 char_length() const;
- uint32 character_octet_length() const;
- bool is_equal(const Column_definition &new_field) const;
+ uint size_of() const override { return sizeof *this; }
+ bool has_charset() const override { return charset() != &my_charset_bin; }
+ uint32 max_display_length() const override;
+ uint32 char_length() const override;
+ uint32 character_octet_length() const override;
+ bool is_equal(const Column_definition &new_field) const override;
bool can_be_converted_by_engine(const Column_definition &new_type) const
+ override
{
return table->file->can_convert_blob(this, new_type);
}
- void print_key_value(String *out, uint32 length);
+ void print_key_value(String *out, uint32 length) override;
+ Binlog_type_info binlog_type_info() const override;
friend void TABLE::remember_blob_values(String *blob_storage);
friend void TABLE::restore_blob_values(String *blob_storage);
-
-private:
- int save_field_metadata(uchar *first_byte);
};
@@ -4078,18 +4536,19 @@ public:
Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
field_name_arg, share, blob_pack_length, collation),
compression_method_ptr(compression_method_arg) {}
- Compression_method *compression_method() const
+ Compression_method *compression_method() const override
{ return compression_method_ptr; }
private:
Compression_method *compression_method_ptr;
- int store(const char *to, size_t length, CHARSET_INFO *charset);
+ int store(const char *to, size_t length, CHARSET_INFO *charset) override;
using Field_str::store;
- String *val_str(String *, String *);
- double val_real(void);
- longlong val_int(void);
- uint size_of() const { return sizeof(*this); }
- enum_field_types binlog_type() const { return MYSQL_TYPE_BLOB_COMPRESSED; }
- void sql_type(String &str) const
+ String *val_str(String *, String *) override;
+ double val_real() override;
+ longlong val_int() override;
+ uint size_of() const override { return sizeof *this; }
+ enum_field_types binlog_type() const override
+ { return MYSQL_TYPE_BLOB_COMPRESSED; }
+ void sql_type(String &str) const override
{
Field_blob::sql_type(str);
str.append(STRING_WITH_LEN(" /*!100301 COMPRESSED*/"));
@@ -4100,133 +4559,33 @@ private:
compression methods or compression levels.
*/
- uint get_key_image(uchar *buff, uint length, imagetype type_arg)
+ uint get_key_image(uchar *, uint, imagetype) override
{ DBUG_ASSERT(0); return 0; }
- void set_key_image(const uchar *buff, uint length)
+ void set_key_image(const uchar *, uint) override
{ DBUG_ASSERT(0); }
- int key_cmp(const uchar *a, const uchar *b)
+ int key_cmp(const uchar *, const uchar *) const override
{ DBUG_ASSERT(0); return 0; }
- int key_cmp(const uchar *str, uint length)
+ int key_cmp(const uchar *, uint) const override
{ DBUG_ASSERT(0); return 0; }
- Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
- uchar *new_ptr, uint32 length,
- uchar *new_null_ptr, uint new_null_bit)
+ Field *new_key_field(MEM_ROOT *, TABLE *, uchar *, uint32, uchar *, uint)
+ override
{ DBUG_ASSERT(0); return 0; }
+ Binlog_type_info binlog_type_info() const override;
};
-#ifdef HAVE_SPATIAL
-class Field_geom :public Field_blob {
-public:
- enum geometry_type geom_type;
- uint srid;
- uint precision;
- enum storage_type { GEOM_STORAGE_WKB= 0, GEOM_STORAGE_BINARY= 1};
- enum storage_type storage;
-
- Field_geom(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
- enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
- TABLE_SHARE *share, uint blob_pack_length,
- enum geometry_type geom_type_arg, uint field_srid)
- :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
- field_name_arg, share, blob_pack_length, &my_charset_bin)
- { geom_type= geom_type_arg; srid= field_srid; }
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY2; }
- const Type_handler *type_handler() const
- {
- return &type_handler_geometry;
- }
- enum_field_types type() const
- {
- return MYSQL_TYPE_GEOMETRY;
- }
- enum_field_types real_type() const
- {
- return MYSQL_TYPE_GEOMETRY;
- }
- Information_schema_character_attributes
- information_schema_character_attributes() const
- {
- return Information_schema_character_attributes();
- }
- void make_send_field(Send_field *to)
- {
- Field_longstr::make_send_field(to);
- }
- bool can_optimize_range(const Item_bool_func *cond,
- const Item *item,
- bool is_eq_func) const;
- void sql_type(String &str) const;
- Copy_func *get_copy_func(const Field *from) const
- {
- if (type_handler() == from->type_handler() &&
- (geom_type == GEOM_GEOMETRY ||
- geom_type == static_cast<const Field_geom*>(from)->geom_type))
- return get_identical_copy_func();
- return do_conv_blob;
- }
- bool memcpy_field_possible(const Field *from) const
- {
- return type_handler() == from->type_handler() &&
- (geom_type == GEOM_GEOMETRY ||
- geom_type == static_cast<const Field_geom*>(from)->geom_type) &&
- !table->copy_blobs;
- }
- bool is_equal(const Column_definition &new_field) const;
- bool can_be_converted_by_engine(const Column_definition &new_type) const
- {
- return table->file->can_convert_geom(this, new_type);
- }
-
- int store(const char *to, size_t length, CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- int store_decimal(const my_decimal *);
- uint size_of() const { return sizeof(*this); }
- /**
- Key length is provided only to support hash joins. (compared byte for byte)
- Ex: SELECT .. FROM t1,t2 WHERE t1.field_geom1=t2.field_geom2.
-
- The comparison is not very relevant, as identical geometry might be
- represented differently, but we need to support it either way.
- */
- uint32 key_length() const { return packlength; }
-
- /**
- Non-nullable GEOMETRY types cannot have defaults,
- but the underlying blob must still be reset.
- */
- int reset(void) { return Field_blob::reset() || !maybe_null(); }
- bool load_data_set_null(THD *thd);
- bool load_data_set_no_data(THD *thd, bool fixed_format);
-
- geometry_type get_geometry_type() const { return geom_type; };
- static geometry_type geometry_type_merge(geometry_type, geometry_type);
- uint get_srid() { return srid; }
- void print_key_value(String *out, uint32 length)
- {
- out->append(STRING_WITH_LEN("unprintable_geometry_value"));
- }
-};
-
-uint gis_field_options_image(uchar *buff, List<Create_field> &create_fields);
-uint gis_field_options_read(const uchar *buf, size_t buf_len,
- Field_geom::storage_type *st_type,uint *precision, uint *scale, uint *srid);
-
-#endif /*HAVE_SPATIAL*/
-
-
class Field_enum :public Field_str {
static void do_field_enum(Copy_field *copy_field);
+ longlong val_int(const uchar *) const;
protected:
uint packlength;
public:
- TYPELIB *typelib;
+ const TYPELIB *typelib;
Field_enum(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
uint packlength_arg,
- TYPELIB *typelib_arg,
+ const TYPELIB *typelib_arg,
const DTCollation &collation)
:Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, collation),
@@ -4234,11 +4593,16 @@ public:
{
flags|=ENUM_FLAG;
}
- Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type);
- const Type_handler *type_handler() const { return &type_handler_enum; }
- enum ha_base_keytype key_type() const;
- sql_mode_t can_handle_sql_mode_dependency_on_store() const;
- Copy_func *get_copy_func(const Field *from) const
+ Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type)
+ override;
+ const Type_handler *type_handler() const override
+ { return &type_handler_enum; }
+ enum ha_base_keytype key_type() const override;
+ sql_mode_t can_handle_sql_mode_dependency_on_store() const override;
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
+ Copy_func *get_copy_func(const Field *from) const override
{
if (eq_def(from))
return get_identical_copy_func();
@@ -4249,7 +4613,7 @@ public:
return do_field_string;
return do_field_int;
}
- int store_field(Field *from)
+ int store_field(Field *from) override
{
if (from->real_type() == MYSQL_TYPE_ENUM && from->val_int() == 0)
{
@@ -4258,14 +4622,15 @@ public:
}
return from->save_in_field(this);
}
- int save_in_field(Field *to)
+ int save_in_field(Field *to) override
{
if (to->result_type() != STRING_RESULT)
return to->store(val_int(), 0);
return save_in_field_str(to);
}
- bool memcpy_field_possible(const Field *from) const { return false; }
- void make_empty_rec_reset(THD *thd)
+ bool memcpy_field_possible(const Field *from) const override
+ { return false; }
+ void make_empty_rec_reset(THD *) override
{
if (flags & NOT_NULL_FLAG)
{
@@ -4275,38 +4640,38 @@ public:
else
reset();
}
- int store(const char *to,size_t length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*,String *);
- int cmp(const uchar *,const uchar *);
- void sort_string(uchar *buff,uint length);
- uint32 pack_length() const { return (uint32) packlength; }
+ int store(const char *to,size_t length,CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ double val_real() override;
+ longlong val_int() override;
+ String *val_str(String *, String *) override;
+ int cmp(const uchar *,const uchar *) const override;
+ void sort_string(uchar *buff,uint length) override;
+ uint32 pack_length() const override { return (uint32) packlength; }
void store_type(ulonglong value);
- void sql_type(String &str) const;
- uint size_of() const { return sizeof(*this); }
- uint pack_length_from_metadata(uint field_metadata)
+ void sql_type(String &str) const override;
+ uint size_of() const override { return sizeof *this; }
+ uint pack_length_from_metadata(uint field_metadata) const override
{ return (field_metadata & 0x00ff); }
- uint row_pack_length() const { return pack_length(); }
- virtual bool zero_pack() const { return 0; }
- bool optimize_range(uint idx, uint part) const { return 0; }
- bool eq_def(const Field *field) const;
- bool has_charset(void) const { return TRUE; }
+ uint row_pack_length() const override { return pack_length(); }
+ bool zero_pack() const override { return false; }
+ bool optimize_range(uint, uint) const override { return false; }
+ bool eq_def(const Field *field) const override;
+ bool has_charset() const override { return true; }
/* enum and set are sorted as integers */
- CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; }
- uint decimals() const { return 0; }
- TYPELIB *get_typelib() const { return typelib; }
+ CHARSET_INFO *sort_charset() const override { return &my_charset_bin; }
+ uint decimals() const override { return 0; }
+ const TYPELIB *get_typelib() const override { return typelib; }
- virtual uchar *pack(uchar *to, const uchar *from, uint max_length);
- virtual const uchar *unpack(uchar *to, const uchar *from,
- const uchar *from_end, uint param_data);
+ uchar *pack(uchar *to, const uchar *from, uint max_length) override;
+ const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end,
+ uint param_data) override;
bool can_optimize_keypart_ref(const Item_bool_func *cond,
- const Item *item) const;
- bool can_optimize_group_min_max(const Item_bool_func *cond,
- const Item *const_item) const
+ const Item *item) const override;
+ bool can_optimize_group_min_max(const Item_bool_func *, const Item *)
+ const override
{
/*
Can't use GROUP_MIN_MAX optimization for ENUM and SET,
@@ -4319,10 +4684,10 @@ public:
}
bool can_optimize_range(const Item_bool_func *cond,
const Item *item,
- bool is_eq_func) const;
+ bool is_eq_func) const override;
+ Binlog_type_info binlog_type_info() const override;
private:
- int save_field_metadata(uchar *first_byte);
- bool is_equal(const Column_definition &new_field) const;
+ bool is_equal(const Column_definition &new_field) const override;
};
@@ -4332,7 +4697,7 @@ public:
uchar null_bit_arg,
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
uint32 packlength_arg,
- TYPELIB *typelib_arg, const DTCollation &collation)
+ const TYPELIB *typelib_arg, const DTCollation &collation)
:Field_enum(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg,
packlength_arg,
@@ -4341,22 +4706,25 @@ public:
{
flags=(flags & ~ENUM_FLAG) | SET_FLAG;
}
- void make_empty_rec_reset(THD *thd)
+ void make_empty_rec_reset(THD *thd) override
{
Field::make_empty_rec_reset(thd);
}
- int store_field(Field *from) { return from->save_in_field(this); }
- int store(const char *to,size_t length,CHARSET_INFO *charset);
- int store(double nr) { return Field_set::store((longlong) nr, FALSE); }
- int store(longlong nr, bool unsigned_val);
-
- virtual bool zero_pack() const { return 1; }
- String *val_str(String*,String *);
- void sql_type(String &str) const;
- uint size_of() const { return sizeof(*this); }
- const Type_handler *type_handler() const { return &type_handler_set; }
- bool has_charset(void) const { return TRUE; }
+ int store_field(Field *from) override { return from->save_in_field(this); }
+ int store(const char *to,size_t length,CHARSET_INFO *charset) override;
+ int store(double nr) override
+ { return Field_set::store((longlong) nr, FALSE); }
+ int store(longlong nr, bool unsigned_val) override;
+
+ bool zero_pack() const override { return true; }
+ String *val_str(String *, String *) override;
+ void sql_type(String &str) const override;
+ uint size_of() const override { return sizeof *this; }
+ const Type_handler *type_handler() const override
+ { return &type_handler_set; }
+ bool has_charset() const override { return true; }
+ Binlog_type_info binlog_type_info() const override;
private:
const String empty_set_string;
};
@@ -4385,42 +4753,55 @@ public:
Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg,
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg);
- const Type_handler *type_handler() const { return &type_handler_bit; }
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; }
- uint32 key_length() const { return (uint32) (field_length + 7) / 8; }
- uint32 max_data_length() const { return (field_length + 7) / 8; }
- uint32 max_display_length() const { return field_length; }
+ const Type_handler *type_handler() const override
+ { return &type_handler_bit; }
+ enum ha_base_keytype key_type() const override { return HA_KEYTYPE_BIT; }
+ uint16 key_part_flag() const override { return HA_BIT_PART; }
+ uint32 key_length() const override
+ { return (uint32) (field_length + 7) / 8; }
+ uint32 max_data_length() const override { return key_length(); }
+ uint32 max_display_length() const override { return field_length; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
+ CHARSET_INFO *charset() const override { return &my_charset_bin; }
+ const DTCollation & dtcollation() const override;
Information_schema_numeric_attributes
- information_schema_numeric_attributes() const
+ information_schema_numeric_attributes() const override
{
return Information_schema_numeric_attributes(field_length);
}
- uint size_of() const { return sizeof(*this); }
- int reset(void) {
+ void update_data_type_statistics(Data_type_statistics *st) const override
+ {
+ st->m_uneven_bit_length+= field_length & 7;
+ }
+ uint size_of() const override { return sizeof *this; }
+ int reset() override
+ {
bzero(ptr, bytes_in_rec);
if (bit_ptr && (bit_len > 0)) // reset odd bits among null bits
clr_rec_bits(bit_ptr, bit_ofs, bit_len);
return 0;
}
- Copy_func *get_copy_func(const Field *from) const
+ Copy_func *get_copy_func(const Field *from) const override
{
if (from->cmp_type() == DECIMAL_RESULT)
return do_field_decimal;
return do_field_int;
}
- int save_in_field(Field *to) { return to->store(val_int(), true); }
- bool memcpy_field_possible(const Field *from) const { return false; }
- int store(const char *to, size_t length, CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- int store_decimal(const my_decimal *);
- double val_real(void);
- longlong val_int(void);
- String *val_str(String*, String *);
- virtual bool str_needs_quotes() { return TRUE; }
- my_decimal *val_decimal(my_decimal *);
- bool val_bool() { return val_int() != 0; }
- int cmp(const uchar *a, const uchar *b)
+ int save_in_field(Field *to) override { return to->store(val_int(), true); }
+ bool memcpy_field_possible(const Field *from) const override{ return false; }
+ int store(const char *to, size_t length, CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ int store_decimal(const my_decimal *) override;
+ double val_real() override;
+ longlong val_int() override;
+ String *val_str(String*, String *) override;
+ bool str_needs_quotes() const override { return true; }
+ my_decimal *val_decimal(my_decimal *) override;
+ bool val_bool() override { return val_int() != 0; }
+ int cmp(const uchar *a, const uchar *b) const override
{
DBUG_ASSERT(ptr == a || ptr == b);
if (ptr == a)
@@ -4428,15 +4809,15 @@ public:
else
return Field_bit::key_cmp(a, bytes_in_rec + MY_TEST(bit_len)) * -1;
}
- int cmp_binary_offset(uint row_offset)
+ int cmp_binary_offset(uint row_offset) override
{ return cmp_offset(row_offset); }
- int cmp_max(const uchar *a, const uchar *b, uint max_length);
- int key_cmp(const uchar *a, const uchar *b)
+ int cmp_max(const uchar *a, const uchar *b, uint max_length) const override;
+ int key_cmp(const uchar *a, const uchar *b) const override
{ return cmp_binary((uchar *) a, (uchar *) b); }
- int key_cmp(const uchar *str, uint length);
- int cmp_offset(my_ptrdiff_t row_offset);
- bool update_min(Field *min_val, bool force_update)
- {
+ int key_cmp(const uchar *str, uint length) const override;
+ int cmp_offset(my_ptrdiff_t row_offset) override;
+ bool update_min(Field *min_val, bool force_update) override
+ {
longlong val= val_int();
bool update_fl= force_update || val < min_val->val_int();
if (update_fl)
@@ -4446,8 +4827,8 @@ public:
}
return update_fl;
}
- bool update_max(Field *max_val, bool force_update)
- {
+ bool update_max(Field *max_val, bool force_update) override
+ {
longlong val= val_int();
bool update_fl= force_update || val > max_val->val_int();
if (update_fl)
@@ -4457,72 +4838,95 @@ public:
}
return update_fl;
}
- void store_field_value(uchar *val, uint len)
+ void store_field_value(uchar *val, uint) override
{
store(*((longlong *)val), TRUE);
}
- double pos_in_interval(Field *min, Field *max)
+ double pos_in_interval(Field *min, Field *max) override
{
return pos_in_interval_val_real(min, max);
}
- void get_image(uchar *buff, uint length, CHARSET_INFO *cs)
- { get_key_image(buff, length, itRAW); }
- void set_image(const uchar *buff,uint length, CHARSET_INFO *cs)
+ void get_image(uchar *buff, uint length, CHARSET_INFO *) override
+ { get_key_image(buff, length, itRAW); }
+ void set_image(const uchar *buff,uint length, CHARSET_INFO *cs) override
{ Field_bit::store((char *) buff, length, cs); }
- uint get_key_image(uchar *buff, uint length, imagetype type);
- void set_key_image(const uchar *buff, uint length)
+ uint get_key_image(uchar *buff, uint length, imagetype type) override;
+ void set_key_image(const uchar *buff, uint length) override
{ Field_bit::store((char*) buff, length, &my_charset_bin); }
- void sort_string(uchar *buff, uint length)
+ void sort_string(uchar *buff, uint length) override
{ get_key_image(buff, length, itRAW); }
- uint32 pack_length() const { return (uint32) (field_length + 7) / 8; }
- uint32 pack_length_in_rec() const { return bytes_in_rec; }
- uint pack_length_from_metadata(uint field_metadata);
- uint row_pack_length() const
+ uint32 pack_length() const override
+ { return (uint32) (field_length + 7) / 8; }
+ uint32 pack_length_in_rec() const override { return bytes_in_rec; }
+ uint pack_length_from_metadata(uint field_metadata) const override;
+ uint row_pack_length() const override
{ return (bytes_in_rec + ((bit_len > 0) ? 1 : 0)); }
- bool compatible_field_size(uint metadata, Relay_log_info *rli,
- uint16 mflags, int *order_var);
- void sql_type(String &str) const;
- virtual uchar *pack(uchar *to, const uchar *from, uint max_length);
- virtual const uchar *unpack(uchar *to, const uchar *from,
- const uchar *from_end, uint param_data);
- virtual int set_default();
+ bool compatible_field_size(uint metadata, const Relay_log_info *rli,
+ uint16 mflags, int *order_var) const override;
+ void sql_type(String &str) const override;
+ uchar *pack(uchar *to, const uchar *from, uint max_length) override;
+ const uchar *unpack(uchar *to, const uchar *from,
+ const uchar *from_end, uint param_data) override;
+ int set_default() override;
Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
uchar *new_ptr, uint32 length,
- uchar *new_null_ptr, uint new_null_bit);
+ uchar *new_null_ptr, uint new_null_bit) override;
void set_bit_ptr(uchar *bit_ptr_arg, uchar bit_ofs_arg)
{
bit_ptr= bit_ptr_arg;
bit_ofs= bit_ofs_arg;
}
- bool eq(Field *field)
+ bool eq(Field *field) override
{
return (Field::eq(field) &&
bit_ptr == ((Field_bit *)field)->bit_ptr &&
bit_ofs == ((Field_bit *)field)->bit_ofs);
}
- bool is_equal(const Column_definition &new_field) const;
- void move_field_offset(my_ptrdiff_t ptr_diff)
+ bool is_equal(const Column_definition &new_field) const override;
+ void move_field_offset(my_ptrdiff_t ptr_diff) override
{
Field::move_field_offset(ptr_diff);
bit_ptr= ADD_TO_PTR(bit_ptr, ptr_diff, uchar*);
}
- void hash(ulong *nr, ulong *nr2);
+ void hash(ulong *nr, ulong *nr2) override;
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
const Item_bool_func *cond,
- scalar_comparison_op op, Item *value)
+ scalar_comparison_op op, Item *value) override
{
return get_mm_leaf_int(param, key_part, cond, op, value, true);
}
- void print_key_value(String *out, uint32 length)
+ void print_key_value(String *out, uint32 length) override
{
val_int_as_str(out, 1);
}
+ /**
+ Save the field metadata for bit fields.
+ Saves the bit length in the first byte and bytes in record in the
+ second byte of the field metadata array at index of *metadata_ptr and
+ *(metadata_ptr + 1).
+
+ @param metadata_ptr First byte of field metadata
+
+ @returns number of bytes written to metadata_ptr
+ */
+ Binlog_type_info binlog_type_info() const override
+ {
+ DBUG_PRINT("debug", ("bit_len: %d, bytes_in_rec: %d",
+ bit_len, bytes_in_rec));
+ /*
+ Since this class and Field_bit_as_char have different ideas of
+ what should be stored here, we compute the values of the metadata
+ explicitly using the field_length.
+ */
+ return Binlog_type_info(type(),
+ static_cast<uint16>((field_length & 7) |
+ ((field_length / 8) << 8)), 2);
+ }
private:
- virtual size_t do_last_null_byte() const;
- int save_field_metadata(uchar *first_byte);
+ size_t do_last_null_byte() const override;
};
@@ -4538,13 +4942,13 @@ public:
Field_bit_as_char(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg);
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
- uint size_of() const { return sizeof(*this); }
- int store(const char *to, size_t length, CHARSET_INFO *charset);
- int store(double nr) { return Field_bit::store(nr); }
- int store(longlong nr, bool unsigned_val)
+ enum ha_base_keytype key_type() const override { return HA_KEYTYPE_BINARY; }
+ uint size_of() const override { return sizeof *this; }
+ int store(const char *to, size_t length, CHARSET_INFO *charset) override;
+ int store(double nr) override { return Field_bit::store(nr); }
+ int store(longlong nr, bool unsigned_val) override
{ return Field_bit::store(nr, unsigned_val); }
- void sql_type(String &str) const;
+ void sql_type(String &str) const override;
};
@@ -4557,6 +4961,18 @@ public:
m_table(NULL)
{}
~Field_row();
+ en_fieldtype tmp_engine_column_type(bool use_packed_rows) const
+ {
+ DBUG_ASSERT(0);
+ return Field::tmp_engine_column_type(use_packed_rows);
+ }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+ {
+ DBUG_ASSERT(0);
+ return CONV_TYPE_IMPOSSIBLE;
+ }
Virtual_tmp_table **virtual_tmp_table_addr() { return &m_table; }
bool sp_prepare_and_store_item(THD *thd, Item **value);
};
@@ -4572,22 +4988,23 @@ public:
max number of characters.
*/
ulonglong length;
+ uint decimals;
Field::utype unireg_check;
- TYPELIB *interval; // Which interval to use
+ const TYPELIB *interval; // Which interval to use
CHARSET_INFO *charset;
uint32 srid;
- Field::geometry_type geom_type;
uint pack_flag;
Column_definition_attributes()
:length(0),
+ decimals(0),
unireg_check(Field::NONE),
interval(NULL),
charset(&my_charset_bin),
srid(0),
- geom_type(Field::GEOM_GEOMETRY),
pack_flag(0)
{ }
Column_definition_attributes(const Field *field);
+ Column_definition_attributes(const Type_all_attributes &attr);
Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root,
const Record_addr *rec,
const Type_handler *handler,
@@ -4600,8 +5017,13 @@ public:
uint pack_flag_to_pack_length() const;
void frm_pack_basic(uchar *buff) const;
void frm_pack_charset(uchar *buff) const;
+ void frm_pack_numeric_with_dec(uchar *buff) const;
void frm_unpack_basic(const uchar *buff);
bool frm_unpack_charset(TABLE_SHARE *share, const uchar *buff);
+ bool frm_unpack_numeric_with_dec(TABLE_SHARE *share, const uchar *buff);
+ bool frm_unpack_temporal_with_dec(TABLE_SHARE *share, uint intlen,
+ const uchar *buff);
+ void set_length_and_dec(const Lex_length_and_dec_st &attr);
};
@@ -4645,7 +5067,7 @@ class Column_definition: public Sql_alloc,
for (pos= interval->type_names, len= interval->type_lengths;
*pos ; pos++, len++)
{
- size_t length= charset->cset->numchars(charset, *pos, *pos + *len);
+ size_t length= charset->numchars(*pos, *pos + *len);
DBUG_ASSERT(length < UINT_MAX32);
*tot_length+= (uint) length;
set_if_bigger(*max_length, (uint32)length);
@@ -4671,7 +5093,7 @@ public:
for most of the types, or of bytes for BLOBs or numeric types.
*/
uint32 char_length;
- uint decimals, flags, pack_length, key_length;
+ uint flags, pack_length;
List<String> interval_list;
engine_option_value *option_list;
@@ -4694,8 +5116,8 @@ public:
:Type_handler_hybrid_field_type(&type_handler_null),
compression_method_ptr(0),
comment(null_clex_str),
- on_update(NULL), invisible(VISIBLE), char_length(0), decimals(0),
- flags(0), pack_length(0), key_length(0),
+ on_update(NULL), invisible(VISIBLE), char_length(0),
+ flags(0), pack_length(0),
option_list(NULL),
vcol_info(0), default_value(0), check_constraint(0),
versioning(VERSIONING_NOT_SET), period(NULL)
@@ -4704,15 +5126,18 @@ public:
}
Column_definition(THD *thd, Field *field, Field *orig_field);
- void set_attributes(const Lex_field_type_st &type, CHARSET_INFO *cs);
+ bool set_attributes(THD *thd,
+ const Lex_field_type_st &attr,
+ CHARSET_INFO *cs,
+ column_definition_type_t type);
void create_length_to_internal_length_null()
{
DBUG_ASSERT(length == 0);
- key_length= pack_length= 0;
+ pack_length= 0;
}
void create_length_to_internal_length_simple()
{
- key_length= pack_length= type_handler()->calc_pack_length((uint32) length);
+ pack_length= type_handler()->calc_pack_length((uint32) length);
}
void create_length_to_internal_length_string()
{
@@ -4720,14 +5145,12 @@ public:
if (real_field_type() == MYSQL_TYPE_VARCHAR && compression_method())
length++;
set_if_smaller(length, UINT_MAX32);
- key_length= (uint) length;
pack_length= type_handler()->calc_pack_length((uint32) length);
}
void create_length_to_internal_length_typelib()
{
/* Pack_length already calculated in sql_parse.cc */
length*= charset->mbmaxlen;
- key_length= pack_length;
}
bool vers_sys_field() const
{
@@ -4795,7 +5218,7 @@ public:
bool prepare_stage2_varchar(ulonglong table_flags);
bool prepare_stage2_typelib(const char *type_name, uint field_flags,
uint *dup_val_count);
- uint pack_flag_numeric(uint dec) const;
+ uint pack_flag_numeric() const;
uint sign_length() const { return flags & UNSIGNED_FLAG ? 0 : 1; }
bool check_length(uint mysql_errno, uint max_allowed_length) const;
bool fix_attributes_real(uint default_length);
@@ -4857,12 +5280,10 @@ public:
decimals= other.decimals;
flags= other.flags;
pack_length= other.pack_length;
- key_length= other.key_length;
unireg_check= other.unireg_check;
interval= other.interval;
charset= other.charset;
srid= other.srid;
- geom_type= other.geom_type;
pack_flag= other.pack_flag;
}
@@ -4880,6 +5301,8 @@ public:
{ compression_method_ptr= compression_method_arg; }
Compression_method *compression_method() const
{ return compression_method_ptr; }
+
+ bool check_vcol_for_key(THD *thd) const;
};
@@ -5056,7 +5479,7 @@ public:
LEX_CSTRING change; // If done with alter table
LEX_CSTRING after; // Put column after this one
Field *field; // For alter table
- TYPELIB *save_interval; // Temporary copy for the above
+ const TYPELIB *save_interval; // Temporary copy for the above
// Used only for UCS2 intervals
/** structure with parsed options (for comparing fields in ALTER TABLE) */
@@ -5090,25 +5513,25 @@ public:
*/
class Send_field :public Sql_alloc,
- public Type_handler_hybrid_field_type
+ public Type_handler_hybrid_field_type,
+ public Send_field_extended_metadata
{
public:
- const char *db_name;
- const char *table_name,*org_table_name;
+ LEX_CSTRING db_name;
+ LEX_CSTRING table_name, org_table_name;
LEX_CSTRING col_name, org_col_name;
ulong length;
uint flags, decimals;
- Send_field() {}
Send_field(Field *field)
{
field->make_send_field(this);
- DBUG_ASSERT(table_name != 0);
+ DBUG_ASSERT(table_name.str != 0);
normalize();
}
Send_field(THD *thd, Item *item);
Send_field(Field *field,
- const char *db_name_arg,
- const char *table_name_arg)
+ const LEX_CSTRING &db_name_arg,
+ const LEX_CSTRING &table_name_arg)
:Type_handler_hybrid_field_type(field->type_handler()),
db_name(db_name_arg),
table_name(table_name_arg),
@@ -5136,9 +5559,9 @@ public:
uint32 max_char_length(CHARSET_INFO *cs) const
{
return type_handler()->field_type() >= MYSQL_TYPE_TINY_BLOB &&
- type_handler()->field_type() <= MYSQL_TYPE_BLOB ?
- length / cs->mbminlen :
- length / cs->mbmaxlen;
+ type_handler()->field_type() <= MYSQL_TYPE_BLOB
+ ? static_cast<uint32>(length / cs->mbminlen)
+ : static_cast<uint32>(length / cs->mbmaxlen);
}
uint32 max_octet_length(CHARSET_INFO *from, CHARSET_INFO *to) const
{
@@ -5163,12 +5586,27 @@ public:
}
// This should move to Type_handler eventually
- bool is_sane() const
+ bool is_sane_float() const
{
return (decimals <= FLOATING_POINT_DECIMALS ||
(type_handler()->field_type() != MYSQL_TYPE_FLOAT &&
type_handler()->field_type() != MYSQL_TYPE_DOUBLE));
}
+ bool is_sane_signess() const
+ {
+ if (type_handler() == type_handler()->type_handler_signed() &&
+ type_handler() == type_handler()->type_handler_unsigned())
+ return true; // Any signess is allowed, e.g. DOUBLE, DECIMAL
+ /*
+ We are here e.g. in case of INT data type.
+ The UNSIGNED_FLAG bit must match in flags and in the type handler.
+ */
+ return ((bool) (flags & UNSIGNED_FLAG)) == type_handler()->is_unsigned();
+ }
+ bool is_sane() const
+ {
+ return is_sane_float() && is_sane_signess();
+ }
};
@@ -5217,7 +5655,7 @@ enum_field_types get_blob_type_from_length(ulong length);
int set_field_to_null(Field *field);
int set_field_to_null_with_conversions(Field *field, bool no_conversions);
int convert_null_to_field_value_or_error(Field *field);
-bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *name,
+bool check_expression(Virtual_column_info *vcol, const LEX_CSTRING *name,
enum_vcol_info_type type);
/*
@@ -5243,6 +5681,8 @@ bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *name,
#define FIELDFLAG_DEC_SHIFT 8
#define FIELDFLAG_MAX_DEC 63U
+#define FIELDFLAG_DEC_MASK 0x3F00U
+
#define MTYP_TYPENR(type) ((type) & 127U) // Remove bits from type
#define f_is_dec(x) ((x) & FIELDFLAG_DECIMAL)
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index bcd4c5fbb38..ff6d60e7626 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, 2018, MariaDB Corporation
+ Copyright (c) 2010, 2020, 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
@@ -30,7 +30,7 @@
#include "sql_class.h" // THD
#include <m_ctype.h>
-static void do_field_eq(Copy_field *copy)
+void Field::do_field_eq(Copy_field *copy)
{
memcpy(copy->to_ptr,copy->from_ptr,copy->from_length);
}
@@ -168,7 +168,7 @@ int convert_null_to_field_value_or_error(Field *field)
{
if (field->type() == MYSQL_TYPE_TIMESTAMP)
{
- ((Field_timestamp*) field)->set_time();
+ field->set_time();
return 0;
}
@@ -230,7 +230,7 @@ static void do_skip(Copy_field *copy __attribute__((unused)))
note: if the record we're copying from is NULL-complemetned (i.e.
from_field->table->null_row==1), it will also have all NULLable columns to be
- set to NULLs, so we dont need to check table->null_row here.
+ set to NULLs, so we don't need to check table->null_row here.
*/
static void do_copy_null(Copy_field *copy)
@@ -315,7 +315,7 @@ static void do_copy_timestamp(Copy_field *copy)
if (*copy->from_null_ptr & copy->from_bit)
{
/* Same as in set_field_to_null_with_conversions() */
- ((Field_timestamp*) copy->to_field)->set_time();
+ copy->to_field->set_time();
}
else
(copy->do_copy2)(copy);
@@ -465,10 +465,9 @@ static void do_cut_string(Copy_field *copy)
memcpy(copy->to_ptr,copy->from_ptr,copy->to_length);
/* Check if we loosed any important characters */
- if (cs->cset->scan(cs,
- (char*) copy->from_ptr + copy->to_length,
- (char*) copy->from_ptr + copy->from_length,
- MY_SEQ_SPACES) < copy->from_length - copy->to_length)
+ if (cs->scan((char*) copy->from_ptr + copy->to_length,
+ (char*) copy->from_ptr + copy->from_length,
+ MY_SEQ_SPACES) < copy->from_length - copy->to_length)
{
copy->to_field->set_warning(Sql_condition::WARN_LEVEL_WARN,
WARN_DATA_TRUNCATED, 1);
@@ -496,9 +495,9 @@ static void do_cut_string_complex(Copy_field *copy)
/* Check if we lost any important characters */
if (unlikely(prefix.well_formed_error_pos() ||
- cs->cset->scan(cs, (char*) copy->from_ptr + copy_length,
- (char*) from_end,
- MY_SEQ_SPACES) <
+ cs->scan((char*) copy->from_ptr + copy_length,
+ (char*) from_end,
+ MY_SEQ_SPACES) <
(copy->from_length - copy_length)))
{
copy->to_field->set_warning(Sql_condition::WARN_LEVEL_WARN,
@@ -506,8 +505,8 @@ static void do_cut_string_complex(Copy_field *copy)
}
if (copy_length < copy->to_length)
- cs->cset->fill(cs, (char*) copy->to_ptr + copy_length,
- copy->to_length - copy_length, ' ');
+ cs->fill((char*) copy->to_ptr + copy_length,
+ copy->to_length - copy_length, ' ');
}
@@ -517,8 +516,8 @@ static void do_expand_binary(Copy_field *copy)
{
CHARSET_INFO *cs= copy->from_field->charset();
memcpy(copy->to_ptr,copy->from_ptr,copy->from_length);
- cs->cset->fill(cs, (char*) copy->to_ptr+copy->from_length,
- copy->to_length-copy->from_length, '\0');
+ cs->fill((char*) copy->to_ptr+copy->from_length,
+ copy->to_length-copy->from_length, '\0');
}
@@ -527,8 +526,8 @@ static void do_expand_string(Copy_field *copy)
{
CHARSET_INFO *cs= copy->from_field->charset();
memcpy(copy->to_ptr,copy->from_ptr,copy->from_length);
- cs->cset->fill(cs, (char*) copy->to_ptr+copy->from_length,
- copy->to_length-copy->from_length, ' ');
+ cs->fill((char*) copy->to_ptr+copy->from_length,
+ copy->to_length-copy->from_length, ' ');
}
@@ -638,7 +637,7 @@ void Copy_field::set(uchar *to,Field *from)
else
{
to_null_ptr= 0; // For easy debugging
- do_copy= do_field_eq;
+ do_copy= Field::do_field_eq;
}
}
@@ -719,7 +718,7 @@ void Copy_field::set(Field *to,Field *from,bool save)
if ((to->flags & BLOB_FLAG) && save)
do_copy2= do_save_blob;
else
- do_copy2= to->get_copy_func(from);
+ do_copy2= from->get_copy_func_to(to);
if (!do_copy) // Not null
do_copy=do_copy2;
}
@@ -786,7 +785,7 @@ Field::Copy_func *Field_string::get_copy_func(const Field *from) const
{
if (from->type() == MYSQL_TYPE_BIT)
return do_field_int;
- if (Field_string::real_type() != from->real_type() ||
+ if (Field_string::type_handler() != from->type_handler() ||
Field_string::charset() != from->charset())
return do_field_string;
if (Field_string::pack_length() < from->pack_length())
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 2e06905a48e..1f491df82eb 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2009, 2015, MariaDB
+ Copyright (c) 2009, 2020, 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
@@ -48,25 +48,55 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
ha_rows *found_rows);
static bool write_keys(Sort_param *param, SORT_INFO *fs_info,
uint count, IO_CACHE *buffer_file, IO_CACHE *tempfile);
-static void make_sortkey(Sort_param *param, uchar *to, uchar *ref_pos);
+static uint make_sortkey(Sort_param *param, uchar *to, uchar *ref_pos,
+ bool using_packed_sortkeys= false);
+static uint make_sortkey(Sort_param *param, uchar *to);
+static uint make_packed_sortkey(Sort_param *param, uchar *to);
+
static void register_used_fields(Sort_param *param);
static bool save_index(Sort_param *param, uint count,
SORT_INFO *table_sort);
static uint suffix_length(ulong string_length);
-static uint sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
- bool *multi_byte_charset);
-static SORT_ADDON_FIELD *get_addon_fields(TABLE *table, uint sortlength,
- LEX_STRING *addon_buf);
-static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
- uchar *buff, uchar *buff_end);
+static uint sortlength(THD *thd, Sort_keys *sortorder,
+ bool *multi_byte_charset,
+ bool *allow_packing_for_sortkeys);
+static Addon_fields *get_addon_fields(TABLE *table, uint sortlength,
+ uint *addon_length,
+ uint *m_packable_length);
+
static bool check_if_pq_applicable(Sort_param *param, SORT_INFO *info,
TABLE *table,
ha_rows records, size_t memory_available);
+static void store_key_part_length(uint32 num, uchar *to, uint bytes)
+{
+ switch(bytes) {
+ case 1: *to= (uchar)num; break;
+ case 2: int2store(to, num); break;
+ case 3: int3store(to, num); break;
+ case 4: int4store(to, num); break;
+ default: DBUG_ASSERT(0);
+ }
+}
+
+
+static uint32 read_keypart_length(const uchar *from, uint bytes)
+{
+ switch(bytes) {
+ case 1: return from[0];
+ case 2: return uint2korr(from);
+ case 3: return uint3korr(from);
+ case 4: return uint4korr(from);
+ default: DBUG_ASSERT(0); return 0;
+ }
+}
+
+
+// @param sortlen [Maximum] length of the sort key
void Sort_param::init_for_filesort(uint sortlen, TABLE *table,
ha_rows maxrows, bool sort_positions)
{
- DBUG_ASSERT(addon_field == 0 && addon_buf.length == 0);
+ DBUG_ASSERT(addon_fields == NULL);
sort_length= sortlen;
ref_length= table->file->ref_length;
@@ -77,12 +107,13 @@ void Sort_param::init_for_filesort(uint sortlen, TABLE *table,
Get the descriptors of all fields whose values are appended
to sorted fields and get its total length in addon_buf.length
*/
- addon_field= get_addon_fields(table, sort_length, &addon_buf);
+ addon_fields= get_addon_fields(table, sort_length, &addon_length,
+ &m_packable_length);
}
- if (addon_field)
+ if (using_addon_fields())
{
- DBUG_ASSERT(addon_buf.length < UINT_MAX32);
- res_length= (uint)addon_buf.length;
+ DBUG_ASSERT(addon_length < UINT_MAX32);
+ res_length= addon_length;
}
else
{
@@ -93,11 +124,42 @@ void Sort_param::init_for_filesort(uint sortlen, TABLE *table,
*/
sort_length+= ref_length;
}
- rec_length= sort_length + (uint)addon_buf.length;
+ rec_length= sort_length + addon_length;
max_rows= maxrows;
}
+void Sort_param::try_to_pack_addons(ulong max_length_for_sort_data)
+{
+ if (!using_addon_fields() || // no addons, or
+ using_packed_addons()) // already packed
+ return;
+
+ if (!Addon_fields::can_pack_addon_fields(res_length))
+ return;
+
+ const uint sz= Addon_fields::size_of_length_field;
+
+ // Heuristic: skip packing if potential savings are less than 10 bytes.
+ if (m_packable_length < (10 + sz))
+ return;
+
+ SORT_ADDON_FIELD *addonf= addon_fields->begin();
+ for (;addonf != addon_fields->end(); ++addonf)
+ {
+ addonf->offset+= sz;
+ addonf->null_offset+= sz;
+ }
+
+ addon_fields->set_using_packed_addons(true);
+ m_using_packed_addons= true;
+ m_packed_format= true;
+
+ addon_length+= sz;
+ res_length+= sz;
+ rec_length+= sz;
+}
+
/**
Sort a table.
Creates a set of pointers that can be used to read the rows
@@ -134,22 +196,25 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort,
DBUG_ASSERT(thd->variables.sortbuff_size <= SIZE_T_MAX);
size_t memory_available= (size_t)thd->variables.sortbuff_size;
uint maxbuffer;
- BUFFPEK *buffpek;
+ Merge_chunk *buffpek;
ha_rows num_rows= HA_POS_ERROR;
IO_CACHE tempfile, buffpek_pointers, *outfile;
Sort_param param;
- bool multi_byte_charset;
+ bool multi_byte_charset, allow_packing_for_sortkeys;
Bounded_queue<uchar, uchar> pq;
SQL_SELECT *const select= filesort->select;
ha_rows max_rows= filesort->limit;
uint s_length= 0;
+ Sort_keys *sort_keys;
DBUG_ENTER("filesort");
- if (!(s_length= filesort->make_sortorder(thd, join, first_table_bit)))
+ if (!(sort_keys= filesort->make_sortorder(thd, join, first_table_bit)))
DBUG_RETURN(NULL); /* purecov: inspected */
- DBUG_EXECUTE("info",TEST_filesort(filesort->sortorder,s_length););
+ s_length= static_cast<uint>(sort_keys->size());
+
+ DBUG_EXECUTE("info",TEST_filesort(filesort->sortorder, s_length););
#ifdef SKIP_DBUG_IN_FILESORT
DBUG_PUSH(""); /* No DBUG here */
#endif
@@ -164,13 +229,16 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort,
if (subselect && subselect->filesort_buffer.is_allocated())
{
- /* Reuse cache from last call */
+ // Reuse cache from last call
sort->filesort_buffer= subselect->filesort_buffer;
sort->buffpek= subselect->sortbuffer;
subselect->filesort_buffer.reset();
subselect->sortbuffer.str=0;
}
+ DBUG_ASSERT(sort->sorted_result_in_fsbuf == FALSE ||
+ sort->record_pointers == NULL);
+
outfile= &sort->io_cache;
my_b_clear(&tempfile);
@@ -179,24 +247,21 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort,
error= 1;
sort->found_rows= HA_POS_ERROR;
- param.init_for_filesort(sortlength(thd, filesort->sortorder, s_length,
- &multi_byte_charset),
- table, max_rows, filesort->sort_positions);
+ param.sort_keys= sort_keys;
+ uint sort_len= sortlength(thd, sort_keys, &multi_byte_charset,
+ &allow_packing_for_sortkeys);
- sort->addon_buf= param.addon_buf;
- sort->addon_field= param.addon_field;
- sort->unpack= unpack_addon_fields;
- if (multi_byte_charset &&
- !(param.tmp_buffer= (char*) my_malloc(param.sort_length,
- MYF(MY_WME | MY_THREAD_SPECIFIC))))
- goto err;
+ param.init_for_filesort(sort_len, table, max_rows, filesort->sort_positions);
+
+ sort->addon_fields= param.addon_fields;
+ sort->sort_keys= param.sort_keys;
if (select && select->quick)
thd->inc_status_sort_range();
else
thd->inc_status_sort_scan();
thd->query_plan_flags|= QPLAN_FILESORT;
- tracker->report_use(max_rows);
+ tracker->report_use(thd, max_rows);
// If number of rows is not known, use as much of sort buffer as possible.
num_rows= table->file->estimate_rows_upper_bound();
@@ -208,7 +273,16 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort,
thd->query_plan_flags|= QPLAN_FILESORT_PRIORITY_QUEUE;
status_var_increment(thd->status_var.filesort_pq_sorts_);
tracker->incr_pq_used();
+ param.using_pq= true;
const size_t compare_length= param.sort_length;
+ DBUG_ASSERT(param.using_packed_sortkeys() == false);
+ /*
+ For PQ queries (with limit) we know exactly how many pointers/records
+ we have in the buffer, so to simplify things, we initialize
+ all pointers here. (We cannot pack fields anyways, so there is no
+ point in doing lazy initialization).
+ */
+ sort->init_record_pointers();
if (pq.init(param.max_rows,
true, // max_at_top
NULL, // compare_function
@@ -223,21 +297,33 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort,
DBUG_ASSERT(thd->is_error());
goto err;
}
- // For PQ queries (with limit) we initialize all pointers.
- sort->init_record_pointers();
}
else
{
DBUG_PRINT("info", ("filesort PQ is not applicable"));
+ if (allow_packing_for_sortkeys)
+ param.try_to_pack_sortkeys();
+
+ param.try_to_pack_addons(thd->variables.max_length_for_sort_data);
+ tracker->report_sort_keys_format(param.using_packed_sortkeys());
+ param.using_pq= false;
+
+ if ((multi_byte_charset || param.using_packed_sortkeys()) &&
+ !(param.tmp_buffer= (char*) my_malloc(key_memory_Sort_param_tmp_buffer, param.sort_length,
+ MYF(MY_WME | MY_THREAD_SPECIFIC))))
+ goto err;
+
+
size_t min_sort_memory= MY_MAX(MIN_SORT_MEMORY,
param.sort_length*MERGEBUFF2);
- set_if_bigger(min_sort_memory, sizeof(BUFFPEK*)*MERGEBUFF2);
+ set_if_bigger(min_sort_memory, sizeof(Merge_chunk*)*MERGEBUFF2);
while (memory_available >= min_sort_memory)
{
ulonglong keys= memory_available / (param.rec_length + sizeof(char*));
param.max_keys_per_buffer= (uint) MY_MIN(num_rows, keys);
- if (sort->alloc_sort_buffer(param.max_keys_per_buffer, param.rec_length))
+ sort->alloc_sort_buffer(param.max_keys_per_buffer, param.rec_length);
+ if (sort->sort_buffer_size() > 0)
break;
size_t old_memory_available= memory_available;
memory_available= memory_available/4*3;
@@ -253,12 +339,20 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort,
tracker->report_sort_buffer_size(sort->sort_buffer_size());
}
+ if (param.using_addon_fields())
+ {
+ // report information whether addon fields are packed or not
+ tracker->report_addon_fields_format(param.using_packed_addons());
+ }
+
if (open_cached_file(&buffpek_pointers,mysql_tmpdir,TEMP_PREFIX,
DISK_BUFFER_SIZE, MYF(MY_WME)))
goto err;
param.sort_form= table;
- param.end=(param.local_sortorder=filesort->sortorder)+s_length;
+ param.local_sortorder=
+ Bounds_checked_array<SORT_FIELD>(filesort->sortorder, s_length);
+
num_rows= find_all_keys(thd, &param, select,
sort,
&buffpek_pointers,
@@ -287,12 +381,20 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort,
my_free(sort->buffpek.str);
sort->buffpek.str= 0;
}
+
+ if (param.using_addon_fields())
+ {
+ DBUG_ASSERT(sort->addon_fields);
+ if (!sort->addon_fields->allocate_addon_buf(param.addon_length))
+ goto err;
+ }
+
if (!(sort->buffpek.str=
(char *) read_buffpek_from_file(&buffpek_pointers, maxbuffer,
(uchar*) sort->buffpek.str)))
goto err;
sort->buffpek.length= maxbuffer;
- buffpek= (BUFFPEK *) sort->buffpek.str;
+ buffpek= (Merge_chunk *) sort->buffpek.str;
close_cached_file(&buffpek_pointers);
/* Open cached file if it isn't open */
if (! my_b_inited(outfile) &&
@@ -306,25 +408,25 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort,
Use also the space previously used by string pointers in sort_buffer
for temporary key storage.
*/
- param.max_keys_per_buffer=((param.max_keys_per_buffer *
- (param.rec_length + sizeof(char*))) /
- param.rec_length - 1);
+
+ param.max_keys_per_buffer= static_cast<uint>(sort->sort_buffer_size()) /
+ param.rec_length;
set_if_bigger(param.max_keys_per_buffer, 1);
maxbuffer--; // Offset from 0
- if (merge_many_buff(&param,
- (uchar*) sort->get_sort_keys(),
+
+ if (merge_many_buff(&param, sort->get_raw_buf(),
buffpek,&maxbuffer,
- &tempfile))
+ &tempfile))
goto err;
if (flush_io_cache(&tempfile) ||
reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
goto err;
if (merge_index(&param,
- (uchar*) sort->get_sort_keys(),
+ sort->get_raw_buf(),
buffpek,
maxbuffer,
&tempfile,
- outfile))
+ outfile))
goto err;
}
@@ -339,7 +441,8 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort,
my_free(param.tmp_buffer);
if (!subselect || !subselect->is_uncacheable())
{
- sort->free_sort_buffer();
+ if (!param.using_addon_fields())
+ sort->free_sort_buffer();
my_free(sort->buffpek.str);
}
else
@@ -347,7 +450,7 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort,
/* Remember sort buffers for next subquery call */
subselect->filesort_buffer= sort->filesort_buffer;
subselect->sortbuffer= sort->buffpek;
- sort->filesort_buffer.reset(); // Don't free this
+ sort->filesort_buffer.reset(); // Don't free this*/
}
sort->buffpek.str= 0;
@@ -361,11 +464,11 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort,
my_off_t save_pos=outfile->pos_in_file;
/* For following reads */
if (reinit_io_cache(outfile,READ_CACHE,0L,0,0))
- error=1;
+ error=1;
outfile->end_of_file=save_pos;
}
}
- tracker->report_merge_passes_at_end(thd->query_plan_fsort_passes);
+ tracker->report_merge_passes_at_end(thd, thd->query_plan_fsort_passes);
if (unlikely(error))
{
int kill_errno= thd->killed_errno();
@@ -423,24 +526,42 @@ void Filesort::cleanup()
}
-uint Filesort::make_sortorder(THD *thd, JOIN *join, table_map first_table_bit)
+/*
+ Create the Sort_keys array and fill the sort_keys[i]->{item|field}.
+
+ This indicates which field/item values will be used as sort keys.
+ Attributes like lengths are not filled yet.
+*/
+
+Sort_keys*
+Filesort::make_sortorder(THD *thd, JOIN *join, table_map first_table_bit)
{
uint count;
SORT_FIELD *sort,*pos;
ORDER *ord;
DBUG_ENTER("make_sortorder");
-
count=0;
for (ord = order; ord; ord= ord->next)
count++;
- if (!sortorder)
- sortorder= (SORT_FIELD*) thd->alloc(sizeof(SORT_FIELD) * (count + 1));
+
+ if (sortorder)
+ DBUG_RETURN(sort_keys);
+
+ DBUG_ASSERT(sort_keys == NULL);
+
+ sortorder= (SORT_FIELD*) thd->alloc(sizeof(SORT_FIELD) * count);
pos= sort= sortorder;
if (!pos)
DBUG_RETURN(0);
+ sort_keys= new Sort_keys(sortorder, count);
+
+ if (!sort_keys)
+ DBUG_RETURN(0);
+
+ pos= sort_keys->begin();
for (ord= order; ord; ord= ord->next, pos++)
{
Item *first= ord->item[0];
@@ -481,7 +602,7 @@ uint Filesort::make_sortorder(THD *thd, JOIN *join, table_map first_table_bit)
pos->reverse= (ord->direction == ORDER::ORDER_DESC);
DBUG_ASSERT(pos->field != NULL || pos->item != NULL);
}
- DBUG_RETURN(count);
+ DBUG_RETURN(sort_keys);
}
@@ -490,13 +611,14 @@ uint Filesort::make_sortorder(THD *thd, JOIN *join, table_map first_table_bit)
static uchar *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint count,
uchar *buf)
{
- size_t length= sizeof(BUFFPEK)*count;
+ size_t length= sizeof(Merge_chunk)*count;
uchar *tmp= buf;
DBUG_ENTER("read_buffpek_from_file");
- if (count > UINT_MAX/sizeof(BUFFPEK))
+ if (count > UINT_MAX/sizeof(Merge_chunk))
return 0; /* sizeof(BUFFPEK)*count will overflow */
if (!tmp)
- tmp= (uchar *)my_malloc(length, MYF(MY_WME | MY_THREAD_SPECIFIC));
+ tmp= (uchar *)my_malloc(key_memory_Filesort_info_merge, length,
+ MYF(MY_WME | MY_THREAD_SPECIFIC));
if (tmp)
{
if (reinit_io_cache(buffpek_pointers,READ_CACHE,0L,0,0) ||
@@ -690,7 +812,7 @@ static void dbug_print_record(TABLE *table, bool print_rowid)
static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
SORT_INFO *fs_info,
- IO_CACHE *buffpek_pointers,
+ IO_CACHE *buffpek_pointers,
IO_CACHE *tempfile,
Bounded_queue<uchar, uchar> *pq,
ha_rows *found_rows)
@@ -702,7 +824,10 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
handler *file;
MY_BITMAP *save_read_set, *save_write_set;
Item *sort_cond;
- ha_rows retval;
+ ha_rows num_records= 0;
+ const bool packed_format= param->is_packed_format();
+ const bool using_packed_sortkeys= param->using_packed_sortkeys();
+
DBUG_ENTER("find_all_keys");
DBUG_PRINT("info",("using: %s",
(select ? select->quick ? "ranges" : "where":
@@ -758,6 +883,7 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
}
DEBUG_SYNC(thd, "after_index_merge_phase1");
+
for (;;)
{
if (quick_select)
@@ -810,23 +936,28 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
if (write_record)
{
- ++(*found_rows);
if (pq)
- {
pq->push(ref_pos);
- idx= pq->num_elements();
- }
else
{
- if (idx == param->max_keys_per_buffer)
+ if (fs_info->isfull())
{
if (write_keys(param, fs_info, idx, buffpek_pointers, tempfile))
goto err;
- idx= 0;
- indexpos++;
+ idx= 0;
+ indexpos++;
}
- make_sortkey(param, fs_info->get_record_buffer(idx++), ref_pos);
+ if (idx == 0)
+ fs_info->init_next_record_pointer();
+ uchar *start_of_rec= fs_info->get_next_record_pointer();
+
+ const uint rec_sz= make_sortkey(param, start_of_rec,
+ ref_pos, using_packed_sortkeys);
+ if (packed_format && rec_sz != param->rec_length)
+ fs_info->adjust_next_record_pointer(rec_sz);
+ idx++;
}
+ num_records++;
}
/* It does not make sense to read more keys in case of a fatal error */
@@ -862,11 +993,14 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
if (indexpos && idx &&
write_keys(param, fs_info, idx, buffpek_pointers, tempfile))
DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
- retval= (my_b_inited(tempfile) ?
- (ha_rows) (my_b_tell(tempfile)/param->rec_length) :
- idx);
- DBUG_PRINT("info", ("find_all_keys return %llu", (ulonglong) retval));
- DBUG_RETURN(retval);
+
+ (*found_rows)= num_records;
+ if (pq)
+ num_records= pq->num_elements();
+
+
+ DBUG_PRINT("info", ("find_all_keys return %llu", (ulonglong) num_records));
+ DBUG_RETURN(num_records);
err:
sort_form->column_bitmaps_set(save_read_set, save_write_set);
@@ -900,45 +1034,45 @@ static bool
write_keys(Sort_param *param, SORT_INFO *fs_info, uint count,
IO_CACHE *buffpek_pointers, IO_CACHE *tempfile)
{
- size_t rec_length;
- uchar **end;
- BUFFPEK buffpek;
+ Merge_chunk buffpek;
DBUG_ENTER("write_keys");
- rec_length= param->rec_length;
- uchar **sort_keys= fs_info->get_sort_keys();
-
fs_info->sort_buffer(param, count);
if (!my_b_inited(tempfile) &&
open_cached_file(tempfile, mysql_tmpdir, TEMP_PREFIX, DISK_BUFFER_SIZE,
MYF(MY_WME)))
- goto err; /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
/* check we won't have more buffpeks than we can possibly keep in memory */
- if (my_b_tell(buffpek_pointers) + sizeof(BUFFPEK) > (ulonglong)UINT_MAX)
- goto err;
- bzero(&buffpek, sizeof(buffpek));
- buffpek.file_pos= my_b_tell(tempfile);
+ if (my_b_tell(buffpek_pointers) + sizeof(Merge_chunk) > (ulonglong)UINT_MAX)
+ DBUG_RETURN(1);
+
+ buffpek.set_file_position(my_b_tell(tempfile));
if ((ha_rows) count > param->max_rows)
count=(uint) param->max_rows; /* purecov: inspected */
- buffpek.count=(ha_rows) count;
- for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
- if (my_b_write(tempfile, (uchar*) *sort_keys, (uint) rec_length))
- goto err;
+ buffpek.set_rowcount(static_cast<ha_rows>(count));
+
+ for (uint ix= 0; ix < count; ++ix)
+ {
+ uchar *record= fs_info->get_sorted_record(ix);
+
+
+ if (my_b_write(tempfile, record, param->get_record_length(record)))
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
+
if (my_b_write(buffpek_pointers, (uchar*) &buffpek, sizeof(buffpek)))
- goto err;
+ DBUG_RETURN(1);
+
DBUG_RETURN(0);
-err:
- DBUG_RETURN(1);
} /* write_keys */
/**
- Store length as suffix in high-byte-first order.
+ Store length in high-byte-first order.
*/
-
-static inline void store_length(uchar *to, uint length, uint pack_length)
+void store_length(uchar *to, uint length, uint pack_length)
{
switch (pack_length) {
case 1:
@@ -958,9 +1092,9 @@ static inline void store_length(uchar *to, uint length, uint pack_length)
void
-Type_handler_string_result::make_sort_key(uchar *to, Item *item,
- const SORT_FIELD_ATTR *sort_field,
- Sort_param *param) const
+Type_handler_string_result::make_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const
{
CHARSET_INFO *cs= item->collation.collation;
bool maybe_null= item->maybe_null;
@@ -997,12 +1131,11 @@ Type_handler_string_result::make_sort_key(uchar *to, Item *item,
#ifdef DBUG_ASSERT_EXISTS
size_t tmp_length=
#endif
- cs->coll->strnxfrm(cs, to, sort_field->length,
- item->max_char_length() *
- cs->strxfrm_multiply,
- (uchar*) res->ptr(), res->length(),
- MY_STRXFRM_PAD_WITH_SPACE |
- MY_STRXFRM_PAD_TO_MAXLEN);
+ cs->strnxfrm(to, sort_field->length,
+ item->max_char_length() * cs->strxfrm_multiply,
+ (uchar*) res->ptr(), res->length(),
+ MY_STRXFRM_PAD_WITH_SPACE |
+ MY_STRXFRM_PAD_TO_MAXLEN);
DBUG_ASSERT(tmp_length == sort_field->length);
}
else
@@ -1023,17 +1156,17 @@ Type_handler_string_result::make_sort_key(uchar *to, Item *item,
store_length(to + sort_field_length, length, sort_field->suffix_length);
}
/* apply cs->sort_order for case-insensitive comparison if needed */
- my_strnxfrm(cs,(uchar*)to,length,(const uchar*)res->ptr(),length);
+ cs->strnxfrm((uchar*)to, length, (const uchar*) res->ptr(), length);
char fill_char= ((cs->state & MY_CS_BINSORT) ? (char) 0 : ' ');
- cs->cset->fill(cs, (char *)to+length,diff,fill_char);
+ cs->fill((char *) to + length, diff, fill_char);
}
}
void
-Type_handler_int_result::make_sort_key(uchar *to, Item *item,
- const SORT_FIELD_ATTR *sort_field,
- Sort_param *param) const
+Type_handler_int_result::make_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const
{
longlong value= item->val_int_result();
make_sort_key_longlong(to, item->maybe_null, item->null_value,
@@ -1042,7 +1175,7 @@ Type_handler_int_result::make_sort_key(uchar *to, Item *item,
void
-Type_handler_temporal_result::make_sort_key(uchar *to, Item *item,
+Type_handler_temporal_result::make_sort_key_part(uchar *to, Item *item,
const SORT_FIELD_ATTR *sort_field,
Sort_param *param) const
{
@@ -1064,7 +1197,7 @@ Type_handler_temporal_result::make_sort_key(uchar *to, Item *item,
void
-Type_handler_timestamp_common::make_sort_key(uchar *to, Item *item,
+Type_handler_timestamp_common::make_sort_key_part(uchar *to, Item *item,
const SORT_FIELD_ATTR *sort_field,
Sort_param *param) const
{
@@ -1097,6 +1230,24 @@ Type_handler_timestamp_common::make_sort_key(uchar *to, Item *item,
void
+Type_handler::store_sort_key_longlong(uchar *to, bool unsigned_flag,
+ longlong value) const
+{
+ to[7]= (uchar) value;
+ to[6]= (uchar) (value >> 8);
+ to[5]= (uchar) (value >> 16);
+ to[4]= (uchar) (value >> 24);
+ to[3]= (uchar) (value >> 32);
+ to[2]= (uchar) (value >> 40);
+ to[1]= (uchar) (value >> 48);
+ if (unsigned_flag) /* Fix sign */
+ to[0]= (uchar) (value >> 56);
+ else
+ to[0]= (uchar) (value >> 56) ^ 128; /* Reverse signbit */
+}
+
+
+void
Type_handler::make_sort_key_longlong(uchar *to,
bool maybe_null,
bool null_value,
@@ -1113,24 +1264,35 @@ Type_handler::make_sort_key_longlong(uchar *to,
}
*to++= 1;
}
- to[7]= (uchar) value;
- to[6]= (uchar) (value >> 8);
- to[5]= (uchar) (value >> 16);
- to[4]= (uchar) (value >> 24);
- to[3]= (uchar) (value >> 32);
- to[2]= (uchar) (value >> 40);
- to[1]= (uchar) (value >> 48);
- if (unsigned_flag) /* Fix sign */
- to[0]= (uchar) (value >> 56);
- else
- to[0]= (uchar) (value >> 56) ^ 128; /* Reverse signbit */
+ store_sort_key_longlong(to, unsigned_flag, value);
+}
+
+
+uint
+Type_handler::make_packed_sort_key_longlong(uchar *to, bool maybe_null,
+ bool null_value, bool unsigned_flag,
+ longlong value,
+ const SORT_FIELD_ATTR *sort_field) const
+{
+ if (maybe_null)
+ {
+ if (null_value)
+ {
+ *to++= 0;
+ return 0;
+ }
+ *to++= 1;
+ }
+ store_sort_key_longlong(to, unsigned_flag, value);
+ DBUG_ASSERT(sort_field->original_length == sort_field->length);
+ return sort_field->original_length;
}
void
-Type_handler_decimal_result::make_sort_key(uchar *to, Item *item,
- const SORT_FIELD_ATTR *sort_field,
- Sort_param *param) const
+Type_handler_decimal_result::make_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const
{
my_decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf);
if (item->maybe_null)
@@ -1148,9 +1310,9 @@ Type_handler_decimal_result::make_sort_key(uchar *to, Item *item,
void
-Type_handler_real_result::make_sort_key(uchar *to, Item *item,
- const SORT_FIELD_ATTR *sort_field,
- Sort_param *param) const
+Type_handler_real_result::make_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const
{
double value= item->val_result();
if (item->maybe_null)
@@ -1168,49 +1330,16 @@ Type_handler_real_result::make_sort_key(uchar *to, Item *item,
/** Make a sort-key from record. */
-static void make_sortkey(Sort_param *param, uchar *to, uchar *ref_pos)
+static uint make_sortkey(Sort_param *param, uchar *to, uchar *ref_pos,
+ bool using_packed_sortkeys)
{
- Field *field;
- SORT_FIELD *sort_field;
- uint length;
+ uchar *orig_to= to;
- for (sort_field=param->local_sortorder ;
- sort_field != param->end ;
- sort_field++)
- {
- bool maybe_null=0;
- if ((field=sort_field->field))
- { // Field
- field->make_sort_key(to, sort_field->length);
- if ((maybe_null = field->maybe_null()))
- to++;
- }
- else
- { // Item
- sort_field->item->type_handler()->make_sort_key(to, sort_field->item,
- sort_field, param);
- if ((maybe_null= sort_field->item->maybe_null))
- to++;
- }
- if (sort_field->reverse)
- { /* Revers key */
- if (maybe_null && (to[-1]= !to[-1]))
- {
- to+= sort_field->length; // don't waste the time reversing all 0's
- continue;
- }
- length=sort_field->length;
- while (length--)
- {
- *to = (uchar) (~ *to);
- to++;
- }
- }
- else
- to+= sort_field->length;
- }
+ to+= using_packed_sortkeys ?
+ make_packed_sortkey(param, to) :
+ make_sortkey(param, to);
- if (param->addon_field)
+ if (param->using_addon_fields())
{
/*
Save field values appended to sorted fields.
@@ -1218,41 +1347,44 @@ static void make_sortkey(Sort_param *param, uchar *to, uchar *ref_pos)
In this implementation we use fixed layout for field values -
the same for all records.
*/
- SORT_ADDON_FIELD *addonf= param->addon_field;
+ SORT_ADDON_FIELD *addonf= param->addon_fields->begin();
uchar *nulls= to;
+ uchar *p_len= to;
DBUG_ASSERT(addonf != 0);
+ const bool packed_addon_fields= param->addon_fields->using_packed_addons();
+ uint32 res_len= addonf->offset;
memset(nulls, 0, addonf->offset);
to+= addonf->offset;
- for ( ; (field= addonf->field) ; addonf++)
+ for ( ; addonf != param->addon_fields->end() ; addonf++)
{
+ Field *field= addonf->field;
if (addonf->null_bit && field->is_null())
{
nulls[addonf->null_offset]|= addonf->null_bit;
-#ifdef HAVE_valgrind
- bzero(to, addonf->length);
-#endif
+ if (!packed_addon_fields)
+ to+= addonf->length;
}
else
{
-#ifdef HAVE_valgrind
uchar *end= field->pack(to, field->ptr);
- uint length= (uint) ((to + addonf->length) - end);
- DBUG_ASSERT((int) length >= 0);
- if (length)
- bzero(end, length);
-#else
- (void) field->pack(to, field->ptr);
-#endif
+ int sz= static_cast<int>(end - to);
+ res_len += sz;
+ if (packed_addon_fields)
+ to+= sz;
+ else
+ to+= addonf->length;
}
- to+= addonf->length;
}
+ if (packed_addon_fields)
+ Addon_fields::store_addon_length(p_len, res_len);
}
else
{
/* Save filepos last */
memcpy((uchar*) to, ref_pos, (size_t) param->ref_length);
+ to+= param->ref_length;
}
- return;
+ return static_cast<uint>(to - orig_to);
}
@@ -1265,8 +1397,8 @@ static void register_used_fields(Sort_param *param)
SORT_FIELD *sort_field;
TABLE *table=param->sort_form;
- for (sort_field= param->local_sortorder ;
- sort_field != param->end ;
+ for (sort_field= param->local_sortorder.begin() ;
+ sort_field != param->local_sortorder.end() ;
sort_field++)
{
Field *field;
@@ -1281,12 +1413,14 @@ static void register_used_fields(Sort_param *param)
}
}
- if (param->addon_field)
+ if (param->using_addon_fields())
{
- SORT_ADDON_FIELD *addonf= param->addon_field;
- Field *field;
- for ( ; (field= addonf->field) ; addonf++)
+ SORT_ADDON_FIELD *addonf= param->addon_fields->begin();
+ for ( ; (addonf != param->addon_fields->end()) ; addonf++)
+ {
+ Field *field= addonf->field;
field->register_field_in_read_map();
+ }
}
else
{
@@ -1299,22 +1433,35 @@ static void register_used_fields(Sort_param *param)
static bool save_index(Sort_param *param, uint count,
SORT_INFO *table_sort)
{
- uint offset,res_length;
+ uint offset,res_length, length;
uchar *to;
DBUG_ENTER("save_index");
DBUG_ASSERT(table_sort->record_pointers == 0);
table_sort->sort_buffer(param, count);
+
+ if (param->using_addon_fields())
+ {
+ table_sort->sorted_result_in_fsbuf= TRUE;
+ table_sort->set_sort_length(param->sort_length);
+ DBUG_RETURN(0);
+ }
+
+ bool using_packed_sortkeys= param->using_packed_sortkeys();
res_length= param->res_length;
offset= param->rec_length-res_length;
if (!(to= table_sort->record_pointers=
- (uchar*) my_malloc(res_length*count,
- MYF(MY_WME | MY_THREAD_SPECIFIC))))
+ (uchar*) my_malloc(key_memory_Filesort_info_record_pointers,
+ res_length*count, MYF(MY_WME | MY_THREAD_SPECIFIC))))
DBUG_RETURN(1); /* purecov: inspected */
- uchar **sort_keys= table_sort->get_sort_keys();
- for (uchar **end= sort_keys+count ; sort_keys != end ; sort_keys++)
+ for (uint ix= 0; ix < count; ++ix)
{
- memcpy(to, *sort_keys+offset, res_length);
+ uchar *record= table_sort->get_sorted_record(ix);
+
+ length= using_packed_sortkeys ?
+ Sort_keys::read_sortkey_length(record) : offset;
+
+ memcpy(to, record + length, res_length);
to+= res_length;
}
DBUG_RETURN(0);
@@ -1385,8 +1532,9 @@ static bool check_if_pq_applicable(Sort_param *param,
// The whole source set fits into memory.
if (param->max_rows < num_rows/PQ_slowness )
{
- DBUG_RETURN(filesort_info->alloc_sort_buffer(param->max_keys_per_buffer,
- param->rec_length) != NULL);
+ filesort_info->alloc_sort_buffer(param->max_keys_per_buffer,
+ param->rec_length);
+ DBUG_RETURN(filesort_info->sort_buffer_size() != 0);
}
else
{
@@ -1398,12 +1546,13 @@ static bool check_if_pq_applicable(Sort_param *param,
// Do we have space for LIMIT rows in memory?
if (param->max_keys_per_buffer < num_available_keys)
{
- DBUG_RETURN(filesort_info->alloc_sort_buffer(param->max_keys_per_buffer,
- param->rec_length) != NULL);
+ filesort_info->alloc_sort_buffer(param->max_keys_per_buffer,
+ param->rec_length);
+ DBUG_RETURN(filesort_info->sort_buffer_size() != 0);
}
// Try to strip off addon fields.
- if (param->addon_field)
+ if (param->addon_fields)
{
const size_t row_length=
param->sort_length + param->ref_length + sizeof(char*);
@@ -1435,14 +1584,15 @@ static bool check_if_pq_applicable(Sort_param *param,
if (sort_merge_cost < pq_cost)
DBUG_RETURN(false);
- if (filesort_info->alloc_sort_buffer(param->max_keys_per_buffer,
- param->sort_length +
- param->ref_length))
+ filesort_info->alloc_sort_buffer(param->max_keys_per_buffer,
+ param->sort_length + param->ref_length);
+
+ if (filesort_info->sort_buffer_size() > 0)
{
/* Make attached data to be references instead of fields. */
- my_free(filesort_info->addon_field);
- filesort_info->addon_field= NULL;
- param->addon_field= NULL;
+ my_free(filesort_info->addon_fields);
+ filesort_info->addon_fields= NULL;
+ param->addon_fields= NULL;
param->res_length= param->ref_length;
param->sort_length+= param->ref_length;
@@ -1458,12 +1608,12 @@ static bool check_if_pq_applicable(Sort_param *param,
/** Merge buffers to make < MERGEBUFF2 buffers. */
-int merge_many_buff(Sort_param *param, uchar *sort_buffer,
- BUFFPEK *buffpek, uint *maxbuffer, IO_CACHE *t_file)
+int merge_many_buff(Sort_param *param, Sort_buffer sort_buffer,
+ Merge_chunk *buffpek, uint *maxbuffer, IO_CACHE *t_file)
{
uint i;
IO_CACHE t_file2,*from_file,*to_file,*temp;
- BUFFPEK *lastbuff;
+ Merge_chunk *lastbuff;
DBUG_ENTER("merge_many_buff");
if (*maxbuffer < MERGEBUFF2)
@@ -1483,11 +1633,11 @@ int merge_many_buff(Sort_param *param, uchar *sort_buffer,
lastbuff=buffpek;
for (i=0 ; i <= *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF)
{
- if (merge_buffers(param,from_file,to_file,sort_buffer,lastbuff++,
+ if (merge_buffers(param,from_file,to_file,sort_buffer, lastbuff++,
buffpek+i,buffpek+i+MERGEBUFF-1,0))
goto cleanup;
}
- if (merge_buffers(param,from_file,to_file,sort_buffer,lastbuff++,
+ if (merge_buffers(param,from_file,to_file,sort_buffer, lastbuff++,
buffpek+i,buffpek+ *maxbuffer,0))
break; /* purecov: inspected */
if (flush_io_cache(to_file))
@@ -1513,24 +1663,85 @@ cleanup:
(ulong)-1 if something goes wrong
*/
-ulong read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
- uint rec_length)
+ulong read_to_buffer(IO_CACHE *fromfile, Merge_chunk *buffpek,
+ Sort_param *param, bool packed_format)
{
- ulong count;
- ulong length= 0;
+ ha_rows count;
+ uint rec_length= param->rec_length;
- if ((count= (ulong) MY_MIN((ha_rows) buffpek->max_keys,buffpek->count)))
+ if ((count= MY_MIN(buffpek->max_keys(),buffpek->rowcount())))
{
- length= rec_length*count;
- if (unlikely(my_b_pread(fromfile, (uchar*) buffpek->base, length,
- buffpek->file_pos)))
+ size_t bytes_to_read;
+ if (packed_format)
+ {
+ count= buffpek->rowcount();
+ bytes_to_read= MY_MIN(buffpek->buffer_size(),
+ static_cast<size_t>(fromfile->end_of_file -
+ buffpek->file_position()));
+ }
+ else
+ bytes_to_read= rec_length * static_cast<size_t>(count);
+
+ if (unlikely(my_b_pread(fromfile, buffpek->buffer_start(),
+ bytes_to_read, buffpek->file_position())))
return ((ulong) -1);
- buffpek->key=buffpek->base;
- buffpek->file_pos+= length; /* New filepos */
- buffpek->count-= count;
- buffpek->mem_count= count;
+
+ size_t num_bytes_read;
+
+ if (packed_format)
+ {
+ /*
+ The last record read is most likely not complete here.
+ We need to loop through all the records, reading the length fields,
+ and then "chop off" the final incomplete record.
+ */
+ uchar *record= buffpek->buffer_start();
+ uint ix= 0;
+ uint size_of_addon_length= param->using_packed_addons() ?
+ Addon_fields::size_of_length_field : 0;
+
+ uint size_of_sort_length= param->using_packed_sortkeys() ?
+ Sort_keys::size_of_length_field : 0;
+
+ for (; ix < count; ++ix)
+ {
+ if (record + size_of_sort_length > buffpek->buffer_end())
+ break;
+ uint sort_length= param->using_packed_sortkeys() ?
+ Sort_keys::read_sortkey_length(record) :
+ param->sort_length;
+
+ DBUG_ASSERT(sort_length <= param->sort_length);
+
+ if (record + sort_length + size_of_addon_length >
+ buffpek->buffer_end())
+ break; // Incomplete record.
+
+ uchar *plen= record + sort_length;
+ uint res_length= param->get_result_length(plen);
+ if (plen + res_length > buffpek->buffer_end())
+ break; // Incomplete record.
+ DBUG_ASSERT(res_length > 0);
+ DBUG_ASSERT(sort_length + res_length <= param->rec_length);
+ record+= sort_length;
+ record+= res_length;
+ }
+ DBUG_ASSERT(ix > 0);
+ count= ix;
+ num_bytes_read= record - buffpek->buffer_start();
+ DBUG_PRINT("info", ("read %llu bytes of complete records",
+ static_cast<ulonglong>(bytes_to_read)));
+ }
+ else
+ num_bytes_read= bytes_to_read;
+
+ buffpek->init_current_key();
+ buffpek->advance_file_position(num_bytes_read); /* New filepos */
+ buffpek->decrement_rowcount(count);
+ buffpek->set_mem_count(count);
+ return (ulong) num_bytes_read;
}
- return (length);
+ return 0;
} /* read_to_buffer */
@@ -1545,25 +1756,15 @@ ulong read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
@param[in] key_length key length
*/
-void reuse_freed_buff(QUEUE *queue, BUFFPEK *reuse, uint key_length)
+void reuse_freed_buff(QUEUE *queue, Merge_chunk *reuse, uint key_length)
{
- uchar *reuse_end= reuse->base + reuse->max_keys * key_length;
for (uint i= queue_first_element(queue);
i <= queue_last_element(queue);
i++)
{
- BUFFPEK *bp= (BUFFPEK *) queue_element(queue, i);
- if (bp->base + bp->max_keys * key_length == reuse->base)
- {
- bp->max_keys+= reuse->max_keys;
+ Merge_chunk *bp= (Merge_chunk *) queue_element(queue, i);
+ if (reuse->merge_freed_buff(bp))
return;
- }
- else if (bp->base == reuse_end)
- {
- bp->base= reuse->base;
- bp->max_keys+= reuse->max_keys;
- return;
- }
}
DBUG_ASSERT(0);
}
@@ -1579,7 +1780,10 @@ void reuse_freed_buff(QUEUE *queue, BUFFPEK *reuse, uint key_length)
@param lastbuff OUT Store here BUFFPEK describing data written to to_file
@param Fb First element in source BUFFPEKs array
@param Tb Last element in source BUFFPEKs array
- @param flag
+ @param flag 0 <=> write {sort_key, addon_fields} pairs as further
+ sorting will be performed
+ 1 <=> write just addon_fields as this is the final
+ merge pass
@retval
0 OK
@@ -1588,8 +1792,8 @@ void reuse_freed_buff(QUEUE *queue, BUFFPEK *reuse, uint key_length)
*/
bool merge_buffers(Sort_param *param, IO_CACHE *from_file,
- IO_CACHE *to_file, uchar *sort_buffer,
- BUFFPEK *lastbuff, BUFFPEK *Fb, BUFFPEK *Tb,
+ IO_CACHE *to_file, Sort_buffer sort_buffer,
+ Merge_chunk *lastbuff, Merge_chunk *Fb, Merge_chunk *Tb,
int flag)
{
bool error= 0;
@@ -1599,7 +1803,7 @@ bool merge_buffers(Sort_param *param, IO_CACHE *from_file,
ha_rows max_rows,org_max_rows;
my_off_t to_start_filepos;
uchar *strpos;
- BUFFPEK *buffpek;
+ Merge_chunk *buffpek;
QUEUE queue;
qsort2_cmp cmp;
void *first_cmp_arg;
@@ -1623,9 +1827,14 @@ bool merge_buffers(Sort_param *param, IO_CACHE *from_file,
(flag && min_dupl_count ? sizeof(dupl_count) : 0)-res_length);
uint wr_len= flag ? res_length : rec_length;
uint wr_offset= flag ? offset : 0;
+
+ const bool using_packed_sortkeys= param->using_packed_sortkeys();
+ bool offset_for_packing= (flag == 1 && using_packed_sortkeys);
+ const bool packed_format= param->is_packed_format();
+
maxcount= (ulong) (param->max_keys_per_buffer/((uint) (Tb-Fb) +1));
to_start_filepos= my_b_tell(to_file);
- strpos= sort_buffer;
+ strpos= sort_buffer.array();
org_max_rows=max_rows= param->max_rows;
set_if_bigger(maxcount, 1);
@@ -1637,22 +1846,26 @@ bool merge_buffers(Sort_param *param, IO_CACHE *from_file,
}
else
{
- cmp= get_ptr_compare(sort_length);
- first_cmp_arg= (void*) &sort_length;
+ cmp= param->get_compare_function();
+ first_cmp_arg= param->get_compare_argument(&sort_length);
}
- if (unlikely(init_queue(&queue, (uint) (Tb-Fb)+1, offsetof(BUFFPEK,key), 0,
+ if (unlikely(init_queue(&queue, (uint) (Tb-Fb)+1,
+ offsetof(Merge_chunk,m_current_key), 0,
(queue_compare) cmp, first_cmp_arg, 0, 0)))
DBUG_RETURN(1); /* purecov: inspected */
for (buffpek= Fb ; buffpek <= Tb ; buffpek++)
{
- buffpek->base= strpos;
- buffpek->max_keys= maxcount;
- bytes_read= read_to_buffer(from_file, buffpek, rec_length);
+ buffpek->set_buffer(strpos,
+ strpos + (sort_buffer.size()/((uint) (Tb-Fb) +1)));
+
+ buffpek->set_max_keys(maxcount);
+ bytes_read= read_to_buffer(from_file, buffpek, param, packed_format);
if (unlikely(bytes_read == (ulong) -1))
goto err; /* purecov: inspected */
-
strpos+= bytes_read;
- buffpek->max_keys= buffpek->mem_count; // If less data in buffers than expected
+ buffpek->set_buffer_end(strpos);
+ // If less data in buffers than expected
+ buffpek->set_max_keys(buffpek->mem_count());
queue_insert(&queue, (uchar*) buffpek);
}
@@ -1663,16 +1876,17 @@ bool merge_buffers(Sort_param *param, IO_CACHE *from_file,
Copy the first argument to unique_buff for unique removal.
Store it also in 'to_file'.
*/
- buffpek= (BUFFPEK*) queue_top(&queue);
- memcpy(unique_buff, buffpek->key, rec_length);
+ buffpek= (Merge_chunk*) queue_top(&queue);
+ memcpy(unique_buff, buffpek->current_key(), rec_length);
if (min_dupl_count)
memcpy(&dupl_count, unique_buff+dupl_count_ofs,
sizeof(dupl_count));
- buffpek->key+= rec_length;
- if (! --buffpek->mem_count)
+ buffpek->advance_current_key(rec_length);
+ buffpek->decrement_mem_count();
+ if (buffpek->mem_count() == 0)
{
if (unlikely(!(bytes_read= read_to_buffer(from_file, buffpek,
- rec_length))))
+ param, packed_format))))
{
(void) queue_remove_top(&queue);
reuse_freed_buff(&queue, buffpek, rec_length);
@@ -1692,61 +1906,72 @@ bool merge_buffers(Sort_param *param, IO_CACHE *from_file,
for (;;)
{
- buffpek= (BUFFPEK*) queue_top(&queue);
- src= buffpek->key;
+ buffpek= (Merge_chunk*) queue_top(&queue);
+ src= buffpek->current_key();
if (cmp) // Remove duplicates
{
- if (!(*cmp)(first_cmp_arg, &unique_buff,
- (uchar**) &buffpek->key))
- {
+ uchar *current_key= buffpek->current_key();
+ if (!(*cmp)(first_cmp_arg, &unique_buff, &current_key))
+ {
if (min_dupl_count)
- {
+ {
element_count cnt;
- memcpy(&cnt, (uchar *) buffpek->key+dupl_count_ofs, sizeof(cnt));
+ memcpy(&cnt, buffpek->current_key() + dupl_count_ofs, sizeof(cnt));
dupl_count+= cnt;
}
goto skip_duplicate;
}
if (min_dupl_count)
- {
+ {
memcpy(unique_buff+dupl_count_ofs, &dupl_count,
sizeof(dupl_count));
}
- src= unique_buff;
- }
-
- /*
- Do not write into the output file if this is the final merge called
- for a Unique object used for intersection and dupl_count is less
- than min_dupl_count.
- If the Unique object is used to intersect N sets of unique elements
- then for any element:
- dupl_count >= N <=> the element is occurred in each of these N sets.
- */
- if (!check_dupl_count || dupl_count >= min_dupl_count)
- {
- if (my_b_write(to_file, src+wr_offset, wr_len))
- goto err; /* purecov: inspected */
+ src= unique_buff;
}
- if (cmp)
- {
- memcpy(unique_buff, (uchar*) buffpek->key, rec_length);
- if (min_dupl_count)
- memcpy(&dupl_count, unique_buff+dupl_count_ofs,
- sizeof(dupl_count));
- }
- if (!--max_rows)
+
{
- /* Nothing more to do */
- goto end; /* purecov: inspected */
- }
+ param->get_rec_and_res_len(buffpek->current_key(),
+ &rec_length, &res_length);
+ const uint bytes_to_write= (flag == 0) ? rec_length : res_length;
+ /*
+ Do not write into the output file if this is the final merge called
+ for a Unique object used for intersection and dupl_count is less
+ than min_dupl_count.
+ If the Unique object is used to intersect N sets of unique elements
+ then for any element:
+ dupl_count >= N <=> the element is occurred in each of these N sets.
+ */
+ if (!check_dupl_count || dupl_count >= min_dupl_count)
+ {
+ if(my_b_write(to_file,
+ src + (offset_for_packing ?
+ rec_length - res_length : // sort length
+ wr_offset),
+ bytes_to_write))
+ goto err; /* purecov: inspected */
+ }
+ if (cmp)
+ {
+ memcpy(unique_buff, buffpek->current_key(), rec_length);
+ if (min_dupl_count)
+ memcpy(&dupl_count, unique_buff+dupl_count_ofs,
+ sizeof(dupl_count));
+ }
+ if (!--max_rows)
+ {
+ /* Nothing more to do */
+ goto end; /* purecov: inspected */
+ }
+ }
skip_duplicate:
- buffpek->key+= rec_length;
- if (! --buffpek->mem_count)
+ buffpek->advance_current_key(rec_length);
+ buffpek->decrement_mem_count();
+
+ if (buffpek->mem_count() == 0)
{
if (unlikely(!(bytes_read= read_to_buffer(from_file, buffpek,
- rec_length))))
+ param, packed_format))))
{
(void) queue_remove_top(&queue);
reuse_freed_buff(&queue, buffpek, rec_length);
@@ -1758,9 +1983,10 @@ bool merge_buffers(Sort_param *param, IO_CACHE *from_file,
queue_replace_top(&queue); /* Top element has been replaced */
}
}
- buffpek= (BUFFPEK*) queue_top(&queue);
- buffpek->base= (uchar*) sort_buffer;
- buffpek->max_keys= param->max_keys_per_buffer;
+ buffpek= (Merge_chunk*) queue_top(&queue);
+ buffpek->set_buffer(sort_buffer.array(),
+ sort_buffer.array() + sort_buffer.size());
+ buffpek->set_max_keys(param->max_keys_per_buffer);
/*
As we know all entries in the buffer are unique, we only have to
@@ -1768,16 +1994,17 @@ bool merge_buffers(Sort_param *param, IO_CACHE *from_file,
*/
if (cmp)
{
- if (!(*cmp)(first_cmp_arg, &unique_buff, (uchar**) &buffpek->key))
+ uchar *current_key= buffpek->current_key();
+ if (!(*cmp)(first_cmp_arg, &unique_buff, &current_key))
{
if (min_dupl_count)
{
element_count cnt;
- memcpy(&cnt, (uchar *) buffpek->key+dupl_count_ofs, sizeof(cnt));
+ memcpy(&cnt, buffpek->current_key() + dupl_count_ofs, sizeof(cnt));
dupl_count+= cnt;
}
- buffpek->key+= rec_length;
- --buffpek->mem_count;
+ buffpek->advance_current_key(rec_length);
+ buffpek->decrement_mem_count();
}
if (min_dupl_count)
@@ -1796,45 +2023,44 @@ bool merge_buffers(Sort_param *param, IO_CACHE *from_file,
do
{
- if ((ha_rows) buffpek->mem_count > max_rows)
+ if (buffpek->mem_count() > max_rows)
{ /* Don't write too many records */
- buffpek->mem_count= (uint) max_rows;
- buffpek->count= 0; /* Don't read more */
+ buffpek->set_mem_count(max_rows);
+ buffpek->set_rowcount(0); /* Don't read more */
}
- max_rows-= buffpek->mem_count;
- if (flag == 0)
+ max_rows-= buffpek->mem_count();
+ for (uint ix= 0; ix < buffpek->mem_count(); ++ix)
{
- if (my_b_write(to_file, (uchar*) buffpek->key,
- (size_t)(rec_length*buffpek->mem_count)))
- goto err; /* purecov: inspected */
- }
- else
- {
- uchar *end;
- src= buffpek->key+offset;
- for (end= src+buffpek->mem_count*rec_length ;
- src != end ;
- src+= rec_length)
+ uchar *src= buffpek->current_key();
+ param->get_rec_and_res_len(src,
+ &rec_length, &res_length);
+ const uint bytes_to_write= (flag == 0) ? rec_length : res_length;
+ if (check_dupl_count)
{
- if (check_dupl_count)
- {
- memcpy((uchar *) &dupl_count, src+dupl_count_ofs, sizeof(dupl_count));
- if (dupl_count < min_dupl_count)
- continue;
- }
- if (my_b_write(to_file, src, wr_len))
- goto err;
+ memcpy((uchar *) &dupl_count,
+ buffpek->current_key() + offset + dupl_count_ofs,
+ sizeof(dupl_count));
+ if (dupl_count < min_dupl_count)
+ continue;
}
+ if(my_b_write(to_file,
+ src + (offset_for_packing ?
+ rec_length - res_length : // sort length
+ wr_offset),
+ bytes_to_write))
+ goto err;
+ buffpek->advance_current_key(rec_length);
}
}
while (likely(!(error=
- (bytes_read= read_to_buffer(from_file, buffpek,
- rec_length)) == (ulong) -1)) &&
+ (bytes_read= read_to_buffer(from_file, buffpek, param,
+ packed_format)) == (ulong) -1)) &&
bytes_read != 0);
end:
- lastbuff->count= MY_MIN(org_max_rows-max_rows, param->max_rows);
- lastbuff->file_pos= to_start_filepos;
+ lastbuff->set_rowcount(MY_MIN(org_max_rows-max_rows, param->max_rows));
+ lastbuff->set_file_position(to_start_filepos);
+
cleanup:
delete_queue(&queue);
DBUG_RETURN(error);
@@ -1848,13 +2074,13 @@ err:
/* Do a merge to output-file (save only positions) */
-int merge_index(Sort_param *param, uchar *sort_buffer,
- BUFFPEK *buffpek, uint maxbuffer,
- IO_CACHE *tempfile, IO_CACHE *outfile)
+int merge_index(Sort_param *param, Sort_buffer sort_buffer,
+ Merge_chunk *buffpek, uint maxbuffer,
+ IO_CACHE *tempfile, IO_CACHE *outfile)
{
DBUG_ENTER("merge_index");
- if (merge_buffers(param,tempfile,outfile,sort_buffer,buffpek,buffpek,
- buffpek+maxbuffer,1))
+ if (merge_buffers(param, tempfile, outfile, sort_buffer, buffpek, buffpek,
+ buffpek + maxbuffer, 1))
DBUG_RETURN(1); /* purecov: inspected */
DBUG_RETURN(0);
} /* merge_index */
@@ -1873,70 +2099,74 @@ static uint suffix_length(ulong string_length)
void
-Type_handler_string_result::sortlength(THD *thd,
+Type_handler_string_result::sort_length(THD *thd,
const Type_std_attributes *item,
SORT_FIELD_ATTR *sortorder) const
{
CHARSET_INFO *cs;
sortorder->length= item->max_length;
- set_if_smaller(sortorder->length, thd->variables.max_sort_length);
+ sortorder->original_length= item->max_length;
+
if (use_strnxfrm((cs= item->collation.collation)))
{
- sortorder->length= (uint)cs->coll->strnxfrmlen(cs, sortorder->length);
+ sortorder->length= (uint) cs->strnxfrmlen(sortorder->length);
}
else if (cs == &my_charset_bin)
{
/* Store length last to be able to sort blob/varbinary */
sortorder->suffix_length= suffix_length(sortorder->length);
sortorder->length+= sortorder->suffix_length;
+ sortorder->original_length+= sortorder->suffix_length;
}
}
void
-Type_handler_temporal_result::sortlength(THD *thd,
- const Type_std_attributes *item,
- SORT_FIELD_ATTR *sortorder) const
+Type_handler_temporal_result::sort_length(THD *thd,
+ const Type_std_attributes *item,
+ SORT_FIELD_ATTR *sortorder) const
{
- sortorder->length= 8; // Sizof intern longlong
+ sortorder->original_length= sortorder->length= 8; // Sizof intern longlong
}
void
-Type_handler_timestamp_common::sortlength(THD *thd,
- const Type_std_attributes *item,
- SORT_FIELD_ATTR *sortorder) const
+Type_handler_timestamp_common::sort_length(THD *thd,
+ const Type_std_attributes *item,
+ SORT_FIELD_ATTR *sortorder) const
{
sortorder->length= my_timestamp_binary_length(item->decimals);
+ sortorder->original_length= sortorder->length;
}
void
-Type_handler_int_result::sortlength(THD *thd,
+Type_handler_int_result::sort_length(THD *thd,
const Type_std_attributes *item,
SORT_FIELD_ATTR *sortorder) const
{
- sortorder->length= 8; // Sizof intern longlong
+ sortorder->original_length= sortorder->length= 8; // Sizof intern longlong
}
void
-Type_handler_real_result::sortlength(THD *thd,
+Type_handler_real_result::sort_length(THD *thd,
const Type_std_attributes *item,
SORT_FIELD_ATTR *sortorder) const
{
- sortorder->length= sizeof(double);
+ sortorder->original_length= sortorder->length= sizeof(double);
}
void
-Type_handler_decimal_result::sortlength(THD *thd,
- const Type_std_attributes *item,
- SORT_FIELD_ATTR *sortorder) const
+Type_handler_decimal_result::sort_length(THD *thd,
+ const Type_std_attributes *item,
+ SORT_FIELD_ATTR *sortorder) const
{
sortorder->length=
my_decimal_get_binary_size(item->max_length - (item->decimals ? 1 : 0),
item->decimals);
+ sortorder->original_length= sortorder->length;
}
@@ -1948,61 +2178,126 @@ Type_handler_decimal_result::sortlength(THD *thd,
@param s_length Number of items to sort
@param[out] multi_byte_charset Set to 1 if we are using multi-byte charset
(In which case we have to use strxnfrm())
+ @param allow_packing_for_sortkeys [out] set to false if packing sort keys is not
+ allowed
@note
- sortorder->length is updated for each sort item.
+ * sortorder->length and other members are updated for each sort item.
+ * TODO what is the meaning of this value if some fields are using packing while
+ others are not?
@return
Total length of sort buffer in bytes
*/
static uint
-sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
- bool *multi_byte_charset)
+sortlength(THD *thd, Sort_keys *sort_keys, bool *multi_byte_charset,
+ bool *allow_packing_for_sortkeys)
{
uint length;
*multi_byte_charset= 0;
+ *allow_packing_for_sortkeys= true;
+ bool allow_packing_for_keys= true;
length=0;
- for (; s_length-- ; sortorder++)
+ uint nullable_cols=0;
+
+ for (SORT_FIELD *sortorder= sort_keys->begin();
+ sortorder != sort_keys->end();
+ sortorder++)
{
sortorder->suffix_length= 0;
+ sortorder->length_bytes= 0;
if (sortorder->field)
{
+ Field *field= sortorder->field;
CHARSET_INFO *cs= sortorder->field->sort_charset();
sortorder->length= sortorder->field->sort_length();
+ sortorder->suffix_length= sortorder->field->sort_suffix_length();
+ sortorder->original_length= sortorder->length;
+ sortorder->type= field->is_packable() ?
+ SORT_FIELD_ATTR::VARIABLE_SIZE :
+ SORT_FIELD_ATTR::FIXED_SIZE;
+ sortorder->cs= cs;
+
if (use_strnxfrm((cs=sortorder->field->sort_charset())))
{
*multi_byte_charset= true;
- sortorder->length= (uint)cs->coll->strnxfrmlen(cs, sortorder->length);
+ sortorder->length= (uint) cs->strnxfrmlen(sortorder->length);
+ }
+ if (sortorder->is_variable_sized() && allow_packing_for_keys)
+ {
+ allow_packing_for_keys= sortorder->check_if_packing_possible(thd);
+ sortorder->length_bytes=
+ number_storage_requirement(MY_MIN(sortorder->original_length,
+ thd->variables.max_sort_length));
}
- if (sortorder->field->maybe_null())
- length++; // Place for NULL marker
+
+ if ((sortorder->maybe_null= sortorder->field->maybe_null()))
+ nullable_cols++; // Place for NULL marker
}
else
{
- sortorder->item->type_handler()->sortlength(thd, sortorder->item,
- sortorder);
- if (use_strnxfrm(sortorder->item->collation.collation))
+ CHARSET_INFO *cs;
+ sortorder->item->type_handler()->sort_length(thd, sortorder->item,
+ sortorder);
+ sortorder->type= sortorder->item->type_handler()->is_packable() ?
+ SORT_FIELD_ATTR::VARIABLE_SIZE :
+ SORT_FIELD_ATTR::FIXED_SIZE;
+ if (use_strnxfrm((cs=sortorder->item->collation.collation)))
{
*multi_byte_charset= true;
}
- if (sortorder->item->maybe_null)
- length++; // Place for NULL marker
+ sortorder->cs= cs;
+ if (sortorder->is_variable_sized() && allow_packing_for_keys)
+ {
+ allow_packing_for_keys= sortorder->check_if_packing_possible(thd);
+ sortorder->length_bytes=
+ number_storage_requirement(MY_MIN(sortorder->original_length,
+ thd->variables.max_sort_length));
+ }
+
+ if ((sortorder->maybe_null= sortorder->item->maybe_null))
+ nullable_cols++; // Place for NULL marker
}
set_if_smaller(sortorder->length, thd->variables.max_sort_length);
+ set_if_smaller(sortorder->original_length, thd->variables.max_sort_length);
length+=sortorder->length;
+
+ sort_keys->increment_size_of_packable_fields(sortorder->length_bytes);
+ sort_keys->increment_original_sort_length(sortorder->original_length);
}
- sortorder->field= (Field*) 0; // end marker
+ // add bytes for nullable_cols
+ sort_keys->increment_original_sort_length(nullable_cols);
+ *allow_packing_for_sortkeys= allow_packing_for_keys;
DBUG_PRINT("info",("sort_length: %d",length));
- return length;
+ return length + nullable_cols;
}
+
+/*
+ Check whether addon fields can be used or not.
+
+ @param table Table structure
+ @param sortlength Length of sort key [strxfrm form]
+ @param length [OUT] Max length of addon fields
+ @param fields [OUT] Number of addon fields
+ @param null_fields [OUT] Number of nullable addon fields
+ @param packable_length [OUT] Max length of addon fields that can be
+ packed
+
+ @retval
+ TRUE Addon fields can be used
+ FALSE Otherwise
+*/
+
bool filesort_use_addons(TABLE *table, uint sortlength,
- uint *length, uint *fields, uint *null_fields)
+ uint *length, uint *fields, uint *null_fields,
+ uint *packable_length)
{
Field **pfield, *field;
- *length= *fields= *null_fields= 0;
+ *length= *fields= *null_fields= *packable_length= 0;
+ uint field_length=0;
for (pfield= table->field; (field= *pfield) ; pfield++)
{
@@ -2010,7 +2305,12 @@ bool filesort_use_addons(TABLE *table, uint sortlength,
continue;
if (field->flags & BLOB_FLAG)
return false;
- (*length)+= field->max_packed_col_length(field->pack_length());
+ field_length= field->max_packed_col_length(field->pack_length());
+ (*length)+= field_length;
+
+ if (field->maybe_null() || field->is_packable())
+ (*packable_length)+= field_length;
+
if (field->maybe_null())
(*null_fields)++;
(*fields)++;
@@ -2019,6 +2319,15 @@ bool filesort_use_addons(TABLE *table, uint sortlength,
return false;
(*length)+= (*null_fields+7)/8;
+ /*
+ sortlength used here is unpacked key length (the strxfrm form). This is
+ done because unpacked key length is a good upper bound for packed sort
+ key length.
+ But for some collations the max packed length may be greater than the
+ length obtained from the strxfrm form.
+ Example: for utf8_general_ci, the original string form can be longer than
+ its mem-comparable form (note that this is rarely achieved in practice).
+ */
return *length + sortlength <
table->in_use->variables.max_length_for_sort_data;
}
@@ -2035,11 +2344,11 @@ bool filesort_use_addons(TABLE *table, uint sortlength,
layouts for the values of the non-sorted fields in the buffer and
fills them.
- @param thd Current thread
- @param ptabfield Array of references to the table fields
- @param sortlength Total length of sorted fields
- @param [out] addon_buf Buffer to us for appended fields
-
+ @param table Table structure
+ @param sortlength Total length of sorted fields
+ @param addon_length [OUT] Length of addon fields
+ @param m_packable_length [OUT] Length of the addon fields that can be
+ packed
@note
The null bits for the appended values are supposed to be put together
and stored the buffer just ahead of the value of the first field.
@@ -2050,13 +2359,13 @@ bool filesort_use_addons(TABLE *table, uint sortlength,
NULL if we do not store field values with sort data.
*/
-static SORT_ADDON_FIELD *
-get_addon_fields(TABLE *table, uint sortlength, LEX_STRING *addon_buf)
+static Addon_fields*
+get_addon_fields(TABLE *table, uint sortlength,
+ uint *addon_length, uint *m_packable_length)
{
Field **pfield;
Field *field;
- SORT_ADDON_FIELD *addonf;
- uint length, fields, null_fields;
+ uint length, fields, null_fields, packable_length;
MY_BITMAP *read_set= table->read_set;
DBUG_ENTER("get_addon_fields");
@@ -2070,23 +2379,34 @@ get_addon_fields(TABLE *table, uint sortlength, LEX_STRING *addon_buf)
the values directly from sorted fields.
But beware the case when item->cmp_type() != item->result_type()
*/
- addon_buf->str= 0;
- addon_buf->length= 0;
// see remove_const() for HA_SLOW_RND_POS explanation
if (table->file->ha_table_flags() & HA_SLOW_RND_POS)
sortlength= 0;
- if (!filesort_use_addons(table, sortlength, &length, &fields, &null_fields) ||
- !my_multi_malloc(MYF(MY_WME | MY_THREAD_SPECIFIC), &addonf,
- sizeof(SORT_ADDON_FIELD) * (fields+1),
- &addon_buf->str, length, NullS))
+ void *raw_mem_addon_field, *raw_mem;
+ if (!filesort_use_addons(table, sortlength, &length, &fields, &null_fields,
+ &packable_length) ||
+ !(my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME | MY_THREAD_SPECIFIC),
+ &raw_mem, sizeof(Addon_fields),
+ &raw_mem_addon_field,
+ sizeof(SORT_ADDON_FIELD) * fields,
+ NullS)))
DBUG_RETURN(0);
- addon_buf->length= length;
+ Addon_fields_array
+ addon_array(static_cast<SORT_ADDON_FIELD*>(raw_mem_addon_field), fields);
+ Addon_fields *addon_fields= new (raw_mem) Addon_fields(addon_array);
+
+ DBUG_ASSERT(addon_fields);
+
+ (*addon_length)= length;
+ (*m_packable_length)= packable_length;
+
length= (null_fields+7)/8;
null_fields= 0;
+ SORT_ADDON_FIELD* addonf= addon_fields->begin();
for (pfield= table->field; (field= *pfield) ; pfield++)
{
if (!bitmap_is_set(read_set, field->field_index))
@@ -2108,47 +2428,12 @@ get_addon_fields(TABLE *table, uint sortlength, LEX_STRING *addon_buf)
length+= addonf->length;
addonf++;
}
- addonf->field= 0; // Put end marker
DBUG_PRINT("info",("addon_length: %d",length));
- DBUG_RETURN(addonf-fields);
+ DBUG_RETURN(addon_fields);
}
-/**
- Copy (unpack) values appended to sorted fields from a buffer back to
- their regular positions specified by the Field::ptr pointers.
-
- @param addon_field Array of descriptors for appended fields
- @param buff Buffer which to unpack the value from
-
- @note
- The function is supposed to be used only as a callback function
- when getting field values for the sorted result set.
-
- @return
- void.
-*/
-
-static void
-unpack_addon_fields(struct st_sort_addon_field *addon_field, uchar *buff,
- uchar *buff_end)
-{
- Field *field;
- SORT_ADDON_FIELD *addonf= addon_field;
-
- for ( ; (field= addonf->field) ; addonf++)
- {
- if (addonf->null_bit && (addonf->null_bit & buff[addonf->null_offset]))
- {
- field->set_null();
- continue;
- }
- field->set_notnull();
- field->unpack(field->ptr, buff + addonf->offset, buff_end, 0);
- }
-}
-
/*
** functions to change a double or float to a sortable string
** The following should work for IEEE
@@ -2197,6 +2482,25 @@ void change_double_for_sort(double nr,uchar *to)
}
}
+bool SORT_INFO::using_packed_addons()
+{
+ return addon_fields != NULL && addon_fields->using_packed_addons();
+}
+
+void SORT_INFO::free_addon_buff()
+{
+ if (addon_fields)
+ addon_fields->free_addon_buff();
+}
+
+/*
+ Check if packed sortkeys are used or not
+*/
+bool SORT_INFO::using_packed_sortkeys()
+{
+ return sort_keys != NULL && sort_keys->using_packed_sortkeys();
+}
+
/**
Free SORT_INFO
*/
@@ -2207,3 +2511,561 @@ SORT_INFO::~SORT_INFO()
free_data();
DBUG_VOID_RETURN;
}
+
+
+void Sort_param::try_to_pack_sortkeys()
+{
+ #ifdef WITHOUT_PACKED_SORT_KEYS
+ return;
+ #endif
+
+ uint size_of_packable_fields= sort_keys->get_size_of_packable_fields();
+
+ /*
+ Disable packing when all fields are fixed-size fields.
+ */
+ if (size_of_packable_fields == 0)
+ return;
+
+ const uint sz= Sort_keys::size_of_length_field;
+ uint sort_len= sort_keys->get_sort_length();
+
+ /*
+ Heuristic introduced, skip packing sort keys if saving less than 128 bytes
+ */
+
+ if (sort_len < 128 + sz + size_of_packable_fields)
+ return;
+
+ sort_keys->set_using_packed_sortkeys(true);
+ m_packed_format= true;
+ m_using_packed_sortkeys= true;
+ sort_length= sort_len + sz + size_of_packable_fields +
+ (using_addon_fields() ? 0 : res_length);
+ /* Only the record length needs to be updated, the res_length does not need
+ to be updated
+ */
+ rec_length= sort_length + addon_length;
+}
+
+
+uint
+Type_handler_string_result::make_packed_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const
+{
+ CHARSET_INFO *cs= item->collation.collation;
+ bool maybe_null= item->maybe_null;
+
+ if (maybe_null)
+ *to++= 1;
+
+ String tmp(param->tmp_buffer, param->sort_length, cs);
+ String *res= item->str_result(&tmp);
+ if (!res)
+ {
+ if (maybe_null)
+ {
+ *(to-1)= 0;
+ return 0;
+ }
+ else
+ {
+ /* purecov: begin deadcode */
+ /*
+ This should only happen during extreme conditions if we run out
+ of memory or have an item marked not null when it can be null.
+ This code is here mainly to avoid a hard crash in this case.
+ */
+ DBUG_ASSERT(0);
+ DBUG_PRINT("warning",
+ ("Got null on something that shouldn't be null"));
+ memset(to, 0, sort_field->length); // Avoid crash
+ /* purecov: end */
+ return sort_field->original_length;
+ }
+ }
+ return sort_field->pack_sort_string(to, res->lex_cstring(), cs);
+}
+
+
+uint
+Type_handler_int_result::make_packed_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const
+{
+ longlong value= item->val_int_result();
+ return make_packed_sort_key_longlong(to, item->maybe_null,
+ item->null_value, item->unsigned_flag,
+ value, sort_field);
+}
+
+
+uint
+Type_handler_decimal_result::make_packed_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const
+{
+ my_decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf);
+ if (item->maybe_null)
+ {
+ if (item->null_value)
+ {
+ *to++=0;
+ return 0;
+ }
+ *to++= 1;
+ }
+ dec_val->to_binary(to, item->max_length - (item->decimals ? 1 : 0),
+ item->decimals);
+ DBUG_ASSERT(sort_field->original_length == sort_field->length);
+ return sort_field->original_length;
+}
+
+
+uint
+Type_handler_real_result::make_packed_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const
+{
+ double value= item->val_result();
+ if (item->maybe_null)
+ {
+ if (item->null_value)
+ {
+ *to++=0;
+ return 0;
+ }
+ *to++= 1;
+ }
+ change_double_for_sort(value, to);
+ DBUG_ASSERT(sort_field->original_length == sort_field->length);
+ return sort_field->original_length;
+}
+
+
+uint
+Type_handler_temporal_result::make_packed_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const
+{
+ MYSQL_TIME buf;
+ // This is a temporal type. No nanoseconds. Rounding mode is not important.
+ DBUG_ASSERT(item->cmp_type() == TIME_RESULT);
+ static const Temporal::Options opt(TIME_INVALID_DATES, TIME_FRAC_NONE);
+ if (item->get_date_result(current_thd, &buf, opt))
+ {
+ DBUG_ASSERT(item->maybe_null);
+ DBUG_ASSERT(item->null_value);
+ return make_packed_sort_key_longlong(to, item->maybe_null, true,
+ item->unsigned_flag, 0, sort_field);
+ }
+ return make_packed_sort_key_longlong(to, item->maybe_null, false,
+ item->unsigned_flag, pack_time(&buf),
+ sort_field);
+}
+
+
+uint
+Type_handler_timestamp_common::make_packed_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const
+{
+ THD *thd= current_thd;
+ uint binlen= my_timestamp_binary_length(item->decimals);
+ Timestamp_or_zero_datetime_native_null native(thd, item);
+ if (native.is_null() || native.is_zero_datetime())
+ {
+ // NULL or '0000-00-00 00:00:00'
+ if (item->maybe_null)
+ {
+ *to++=0;
+ return 0;
+ }
+ else
+ {
+ bzero(to, binlen);
+ return binlen;
+ }
+ }
+ else
+ {
+ if (item->maybe_null)
+ *to++= 1;
+ if (native.length() != binlen)
+ {
+ /*
+ Some items can return native representation with a different
+ number of fractional digits, e.g.: GREATEST(ts_3, ts_4) can
+ return a value with 3 fractional digits, although its fractional
+ precision is 4. Re-pack with a proper precision now.
+ */
+ Timestamp(native).to_native(&native, item->datetime_precision(thd));
+ }
+ DBUG_ASSERT(native.length() == binlen);
+ memcpy((char *) to, native.ptr(), binlen);
+ return binlen;
+ }
+}
+
+
+/*
+ @brief
+ Reverse the key for DESC clause
+ @param to buffer where values are written
+ @param maybe_null nullability of a column
+ @param sort_field Sort field structure
+ @details
+ used for mem-comparable sort keys
+*/
+
+void reverse_key(uchar *to, const SORT_FIELD_ATTR *sort_field)
+{
+ uint length;
+ if (sort_field->maybe_null && (to[-1]= !to[-1]))
+ {
+ to+= sort_field->length; // don't waste the time reversing all 0's
+ return;
+ }
+ length=sort_field->length;
+ while (length--)
+ {
+ *to = (uchar) (~ *to);
+ to++;
+ }
+}
+
+
+/*
+ @brief
+ Check if packing sort keys is allowed
+ @param THD thread structure
+ @retval
+ TRUE packing allowed
+ FALSE packing not allowed
+*/
+bool SORT_FIELD_ATTR::check_if_packing_possible(THD *thd) const
+{
+ /*
+ Packing not allowed when original length is greater than max_sort_length
+ and we have a complex collation because cutting a prefix is not safe in
+ such a case
+ */
+ if (original_length > thd->variables.max_sort_length &&
+ cs->state & MY_CS_NON1TO1)
+ return false;
+ return true;
+}
+
+
+/*
+ Compare function used for packing sort keys
+*/
+
+qsort2_cmp get_packed_keys_compare_ptr()
+{
+ return (qsort2_cmp) compare_packed_sort_keys;
+}
+
+
+/*
+ Compare two varstrings.
+
+ The strings are in this data format:
+
+ [null_byte] [length of string + suffix_bytes] [the string] [suffix_bytes]
+
+ suffix_bytes are used only for binary columns.
+*/
+
+int SORT_FIELD_ATTR::compare_packed_varstrings(uchar *a, size_t *a_len,
+ uchar *b, size_t *b_len)
+{
+ int retval;
+ size_t a_length, b_length;
+ if (maybe_null)
+ {
+ *a_len= *b_len= 1; // NULL bytes are always stored
+ if (*a != *b)
+ {
+ // Note we don't return a proper value in *{a|b}_len for the non-NULL
+ // value but that's ok
+ if (*a == 0)
+ return -1;
+ else
+ return 1;
+ }
+ else
+ {
+ if (*a == 0)
+ return 0;
+ }
+ a++;
+ b++;
+ }
+ else
+ *a_len= *b_len= 0;
+
+ a_length= read_keypart_length(a, length_bytes);
+ b_length= read_keypart_length(b, length_bytes);
+
+ *a_len+= length_bytes + a_length;
+ *b_len+= length_bytes + b_length;
+
+ retval= cs->strnncollsp(a + length_bytes,
+ a_length - suffix_length,
+ b + length_bytes,
+ b_length - suffix_length);
+
+ if (!retval && suffix_length)
+ {
+ DBUG_ASSERT(cs == &my_charset_bin);
+ // comparing the length stored in suffix bytes for binary strings
+ a= a + length_bytes + a_length - suffix_length;
+ b= b + length_bytes + b_length - suffix_length;
+ retval= memcmp(a, b, suffix_length);
+ }
+
+ return retval;
+}
+
+
+/*
+ A value comparison function that has a signature that's suitable for
+ comparing packed values, but actually compares fixed-size values with memcmp.
+
+ This is used for ordering fixed-size columns when the sorting procedure used
+ packed-value format.
+*/
+
+int SORT_FIELD_ATTR::compare_packed_fixed_size_vals(uchar *a, size_t *a_len,
+ uchar *b, size_t *b_len)
+{
+ if (maybe_null)
+ {
+ *a_len=1;
+ *b_len=1;
+ if (*a != *b)
+ {
+ if (*a == 0)
+ return -1;
+ else
+ return 1;
+ }
+ else
+ {
+ if (*a == 0)
+ return 0;
+ }
+ a++;
+ b++;
+ }
+ else
+ *a_len= *b_len= 0;
+
+ *a_len+= length;
+ *b_len+= length;
+ return memcmp(a,b, length);
+}
+
+
+/*
+ @brief
+ Comparison function to compare two packed sort keys
+
+ @param sort_param cmp argument
+ @param a_ptr packed sort key
+ @param b_ptr packed sort key
+
+ @retval
+ >0 key a_ptr greater than b_ptr
+ =0 key a_ptr equal to b_ptr
+ <0 key a_ptr less than b_ptr
+
+*/
+
+int compare_packed_sort_keys(void *sort_param,
+ unsigned char **a_ptr, unsigned char **b_ptr)
+{
+ int retval= 0;
+ size_t a_len, b_len;
+ Sort_param *param= (Sort_param*)sort_param;
+ Sort_keys *sort_keys= param->sort_keys;
+ uchar *a= *a_ptr;
+ uchar *b= *b_ptr;
+
+ a+= Sort_keys::size_of_length_field;
+ b+= Sort_keys::size_of_length_field;
+ for (SORT_FIELD *sort_field= sort_keys->begin();
+ sort_field != sort_keys->end(); sort_field++)
+ {
+ retval= sort_field->is_variable_sized() ?
+ sort_field->compare_packed_varstrings(a, &a_len, b, &b_len) :
+ sort_field->compare_packed_fixed_size_vals(a, &a_len, b, &b_len);
+
+ if (retval)
+ return sort_field->reverse ? -retval : retval;
+
+ a+= a_len;
+ b+= b_len;
+
+ }
+ /*
+ this comparison is done for the case when the sort keys is appended with
+ the ROW_ID pointer. For such cases we don't have addon fields
+ so we can make a memcmp check over both the sort keys
+ */
+ if (!param->using_addon_fields())
+ retval= memcmp(a, b, param->res_length);
+ return retval;
+}
+
+
+/*
+ @brief
+ Store a packed string in the buffer
+
+ @param to buffer
+ @param str packed string value
+ @param cs character set
+
+ @details
+ This function writes to the buffer the packed value of a key_part
+ of the sort key.
+
+ The values written to the buffer are in this order
+ - value for null byte
+ - length of the string
+ - value of the string
+ - suffix length (for binary character set)
+*/
+
+uint
+SORT_FIELD_ATTR::pack_sort_string(uchar *to, const LEX_CSTRING &str,
+ CHARSET_INFO *cs) const
+{
+ uchar *orig_to= to;
+ uint32 length, data_length;
+ DBUG_ASSERT(str.length <= UINT32_MAX);
+ length= (uint32)str.length;
+
+ if (length + suffix_length <= original_length)
+ data_length= length;
+ else
+ data_length= original_length - suffix_length;
+
+ // length stored in lowendian form
+ store_key_part_length(data_length + suffix_length, to, length_bytes);
+ to+= length_bytes;
+ // copying data length bytes to the buffer
+ memcpy(to, (uchar*)str.str, data_length);
+ to+= data_length;
+
+ if (cs == &my_charset_bin && suffix_length)
+ {
+ // suffix length stored in bigendian form
+ store_bigendian(str.length, to, suffix_length);
+ to+= suffix_length;
+ }
+ return static_cast<uint>(to - orig_to);
+}
+
+
+/*
+ @brief
+ Create a mem-comparable sort key
+
+ @param param sort param structure
+ @param to buffer where values are written
+
+ @retval
+ length of the bytes written including the NULL bytes
+*/
+
+static uint make_sortkey(Sort_param *param, uchar *to)
+{
+ Field *field;
+ SORT_FIELD *sort_field;
+ uchar *orig_to= to;
+
+ for (sort_field=param->local_sortorder.begin() ;
+ sort_field != param->local_sortorder.end() ;
+ sort_field++)
+ {
+ bool maybe_null=0;
+ if ((field=sort_field->field))
+ {
+ // Field
+ field->make_sort_key_part(to, sort_field->length);
+ if ((maybe_null= field->maybe_null()))
+ to++;
+ }
+ else
+ { // Item
+ sort_field->item->type_handler()->make_sort_key_part(to,
+ sort_field->item,
+ sort_field, param);
+ if ((maybe_null= sort_field->item->maybe_null))
+ to++;
+ }
+
+ if (sort_field->reverse)
+ reverse_key(to, sort_field);
+ to+= sort_field->length;
+ }
+
+ DBUG_ASSERT(static_cast<uint>(to - orig_to) <= param->sort_length);
+ return static_cast<uint>(to - orig_to);
+}
+
+
+/*
+ @brief
+ create a compact sort key which can be compared with a comparison
+ function. They are called packed sort keys
+
+ @param param sort param structure
+ @param to buffer where values are written
+
+ @retval
+ length of the bytes written including the NULL bytes
+*/
+
+static uint make_packed_sortkey(Sort_param *param, uchar *to)
+{
+ Field *field;
+ SORT_FIELD *sort_field;
+ uint length;
+ uchar *orig_to= to;
+
+ to+= Sort_keys::size_of_length_field;
+
+ for (sort_field=param->local_sortorder.begin() ;
+ sort_field != param->local_sortorder.end() ;
+ sort_field++)
+ {
+ bool maybe_null=0;
+ if ((field=sort_field->field))
+ {
+ // Field
+ length= field->make_packed_sort_key_part(to, sort_field);
+ if ((maybe_null= field->maybe_null()))
+ to++;
+ }
+ else
+ { // Item
+ Item *item= sort_field->item;
+ length= item->type_handler()->make_packed_sort_key_part(to, item,
+ sort_field,
+ param);
+ if ((maybe_null= sort_field->item->maybe_null))
+ to++;
+ }
+ to+= length;
+ }
+
+ length= static_cast<int>(to - orig_to);
+ DBUG_ASSERT(length <= param->sort_length);
+ Sort_keys::store_sortkey_length(orig_to, length);
+ return length;
+}
diff --git a/sql/filesort.h b/sql/filesort.h
index 5f79a5095cc..9f71da02c96 100644
--- a/sql/filesort.h
+++ b/sql/filesort.h
@@ -25,9 +25,12 @@ class THD;
struct TABLE;
class Filesort_tracker;
struct SORT_FIELD;
+struct SORT_FIELD_ATTR;
typedef struct st_order ORDER;
class JOIN;
-
+class Addon_fields;
+class Sort_keys;
+
/**
Sorting related info.
@@ -57,6 +60,7 @@ public:
bool sort_positions;
Filesort_tracker *tracker;
+ Sort_keys *sort_keys;
Filesort(ORDER *order_arg, ha_rows limit_arg, bool sort_positions_arg,
SQL_SELECT *select_arg):
@@ -66,14 +70,15 @@ public:
select(select_arg),
own_select(false),
using_pq(false),
- sort_positions(sort_positions_arg)
+ sort_positions(sort_positions_arg),
+ sort_keys(NULL)
{
DBUG_ASSERT(order);
};
~Filesort() { cleanup(); }
/* Prepare ORDER BY list for sorting. */
- uint make_sortorder(THD *thd, JOIN *join, table_map first_table_bit);
+ Sort_keys* make_sortorder(THD *thd, JOIN *join, table_map first_table_bit);
private:
void cleanup();
@@ -87,7 +92,9 @@ class SORT_INFO
public:
SORT_INFO()
- :addon_field(0), record_pointers(0)
+ :addon_fields(NULL), record_pointers(0),
+ sort_keys(NULL),
+ sorted_result_in_fsbuf(FALSE)
{
buffpek.str= 0;
my_b_clear(&io_cache);
@@ -98,9 +105,11 @@ public:
void free_data()
{
close_cached_file(&io_cache);
+ free_addon_buff();
my_free(record_pointers);
my_free(buffpek.str);
- my_free(addon_field);
+ my_free(addon_fields);
+ free_sort_buffer();
}
void reset()
@@ -108,17 +117,27 @@ public:
free_data();
record_pointers= 0;
buffpek.str= 0;
- addon_field= 0;
+ addon_fields= 0;
+ sorted_result_in_fsbuf= false;
}
+ void free_addon_buff();
IO_CACHE io_cache; /* If sorted through filesort */
LEX_STRING buffpek; /* Buffer for buffpek structures */
- LEX_STRING addon_buf; /* Pointer to a buffer if sorted with fields */
- struct st_sort_addon_field *addon_field; /* Pointer to the fields info */
- /* To unpack back */
- void (*unpack)(struct st_sort_addon_field *, uchar *, uchar *);
+ Addon_fields *addon_fields; /* Addon field descriptors */
uchar *record_pointers; /* If sorted in memory */
+ Sort_keys *sort_keys; /* Sort key descriptors*/
+
+ /**
+ If the entire result of filesort fits in memory, we skip the merge phase.
+ We may leave the result in filesort_buffer
+ (indicated by sorted_result_in_fsbuf), or we may strip away
+ the sort keys, and copy the sorted result into a new buffer.
+ @see save_index()
+ */
+ bool sorted_result_in_fsbuf;
+
/*
How many rows in final result.
Also how many rows in record_pointers, if used
@@ -131,27 +150,66 @@ public:
void sort_buffer(Sort_param *param, uint count)
{ filesort_buffer.sort_buffer(param, count); }
- /**
- Accessors for Filesort_buffer (which @c).
- */
- uchar *get_record_buffer(uint idx)
- { return filesort_buffer.get_record_buffer(idx); }
-
uchar **get_sort_keys()
{ return filesort_buffer.get_sort_keys(); }
- uchar **alloc_sort_buffer(uint num_records, uint record_length)
+ uchar *get_sorted_record(uint ix)
+ { return filesort_buffer.get_sorted_record(ix); }
+
+ uchar *alloc_sort_buffer(uint num_records, uint record_length)
{ return filesort_buffer.alloc_sort_buffer(num_records, record_length); }
void free_sort_buffer()
{ filesort_buffer.free_sort_buffer(); }
+ bool isfull() const
+ { return filesort_buffer.isfull(); }
void init_record_pointers()
{ filesort_buffer.init_record_pointers(); }
+ void init_next_record_pointer()
+ { filesort_buffer.init_next_record_pointer(); }
+ uchar *get_next_record_pointer()
+ { return filesort_buffer.get_next_record_pointer(); }
+ void adjust_next_record_pointer(uint val)
+ { filesort_buffer.adjust_next_record_pointer(val); }
+
+ Bounds_checked_array<uchar> get_raw_buf()
+ { return filesort_buffer.get_raw_buf(); }
size_t sort_buffer_size() const
{ return filesort_buffer.sort_buffer_size(); }
+ bool is_allocated() const
+ { return filesort_buffer.is_allocated(); }
+ void set_sort_length(uint val)
+ { filesort_buffer.set_sort_length(val); }
+ uint get_sort_length() const
+ { return filesort_buffer.get_sort_length(); }
+
+ bool has_filesort_result_in_memory() const
+ {
+ return record_pointers || sorted_result_in_fsbuf;
+ }
+
+ /// Are we using "addon fields"?
+ bool using_addon_fields() const
+ {
+ return addon_fields != NULL;
+ }
+
+ /// Are we using "packed addon fields"?
+ bool using_packed_addons();
+
+ /**
+ Copies (unpacks) values appended to sorted fields from a buffer back to
+ their regular positions specified by the Field::ptr pointers.
+ @param buff Buffer which to unpack the value from
+ */
+ template<bool Packed_addon_fields>
+ inline void unpack_addon_fields(uchar *buff);
+
+ bool using_packed_sortkeys();
+
friend SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort,
Filesort_tracker* tracker, JOIN *join,
table_map first_table_bit);
@@ -162,8 +220,12 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort,
table_map first_table_bit=0);
bool filesort_use_addons(TABLE *table, uint sortlength,
- uint *length, uint *fields, uint *null_fields);
+ uint *length, uint *fields, uint *null_fields,
+ uint *m_packable_length);
void change_double_for_sort(double nr,uchar *to);
+void store_length(uchar *to, uint length, uint pack_length);
+void
+reverse_key(uchar *to, const SORT_FIELD_ATTR *sort_field);
#endif /* FILESORT_INCLUDED */
diff --git a/sql/filesort_utils.cc b/sql/filesort_utils.cc
index 703db84495f..5bd552f76be 100644
--- a/sql/filesort_utils.cc
+++ b/sql/filesort_utils.cc
@@ -20,6 +20,8 @@
#include "table.h"
+PSI_memory_key key_memory_Filesort_buffer_sort_keys;
+
namespace {
/**
A local helper function. See comments for get_merge_buffers_cost().
@@ -96,82 +98,98 @@ double get_merge_many_buffs_cost_fast(ha_rows num_rows,
# Pointer to allocated buffer
*/
-uchar **Filesort_buffer::alloc_sort_buffer(uint num_records,
- uint record_length)
+uchar *Filesort_buffer::alloc_sort_buffer(uint num_records,
+ uint record_length)
{
size_t buff_size;
- uchar **sort_keys, **start_of_data;
DBUG_ENTER("alloc_sort_buffer");
DBUG_EXECUTE_IF("alloc_sort_buffer_fail",
DBUG_SET("+d,simulate_out_of_memory"););
- buff_size= ((size_t)num_records) * (record_length + sizeof(uchar*));
- set_if_bigger(buff_size, record_length * MERGEBUFF2);
+ buff_size= ALIGN_SIZE(num_records * (record_length + sizeof(uchar*)));
+
+ /*
+ The minimum memory required should be each merge buffer can hold atmost
+ one key.
+ TODO varun: move this to the place where min_sort_memory is used.
+ */
+ set_if_bigger(buff_size,
+ ALIGN_SIZE((record_length +sizeof(uchar*)) * MERGEBUFF2));
- if (!m_idx_array.is_null())
+ if (m_rawmem)
{
/*
Reuse old buffer if exists and is large enough
Note that we don't make the buffer smaller, as we want to be
prepared for next subquery iteration.
*/
-
- sort_keys= m_idx_array.array();
- if (buff_size > allocated_size)
+ if (buff_size > m_size_in_bytes)
{
/*
Better to free and alloc than realloc as we don't have to remember
the old values
*/
- my_free(sort_keys);
- if (!(sort_keys= (uchar**) my_malloc(buff_size,
- MYF(MY_THREAD_SPECIFIC))))
+ my_free(m_rawmem);
+ if (!(m_rawmem= (uchar*) my_malloc(key_memory_Filesort_buffer_sort_keys,
+ buff_size, MYF(MY_THREAD_SPECIFIC))))
{
- reset();
+ m_size_in_bytes= 0;
DBUG_RETURN(0);
}
- allocated_size= buff_size;
}
}
else
{
- if (!(sort_keys= (uchar**) my_malloc(buff_size, MYF(MY_THREAD_SPECIFIC))))
+ if (!(m_rawmem= (uchar*) my_malloc(key_memory_Filesort_buffer_sort_keys,
+ buff_size, MYF(MY_THREAD_SPECIFIC))))
+ {
+ m_size_in_bytes= 0;
DBUG_RETURN(0);
- allocated_size= buff_size;
+ }
+
}
- m_idx_array= Idx_array(sort_keys, num_records);
+ m_size_in_bytes= buff_size;
+ m_record_pointers= reinterpret_cast<uchar**>(m_rawmem) +
+ ((m_size_in_bytes / sizeof(uchar*)) - 1);
+ m_num_records= num_records;
m_record_length= record_length;
- start_of_data= m_idx_array.array() + m_idx_array.size();
- m_start_of_data= reinterpret_cast<uchar*>(start_of_data);
-
- DBUG_RETURN(m_idx_array.array());
+ m_idx= 0;
+ DBUG_RETURN(m_rawmem);
}
void Filesort_buffer::free_sort_buffer()
{
- my_free(m_idx_array.array());
- m_idx_array.reset();
- m_start_of_data= NULL;
+ my_free(m_rawmem);
+ *this= Filesort_buffer();
}
void Filesort_buffer::sort_buffer(const Sort_param *param, uint count)
{
size_t size= param->sort_length;
+ m_sort_keys= get_sort_keys();
+
if (count <= 1 || size == 0)
return;
- uchar **keys= get_sort_keys();
+
+ // don't reverse for PQ, it is already done
+ if (!param->using_pq)
+ reverse_record_pointers();
+
uchar **buffer= NULL;
- if (radixsort_is_appliccable(count, param->sort_length) &&
- (buffer= (uchar**) my_malloc(count*sizeof(char*),
+ if (!param->using_packed_sortkeys() &&
+ radixsort_is_appliccable(count, param->sort_length) &&
+ (buffer= (uchar**) my_malloc(PSI_INSTRUMENT_ME, count*sizeof(char*),
MYF(MY_THREAD_SPECIFIC))))
{
- radixsort_for_str_ptr(keys, count, param->sort_length, buffer);
+ radixsort_for_str_ptr(m_sort_keys, count, param->sort_length, buffer);
my_free(buffer);
return;
}
-
- my_qsort2(keys, count, sizeof(uchar*), get_ptr_compare(size), &size);
+
+ my_qsort2(m_sort_keys, count, sizeof(uchar*),
+ param->get_compare_function(),
+ param->get_compare_argument(&size));
}
diff --git a/sql/filesort_utils.h b/sql/filesort_utils.h
index 1ab1ba2daa8..1962f149893 100644
--- a/sql/filesort_utils.h
+++ b/sql/filesort_utils.h
@@ -46,68 +46,194 @@ double get_merge_many_buffs_cost_fast(ha_rows num_rows,
/**
A wrapper class around the buffer used by filesort().
- The buffer is a contiguous chunk of memory,
- where the first part is <num_records> pointers to the actual data.
+ The sort buffer is a contiguous chunk of memory,
+ containing both records to be sorted, and pointers to said records:
+
+ <start of buffer | still unused | end of buffer>
+ |rec 0|record 1 |rec 2| ............ |ptr to rec2|ptr to rec1|ptr to rec0|
+
+ Records will be inserted "left-to-right". Records are not necessarily
+ fixed-size, they can be packed and stored without any "gaps".
+
+ Record pointers will be inserted "right-to-left", as a side-effect
+ of inserting the actual records.
We wrap the buffer in order to be able to do lazy initialization of the
pointers: the buffer is often much larger than what we actually need.
+ With this allocation scheme, and lazy initialization of the pointers,
+ we are able to pack variable-sized records in the buffer,
+ and thus possibly have space for more records than we initially estimated.
+
The buffer must be kept available for multiple executions of the
same sort operation, so we have explicit allocate and free functions,
rather than doing alloc/free in CTOR/DTOR.
*/
+
class Filesort_buffer
{
public:
- Filesort_buffer()
- : m_idx_array(), m_start_of_data(NULL), allocated_size(0)
+ Filesort_buffer() :
+ m_next_rec_ptr(NULL), m_rawmem(NULL), m_record_pointers(NULL),
+ m_sort_keys(NULL),
+ m_num_records(0), m_record_length(0),
+ m_sort_length(0),
+ m_size_in_bytes(0), m_idx(0)
{}
-
- ~Filesort_buffer()
+
+ /** Sort me... */
+ void sort_buffer(const Sort_param *param, uint count);
+
+ /**
+ Reverses the record pointer array, to avoid recording new results for
+ non-deterministic mtr tests.
+ */
+ void reverse_record_pointers()
{
- my_free(m_idx_array.array());
+ if (m_idx < 2) // There is nothing to swap.
+ return;
+ uchar **keys= get_sort_keys();
+ const longlong count= m_idx - 1;
+ for (longlong ix= 0; ix <= count/2; ++ix)
+ {
+ uchar *tmp= keys[count - ix];
+ keys[count - ix] = keys[ix];
+ keys[ix]= tmp;
+ }
}
- bool is_allocated()
+ /**
+ Initializes all the record pointers.
+ */
+ void init_record_pointers()
{
- return m_idx_array.array() != 0;
+ init_next_record_pointer();
+ while (m_idx < m_num_records)
+ (void) get_next_record_pointer();
+ reverse_record_pointers();
}
- void reset()
+
+ /**
+ Prepares the buffer for the next batch of records to process.
+ */
+ void init_next_record_pointer()
{
- m_idx_array.reset();
+ m_idx= 0;
+ m_next_rec_ptr= m_rawmem;
+ m_sort_keys= NULL;
}
- /** Sort me... */
- void sort_buffer(const Sort_param *param, uint count);
+ /**
+ @returns the number of bytes currently in use for data.
+ */
+ size_t space_used_for_data() const
+ {
+ return m_next_rec_ptr ? m_next_rec_ptr - m_rawmem : 0;
+ }
- /// Initializes a record pointer.
- uchar *get_record_buffer(uint idx)
+ /**
+ @returns the number of bytes left in the buffer.
+ */
+ size_t spaceleft() const
{
- m_idx_array[idx]= m_start_of_data + (idx * m_record_length);
- return m_idx_array[idx];
+ DBUG_ASSERT(m_next_rec_ptr >= m_rawmem);
+ const size_t spaceused=
+ (m_next_rec_ptr - m_rawmem) +
+ (static_cast<size_t>(m_idx) * sizeof(uchar*));
+ return m_size_in_bytes - spaceused;
}
- /// Initializes all the record pointers.
- void init_record_pointers()
+ /**
+ Is the buffer full?
+ */
+ bool isfull() const
+ {
+ if (m_idx < m_num_records)
+ return false;
+ return spaceleft() < (m_record_length + sizeof(uchar*));
+ }
+
+ /**
+ Where should the next record be stored?
+ */
+ uchar *get_next_record_pointer()
{
- for (uint ix= 0; ix < m_idx_array.size(); ++ix)
- (void) get_record_buffer(ix);
+ uchar *retval= m_next_rec_ptr;
+ // Save the return value in the record pointer array.
+ m_record_pointers[-m_idx]= m_next_rec_ptr;
+ // Prepare for the subsequent request.
+ m_idx++;
+ m_next_rec_ptr+= m_record_length;
+ return retval;
+ }
+
+ /**
+ Adjusts for actual record length. get_next_record_pointer() above was
+ pessimistic, and assumed that the record could not be packed.
+ */
+ void adjust_next_record_pointer(uint val)
+ {
+ m_next_rec_ptr-= (m_record_length - val);
}
/// Returns total size: pointer array + record buffers.
size_t sort_buffer_size() const
{
- return allocated_size;
+ return m_size_in_bytes;
}
- /// Allocates the buffer, but does *not* initialize pointers.
- uchar **alloc_sort_buffer(uint num_records, uint record_length);
+ bool is_allocated() const
+ {
+ return m_rawmem;
+ }
+
+ /**
+ Allocates the buffer, but does *not* initialize pointers.
+ Total size = (num_records * record_length) + (num_records * sizeof(pointer))
+ space for records space for pointer to records
+ Caller is responsible for raising an error if allocation fails.
+
+ @param num_records Number of records.
+ @param record_length (maximum) size of each record.
+ @returns Pointer to allocated area, or NULL in case of out-of-memory.
+ */
+ uchar *alloc_sort_buffer(uint num_records, uint record_length);
/// Frees the buffer.
void free_sort_buffer();
- /// Getter, for calling routines which still use the uchar** interface.
- uchar **get_sort_keys() { return m_idx_array.array(); }
+ void reset()
+ {
+ m_rawmem= NULL;
+ }
+ /**
+ Used to access the "right-to-left" array of record pointers as an ordinary
+ "left-to-right" array, so that we can pass it directly on to std::sort().
+ */
+ uchar **get_sort_keys()
+ {
+ if (m_idx == 0)
+ return NULL;
+ return &m_record_pointers[1 - m_idx];
+ }
+
+ /**
+ Gets sorted record number ix. @see get_sort_keys()
+ Only valid after buffer has been sorted!
+ */
+ uchar *get_sorted_record(uint ix)
+ {
+ return m_sort_keys[ix];
+ }
+
+ /**
+ @returns The entire buffer, as a character array.
+ This is for reusing the memory for merge buffers.
+ */
+ Bounds_checked_array<uchar> get_raw_buf()
+ {
+ return Bounds_checked_array<uchar>(m_rawmem, m_size_in_bytes);
+ }
/**
We need an assignment operator, see filesort().
@@ -117,20 +243,44 @@ public:
*/
Filesort_buffer &operator=(const Filesort_buffer &rhs)
{
- m_idx_array= rhs.m_idx_array;
+ m_next_rec_ptr= rhs.m_next_rec_ptr;
+ m_rawmem= rhs.m_rawmem;
+ m_record_pointers= rhs.m_record_pointers;
+ m_sort_keys= rhs.m_sort_keys;
+ m_num_records= rhs.m_num_records;
m_record_length= rhs.m_record_length;
- m_start_of_data= rhs.m_start_of_data;
- allocated_size= rhs.allocated_size;
+ m_sort_length= rhs.m_sort_length;
+ m_size_in_bytes= rhs.m_size_in_bytes;
+ m_idx= rhs.m_idx;
return *this;
}
+ uint get_sort_length() const { return m_sort_length; }
+ void set_sort_length(uint val) { m_sort_length= val; }
+
private:
- typedef Bounds_checked_array<uchar*> Idx_array;
+ uchar *m_next_rec_ptr; /// The next record will be inserted here.
+ uchar *m_rawmem; /// The raw memory buffer.
+ uchar **m_record_pointers; /// The "right-to-left" array of record pointers.
+ uchar **m_sort_keys; /// Caches the value of get_sort_keys()
+ uint m_num_records; /// Saved value from alloc_sort_buffer()
+ uint m_record_length; /// Saved value from alloc_sort_buffer()
+ uint m_sort_length; /// The length of the sort key.
+ size_t m_size_in_bytes; /// Size of raw buffer, in bytes.
- Idx_array m_idx_array; /* Pointers to key data */
- uint m_record_length;
- uchar *m_start_of_data; /* Start of key data */
- size_t allocated_size;
+ /**
+ This is the index in the "right-to-left" array of the next record to
+ be inserted into the buffer. It is signed, because we use it in signed
+ expressions like:
+ m_record_pointers[-m_idx];
+ It is longlong rather than int, to ensure that it covers UINT_MAX32
+ without any casting/warning.
+ */
+ longlong m_idx;
};
+int compare_packed_sort_keys(void *sort_keys, unsigned char **a,
+ unsigned char **b);
+qsort2_cmp get_packed_keys_compare_ptr();
+
#endif // FILESORT_UTILS_INCLUDED
diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc
index 4919e5b959b..6d7ab7e29c3 100644
--- a/sql/gcalc_slicescan.cc
+++ b/sql/gcalc_slicescan.cc
@@ -204,7 +204,7 @@ void Gcalc_dyn_list::format_blk(void* block)
Gcalc_dyn_list::Item *Gcalc_dyn_list::alloc_new_blk()
{
- void *new_block= my_malloc(m_blk_size, MYF(MY_WME));
+ void *new_block= my_malloc(PSI_INSTRUMENT_ME, m_blk_size, MYF(MY_WME));
if (!new_block)
return NULL;
*m_blk_hook= new_block;
diff --git a/sql/gen_sql_yacc_ora_yy.cmake b/sql/gen_sql_yacc_ora_yy.cmake
new file mode 100644
index 00000000000..3fdd5d43f8d
--- /dev/null
+++ b/sql/gen_sql_yacc_ora_yy.cmake
@@ -0,0 +1,15 @@
+
+file(READ "${IN}" yytmp)
+
+# Comment out sql_mode=DEFAULT rules and directives (e.g. %expect, %type)
+string(REPLACE "/* Start SQL_MODE_DEFAULT_SPECIFIC */"
+ "/* Start SQL_MODE_DEFAULT_SPECIFIC" yytmp "${yytmp}")
+string(REPLACE "/* End SQL_MODE_DEFAULT_SPECIFIC */"
+ "End SQL_MODE_DEFAULT_SPECIFIC */" yytmp "${yytmp}")
+
+# Uncomment sql_mode=ORACLE rules and directives
+string(REPLACE "/* Start SQL_MODE_ORACLE_SPECIFIC"
+ "/* Start SQL_MODE_ORACLE_SPECIFIC */" yytmp "${yytmp}")
+string(REPLACE "End SQL_MODE_ORACLE_SPECIFIC */"
+ "/* End SQL_MODE_ORACLE_SPECIFIC */" yytmp "${yytmp}")
+file(WRITE "${OUT}" "${yytmp}")
diff --git a/sql/grant.cc b/sql/grant.cc
new file mode 100644
index 00000000000..1ba197bc1d9
--- /dev/null
+++ b/sql/grant.cc
@@ -0,0 +1,108 @@
+/*
+ Copyright (c) 2009, 2020, 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 St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "mariadb.h"
+#include "sql_acl.h"
+
+
+bool Grant_privilege::add_column_privilege(THD *thd,
+ const Lex_ident_sys &name,
+ privilege_t which_grant)
+{
+ String *new_str= new (thd->mem_root) String((const char*) name.str,
+ name.length,
+ system_charset_info);
+ if (unlikely(new_str == NULL))
+ return true;
+ List_iterator <LEX_COLUMN> iter(m_columns);
+ class LEX_COLUMN *point;
+ while ((point=iter++))
+ {
+ if (!my_strcasecmp(system_charset_info,
+ point->column.c_ptr(), new_str->c_ptr()))
+ break;
+ }
+ m_column_privilege_total|= which_grant;
+ if (point)
+ {
+ point->rights |= which_grant;
+ return false;
+ }
+
+ LEX_COLUMN *col= new (thd->mem_root) LEX_COLUMN(*new_str, which_grant);
+ if (unlikely(col == NULL))
+ return true;
+ return m_columns.push_back(col, thd->mem_root);
+}
+
+
+bool Grant_privilege::add_column_list_privilege(THD *thd,
+ List<Lex_ident_sys> &list,
+ privilege_t privilege)
+{
+ Lex_ident_sys *col;
+ List_iterator<Lex_ident_sys> it(list);
+ while ((col= it++))
+ {
+ if (add_column_privilege(thd, *col, privilege))
+ return true;
+ }
+ return false;
+}
+
+
+privilege_t Grant_object_name::all_privileges_by_type() const
+{
+ switch (m_type) {
+ case STAR: return DB_ACLS & ~GRANT_ACL;
+ case IDENT_STAR: return DB_ACLS & ~GRANT_ACL;
+ case STAR_STAR: return GLOBAL_ACLS & ~GRANT_ACL;
+ case TABLE_IDENT: return TABLE_ACLS & ~GRANT_ACL;
+ }
+ return NO_ACL;
+}
+
+
+bool Grant_privilege::set_object_name(THD *thd,
+ const Grant_object_name &ident,
+ SELECT_LEX *sel,
+ privilege_t with_grant_option)
+{
+ DBUG_ASSERT(!m_all_privileges || !m_columns.elements);
+
+ m_db= ident.m_db;
+ if (m_all_privileges)
+ m_object_privilege= ident.all_privileges_by_type();
+ m_object_privilege|= with_grant_option;
+ switch (ident.m_type)
+ {
+ case Lex_grant_object_name::STAR:
+ case Lex_grant_object_name::IDENT_STAR:
+ case Lex_grant_object_name::STAR_STAR:
+ if (!m_all_privileges && m_columns.elements)
+ {
+ // e.g. GRANT SELECT (a) ON db.*
+ my_error(ER_ILLEGAL_GRANT_FOR_TABLE, MYF(0));
+ return true;
+ }
+ return false;
+ case Lex_grant_object_name::TABLE_IDENT:
+ m_db= ident.m_table_ident->db;
+ return !sel->add_table_to_list(thd, ident.m_table_ident,
+ NULL, TL_OPTION_UPDATING);
+ }
+ return false; // Make gcc happy
+}
diff --git a/sql/grant.h b/sql/grant.h
new file mode 100644
index 00000000000..5fbec4469d4
--- /dev/null
+++ b/sql/grant.h
@@ -0,0 +1,99 @@
+/*
+ Copyright (c) 2020, 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-1335 USA */
+
+#ifndef SQL_GRANT_INCLUDED
+#define SQL_GRANT_INCLUDED
+
+#include "lex_string.h"
+#include "privilege.h"
+
+class LEX_COLUMN;
+class Lex_ident_sys;
+class Table_ident;
+
+/*
+ Represents the object name in this standard SQL grammar:
+ GRANT <object privileges> ON <object name>
+*/
+class Grant_object_name
+{
+public:
+ enum Type
+ {
+ STAR, // ON *
+ IDENT_STAR, // ON db.*
+ STAR_STAR, // ON *.*
+ TABLE_IDENT // ON db.name
+ };
+ Lex_cstring m_db;
+ Table_ident *m_table_ident;
+ Type m_type;
+public:
+ Grant_object_name(Table_ident *table_ident)
+ :m_table_ident(table_ident),
+ m_type(TABLE_IDENT)
+ { }
+ Grant_object_name(const LEX_CSTRING &db, Type type)
+ :m_db(db),
+ m_table_ident(NULL),
+ m_type(type)
+ { }
+ privilege_t all_privileges_by_type() const;
+};
+
+
+
+/*
+ Represents standard SQL statements described by:
+ - <grant privilege statement>
+ - <revoke privilege statement>
+*/
+class Grant_privilege
+{
+protected:
+ List<LEX_COLUMN> m_columns;
+ Lex_cstring m_db;
+ privilege_t m_object_privilege;
+ privilege_t m_column_privilege_total;
+ bool m_all_privileges;
+public:
+ Grant_privilege()
+ :m_object_privilege(NO_ACL),
+ m_column_privilege_total(NO_ACL),
+ m_all_privileges(false)
+ { }
+ Grant_privilege(privilege_t privilege, bool all_privileges)
+ :m_object_privilege(privilege),
+ m_column_privilege_total(NO_ACL),
+ m_all_privileges(all_privileges)
+ { }
+ void add_object_privilege(privilege_t privilege)
+ {
+ m_object_privilege|= privilege;
+ }
+ bool add_column_privilege(THD *thd, const Lex_ident_sys &col,
+ privilege_t privilege);
+ bool add_column_list_privilege(THD *thd, List<Lex_ident_sys> &list,
+ privilege_t privilege);
+ bool set_object_name(THD *thd,
+ const Grant_object_name &ident,
+ SELECT_LEX *sel,
+ privilege_t with_grant_option);
+ const List<LEX_COLUMN> & columns() const { return m_columns; }
+};
+
+
+#endif // SQL_GRANT_INCLUDED
diff --git a/sql/group_by_handler.cc b/sql/group_by_handler.cc
index 326aad439ef..71703cf09b6 100644
--- a/sql/group_by_handler.cc
+++ b/sql/group_by_handler.cc
@@ -40,7 +40,7 @@ int Pushdown_query::execute(JOIN *join)
{
int err;
ha_rows max_limit;
- ha_rows *reset_limit= 0;
+ bool reset_limit= FALSE;
Item **reset_item= 0;
THD *thd= handler->thd;
TABLE *table= handler->table;
@@ -52,11 +52,11 @@ int Pushdown_query::execute(JOIN *join)
if (store_data_in_temp_table)
{
max_limit= join->tmp_table_param.end_write_records;
- reset_limit= &join->unit->select_limit_cnt;
+ reset_limit= TRUE;
}
else
{
- max_limit= join->unit->select_limit_cnt;
+ max_limit= join->unit->lim.get_select_limit();
if (join->unit->fake_select_lex)
reset_item= &join->unit->fake_select_lex->select_limit;
}
@@ -97,7 +97,10 @@ int Pushdown_query::execute(JOIN *join)
{
int error;
/* result < 0 if row was not accepted and should not be counted */
- if (unlikely((error= join->result->send_data(*join->fields))))
+ if (unlikely((error=
+ join->result->send_data_with_check(*join->fields,
+ join->unit,
+ join->send_records))))
{
handler->end_scan();
DBUG_RETURN(error < 0 ? 0 : -1);
@@ -112,7 +115,7 @@ int Pushdown_query::execute(JOIN *join)
break; // LIMIT reached
join->do_send_rows= 0; // Calculate FOUND_ROWS()
if (reset_limit)
- *reset_limit= HA_POS_ERROR;
+ join->unit->lim.set_unlimited();
if (reset_item)
*reset_item= 0;
}
diff --git a/sql/group_by_handler.h b/sql/group_by_handler.h
index 108ebc989d9..ff3b204fa56 100644
--- a/sql/group_by_handler.h
+++ b/sql/group_by_handler.h
@@ -14,6 +14,10 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+#ifndef GROUP_BY_HANDLER_INCLUDED
+#define GROUP_BY_HANDLER_INCLUDED
+
+class Select_limit_counters;
/*
This file implements the group_by_handler interface. This interface
can be used by storage handlers that can intercept summary or GROUP
@@ -56,6 +60,7 @@ struct Query
ORDER *order_by;
Item *having;
// LIMIT
+ Select_limit_counters *limit;
};
class group_by_handler
@@ -100,3 +105,4 @@ public:
virtual void print_error(int error, myf errflag);
};
+#endif //GROUP_BY_HANDLER_INCLUDED
diff --git a/sql/gstream.cc b/sql/gstream.cc
index 4678e85019e..f8e84e70560 100644
--- a/sql/gstream.cc
+++ b/sql/gstream.cc
@@ -1,4 +1,5 @@
/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2009, 2020, 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
@@ -22,6 +23,7 @@
#include "sql_priv.h"
#include "gstream.h"
#include "m_string.h" // LEX_STRING
+#include "mysqld.h"
enum Gis_read_stream::enum_tok_types Gis_read_stream::get_next_toc_type()
{
@@ -107,8 +109,7 @@ bool Gis_read_stream::get_next_number(double *d)
return 1;
}
- *d = my_strntod(m_charset, (char *)m_cur,
- (uint) (m_limit-m_cur), &endptr, &err);
+ *d = m_charset->strntod((char *)m_cur, (uint) (m_limit-m_cur), &endptr, &err);
if (err)
return 1;
if (endptr)
@@ -140,6 +141,7 @@ bool Gis_read_stream::check_next_symbol(char symbol)
void Gis_read_stream::set_error_msg(const char *msg)
{
size_t len= strlen(msg); // ok in this context
- m_err_msg= (char *) my_realloc(m_err_msg, (uint) len + 1, MYF(MY_ALLOW_ZERO_PTR));
+ m_err_msg= (char *) my_realloc(key_memory_Gis_read_stream_err_msg,
+ m_err_msg, (uint) len + 1, MYF(MY_ALLOW_ZERO_PTR));
memcpy(m_err_msg, msg, len + 1);
}
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index d65a4963905..2e5355580c7 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -72,7 +72,8 @@
#define PAR_ENGINES_OFFSET 12
#define PARTITION_ENABLED_TABLE_FLAGS (HA_FILE_BASED | \
HA_REC_NOT_IN_SEQ | \
- HA_CAN_REPAIR)
+ HA_CAN_REPAIR | \
+ HA_REUSES_FILE_NAMES)
#define PARTITION_DISABLED_TABLE_FLAGS (HA_CAN_GEOMETRY | \
HA_DUPLICATE_POS | \
HA_CAN_INSERT_DELAYED | \
@@ -101,22 +102,43 @@ static const char *ha_partition_ext[]=
ha_par_ext, NullS
};
+static PSI_memory_key key_memory_Partition_share;
+static PSI_memory_key key_memory_partition_sort_buffer;
+static PSI_memory_key key_memory_Partition_admin;
+
+static PSI_memory_key key_memory_ha_partition_file;
+//static PSI_memory_key key_memory_ha_partition_engine_array;
+static PSI_memory_key key_memory_ha_partition_part_ids;
#ifdef HAVE_PSI_INTERFACE
PSI_mutex_key key_partition_auto_inc_mutex;
+PSI_file_key key_file_ha_partition_par;
static PSI_mutex_info all_partition_mutexes[]=
{
{ &key_partition_auto_inc_mutex, "Partition_share::auto_inc_mutex", 0}
};
+static PSI_memory_info all_partitioning_memory[]=
+{ { &key_memory_Partition_share, "Partition_share", 0},
+ { &key_memory_partition_sort_buffer, "partition_sort_buffer", 0},
+ { &key_memory_Partition_admin, "Partition_admin", 0},
+ { &key_memory_ha_partition_file, "ha_partition::file", 0},
+// { &key_memory_ha_partition_engine_array, "ha_partition::engine_array", 0},
+ { &key_memory_ha_partition_part_ids, "ha_partition::part_ids", 0} };
+static PSI_file_info all_partition_file[]=
+{ { &key_file_ha_partition_par, "ha_partition::parfile", 0} };
static void init_partition_psi_keys(void)
{
const char* category= "partition";
int count;
+ count= array_elements(all_partitioning_memory);
+ mysql_memory_register(category, all_partitioning_memory, count);
count= array_elements(all_partition_mutexes);
mysql_mutex_register(category, all_partition_mutexes, count);
+ count= array_elements(all_partition_file);
+ mysql_file_register(category, all_partition_file, count);
}
#endif /* HAVE_PSI_INTERFACE */
@@ -125,7 +147,6 @@ static int partition_initialize(void *p)
handlerton *partition_hton;
partition_hton= (handlerton *)p;
- partition_hton->state= SHOW_OPTION_YES;
partition_hton->db_type= DB_TYPE_PARTITION_DB;
partition_hton->create= partition_create_handler;
partition_hton->partition_flags= partition_flags;
@@ -244,7 +265,7 @@ ha_partition::ha_partition(handlerton *hton, TABLE_SHARE *share)
void ha_partition::ha_partition_init()
{
- init_alloc_root(&m_mem_root, "ha_partition", 512, 512, MYF(0));
+ init_alloc_root(PSI_INSTRUMENT_ME, &m_mem_root, 512, 512, MYF(0));
init_handler_variables();
}
@@ -649,9 +670,9 @@ int ha_partition::create_partitioning_metadata(const char *path,
strxmov(name, path, ha_par_ext, NullS);
strxmov(old_name, old_path, ha_par_ext, NullS);
if ((action_flag == CHF_DELETE_FLAG &&
- mysql_file_delete(key_file_partition, name, MYF(MY_WME))) ||
+ mysql_file_delete(key_file_ha_partition_par, name, MYF(MY_WME))) ||
(action_flag == CHF_RENAME_FLAG &&
- mysql_file_rename(key_file_partition, old_name, name, MYF(MY_WME))))
+ mysql_file_rename(key_file_ha_partition_par, old_name, name, MYF(MY_WME))))
{
DBUG_RETURN(TRUE);
}
@@ -1333,7 +1354,7 @@ bool print_admin_msg(THD* thd, uint len,
char *msgbuf;
bool error= true;
- if (!(msgbuf= (char*) my_malloc(len, MYF(0))))
+ if (!(msgbuf= (char*) my_malloc(key_memory_Partition_admin, len, MYF(0))))
return true;
va_start(args, fmt);
msg_length= my_vsnprintf(msgbuf, len, fmt, args);
@@ -2547,9 +2568,9 @@ register_query_cache_dependant_tables(THD *thd,
sub_elem= subpart_it++;
part= i * num_subparts + j;
/* we store the end \0 as part of the key */
- end= strmov(engine_pos, sub_elem->partition_name);
+ end= strmov(engine_pos, sub_elem->partition_name) + 1;
length= (uint)(end - engine_key);
- /* Copy the suffix also to query cache key */
+ /* Copy the suffix and end 0 to query cache key */
memcpy(query_cache_key_end, engine_key_end, (end - engine_key_end));
if (reg_query_cache_dependant_table(thd, engine_key, length,
query_cache_key,
@@ -2565,7 +2586,7 @@ register_query_cache_dependant_tables(THD *thd,
{
char *end= engine_pos+1; // copy end \0
uint length= (uint)(end - engine_key);
- /* Copy the suffix also to query cache key */
+ /* Copy the suffix and end 0 to query cache key */
memcpy(query_cache_key_end, engine_key_end, (end - engine_key_end));
if (reg_query_cache_dependant_table(thd, engine_key, length,
query_cache_key,
@@ -2749,7 +2770,8 @@ bool ha_partition::create_handler_file(const char *name)
/* 4 static words (tot words, checksum, tot partitions, name length) */
tot_len_words= 4 + tot_partition_words + tot_name_words;
tot_len_byte= PAR_WORD_SIZE * tot_len_words;
- if (!(file_buffer= (uchar *) my_malloc(tot_len_byte, MYF(MY_ZEROFILL))))
+ if (!(file_buffer= (uchar *) my_malloc(key_memory_ha_partition_file,
+ tot_len_byte, MYF(MY_ZEROFILL))))
DBUG_RETURN(TRUE);
engine_array= (file_buffer + PAR_ENGINES_OFFSET);
name_buffer_ptr= (char*) (engine_array + tot_partition_words * PAR_WORD_SIZE
@@ -2804,7 +2826,7 @@ bool ha_partition::create_handler_file(const char *name)
to be used at open, delete_table and rename_table
*/
fn_format(file_name, name, "", ha_par_ext, MY_APPEND_EXT);
- if ((file= mysql_file_create(key_file_partition,
+ if ((file= mysql_file_create(key_file_ha_partition_par,
file_name, CREATE_MODE, O_RDWR | O_TRUNC,
MYF(MY_WME))) >= 0)
{
@@ -2829,7 +2851,7 @@ bool ha_partition::create_handler_file(const char *name)
}
(void) mysql_file_close(file, MYF(0));
if (result)
- mysql_file_delete(key_file_partition, file_name, MYF(MY_WME));
+ mysql_file_delete(key_file_ha_partition_par, file_name, MYF(MY_WME));
}
else
result= TRUE;
@@ -2993,7 +3015,7 @@ bool ha_partition::read_par_file(const char *name)
fn_format(buff, name, "", ha_par_ext, MY_APPEND_EXT);
/* Following could be done with mysql_file_stat to read in whole file */
- if ((file= mysql_file_open(key_file_partition,
+ if ((file= mysql_file_open(key_file_ha_partition_par,
buff, O_RDONLY | O_SHARE, MYF(0))) < 0)
DBUG_RETURN(TRUE);
if (mysql_file_read(file, (uchar *) &buff[0], PAR_WORD_SIZE, MYF(MY_NABP)))
@@ -3219,7 +3241,7 @@ bool ha_partition::insert_partition_name_in_hash(const char *name, uint part_id,
Since we use my_multi_malloc, then my_free(part_def) will also free
part_name, as a part of my_hash_free.
*/
- if (!my_multi_malloc(MY_WME,
+ if (!my_multi_malloc(key_memory_Partition_share, MY_WME,
&part_def, sizeof(PART_NAME_DEF),
&part_name, part_name_length + 1,
NULL))
@@ -3267,10 +3289,10 @@ bool ha_partition::populate_partition_name_hash()
DBUG_RETURN(false);
}
tot_names= m_is_sub_partitioned ? m_tot_parts + num_parts : num_parts;
- if (my_hash_init(&part_share->partition_name_hash,
- system_charset_info, tot_names, 0, 0,
- (my_hash_get_key) get_part_name,
- my_free, HASH_UNIQUE))
+ if (my_hash_init(key_memory_Partition_share,
+ &part_share->partition_name_hash, system_charset_info,
+ tot_names, 0, 0, (my_hash_get_key) get_part_name, my_free,
+ HASH_UNIQUE))
{
unlock_shared_ha_data();
DBUG_RETURN(TRUE);
@@ -3506,7 +3528,8 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
if (!m_part_ids_sorted_by_num_of_records)
{
if (!(m_part_ids_sorted_by_num_of_records=
- (uint32*) my_malloc(m_tot_parts * sizeof(uint32), MYF(MY_WME))))
+ (uint32*) my_malloc(key_memory_ha_partition_part_ids,
+ m_tot_parts * sizeof(uint32), MYF(MY_WME))))
DBUG_RETURN(error);
uint32 i;
/* Initialize it with all partition ids. */
@@ -3524,7 +3547,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
/* Allocate memory used with MMR */
if (!(m_range_info= (void **)
- my_multi_malloc(MYF(MY_WME),
+ my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME),
&m_range_info, sizeof(range_id_t) * m_tot_parts,
&m_stock_range_seq, sizeof(uint) * m_tot_parts,
&m_mrr_buffer, sizeof(HANDLER_BUFFER) * m_tot_parts,
@@ -3535,8 +3558,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
&m_part_mrr_range_current,
sizeof(PARTITION_PART_KEY_MULTI_RANGE *) * m_tot_parts,
&m_partition_part_key_multi_range_hld,
- sizeof(PARTITION_PART_KEY_MULTI_RANGE_HLD) *
- m_tot_parts,
+ sizeof(PARTITION_PART_KEY_MULTI_RANGE_HLD) * m_tot_parts,
NullS)))
goto err_alloc;
@@ -4276,7 +4298,7 @@ int ha_partition::write_row(const uchar * buf)
bool have_auto_increment= table->next_number_field && buf == table->record[0];
my_bitmap_map *old_map;
THD *thd= ha_thd();
- sql_mode_t saved_sql_mode= thd->variables.sql_mode;
+ Sql_mode_save sms(thd);
bool saved_auto_inc_field_not_null= table->auto_increment_field_not_null;
DBUG_ENTER("ha_partition::write_row");
DBUG_PRINT("enter", ("partition this: %p", this));
@@ -4342,7 +4364,6 @@ int ha_partition::write_row(const uchar * buf)
reenable_binlog(thd);
exit:
- thd->variables.sql_mode= saved_sql_mode;
table->auto_increment_field_not_null= saved_auto_inc_field_not_null;
DBUG_RETURN(error);
}
@@ -5316,7 +5337,8 @@ bool ha_partition::init_record_priority_queue()
/* Allocate a key for temporary use when setting up the scan. */
alloc_len+= table_share->max_key_length;
- if (!(m_ordered_rec_buffer= (uchar*)my_malloc(alloc_len, MYF(MY_WME))))
+ if (!(m_ordered_rec_buffer= (uchar*)my_malloc(key_memory_partition_sort_buffer,
+ alloc_len, MYF(MY_WME))))
DBUG_RETURN(true);
/*
@@ -6067,9 +6089,8 @@ int ha_partition::multi_range_key_create_key(RANGE_SEQ_IF *seq,
if (!m_mrr_range_first)
{
if (!(m_mrr_range_first= (PARTITION_KEY_MULTI_RANGE *)
- my_multi_malloc(MYF(MY_WME),
- &m_mrr_range_current,
- sizeof(PARTITION_KEY_MULTI_RANGE),
+ my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME),
+ &m_mrr_range_current, sizeof(PARTITION_KEY_MULTI_RANGE),
NullS)))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
@@ -6086,9 +6107,8 @@ int ha_partition::multi_range_key_create_key(RANGE_SEQ_IF *seq,
if (!m_part_mrr_range_first[i])
{
if (!(m_part_mrr_range_first[i]= (PARTITION_PART_KEY_MULTI_RANGE *)
- my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
- &m_part_mrr_range_current[i],
- sizeof(PARTITION_PART_KEY_MULTI_RANGE),
+ my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME | MY_ZEROFILL),
+ &m_part_mrr_range_current[i], sizeof(PARTITION_PART_KEY_MULTI_RANGE),
NullS)))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
}
@@ -6124,7 +6144,7 @@ int ha_partition::multi_range_key_create_key(RANGE_SEQ_IF *seq,
if (m_mrr_range_current->key[0])
my_free(m_mrr_range_current->key[0]);
if (!(m_mrr_range_current->key[0]=
- (uchar *) my_malloc(length, MYF(MY_WME))))
+ (uchar *) my_malloc(PSI_INSTRUMENT_ME, length, MYF(MY_WME))))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
m_mrr_range_current->length[0]= length;
}
@@ -6148,7 +6168,7 @@ int ha_partition::multi_range_key_create_key(RANGE_SEQ_IF *seq,
if (m_mrr_range_current->key[1])
my_free(m_mrr_range_current->key[1]);
if (!(m_mrr_range_current->key[1]=
- (uchar *) my_malloc(length, MYF(MY_WME))))
+ (uchar *) my_malloc(PSI_INSTRUMENT_ME, length, MYF(MY_WME))))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
m_mrr_range_current->length[1]= length;
}
@@ -6182,7 +6202,7 @@ int ha_partition::multi_range_key_create_key(RANGE_SEQ_IF *seq,
{
PARTITION_PART_KEY_MULTI_RANGE *tmp_part_mrr_range;
if (!(tmp_part_mrr_range= (PARTITION_PART_KEY_MULTI_RANGE *)
- my_malloc(sizeof(PARTITION_PART_KEY_MULTI_RANGE),
+ my_malloc(PSI_INSTRUMENT_ME, sizeof(PARTITION_PART_KEY_MULTI_RANGE),
MYF(MY_WME | MY_ZEROFILL))))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
@@ -6202,7 +6222,7 @@ int ha_partition::multi_range_key_create_key(RANGE_SEQ_IF *seq,
/* Add end of range sentinel */
PARTITION_KEY_MULTI_RANGE *tmp_mrr_range;
if (!(tmp_mrr_range= (PARTITION_KEY_MULTI_RANGE *)
- my_malloc(sizeof(PARTITION_KEY_MULTI_RANGE), MYF(MY_WME))))
+ my_malloc(PSI_INSTRUMENT_ME, sizeof(PARTITION_KEY_MULTI_RANGE), MYF(MY_WME))))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
tmp_mrr_range->id= m_mrr_range_current->id + 1;
@@ -6475,7 +6495,7 @@ int ha_partition::multi_range_read_init(RANGE_SEQ_IF *seq,
if (m_mrr_full_buffer)
my_free(m_mrr_full_buffer);
if (!(m_mrr_full_buffer=
- (uchar *) my_malloc(m_mrr_new_full_buffer_size, MYF(MY_WME))))
+ (uchar *) my_malloc(PSI_INSTRUMENT_ME, m_mrr_new_full_buffer_size, MYF(MY_WME))))
{
m_mrr_full_buffer_size= 0;
error= HA_ERR_OUT_OF_MEM;
@@ -6873,11 +6893,9 @@ FT_INFO *ha_partition::ft_init_ext(uint flags, uint inx, String *key)
{
FT_INFO **tmp_ft_info;
if (!(ft_target= (st_partition_ft_info *)
- my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
- &ft_target,
- sizeof(st_partition_ft_info),
- &tmp_ft_info,
- sizeof(FT_INFO *) * m_tot_parts,
+ my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME | MY_ZEROFILL),
+ &ft_target, sizeof(st_partition_ft_info),
+ &tmp_ft_info, sizeof(FT_INFO *) * m_tot_parts,
NullS)))
{
my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL));
@@ -9700,8 +9718,7 @@ uint32 ha_partition::calculate_key_hash_value(Field **field_array)
}
/* Force this to my_hash_sort_bin, which was used in 5.1! */
uint len= field->pack_length();
- my_charset_bin.coll->hash_sort(&my_charset_bin, field->ptr, len,
- &nr1, &nr2);
+ my_charset_bin.hash_sort(field->ptr, len, &nr1, &nr2);
/* Done with this field, continue with next one. */
continue;
}
@@ -9724,8 +9741,7 @@ uint32 ha_partition::calculate_key_hash_value(Field **field_array)
}
/* Force this to my_hash_sort_bin, which was used in 5.1! */
uint len= field->pack_length();
- my_charset_latin1.coll->hash_sort(&my_charset_latin1, field->ptr,
- len, &nr1, &nr2);
+ my_charset_latin1.hash_sort(field->ptr, len, &nr1, &nr2);
continue;
}
/* New types in mysql-5.6. */
@@ -10294,19 +10310,6 @@ end:
}
-void ha_partition::notify_table_changed()
-{
- handler **file;
-
- DBUG_ENTER("ha_partition::notify_table_changed");
-
- for (file= m_file; *file; file++)
- (*file)->ha_notify_table_changed();
-
- DBUG_VOID_RETURN;
-}
-
-
uint ha_partition::min_of_the_max_uint(
uint (handler::*operator_func)(void) const) const
{
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index ea9d3e0f610..e50ed2aeef7 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -1508,12 +1508,10 @@ public:
Alter_inplace_info *ha_alter_info)
override;
bool inplace_alter_table(TABLE *altered_table,
- Alter_inplace_info *ha_alter_info) override;
+ Alter_inplace_info *ha_alter_info) override;
bool commit_inplace_alter_table(TABLE *altered_table,
Alter_inplace_info *ha_alter_info,
bool commit) override;
- void notify_table_changed() override;
-
/*
-------------------------------------------------------------------------
MODULE tablespace support
diff --git a/sql/ha_sequence.cc b/sql/ha_sequence.cc
index 22a92c70425..6cb9937ebb4 100644
--- a/sql/ha_sequence.cc
+++ b/sql/ha_sequence.cc
@@ -101,7 +101,7 @@ int ha_sequence::open(const char *name, int mode, uint flags)
ha_open() sets the following for us. We have to set this for the
underlying handler
*/
- file->cached_table_flags= file->table_flags();
+ file->cached_table_flags= (file->table_flags() | HA_REUSES_FILE_NAMES);
file->reset_statistics();
internal_tmp_table= file->internal_tmp_table=
@@ -413,7 +413,6 @@ static int sequence_initialize(void *p)
handlerton *local_sequence_hton= (handlerton *)p;
DBUG_ENTER("sequence_initialize");
- local_sequence_hton->state= SHOW_OPTION_YES;
local_sequence_hton->db_type= DB_TYPE_SEQUENCE;
local_sequence_hton->create= sequence_create_handler;
local_sequence_hton->panic= sequence_end;
diff --git a/sql/handle_connections_win.cc b/sql/handle_connections_win.cc
index 0046dcdfd8c..44ad8ddc865 100644
--- a/sql/handle_connections_win.cc
+++ b/sql/handle_connections_win.cc
@@ -360,7 +360,7 @@ struct Pipe_Listener : public Listener
{
sql_perror("Create named pipe failed");
sql_print_error("Aborting");
- exit(1);
+ unireg_abort(1);
}
first_instance= false;
return pipe_handle;
@@ -368,17 +368,14 @@ struct Pipe_Listener : public Listener
static void create_pipe_connection(HANDLE pipe)
{
- CONNECT *connect;
- if (!(connect= new CONNECT) || !(connect->vio= vio_new_win32pipe(pipe)))
+ if (auto connect= new CONNECT(pipe))
+ create_new_thread(connect);
+ else
{
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.*/
diff --git a/sql/handler.cc b/sql/handler.cc
index 5f69a70d5e2..d43a9a0aaa0 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2009, 2019, MariaDB Corporation.
+ Copyright (c) 2009, 2020, 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
@@ -30,7 +30,6 @@
#include "key.h" // key_copy, key_unpack, key_cmp_if_same, key_cmp
#include "sql_table.h" // build_table_filename
#include "sql_parse.h" // check_stack_overrun
-#include "sql_acl.h" // SUPER_ACL
#include "sql_base.h" // TDC_element
#include "discover.h" // extension_based_table_discovery, etc
#include "log_event.h" // *_rows_log_event
@@ -40,6 +39,8 @@
#include "myisam.h"
#include "probes_mysql.h"
#include <mysql/psi/mysql_table.h>
+#include <pfs_transaction_provider.h>
+#include <mysql/psi/mysql_transaction.h>
#include "debug_sync.h" // DEBUG_SYNC
#include "sql_audit.h"
#include "ha_sequence.h"
@@ -62,6 +63,39 @@
#include "wsrep_trans_observer.h" /* wsrep transaction hooks */
#endif /* WITH_WSREP */
+/**
+ @def MYSQL_TABLE_LOCK_WAIT
+ Instrumentation helper for table io_waits.
+ @param OP the table operation to be performed
+ @param FLAGS per table operation flags.
+ @param PAYLOAD the code to instrument.
+ @sa MYSQL_END_TABLE_WAIT.
+*/
+#ifdef HAVE_PSI_TABLE_INTERFACE
+ #define MYSQL_TABLE_LOCK_WAIT(OP, FLAGS, PAYLOAD) \
+ { \
+ if (m_psi != NULL) \
+ { \
+ PSI_table_locker *locker; \
+ PSI_table_locker_state state; \
+ locker= PSI_TABLE_CALL(start_table_lock_wait) \
+ (& state, m_psi, OP, FLAGS, \
+ __FILE__, __LINE__); \
+ PAYLOAD \
+ if (locker != NULL) \
+ PSI_TABLE_CALL(end_table_lock_wait)(locker); \
+ } \
+ else \
+ { \
+ PAYLOAD \
+ } \
+ }
+#else
+ #define MYSQL_TABLE_LOCK_WAIT(OP, FLAGS, PAYLOAD) \
+ PAYLOAD
+#endif
+
+
/*
While we have legacy_db_type, we have this array to
check for dups and to find handlerton from legacy_db_type.
@@ -182,8 +216,7 @@ plugin_ref ha_resolve_by_name(THD *thd, const LEX_CSTRING *name,
plugin_ref plugin;
redo:
- /* my_strnncoll is a macro and gcc doesn't do early expansion of macro */
- if (thd && !my_charset_latin1.coll->strnncoll(&my_charset_latin1,
+ if (thd && !my_charset_latin1.strnncoll(
(const uchar *)name->str, name->length,
(const uchar *)STRING_WITH_LEN("DEFAULT"), 0))
return tmp_table ? ha_default_tmp_plugin(thd) : ha_default_plugin(thd);
@@ -205,7 +238,7 @@ redo:
*/
for (table_alias= sys_table_aliases; table_alias->str; table_alias+= 2)
{
- if (!my_strnncoll(&my_charset_latin1,
+ if (!my_charset_latin1.strnncoll(
(const uchar *)name->str, name->length,
(const uchar *)table_alias->str, table_alias->length))
{
@@ -297,7 +330,7 @@ handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc,
DBUG_ENTER("get_new_handler");
DBUG_PRINT("enter", ("alloc: %p", alloc));
- if (db_type && db_type->state == SHOW_OPTION_YES && db_type->create)
+ if (ha_storage_engine_is_enabled(db_type))
{
if ((file= db_type->create(db_type, share, alloc)))
file->init();
@@ -362,7 +395,8 @@ int ha_init_errors(void)
/* Allocate a pointer array for the error message strings. */
/* Zerofill it to avoid uninitialized gaps. */
- if (! (handler_errmsgs= (const char**) my_malloc(HA_ERR_ERRORS * sizeof(char*),
+ if (! (handler_errmsgs= (const char**) my_malloc(key_memory_handler_errmsgs,
+ HA_ERR_ERRORS * sizeof(char*),
MYF(MY_WME | MY_ZEROFILL))))
return 1;
@@ -482,15 +516,8 @@ int ha_finalize_handlerton(st_plugin_int *plugin)
if (!hton)
goto end;
- switch (hton->state) {
- case SHOW_OPTION_NO:
- case SHOW_OPTION_DISABLED:
- break;
- case SHOW_OPTION_YES:
- if (installed_htons[hton->db_type] == hton)
- installed_htons[hton->db_type]= NULL;
- break;
- };
+ if (installed_htons[hton->db_type] == hton)
+ installed_htons[hton->db_type]= NULL;
if (hton->panic)
hton->panic(hton, HA_PANIC_CLOSE);
@@ -539,7 +566,7 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
DBUG_ENTER("ha_initialize_handlerton");
DBUG_PRINT("plugin", ("initialize plugin: '%s'", plugin->name.str));
- hton= (handlerton *)my_malloc(sizeof(handlerton),
+ hton= (handlerton *)my_malloc(key_memory_handlerton, sizeof(handlerton),
MYF(MY_WME | MY_ZEROFILL));
if (hton == NULL)
{
@@ -557,7 +584,7 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
if (plugin->plugin->init && plugin->plugin->init(hton))
{
sql_print_error("Plugin '%s' init function returned error.",
- plugin->name.str);
+ plugin->name.str);
goto err;
}
@@ -576,90 +603,78 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
hton->discover_table_existence= full_discover_for_existence;
}
- switch (hton->state) {
- case SHOW_OPTION_NO:
- break;
- case SHOW_OPTION_YES:
- {
- uint tmp;
- ulong fslot;
-
- DBUG_EXECUTE_IF("unstable_db_type", {
- static int i= (int) DB_TYPE_FIRST_DYNAMIC;
- hton->db_type= (enum legacy_db_type)++i;
- });
-
- /* now check the db_type for conflict */
- if (hton->db_type <= DB_TYPE_UNKNOWN ||
- hton->db_type >= DB_TYPE_DEFAULT ||
- installed_htons[hton->db_type])
- {
- int idx= (int) DB_TYPE_FIRST_DYNAMIC;
+ uint tmp;
+ ulong fslot;
- while (idx < (int) DB_TYPE_DEFAULT && installed_htons[idx])
- idx++;
+ DBUG_EXECUTE_IF("unstable_db_type", {
+ static int i= (int) DB_TYPE_FIRST_DYNAMIC;
+ hton->db_type= (enum legacy_db_type)++i;
+ });
- if (idx == (int) DB_TYPE_DEFAULT)
- {
- sql_print_warning("Too many storage engines!");
- goto err_deinit;
- }
- if (hton->db_type != DB_TYPE_UNKNOWN)
- sql_print_warning("Storage engine '%s' has conflicting typecode. "
- "Assigning value %d.", plugin->plugin->name, idx);
- hton->db_type= (enum legacy_db_type) idx;
- }
+ /* now check the db_type for conflict */
+ if (hton->db_type <= DB_TYPE_UNKNOWN ||
+ hton->db_type >= DB_TYPE_DEFAULT ||
+ installed_htons[hton->db_type])
+ {
+ int idx= (int) DB_TYPE_FIRST_DYNAMIC;
- /*
- In case a plugin is uninstalled and re-installed later, it should
- reuse an array slot. Otherwise the number of uninstall/install
- cycles would be limited. So look for a free slot.
- */
- DBUG_PRINT("plugin", ("total_ha: %lu", total_ha));
- for (fslot= 0; fslot < total_ha; fslot++)
- {
- if (!hton2plugin[fslot])
- break;
- }
- if (fslot < total_ha)
- hton->slot= fslot;
- else
- {
- if (total_ha >= MAX_HA)
- {
- sql_print_error("Too many plugins loaded. Limit is %lu. "
- "Failed on '%s'", (ulong) MAX_HA, plugin->name.str);
- goto err_deinit;
- }
- hton->slot= total_ha++;
- }
- installed_htons[hton->db_type]= hton;
- tmp= hton->savepoint_offset;
- hton->savepoint_offset= savepoint_alloc_size;
- savepoint_alloc_size+= tmp;
- hton2plugin[hton->slot]=plugin;
- if (hton->prepare)
- {
- total_ha_2pc++;
- if (tc_log && tc_log != get_tc_log_implementation())
- {
- total_ha_2pc--;
- hton->prepare= 0;
- push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
- ER_UNKNOWN_ERROR,
- "Cannot enable tc-log at run-time. "
- "XA features of %s are disabled",
- plugin->name.str);
- }
- }
+ while (idx < (int) DB_TYPE_DEFAULT && installed_htons[idx])
+ idx++;
+
+ if (idx == (int) DB_TYPE_DEFAULT)
+ {
+ sql_print_warning("Too many storage engines!");
+ goto err_deinit;
+ }
+ if (hton->db_type != DB_TYPE_UNKNOWN)
+ sql_print_warning("Storage engine '%s' has conflicting typecode. "
+ "Assigning value %d.", plugin->plugin->name, idx);
+ hton->db_type= (enum legacy_db_type) idx;
+ }
+
+ /*
+ In case a plugin is uninstalled and re-installed later, it should
+ reuse an array slot. Otherwise the number of uninstall/install
+ cycles would be limited. So look for a free slot.
+ */
+ DBUG_PRINT("plugin", ("total_ha: %lu", total_ha));
+ for (fslot= 0; fslot < total_ha; fslot++)
+ {
+ if (!hton2plugin[fslot])
break;
+ }
+ if (fslot < total_ha)
+ hton->slot= fslot;
+ else
+ {
+ if (total_ha >= MAX_HA)
+ {
+ sql_print_error("Too many plugins loaded. Limit is %lu. "
+ "Failed on '%s'", (ulong) MAX_HA, plugin->name.str);
+ goto err_deinit;
}
- /* fall through */
- default:
- hton->state= SHOW_OPTION_DISABLED;
- break;
+ hton->slot= total_ha++;
}
-
+ installed_htons[hton->db_type]= hton;
+ tmp= hton->savepoint_offset;
+ hton->savepoint_offset= savepoint_alloc_size;
+ savepoint_alloc_size+= tmp;
+ hton2plugin[hton->slot]=plugin;
+ if (hton->prepare)
+ {
+ total_ha_2pc++;
+ if (tc_log && tc_log != get_tc_log_implementation())
+ {
+ total_ha_2pc--;
+ hton->prepare= 0;
+ push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_UNKNOWN_ERROR,
+ "Cannot enable tc-log at run-time. "
+ "XA features of %s are disabled",
+ plugin->name.str);
+ }
+ }
+
/*
This is entirely for legacy. We will create a new "disk based" hton and a
"memory" hton which will be configurable longterm. We should be able to
@@ -694,10 +709,10 @@ err_deinit:
*/
if (plugin->plugin->deinit)
(void) plugin->plugin->deinit(NULL);
-
+
err:
#ifdef DBUG_ASSERT_EXISTS
- if (hton->prepare && hton->state == SHOW_OPTION_YES)
+ if (hton->prepare)
failed_ha_2pc++;
#endif
my_free(hton);
@@ -742,7 +757,7 @@ static my_bool dropdb_handlerton(THD *unused1, plugin_ref plugin,
void *path)
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->drop_database)
+ if (hton->drop_database)
hton->drop_database(hton, (char *)path);
return FALSE;
}
@@ -758,7 +773,7 @@ static my_bool checkpoint_state_handlerton(THD *unused1, plugin_ref plugin,
void *disable)
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->checkpoint_state)
+ if (hton->checkpoint_state)
hton->checkpoint_state(hton, (int) *(bool*) disable);
return FALSE;
}
@@ -780,7 +795,7 @@ static my_bool commit_checkpoint_request_handlerton(THD *unused1, plugin_ref plu
{
st_commit_checkpoint_request *st= (st_commit_checkpoint_request *)data;
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->commit_checkpoint_request)
+ if (hton->commit_checkpoint_request)
{
void *cookie= st->cookie;
if (st->pre_hook)
@@ -807,34 +822,29 @@ ha_commit_checkpoint_request(void *cookie, void (*pre_hook)(void *))
}
-
-static my_bool closecon_handlerton(THD *thd, plugin_ref plugin,
- void *unused)
-{
- handlerton *hton= plugin_hton(plugin);
- /*
- there's no need to rollback here as all transactions must
- be rolled back already
- */
- if (hton->state == SHOW_OPTION_YES && thd_get_ha_data(thd, hton))
- {
- if (hton->close_connection)
- hton->close_connection(hton, thd);
- /* make sure ha_data is reset and ha_data_lock is released */
- thd_set_ha_data(thd, hton, NULL);
- }
- return FALSE;
-}
-
/**
@note
don't bother to rollback here, it's done already
+
+ there's no need to rollback here as all transactions must
+ be rolled back already
*/
void ha_close_connection(THD* thd)
{
- plugin_foreach_with_mask(thd, closecon_handlerton,
- MYSQL_STORAGE_ENGINE_PLUGIN,
- PLUGIN_IS_DELETED|PLUGIN_IS_READY, 0);
+ for (auto i= 0; i < MAX_HA; i++)
+ {
+ if (thd->ha_data[i].lock)
+ {
+ handlerton *hton= plugin_hton(thd->ha_data[i].lock);
+ if (hton->close_connection)
+ hton->close_connection(hton, thd);
+ /* make sure SE didn't reset ha_data in close_connection() */
+ DBUG_ASSERT(thd->ha_data[i].lock);
+ /* make sure ha_data is reset and ha_data_lock is released */
+ thd_set_ha_data(thd, hton, 0);
+ }
+ DBUG_ASSERT(!thd->ha_data[i].ha_ptr);
+ }
}
static my_bool kill_handlerton(THD *thd, plugin_ref plugin,
@@ -842,8 +852,7 @@ static my_bool kill_handlerton(THD *thd, plugin_ref plugin,
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->kill_query &&
- thd_get_ha_data(thd, hton))
+ if (hton->kill_query && thd_get_ha_data(thd, hton))
hton->kill_query(hton, thd, *(enum thd_kill_levels *) level);
return FALSE;
}
@@ -864,7 +873,7 @@ static my_bool plugin_prepare_for_backup(THD *unused1, plugin_ref plugin,
void *not_used)
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->prepare_for_backup)
+ if (hton->prepare_for_backup)
hton->prepare_for_backup();
return FALSE;
}
@@ -880,7 +889,7 @@ static my_bool plugin_end_backup(THD *unused1, plugin_ref plugin,
void *not_used)
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->end_backup)
+ if (hton->end_backup)
hton->end_backup();
return FALSE;
}
@@ -893,6 +902,33 @@ void ha_end_backup()
}
+/*
+ Inform plugin of the server shutdown.
+ Called after all connections are down.
+
+ Under some circumstances, storage engine might need to
+ so some work, before deinit() can be safely called.
+ (an example is Innodb purge that might call into server
+ to calculate virtual columns, which might potentially also
+ invoke other plugins, such as audit
+*/
+static my_bool plugin_pre_shutdown(THD *, plugin_ref plugin, void *)
+{
+ handlerton *hton= plugin_hton(plugin);
+ if (hton->pre_shutdown)
+ hton->pre_shutdown();
+ return FALSE;
+}
+
+
+void ha_pre_shutdown()
+{
+ plugin_foreach_with_mask(0, plugin_pre_shutdown,
+ MYSQL_STORAGE_ENGINE_PLUGIN,
+ PLUGIN_IS_DELETED | PLUGIN_IS_READY, 0);
+}
+
+
/* ========================================================================
======================= TRANSACTIONS ===================================*/
@@ -1199,7 +1235,7 @@ void ha_end_backup()
times per transaction.
*/
-void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
+void trans_register_ha(THD *thd, bool all, handlerton *ht_arg, ulonglong trxid)
{
THD_TRANS *trans;
Ha_trx_info *ha_info;
@@ -1230,6 +1266,25 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
if (thd->transaction.implicit_xid.is_null())
thd->transaction.implicit_xid.set(thd->query_id);
+/*
+ Register transaction start in performance schema if not done already.
+ By doing this, we handle cases when the transaction is started implicitly in
+ autocommit=0 mode, and cases when we are in normal autocommit=1 mode and the
+ executed statement is a single-statement transaction.
+
+ Explicitly started transactions are handled in trans_begin().
+
+ Do not register transactions in which binary log is the only participating
+ transactional storage engine.
+*/
+ if (thd->m_transaction_psi == NULL && ht_arg->db_type != DB_TYPE_BINLOG)
+ {
+ thd->m_transaction_psi= MYSQL_START_TRANSACTION(&thd->m_transaction_state,
+ thd->get_xid(), trxid, thd->tx_isolation, thd->tx_read_only,
+ !thd->in_multi_stmt_transaction_mode());
+ DEBUG_SYNC(thd, "after_set_transaction_psi_before_set_transaction_gtid");
+ //gtid_set_performance_schema_values(thd);
+ }
DBUG_VOID_RETURN;
}
@@ -1299,11 +1354,42 @@ int ha_prepare(THD *thd)
}
}
+
+ DEBUG_SYNC(thd, "at_unlog_xa_prepare");
+
+ if (tc_log->unlog_xa_prepare(thd, all))
+ {
+ ha_rollback_trans(thd, all);
+ error=1;
+ }
}
DBUG_RETURN(error);
}
+/*
+ Like ha_check_and_coalesce_trx_read_only to return counted number of
+ read-write transaction participants limited to two, but works in the 'all'
+ context.
+ Also returns the last found rw ha_info through the 2nd argument.
+*/
+uint ha_count_rw_all(THD *thd, Ha_trx_info **ptr_ha_info)
+{
+ unsigned rw_ha_count= 0;
+
+ for (auto ha_info= thd->transaction.all.ha_list; ha_info;
+ ha_info= ha_info->next())
+ {
+ if (ha_info->is_trx_read_write())
+ {
+ *ptr_ha_info= ha_info;
+ if (++rw_ha_count > 1)
+ break;
+ }
+ }
+ return rw_ha_count;
+}
+
/**
Check if we can skip the two-phase commit.
@@ -1455,12 +1541,14 @@ int ha_commit_trans(THD *thd, bool all)
Free resources and perform other cleanup even for 'empty' transactions.
*/
if (is_real_trans)
+ {
thd->transaction.cleanup();
+ MYSQL_COMMIT_TRANSACTION(thd->m_transaction_psi);
+ thd->m_transaction_psi= NULL;
+ }
#ifdef WITH_WSREP
if (wsrep_is_active(thd) && is_real_trans && !error)
- {
wsrep_commit_empty(thd, all);
- }
#endif /* WITH_WSREP */
DBUG_RETURN(0);
}
@@ -1489,7 +1577,8 @@ int ha_commit_trans(THD *thd, bool all)
We allow the owner of FTWRL to COMMIT; we assume that it knows
what it does.
*/
- mdl_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT, MDL_EXPLICIT);
+ MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
+ MDL_EXPLICIT);
if (!WSREP(thd) &&
thd->mdl_context.acquire_lock(&mdl_request,
@@ -1504,7 +1593,7 @@ int ha_commit_trans(THD *thd, bool all)
if (rw_trans &&
opt_readonly &&
- !(thd->security_ctx->master_access & SUPER_ACL) &&
+ !(thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY) &&
!thd->slave_thread)
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
@@ -1563,18 +1652,15 @@ int ha_commit_trans(THD *thd, bool all)
#endif /* WITH_WSREP */
error= ha_commit_one_phase(thd, all);
#ifdef WITH_WSREP
- if (run_wsrep_hooks)
- error= error || wsrep_after_commit(thd, all);
+ // Here in case of error we must return 2 for inconsistency
+ if (run_wsrep_hooks && !error)
+ error= wsrep_after_commit(thd, all) ? 2 : 0;
#endif /* WITH_WSREP */
goto done;
}
need_prepare_ordered= FALSE;
need_commit_ordered= FALSE;
- DBUG_ASSERT(thd->transaction.implicit_xid.get_my_xid() ==
- thd->transaction.implicit_xid.quick_get_my_xid());
- xid= thd->transaction.xid_state.is_explicit_XA() ? 0 :
- thd->transaction.implicit_xid.quick_get_my_xid();
for (Ha_trx_info *hi= ha_info; hi; hi= hi->next())
{
@@ -1599,6 +1685,18 @@ int ha_commit_trans(THD *thd, bool all)
DEBUG_SYNC(thd, "ha_commit_trans_after_prepare");
DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_SUICIDE(););
+ if (!is_real_trans)
+ {
+ error= commit_one_phase_2(thd, all, trans, is_real_trans);
+ goto done;
+ }
+
+ DBUG_ASSERT(thd->transaction.implicit_xid.get_my_xid() ==
+ thd->transaction.implicit_xid.quick_get_my_xid());
+ DBUG_ASSERT(!thd->transaction.xid_state.is_explicit_XA() ||
+ thd->lex->xa_opt == XA_ONE_PHASE);
+ xid= thd->transaction.implicit_xid.quick_get_my_xid();
+
#ifdef WITH_WSREP
if (run_wsrep_hooks && !error)
{
@@ -1609,14 +1707,6 @@ int ha_commit_trans(THD *thd, bool all)
xid= s.get();
}
}
-#endif /* WITH_WSREP */
-
- if (!is_real_trans)
- {
- error= commit_one_phase_2(thd, all, trans, is_real_trans);
- goto done;
- }
-#ifdef WITH_WSREP
if (run_wsrep_hooks && (error = wsrep_before_commit(thd, all)))
goto wsrep_err;
#endif /* WITH_WSREP */
@@ -1633,8 +1723,10 @@ int ha_commit_trans(THD *thd, bool all)
error= commit_one_phase_2(thd, all, trans, is_real_trans) ? 2 : 0;
#ifdef WITH_WSREP
- if (run_wsrep_hooks && (error || (error = wsrep_after_commit(thd, all))))
+ if (run_wsrep_hooks &&
+ (error || (error = wsrep_after_commit(thd, all))))
{
+ error = 2;
mysql_mutex_lock(&thd->LOCK_thd_data);
if (wsrep_must_abort(thd))
{
@@ -1647,12 +1739,15 @@ int ha_commit_trans(THD *thd, bool all)
#endif /* WITH_WSREP */
DBUG_EXECUTE_IF("crash_commit_before_unlog", DBUG_SUICIDE(););
if (tc_log->unlog(cookie, xid))
- {
error= 2; /* Error during commit */
- goto end;
- }
done:
+ if (is_real_trans)
+ {
+ MYSQL_COMMIT_TRANSACTION(thd->m_transaction_psi);
+ thd->m_transaction_psi= NULL;
+ }
+
DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
mysql_mutex_assert_not_owner(&LOCK_prepare_ordered);
@@ -1690,6 +1785,8 @@ err:
ha_rollback_trans(thd, all);
else
{
+ MYSQL_ROLLBACK_TRANSACTION(thd->m_transaction_psi);
+ thd->m_transaction_psi= NULL;
WSREP_DEBUG("rollback skipped %p %d",thd->rgi_slave,
thd->rgi_slave->is_parallel_exec);
}
@@ -1849,7 +1946,8 @@ int ha_rollback_trans(THD *thd, bool all)
rollback without signalling following transactions. And in release
builds, we explicitly do the signalling before rolling back.
*/
- DBUG_ASSERT(!(thd->rgi_slave && thd->rgi_slave->did_mark_start_commit));
+ DBUG_ASSERT(!(thd->rgi_slave && thd->rgi_slave->did_mark_start_commit) ||
+ thd->transaction.xid_state.is_explicit_XA());
if (thd->rgi_slave && thd->rgi_slave->did_mark_start_commit)
thd->rgi_slave->unmark_start_commit();
}
@@ -1909,6 +2007,13 @@ int ha_rollback_trans(THD *thd, bool all)
}
(void) wsrep_after_rollback(thd, all);
#endif /* WITH_WSREP */
+
+ if (all || !thd->in_active_multi_stmt_transaction())
+ {
+ MYSQL_ROLLBACK_TRANSACTION(thd->m_transaction_psi);
+ thd->m_transaction_psi= NULL;
+ }
+
/* Always cleanup. Even if nht==0. There may be savepoints. */
if (is_real_trans)
{
@@ -1959,7 +2064,7 @@ static my_bool xacommit_handlerton(THD *unused1, plugin_ref plugin,
void *arg)
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->recover)
+ if (hton->recover)
{
hton->commit_by_xid(hton, ((struct xahton_st *)arg)->xid);
((struct xahton_st *)arg)->result= 0;
@@ -1971,7 +2076,7 @@ static my_bool xarollback_handlerton(THD *unused1, plugin_ref plugin,
void *arg)
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->recover)
+ if (hton->recover)
{
hton->rollback_by_xid(hton, ((struct xahton_st *)arg)->xid);
((struct xahton_st *)arg)->result= 0;
@@ -2053,7 +2158,7 @@ static my_xid wsrep_order_and_check_continuity(XID *list, int len)
{
#ifdef WITH_WSREP
wsrep_sort_xid_array(list, len);
- wsrep::gtid cur_position= wsrep_get_SE_checkpoint();
+ wsrep::gtid cur_position= wsrep_get_SE_checkpoint<wsrep::gtid>();
long long cur_seqno= cur_position.seqno().get();
for (int i= 0; i < len; ++i)
{
@@ -2104,7 +2209,7 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
struct xarecover_st *info= (struct xarecover_st *) arg;
int got;
- if (hton->state == SHOW_OPTION_YES && hton->recover)
+ if (hton->recover)
{
while ((got= hton->recover(hton, info->list, info->len)) > 0 )
{
@@ -2214,7 +2319,7 @@ int ha_recover(HASH *commit_list)
info.list==0 && info.len > MIN_XID_LIST_SIZE; info.len/=2)
{
DBUG_EXECUTE_IF("min_xa_len", info.len = 16;);
- info.list=(XID *)my_malloc(info.len*sizeof(XID), MYF(0));
+ info.list=(XID *)my_malloc(key_memory_XID, info.len*sizeof(XID), MYF(0));
}
if (!info.list)
{
@@ -2356,6 +2461,10 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv)
ha_info->reset(); /* keep it conveniently zero-filled */
}
trans->ha_list= sv->ha_list;
+
+ if (thd->m_transaction_psi != NULL)
+ MYSQL_INC_TRANSACTION_ROLLBACK_TO_SAVEPOINT(thd->m_transaction_psi, 1);
+
DBUG_RETURN(error);
}
@@ -2407,6 +2516,9 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv)
*/
sv->ha_list= trans->ha_list;
+ if (!error && thd->m_transaction_psi != NULL)
+ MYSQL_INC_TRANSACTION_SAVEPOINTS(thd->m_transaction_psi, 1);
+
DBUG_RETURN(error);
}
@@ -2431,6 +2543,10 @@ int ha_release_savepoint(THD *thd, SAVEPOINT *sv)
error=1;
}
}
+
+ if (thd->m_transaction_psi != NULL)
+ MYSQL_INC_TRANSACTION_RELEASE_SAVEPOINT(thd->m_transaction_psi, 1);
+
DBUG_RETURN(error);
}
@@ -2439,8 +2555,7 @@ static my_bool snapshot_handlerton(THD *thd, plugin_ref plugin,
void *arg)
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES &&
- hton->start_consistent_snapshot)
+ if (hton->start_consistent_snapshot)
{
if (hton->start_consistent_snapshot(hton, thd))
return TRUE;
@@ -2486,28 +2601,14 @@ static my_bool flush_handlerton(THD *thd, plugin_ref plugin,
void *arg)
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->flush_logs &&
- hton->flush_logs(hton))
- return TRUE;
- return FALSE;
+ return hton->flush_logs && hton->flush_logs(hton);
}
-bool ha_flush_logs(handlerton *db_type)
+bool ha_flush_logs()
{
- if (db_type == NULL)
- {
- if (plugin_foreach(NULL, flush_handlerton,
- MYSQL_STORAGE_ENGINE_PLUGIN, 0))
- return TRUE;
- }
- else
- {
- if (db_type->state != SHOW_OPTION_YES ||
- (db_type->flush_logs && db_type->flush_logs(db_type)))
- return TRUE;
- }
- return FALSE;
+ return plugin_foreach(NULL, flush_handlerton,
+ MYSQL_STORAGE_ENGINE_PLUGIN, 0);
}
@@ -2591,9 +2692,10 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
it's not an error if the table doesn't exist in the engine.
warn the user, but still report DROP being a success
*/
- bool intercept= error == ENOENT || error == HA_ERR_NO_SUCH_TABLE;
+ bool intercept= (error == ENOENT || error == HA_ERR_NO_SUCH_TABLE ||
+ error == HA_ERR_UNSUPPORTED);
- if (!intercept || generate_warning)
+ if ((!intercept || generate_warning) && ! thd->is_error())
{
/* Fill up strucutures that print_error may need */
dummy_share.path.str= (char*) path;
@@ -2606,7 +2708,10 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
file->print_error(error, MYF(intercept ? ME_WARNING : 0));
}
if (intercept)
+ {
+ thd->clear_error();
error= 0;
+ }
}
delete file;
@@ -2685,10 +2790,6 @@ double handler::keyread_time(uint index, uint ranges, ha_rows rows)
return cost;
}
-void **handler::ha_data(THD *thd) const
-{
- return thd_ha_data(thd, ht);
-}
THD *handler::ha_thd(void) const
{
@@ -2715,6 +2816,30 @@ void handler::rebind_psi()
}
+void handler::start_psi_batch_mode()
+{
+#ifdef HAVE_PSI_TABLE_INTERFACE
+ DBUG_ASSERT(m_psi_batch_mode == PSI_BATCH_MODE_NONE);
+ DBUG_ASSERT(m_psi_locker == NULL);
+ m_psi_batch_mode= PSI_BATCH_MODE_STARTING;
+ m_psi_numrows= 0;
+#endif
+}
+
+void handler::end_psi_batch_mode()
+{
+#ifdef HAVE_PSI_TABLE_INTERFACE
+ DBUG_ASSERT(m_psi_batch_mode != PSI_BATCH_MODE_NONE);
+ if (m_psi_locker != NULL)
+ {
+ DBUG_ASSERT(m_psi_batch_mode == PSI_BATCH_MODE_STARTED);
+ PSI_TABLE_CALL(end_table_io_wait)(m_psi_locker, m_psi_numrows);
+ m_psi_locker= NULL;
+ }
+ m_psi_batch_mode= PSI_BATCH_MODE_NONE;
+#endif
+}
+
PSI_table_share *handler::ha_table_share_psi() const
{
return table_share->m_psi;
@@ -2804,8 +2929,10 @@ int handler::ha_close(void)
*/
if (table->in_use)
status_var_add(table->in_use->status_var.rows_tmp_read, rows_tmp_read);
- PSI_CALL_close_table(m_psi);
+ PSI_CALL_close_table(table_share, m_psi);
m_psi= NULL; /* instrumentation handle, invalid after close_table() */
+ DBUG_ASSERT(m_psi_batch_mode == PSI_BATCH_MODE_NONE);
+ DBUG_ASSERT(m_psi_locker == NULL);
/* Detach from ANALYZE tracker */
tracker= NULL;
@@ -2826,7 +2953,7 @@ int handler::ha_rnd_next(uchar *buf)
do
{
- TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, MAX_KEY, 0,
+ TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, MAX_KEY, result,
{ result= rnd_next(buf); })
if (result != HA_ERR_RECORD_DELETED)
break;
@@ -2858,7 +2985,7 @@ int handler::ha_rnd_pos(uchar *buf, uchar *pos)
m_lock_type != F_UNLCK);
DBUG_ASSERT(inited == RND);
- TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, MAX_KEY, 0,
+ TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, MAX_KEY, result,
{ result= rnd_pos(buf, pos); })
increment_statistics(&SSV::ha_read_rnd_count);
if (result == HA_ERR_RECORD_DELETED)
@@ -2883,7 +3010,7 @@ int handler::ha_index_read_map(uchar *buf, const uchar *key,
m_lock_type != F_UNLCK);
DBUG_ASSERT(inited==INDEX);
- TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
+ TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, active_index, result,
{ result= index_read_map(buf, key, keypart_map, find_flag); })
increment_statistics(&SSV::ha_read_key_count);
if (!result)
@@ -2911,7 +3038,7 @@ int handler::ha_index_read_idx_map(uchar *buf, uint index, const uchar *key,
DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE ||
m_lock_type != F_UNLCK);
DBUG_ASSERT(end_range == NULL);
- TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, index, 0,
+ TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, index, result,
{ result= index_read_idx_map(buf, index, key, keypart_map, find_flag); })
increment_statistics(&SSV::ha_read_key_count);
if (!result)
@@ -2933,7 +3060,7 @@ int handler::ha_index_next(uchar * buf)
m_lock_type != F_UNLCK);
DBUG_ASSERT(inited==INDEX);
- TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
+ TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, active_index, result,
{ result= index_next(buf); })
increment_statistics(&SSV::ha_read_next_count);
if (!result)
@@ -2954,7 +3081,7 @@ int handler::ha_index_prev(uchar * buf)
m_lock_type != F_UNLCK);
DBUG_ASSERT(inited==INDEX);
- TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
+ TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, active_index, result,
{ result= index_prev(buf); })
increment_statistics(&SSV::ha_read_prev_count);
if (!result)
@@ -2974,7 +3101,7 @@ int handler::ha_index_first(uchar * buf)
m_lock_type != F_UNLCK);
DBUG_ASSERT(inited==INDEX);
- TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
+ TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, active_index, result,
{ result= index_first(buf); })
increment_statistics(&SSV::ha_read_first_count);
if (!result)
@@ -2994,7 +3121,7 @@ int handler::ha_index_last(uchar * buf)
m_lock_type != F_UNLCK);
DBUG_ASSERT(inited==INDEX);
- TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
+ TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, active_index, result,
{ result= index_last(buf); })
increment_statistics(&SSV::ha_read_last_count);
if (!result)
@@ -3014,7 +3141,7 @@ int handler::ha_index_next_same(uchar *buf, const uchar *key, uint keylen)
m_lock_type != F_UNLCK);
DBUG_ASSERT(inited==INDEX);
- TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
+ TABLE_IO_WAIT(tracker, PSI_TABLE_FETCH_ROW, active_index, result,
{ result= index_next_same(buf, key, keylen); })
increment_statistics(&SSV::ha_read_next_count);
if (!result)
@@ -4060,7 +4187,7 @@ int handler::check_collation_compatibility()
cs_number == 23 || /* cp1251_ukrainian_ci - bug #29461 */
cs_number == 26)) || /* cp1250_general_ci - bug #29461 */
(mysql_version < 50124 &&
- (cs_number == 33 || /* utf8_general_ci - bug #27877 */
+ (cs_number == 33 || /* utf8mb3_general_ci - bug #27877 */
cs_number == 35))) /* ucs2_general_ci - bug #27877 */
return HA_ADMIN_NEEDS_UPGRADE;
}
@@ -4598,7 +4725,8 @@ handler::check_if_supported_inplace_alter(TABLE *altered_table,
ALTER_DROP_CHECK_CONSTRAINT |
ALTER_PARTITIONED |
ALTER_VIRTUAL_GCOL_EXPR |
- ALTER_RENAME;
+ ALTER_RENAME |
+ ALTER_RENAME_INDEX;
/* Is there at least one operation that requires copy algorithm? */
if (ha_alter_info->handler_flags & ~inplace_offline_operations)
@@ -4955,7 +5083,7 @@ void handler::update_global_table_stats()
table->s->table_cache_key.length)))
{
if (!(table_stats = ((TABLE_STATS*)
- my_malloc(sizeof(TABLE_STATS),
+ my_malloc(PSI_INSTRUMENT_ME, sizeof(TABLE_STATS),
MYF(MY_WME | MY_ZEROFILL)))))
{
/* Out of memory error already given */
@@ -5020,7 +5148,7 @@ void handler::update_global_index_stats()
key_length)))
{
if (!(index_stats = ((INDEX_STATS*)
- my_malloc(sizeof(INDEX_STATS),
+ my_malloc(PSI_INSTRUMENT_ME, sizeof(INDEX_STATS),
MYF(MY_WME | MY_ZEROFILL)))))
goto end; // Error is already given
@@ -5343,7 +5471,7 @@ static my_bool discover_handlerton(THD *thd, plugin_ref plugin,
{
TABLE_SHARE *share= (TABLE_SHARE *)arg;
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->discover_table)
+ if (hton->discover_table)
{
share->db_plugin= plugin;
int error= hton->discover_table(hton, thd, share);
@@ -5419,7 +5547,7 @@ static my_bool discover_existence(THD *thd, plugin_ref plugin,
{
st_discover_existence_args *args= (st_discover_existence_args*)arg;
handlerton *ht= plugin_hton(plugin);
- if (ht->state != SHOW_OPTION_YES || !ht->discover_table_existence)
+ if (!ht->discover_table_existence)
return args->frm_exists;
args->hton= ht;
@@ -5599,13 +5727,13 @@ static int cmp_file_names(const void *a, const void *b)
CHARSET_INFO *cs= character_set_filesystem;
char *aa= ((FILEINFO *)a)->name;
char *bb= ((FILEINFO *)b)->name;
- return my_strnncoll(cs, (uchar*)aa, strlen(aa), (uchar*)bb, strlen(bb));
+ return cs->strnncoll(aa, strlen(aa), bb, strlen(bb));
}
static int cmp_table_names(LEX_CSTRING * const *a, LEX_CSTRING * const *b)
{
- return my_strnncoll(&my_charset_bin, (uchar*)((*a)->str), (*a)->length,
- (uchar*)((*b)->str), (*b)->length);
+ return my_charset_bin.strnncoll((*a)->str, (*a)->length,
+ (*b)->str, (*b)->length);
}
#ifndef DBUG_OFF
@@ -5639,8 +5767,8 @@ bool Discovered_table_list::add_table(const char *tname, size_t tlen)
custom discover_table_names() method, that calls add_table() directly).
Note: avoid comparing the same name twice (here and in add_file).
*/
- if (wild && my_wildcmp(table_alias_charset, tname, tname + tlen, wild, wend,
- wild_prefix, wild_one, wild_many))
+ if (wild && table_alias_charset->wildcmp(tname, tname + tlen, wild, wend,
+ wild_prefix, wild_one, wild_many))
return 0;
LEX_CSTRING *name= thd->make_clex_string(tname, tlen);
@@ -5709,7 +5837,7 @@ static my_bool discover_names(THD *thd, plugin_ref plugin,
st_discover_names_args *args= (st_discover_names_args *)arg;
handlerton *ht= plugin_hton(plugin);
- if (ht->state == SHOW_OPTION_YES && ht->discover_table_names)
+ if (ht->discover_table_names)
{
size_t old_elements= args->result->tables->elements();
if (ht->discover_table_names(ht, args->db, args->dirp, args->result))
@@ -5754,6 +5882,8 @@ int ha_discover_table_names(THD *thd, LEX_CSTRING *db, MY_DIR *dirp,
error= ext_table_discovery_simple(dirp, result) ||
plugin_foreach(thd, discover_names,
MYSQL_STORAGE_ENGINE_PLUGIN, &args);
+ if (args.possible_duplicates > 0)
+ result->remove_duplicates();
}
else
{
@@ -6108,7 +6238,7 @@ static my_bool showstat_handlerton(THD *thd, plugin_ref plugin,
{
enum ha_stat_type stat= *(enum ha_stat_type *) arg;
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->show_status &&
+ if (hton->show_status &&
hton->show_status(hton, thd, stat_print, stat))
return TRUE;
return FALSE;
@@ -6140,17 +6270,8 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
}
else
{
- if (db_type->state != SHOW_OPTION_YES)
- {
- const LEX_CSTRING *name= hton_name(db_type);
- result= stat_print(thd, name->str, name->length,
- "", 0, "DISABLED", 8) ? 1 : 0;
- }
- else
- {
- result= db_type->show_status &&
- db_type->show_status(db_type, thd, stat_print, stat) ? 1 : 0;
- }
+ result= db_type->show_status &&
+ db_type->show_status(db_type, thd, stat_print, stat) ? 1 : 0;
}
/*
@@ -6409,7 +6530,7 @@ int handler::ha_external_lock(THD *thd, int lock_type)
We cache the table flags if the locking succeeded. Otherwise, we
keep them as they were when they were fetched in ha_open().
*/
- MYSQL_TABLE_LOCK_WAIT(m_psi, PSI_TABLE_EXTERNAL_LOCK, lock_type,
+ MYSQL_TABLE_LOCK_WAIT(PSI_TABLE_EXTERNAL_LOCK, lock_type,
{ error= external_lock(thd, lock_type); })
DBUG_EXECUTE_IF("external_lock_failure", error= HA_ERR_GENERIC;);
@@ -6666,15 +6787,15 @@ int handler::ha_write_row(const uchar *buf)
mark_trx_read_write();
increment_statistics(&SSV::ha_write_count);
- if (table->s->long_unique_table)
+ if (table->s->long_unique_table && this == table->file)
{
- if (this->inited == RND)
+ if (inited == RND)
table->clone_handler_for_update();
handler *h= table->update_handler ? table->update_handler : table->file;
if ((error= check_duplicate_long_entries(table, h, buf)))
DBUG_RETURN(error);
}
- TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0,
+ TABLE_IO_WAIT(tracker, PSI_TABLE_WRITE_ROW, MAX_KEY, error,
{ error= write_row(buf); })
MYSQL_INSERT_ROW_DONE(error);
@@ -6719,7 +6840,7 @@ int handler::ha_update_row(const uchar *old_data, const uchar *new_data)
return error;
}
- TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_UPDATE_ROW, active_index, 0,
+ TABLE_IO_WAIT(tracker, PSI_TABLE_UPDATE_ROW, active_index, error,
{ error= update_row(old_data, new_data);})
MYSQL_UPDATE_ROW_DONE(error);
@@ -6782,7 +6903,7 @@ int handler::ha_delete_row(const uchar *buf)
mark_trx_read_write();
increment_statistics(&SSV::ha_delete_count);
- TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_DELETE_ROW, active_index, 0,
+ TABLE_IO_WAIT(tracker, PSI_TABLE_DELETE_ROW, active_index, error,
{ error= delete_row(buf);})
MYSQL_DELETE_ROW_DONE(error);
if (likely(!error))
@@ -7256,7 +7377,7 @@ int del_global_table_stat(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *ta
cache_key_length= db->length + 1 + table->length + 1;
- if(!(cache_key= (uchar *)my_malloc(cache_key_length,
+ if(!(cache_key= (uchar *)my_malloc(PSI_INSTRUMENT_ME, cache_key_length,
MYF(MY_WME | MY_ZEROFILL))))
{
/* Out of memory error already given */
@@ -7480,11 +7601,7 @@ bool Table_scope_and_contents_source_st::vers_check_system_fields(
if (!(alter_info->flags & ALTER_ADD_SYSTEM_VERSIONING))
return false;
- bool can_native= ha_check_storage_engine_flag(db_type,
- HTON_NATIVE_SYS_VERSIONING)
- || db_type->db_type == DB_TYPE_PARTITION_DB;
-
- return vers_info.check_sys_fields(table_name, db, alter_info, can_native);
+ return vers_info.check_sys_fields(table_name, db, alter_info);
}
@@ -7590,7 +7707,16 @@ bool Vers_parse_info::fix_alter_info(THD *thd, Alter_info *alter_info,
return false;
}
- return fix_implicit(thd, alter_info);
+ if (fix_implicit(thd, alter_info))
+ return true;
+
+ if (alter_info->flags & ALTER_ADD_SYSTEM_VERSIONING)
+ {
+ if (check_sys_fields(table_name, share->db, alter_info))
+ return true;
+ }
+
+ return false;
}
bool
@@ -7691,83 +7817,121 @@ bool Vers_parse_info::check_conditions(const Lex_table_name &table_name,
return false;
}
-static bool is_versioning_timestamp(const Create_field *f)
+static bool is_versioning_timestamp(const Column_definition *f)
{
return f->type_handler() == &type_handler_timestamp2 &&
f->length == MAX_DATETIME_FULL_WIDTH;
}
-static bool is_some_bigint(const Create_field *f)
+static bool is_some_bigint(const Column_definition *f)
{
- return f->type_handler() == &type_handler_longlong ||
+ return f->type_handler() == &type_handler_slonglong ||
+ f->type_handler() == &type_handler_ulonglong ||
f->type_handler() == &type_handler_vers_trx_id;
}
-static bool is_versioning_bigint(const Create_field *f)
+static bool is_versioning_bigint(const Column_definition *f)
{
return is_some_bigint(f) && f->flags & UNSIGNED_FLAG &&
f->length == MY_INT64_NUM_DECIMAL_DIGITS - 1;
}
-static bool require_timestamp(const Create_field *f, Lex_table_name table_name)
+static void require_timestamp_error(const char *field, const char *table)
+{
+ my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), field, "TIMESTAMP(6)", table);
+}
+
+static void require_trx_id_error(const char *field, const char *table)
+{
+ my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), field, "BIGINT(20) UNSIGNED",
+ table);
+}
+
+
+bool Vers_type_timestamp::check_sys_fields(const LEX_CSTRING &table_name,
+ const Column_definition *row_start,
+ const Column_definition *row_end) const
{
- my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), f->field_name.str, "TIMESTAMP(6)",
- table_name.str);
- return true;
+ if (!is_versioning_timestamp(row_start))
+ {
+ require_timestamp_error(row_start->field_name.str, table_name.str);
+ return true;
+ }
+
+ if (row_end->type_handler()->vers() != this ||
+ !is_versioning_timestamp(row_end))
+ {
+ require_timestamp_error(row_end->field_name.str, table_name.str);
+ return true;
+ }
+
+ return false;
}
-static bool require_bigint(const Create_field *f, Lex_table_name table_name)
+
+
+bool Vers_type_trx::check_sys_fields(const LEX_CSTRING &table_name,
+ const Column_definition *row_start,
+ const Column_definition *row_end) const
{
- my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), f->field_name.str,
- "BIGINT(20) UNSIGNED", table_name.str);
- return true;
+ if (!is_versioning_bigint(row_start))
+ {
+ require_trx_id_error(row_start->field_name.str, table_name.str);
+ return true;
+ }
+
+ if (row_end->type_handler()->vers() != this ||
+ !is_versioning_bigint(row_end))
+ {
+ require_trx_id_error(row_end->field_name.str, table_name.str);
+ return true;
+ }
+
+ if (!is_some_bigint(row_start))
+ {
+ require_timestamp_error(row_start->field_name.str, table_name.str);
+ return true;
+ }
+
+ if (!TR_table::use_transaction_registry)
+ {
+ my_error(ER_VERS_TRT_IS_DISABLED, MYF(0));
+ return true;
+ }
+
+ return false;
}
bool Vers_parse_info::check_sys_fields(const Lex_table_name &table_name,
const Lex_table_name &db,
- Alter_info *alter_info,
- bool can_native) const
+ Alter_info *alter_info) const
{
if (check_conditions(table_name, db))
return true;
+ List_iterator<Create_field> it(alter_info->create_list);
const Create_field *row_start= NULL;
const Create_field *row_end= NULL;
-
- List_iterator<Create_field> it(alter_info->create_list);
- while (Create_field *f= it++)
+ while (const Create_field *f= it++)
{
- if (!row_start && f->flags & VERS_SYS_START_FLAG)
+ if (f->flags & VERS_SYS_START_FLAG && !row_start)
row_start= f;
- else if (!row_end && f->flags & VERS_SYS_END_FLAG)
+ if (f->flags & VERS_SYS_END_FLAG && !row_end)
row_end= f;
}
- const bool expect_timestamp=
- !can_native || !is_some_bigint(row_start) || !is_some_bigint(row_end);
+ DBUG_ASSERT(row_start);
+ DBUG_ASSERT(row_end);
- if (expect_timestamp)
- {
- if (!is_versioning_timestamp(row_start))
- return require_timestamp(row_start, table_name);
+ const Vers_type_handler *row_start_vers= row_start->type_handler()->vers();
- if (!is_versioning_timestamp(row_end))
- return require_timestamp(row_end, table_name);
- }
- else
+ if (!row_start_vers)
{
- if (!is_versioning_bigint(row_start))
- return require_bigint(row_start, table_name);
-
- if (!is_versioning_bigint(row_end))
- return require_bigint(row_end, table_name);
+ require_timestamp_error(row_start->field_name.str, table_name);
+ return true;
}
- if (is_versioning_bigint(row_start) && is_versioning_bigint(row_end) &&
- !TR_table::use_transaction_registry)
- {
- my_error(ER_VERS_TRT_IS_DISABLED, MYF(0));
+ if (row_start_vers->check_sys_fields(table_name, row_start, row_end))
return true;
- }
return false;
}
diff --git a/sql/handler.h b/sql/handler.h
index e9b52b16aa8..8674ccfd70e 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -2,7 +2,7 @@
#define HANDLER_INCLUDED
/*
Copyright (c) 2000, 2019, Oracle and/or its affiliates.
- Copyright (c) 2009, 2019, MariaDB
+ Copyright (c) 2009, 2020, MariaDB
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -52,7 +52,6 @@ class Rowid_filter;
class Field_string;
class Field_varstring;
class Field_blob;
-class Field_geom;
class Column_definition;
// the following is for checking tables
@@ -213,7 +212,8 @@ enum enum_alter_inplace_result {
#define HA_HAS_NEW_CHECKSUM (1ULL << 38)
#define HA_CAN_VIRTUAL_COLUMNS (1ULL << 39)
#define HA_MRR_CANT_SORT (1ULL << 40)
-#define HA_RECORD_MUST_BE_CLEAN_ON_WRITE (1ULL << 41) /* unused */
+/* All of VARCHAR is stored, including bytes after real varchar data */
+#define HA_RECORD_MUST_BE_CLEAN_ON_WRITE (1ULL << 41)
/*
This storage engine supports condition pushdown
@@ -297,6 +297,9 @@ enum enum_alter_inplace_result {
#define HA_PERSISTENT_TABLE (1ULL << 48)
+/* If storage engine uses another engine as a base */
+#define HA_REUSES_FILE_NAMES (1ULL << 49)
+
/*
Set of all binlog flags. Currently only contain the capabilities
flags.
@@ -511,6 +514,7 @@ enum legacy_db_type
DB_TYPE_BINLOG=21,
DB_TYPE_PBXT=23,
DB_TYPE_PERFORMANCE_SCHEMA=28,
+ DB_TYPE_S3=41,
DB_TYPE_ARIA=42,
DB_TYPE_TOKUDB=43,
DB_TYPE_SEQUENCE=44,
@@ -1029,11 +1033,7 @@ enum enum_schema_tables
SCH_TABLE_PRIVILEGES,
SCH_TRIGGERS,
SCH_USER_PRIVILEGES,
- SCH_VIEWS,
-#ifdef HAVE_SPATIAL
- SCH_GEOMETRY_COLUMNS,
- SCH_SPATIAL_REF_SYS,
-#endif /*HAVE_SPATIAL*/
+ SCH_VIEWS
};
struct TABLE_SHARE;
@@ -1247,11 +1247,6 @@ typedef struct st_order ORDER;
struct handlerton
{
/*
- Historical marker for if the engine is available of not
- */
- SHOW_COMP_OPTION state;
-
- /*
Historical number used for frm file to determine the correct
storage engine. This is going away and new engines will just use
"name" for this.
@@ -1650,6 +1645,14 @@ struct handlerton
int (*discover_table_structure)(handlerton *hton, THD* thd,
TABLE_SHARE *share, HA_CREATE_INFO *info);
+ /*
+ Notify the storage engine that the definition of the table (and the .frm
+ file) has changed. Returns 0 if ok.
+ */
+ int (*notify_tabledef_changed)(handlerton *hton, LEX_CSTRING *db,
+ LEX_CSTRING *table_name, LEX_CUSTRING *frm,
+ LEX_CUSTRING *org_tabledef_version);
+
/*
System Versioning
*/
@@ -1663,6 +1666,9 @@ struct handlerton
/* backup */
void (*prepare_for_backup)(void);
void (*end_backup)(void);
+
+ /* Server shutdown early notification.*/
+ void (*pre_shutdown)(void);
};
@@ -1954,11 +1960,13 @@ enum enum_stats_auto_recalc { HA_STATS_AUTO_RECALC_DEFAULT= 0,
It stores the "schema_specification" part of the CREATE/ALTER statements and
is passed to mysql_create_db() and mysql_alter_db().
- Currently consists only of the schema default character set and collation.
+ Currently consists of the schema default character set, collation
+ and schema_comment.
*/
struct Schema_specification_st
{
CHARSET_INFO *default_table_charset;
+ LEX_CSTRING *schema_comment;
void init()
{
bzero(this, sizeof(*this));
@@ -1967,13 +1975,6 @@ struct Schema_specification_st
class Create_field;
-enum vers_sys_type_t
-{
- VERS_UNDEFINED= 0,
- VERS_TIMESTAMP,
- VERS_TRX_ID
-};
-
struct Table_period_info: Sql_alloc
{
Table_period_info() :
@@ -2056,8 +2057,7 @@ public:
bool fix_create_like(Alter_info &alter_info, HA_CREATE_INFO &create_info,
TABLE_LIST &src_table, TABLE_LIST &table);
bool check_sys_fields(const Lex_table_name &table_name,
- const Lex_table_name &db, Alter_info *alter_info,
- bool can_native) const;
+ const Lex_table_name &db, Alter_info *alter_info) const;
/**
At least one field was specified 'WITH/WITHOUT SYSTEM VERSIONING'.
@@ -2200,10 +2200,14 @@ struct Table_scope_and_contents_source_st:
struct HA_CREATE_INFO: public Table_scope_and_contents_source_st,
public Schema_specification_st
{
+ /* TODO: remove after MDEV-20865 */
+ Alter_info *alter_info;
+
void init()
{
Table_scope_and_contents_source_st::init();
Schema_specification_st::init();
+ alter_info= NULL;
}
bool check_conflicting_charset_declarations(CHARSET_INFO *cs);
bool add_table_option_default_charset(CHARSET_INFO *cs)
@@ -2660,18 +2664,18 @@ public:
double idx_cpu_cost; /* cost of operations in CPU for index */
double import_cost; /* cost of remote operations */
double mem_cost; /* cost of used memory */
-
- enum { IO_COEFF=1 };
- enum { CPU_COEFF=1 };
- enum { MEM_COEFF=1 };
- enum { IMPORT_COEFF=1 };
+
+ static constexpr double IO_COEFF= 1;
+ static constexpr double CPU_COEFF= 1;
+ static constexpr double MEM_COEFF= 1;
+ static constexpr double IMPORT_COEFF= 1;
Cost_estimate()
{
reset();
}
- double total_cost()
+ double total_cost() const
{
return IO_COEFF*io_count*avg_io_cost +
IO_COEFF*idx_io_count*idx_avg_io_cost +
@@ -2692,7 +2696,7 @@ public:
*/
bool is_zero() const
{
- return io_count == 0.0 && idx_io_count && cpu_cost == 0.0 &&
+ return io_count == 0.0 && idx_io_count == 0.0 && cpu_cost == 0.0 &&
import_cost == 0.0 && mem_cost == 0.0;
}
@@ -2715,7 +2719,7 @@ public:
void add(const Cost_estimate* cost)
{
- if (cost->io_count)
+ if (cost->io_count != 0.0)
{
double io_count_sum= io_count + cost->io_count;
avg_io_cost= (io_count * avg_io_cost +
@@ -2723,7 +2727,7 @@ public:
/io_count_sum;
io_count= io_count_sum;
}
- if (cost->idx_io_count)
+ if (cost->idx_io_count != 0.0)
{
double idx_io_count_sum= idx_io_count + cost->idx_io_count;
idx_avg_io_cost= (idx_io_count * idx_avg_io_cost +
@@ -2938,7 +2942,7 @@ public:
enum class Compare_keys : uint32_t
{
- Equal,
+ Equal= 0,
EqualButKeyPartLength,
EqualButComment,
NotEqual
@@ -3118,8 +3122,59 @@ public:
*/
PSI_table *m_psi;
+private:
+ /** Internal state of the batch instrumentation. */
+ enum batch_mode_t
+ {
+ /** Batch mode not used. */
+ PSI_BATCH_MODE_NONE,
+ /** Batch mode used, before first table io. */
+ PSI_BATCH_MODE_STARTING,
+ /** Batch mode used, after first table io. */
+ PSI_BATCH_MODE_STARTED
+ };
+ /**
+ Batch mode state.
+ @sa start_psi_batch_mode.
+ @sa end_psi_batch_mode.
+ */
+ batch_mode_t m_psi_batch_mode;
+ /**
+ The number of rows in the batch.
+ @sa start_psi_batch_mode.
+ @sa end_psi_batch_mode.
+ */
+ ulonglong m_psi_numrows;
+ /**
+ The current event in a batch.
+ @sa start_psi_batch_mode.
+ @sa end_psi_batch_mode.
+ */
+ PSI_table_locker *m_psi_locker;
+ /**
+ Storage for the event in a batch.
+ @sa start_psi_batch_mode.
+ @sa end_psi_batch_mode.
+ */
+ PSI_table_locker_state m_psi_locker_state;
+
+public:
virtual void unbind_psi();
virtual void rebind_psi();
+ /**
+ Put the handler in 'batch' mode when collecting
+ table io instrumented events.
+ When operating in batch mode:
+ - a single start event is generated in the performance schema.
+ - all table io performed between @c start_psi_batch_mode
+ and @c end_psi_batch_mode is not instrumented:
+ the number of rows affected is counted instead in @c m_psi_numrows.
+ - a single end event is generated in the performance schema
+ when the batch mode ends with @c end_psi_batch_mode.
+ */
+ void start_psi_batch_mode();
+ /** End a batch started with @c start_psi_batch_mode. */
+ void end_psi_batch_mode();
bool set_top_table_fields;
struct TABLE *top_table;
@@ -3166,7 +3221,11 @@ public:
pushed_rowid_filter(NULL),
rowid_filter_is_active(0),
auto_inc_intervals_count(0),
- m_psi(NULL), set_top_table_fields(FALSE), top_table(0),
+ m_psi(NULL),
+ m_psi_batch_mode(PSI_BATCH_MODE_NONE),
+ m_psi_numrows(0),
+ m_psi_locker(NULL),
+ set_top_table_fields(FALSE), top_table(0),
top_table_field(0), top_table_fields(0),
m_lock_type(F_UNLCK), ha_share(NULL), m_prev_insert_id(0)
{
@@ -4039,11 +4098,10 @@ public:
virtual my_bool register_query_cache_table(THD *thd, const char *table_key,
uint key_length,
- qc_engine_callback
- *engine_callback,
+ qc_engine_callback *callback,
ulonglong *engine_data)
{
- *engine_callback= 0;
+ *callback= 0;
return TRUE;
}
@@ -4312,7 +4370,7 @@ public:
*) Update SQL-layer data-dictionary by installing .FRM file for the new version
of the table.
*) Inform the storage engine about this change by calling the
- handler::ha_notify_table_changed() method.
+ hton::notify_table_changed()
*) Destroy the Alter_inplace_info and handler_ctx objects.
*/
@@ -4379,16 +4437,6 @@ public:
bool commit);
- /**
- Public function wrapping the actual handler call.
- @see notify_table_changed()
- */
- void ha_notify_table_changed()
- {
- notify_table_changed();
- }
-
-
protected:
/**
Allows the storage engine to update internal structures with concurrent
@@ -4487,14 +4535,6 @@ protected:
return false;
}
-
- /**
- Notify the storage engine that the table structure (.FRM) has been updated.
-
- @note No errors are allowed during notify_table_changed().
- */
- virtual void notify_table_changed() { }
-
public:
/* End of On-line/in-place ALTER TABLE interface. */
@@ -4518,7 +4558,6 @@ public:
TABLE_SHARE* get_table_share() { return table_share; }
protected:
/* Service methods for use by storage engines. */
- void **ha_data(THD *) const;
THD *ha_thd(void) const;
/**
@@ -4878,11 +4917,6 @@ public:
{
return false;
}
- virtual bool can_convert_geom(const Field_geom *field,
- const Column_definition &new_type) const
- {
- return false;
- }
/* Used for ALTER TABLE.
Some engines can handle some differences in indexes by themself. */
@@ -4943,8 +4977,7 @@ static inline bool ha_check_storage_engine_flag(const handlerton *db_type, uint3
static inline bool ha_storage_engine_is_enabled(const handlerton *db_type)
{
- return (db_type && db_type->create) ?
- (db_type->state == SHOW_OPTION_YES) : FALSE;
+ return db_type && db_type->create;
}
#define view_pseudo_hton ((handlerton *)1)
@@ -4960,7 +4993,7 @@ TYPELIB *ha_known_exts(void);
int ha_panic(enum ha_panic_function flag);
void ha_close_connection(THD* thd);
void ha_kill_query(THD* thd, enum thd_kill_levels level);
-bool ha_flush_logs(handlerton *db_type);
+bool ha_flush_logs();
void ha_drop_database(char* path);
void ha_checkpoint_state(bool disable);
void ha_commit_checkpoint_request(void *cookie, void (*pre_hook)(void *));
@@ -4971,6 +5004,7 @@ int ha_delete_table(THD *thd, handlerton *db_type, const char *path,
const LEX_CSTRING *db, const LEX_CSTRING *alias, bool generate_warning);
void ha_prepare_for_backup();
void ha_end_backup();
+void ha_pre_shutdown();
/* statistics and info */
bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat);
@@ -5041,7 +5075,8 @@ int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal);
#endif
/* these are called by storage engines */
-void trans_register_ha(THD *thd, bool all, handlerton *ht);
+void trans_register_ha(THD *thd, bool all, handlerton *ht,
+ ulonglong trxid);
/*
Storage engine has to assume the transaction will end up with 2pc if
@@ -5066,16 +5101,85 @@ int binlog_log_row(TABLE* table,
const uchar *after_record,
Log_func *log_func);
-#define TABLE_IO_WAIT(TRACKER, PSI, OP, INDEX, FLAGS, PAYLOAD) \
+/**
+ @def MYSQL_TABLE_IO_WAIT
+ Instrumentation helper for table io_waits.
+ Note that this helper is intended to be used from
+ within the handler class only, as it uses members
+ from @c handler
+ Performance schema events are instrumented as follows:
+ - in non batch mode, one event is generated per call
+ - in batch mode, the number of rows affected is saved
+ in @c m_psi_numrows, so that @c end_psi_batch_mode()
+ generates a single event for the batch.
+ @param OP the table operation to be performed
+ @param INDEX the table index used if any, or MAX_KEY.
+ @param PAYLOAD instrumented code to execute
+ @sa handler::end_psi_batch_mode.
+*/
+#ifdef HAVE_PSI_TABLE_INTERFACE
+ #define MYSQL_TABLE_IO_WAIT(OP, INDEX, RESULT, PAYLOAD) \
+ { \
+ if (m_psi != NULL) \
+ { \
+ switch (m_psi_batch_mode) \
+ { \
+ case PSI_BATCH_MODE_NONE: \
+ { \
+ PSI_table_locker *sub_locker= NULL; \
+ PSI_table_locker_state reentrant_safe_state; \
+ sub_locker= PSI_TABLE_CALL(start_table_io_wait) \
+ (& reentrant_safe_state, m_psi, OP, INDEX, \
+ __FILE__, __LINE__); \
+ PAYLOAD \
+ if (sub_locker != NULL) \
+ PSI_TABLE_CALL(end_table_io_wait) \
+ (sub_locker, 1); \
+ break; \
+ } \
+ case PSI_BATCH_MODE_STARTING: \
+ { \
+ m_psi_locker= PSI_TABLE_CALL(start_table_io_wait) \
+ (& m_psi_locker_state, m_psi, OP, INDEX, \
+ __FILE__, __LINE__); \
+ PAYLOAD \
+ if (!RESULT) \
+ m_psi_numrows++; \
+ m_psi_batch_mode= PSI_BATCH_MODE_STARTED; \
+ break; \
+ } \
+ case PSI_BATCH_MODE_STARTED: \
+ default: \
+ { \
+ DBUG_ASSERT(m_psi_batch_mode \
+ == PSI_BATCH_MODE_STARTED); \
+ PAYLOAD \
+ if (!RESULT) \
+ m_psi_numrows++; \
+ break; \
+ } \
+ } \
+ } \
+ else \
+ { \
+ PAYLOAD \
+ } \
+ }
+#else
+ #define MYSQL_TABLE_IO_WAIT(OP, INDEX, RESULT, PAYLOAD) \
+ PAYLOAD
+#endif
+
+#define TABLE_IO_WAIT(TRACKER, OP, INDEX, RESULT, PAYLOAD) \
{ \
Exec_time_tracker *this_tracker; \
if (unlikely((this_tracker= tracker))) \
- tracker->start_tracking(); \
+ tracker->start_tracking(table->in_use); \
\
- MYSQL_TABLE_IO_WAIT(PSI, OP, INDEX, FLAGS, PAYLOAD); \
+ MYSQL_TABLE_IO_WAIT(OP, INDEX, RESULT, PAYLOAD); \
\
if (unlikely(this_tracker)) \
- tracker->stop_tracking(); \
+ tracker->stop_tracking(table->in_use); \
}
void print_keydup_error(TABLE *table, KEY *key, const char *msg, myf errflag);
@@ -5083,4 +5187,5 @@ 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, const LEX_CSTRING *db, const LEX_CSTRING *table);
+uint ha_count_rw_all(THD *thd, Ha_trx_info **ptr_ha_info);
#endif /* HANDLER_INCLUDED */
diff --git a/sql/hash_filo.h b/sql/hash_filo.h
index d815c428ac6..ac84e5ccb7b 100644
--- a/sql/hash_filo.h
+++ b/sql/hash_filo.h
@@ -48,6 +48,7 @@ private:
class hash_filo
{
private:
+ PSI_memory_key m_psi_key;
const uint key_offset, key_length;
const my_hash_get_key get_key;
/** Size of this hash table. */
@@ -61,15 +62,13 @@ public:
mysql_mutex_t lock;
HASH cache;
- hash_filo(uint size_arg, uint key_offset_arg , uint key_length_arg,
- my_hash_get_key get_key_arg, my_hash_free_key free_element_arg,
- CHARSET_INFO *hash_charset_arg)
- :key_offset(key_offset_arg), key_length(key_length_arg),
- get_key(get_key_arg), m_size(size_arg),
- free_element(free_element_arg),init(0),
- hash_charset(hash_charset_arg),
- first_link(NULL),
- last_link(NULL)
+ hash_filo(PSI_memory_key psi_key, uint size_arg, uint key_offset_arg,
+ uint key_length_arg, my_hash_get_key get_key_arg,
+ my_hash_free_key free_element_arg, CHARSET_INFO *hash_charset_arg)
+ : m_psi_key(psi_key), key_offset(key_offset_arg),
+ key_length(key_length_arg), get_key(get_key_arg), m_size(size_arg),
+ free_element(free_element_arg),init(0), hash_charset(hash_charset_arg),
+ first_link(NULL), last_link(NULL)
{
bzero((char*) &cache,sizeof(cache));
}
@@ -95,8 +94,8 @@ public:
first_link= NULL;
last_link= NULL;
(void) my_hash_free(&cache);
- (void) my_hash_init(&cache,hash_charset,m_size,key_offset,
- key_length, get_key, free_element,0);
+ (void) my_hash_init(m_psi_key, &cache,hash_charset,m_size,key_offset,
+ key_length, get_key, free_element, 0);
if (!locked)
mysql_mutex_unlock(&lock);
}
@@ -202,10 +201,10 @@ public:
template <class T> class Hash_filo: public hash_filo
{
public:
- Hash_filo(uint size_arg, uint key_offset_arg, uint key_length_arg,
- my_hash_get_key get_key_arg, my_hash_free_key free_element_arg,
- CHARSET_INFO *hash_charset_arg) :
- hash_filo(size_arg, key_offset_arg, key_length_arg,
+ Hash_filo(PSI_memory_key psi_key, uint size_arg, uint key_offset_arg, uint
+ key_length_arg, my_hash_get_key get_key_arg, my_hash_free_key
+ free_element_arg, CHARSET_INFO *hash_charset_arg) :
+ hash_filo(psi_key, size_arg, key_offset_arg, key_length_arg,
get_key_arg, free_element_arg, hash_charset_arg) {}
T* first() { return (T*)hash_filo::first(); }
T* last() { return (T*)hash_filo::last(); }
diff --git a/sql/hostname.cc b/sql/hostname.cc
index 968914fd56e..edf31c11081 100644
--- a/sql/hostname.cc
+++ b/sql/hostname.cc
@@ -150,10 +150,9 @@ bool hostname_cache_init()
Host_entry tmp;
uint key_offset= (uint) ((char*) (&tmp.ip_key) - (char*) &tmp);
- if (!(hostname_cache= new Hash_filo<Host_entry>(host_cache_size,
- key_offset, HOST_ENTRY_KEY_SIZE,
- NULL, (my_hash_free_key) free,
- &my_charset_bin)))
+ if (!(hostname_cache= new Hash_filo<Host_entry>(key_memory_host_cache_hostname,
+ host_cache_size, key_offset, HOST_ENTRY_KEY_SIZE,
+ NULL, (my_hash_free_key) free, &my_charset_bin)))
return 1;
hostname_cache->clear();
@@ -476,7 +475,8 @@ int ip_to_hostname(struct sockaddr_storage *ip_storage,
if (entry->m_host_validated)
{
if (entry->m_hostname_length)
- *hostname= my_strdup(entry->m_hostname, MYF(0));
+ *hostname= my_strdup(key_memory_host_cache_hostname,
+ entry->m_hostname, MYF(0));
DBUG_PRINT("info",("IP (%s) has been found in the cache. "
"Hostname: '%s'",
@@ -926,7 +926,8 @@ int ip_to_hostname(struct sockaddr_storage *ip_storage,
{
/* Copy host name string to be stored in the cache. */
- *hostname= my_strdup(hostname_buffer, MYF(0));
+ *hostname= my_strdup(key_memory_host_cache_hostname,
+ hostname_buffer, MYF(0));
if (!*hostname)
{
diff --git a/sql/item.cc b/sql/item.cc
index 9b721266e9d..89e23173b0e 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2018, Oracle and/or its affiliates.
- Copyright (c) 2010, 2019, MariaDB Corporation
+ Copyright (c) 2010, 2020, 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
@@ -329,6 +329,7 @@ my_decimal *Item::val_decimal_from_real(my_decimal *decimal_value)
my_decimal *Item::val_decimal_from_int(my_decimal *decimal_value)
{
+ DBUG_ASSERT(is_fixed());
longlong nr= val_int();
if (null_value)
return 0;
@@ -402,7 +403,7 @@ int Item::save_str_value_in_field(Field *field, String *result)
Item::Item(THD *thd):
is_expensive_cache(-1), rsize(0), name(null_clex_str), orig_name(0),
- is_autogenerated_name(TRUE)
+ common_flags(IS_AUTO_GENERATED_NAME)
{
DBUG_ASSERT(thd);
marker= 0;
@@ -448,7 +449,7 @@ const TABLE_SHARE *Item::field_table_or_null()
tables.
*/
Item::Item(THD *thd, Item *item):
- Type_all_attributes(item),
+ Type_all_attributes(*item),
join_tab_idx(item->join_tab_idx),
is_expensive_cache(-1),
rsize(0),
@@ -462,7 +463,7 @@ Item::Item(THD *thd, Item *item):
with_param(item->with_param),
with_window_func(item->with_window_func),
with_field(item->with_field),
- is_autogenerated_name(item->is_autogenerated_name)
+ common_flags(item->common_flags)
{
next= thd->free_list; // Put in free list
thd->free_list= this;
@@ -623,33 +624,34 @@ Item* Item::set_expr_cache(THD *thd)
Item_ident::Item_ident(THD *thd, Name_resolution_context *context_arg,
- const char *db_name_arg,const char *table_name_arg,
- const LEX_CSTRING *field_name_arg)
+ const LEX_CSTRING &db_name_arg,
+ const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg)
:Item_result_field(thd), orig_db_name(db_name_arg),
orig_table_name(table_name_arg),
- orig_field_name(*field_name_arg), context(context_arg),
+ orig_field_name(field_name_arg), context(context_arg),
db_name(db_name_arg), table_name(table_name_arg),
- field_name(*field_name_arg),
+ field_name(field_name_arg),
alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX),
cached_table(0), depended_from(0), can_be_depended(TRUE)
{
- name= *field_name_arg;
+ name= field_name_arg;
}
Item_ident::Item_ident(THD *thd, TABLE_LIST *view_arg,
- const LEX_CSTRING *field_name_arg)
- :Item_result_field(thd), orig_db_name(NullS),
- orig_table_name(view_arg->table_name.str),
- orig_field_name(*field_name_arg),
+ const LEX_CSTRING &field_name_arg)
+ :Item_result_field(thd), orig_db_name(null_clex_str),
+ orig_table_name(view_arg->table_name),
+ orig_field_name(field_name_arg),
/* TODO: suspicious use of first_select_lex */
context(&view_arg->view->first_select_lex()->context),
- db_name(NullS), table_name(view_arg->alias.str),
- field_name(*field_name_arg),
+ db_name(null_clex_str), table_name(view_arg->alias),
+ field_name(field_name_arg),
alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX),
cached_table(NULL), depended_from(NULL), can_be_depended(TRUE)
{
- name= *field_name_arg;
+ name= field_name_arg;
}
@@ -780,10 +782,10 @@ bool Item_field::rename_fields_processor(void *arg)
while ((def=def_it++))
{
if (def->change.str &&
- (!db_name || !db_name[0] ||
- !my_strcasecmp(table_alias_charset, db_name, rename->db_name.str)) &&
- (!table_name || !table_name[0] ||
- !my_strcasecmp(table_alias_charset, table_name, rename->table_name.str)) &&
+ (!db_name.str || !db_name.str[0] ||
+ !my_strcasecmp(table_alias_charset, db_name.str, rename->db_name.str)) &&
+ (!table_name.str || !table_name.str[0] ||
+ !my_strcasecmp(table_alias_charset, table_name.str, rename->table_name.str)) &&
!my_strcasecmp(system_charset_info, field_name.str, def->change.str))
{
field_name= def->field_name;
@@ -977,7 +979,7 @@ bool Item::check_type_general_purpose_string(const char *opname) const
bool Item::check_type_traditional_scalar(const char *opname) const
{
const Type_handler *handler= type_handler();
- if (handler->is_traditional_type() && handler->is_scalar_type())
+ if (handler->is_traditional_scalar_type())
return false;
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
handler->name().ptr(), opname);
@@ -1098,9 +1100,9 @@ void Item::set_name(THD *thd, const char *str, size_t length, CHARSET_INFO *cs)
}
const char *str_start= str;
- if (!cs->ctype || cs->mbminlen > 1)
+ if (!cs->m_ctype || cs->mbminlen > 1)
{
- str+= cs->cset->scan(cs, str, str + length, MY_SEQ_SPACES);
+ str+= cs->scan(str, str + length, MY_SEQ_SPACES);
length-= (uint)(str - str_start);
}
else
@@ -1115,7 +1117,7 @@ void Item::set_name(THD *thd, const char *str, size_t length, CHARSET_INFO *cs)
str++;
}
}
- if (str != str_start && !is_autogenerated_name)
+ if (str != str_start && !is_autogenerated_name())
{
char buff[SAFE_NAME_LEN];
@@ -1291,7 +1293,7 @@ Item *Item::const_charset_converter(THD *thd, CHARSET_INFO *tocs,
uint conv_errors;
Item_string *conv= (func_name ?
new (mem_root)
- Item_static_string_func(thd, func_name,
+ Item_static_string_func(thd, Lex_cstring_strlen(func_name),
s, tocs, &conv_errors,
collation.derivation,
collation.repertoire) :
@@ -1410,7 +1412,7 @@ int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
THD *thd= table->in_use;
enum_check_fields tmp= thd->count_cuted_fields;
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
- sql_mode_t sql_mode= thd->variables.sql_mode;
+ Sql_mode_save sms(thd);
thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE);
thd->variables.sql_mode|= MODE_INVALID_DATES;
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
@@ -1419,7 +1421,6 @@ int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
thd->count_cuted_fields= tmp;
dbug_tmp_restore_column_map(table->write_set, old_map);
- thd->variables.sql_mode= sql_mode;
return res;
}
@@ -2014,7 +2015,7 @@ Item_name_const::Item_name_const(THD *thd, Item *name_arg, Item *val):
Item::maybe_null= TRUE;
if (name_item->basic_const_item() &&
(name_str= name_item->val_str(&name_buffer))) // Can't have a NULL name
- set_name(thd, name_str->ptr(), name_str->length(), name_str->charset());
+ set_name(thd, name_str->lex_cstring(), name_str->charset());
}
@@ -2059,7 +2060,7 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref)
return TRUE;
}
if (value_item->collation.derivation == DERIVATION_NUMERIC)
- collation.set_numeric();
+ collation= DTCollation_numeric();
else
collation.set(value_item->collation.collation, DERIVATION_IMPLICIT);
max_length= value_item->max_length;
@@ -2089,8 +2090,8 @@ class Item_aggregate_ref : public Item_ref
{
public:
Item_aggregate_ref(THD *thd, Name_resolution_context *context_arg,
- Item **item, const char *table_name_arg,
- const LEX_CSTRING *field_name_arg):
+ Item **item, const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg):
Item_ref(thd, context_arg, item, table_name_arg, field_name_arg) {}
virtual inline void print (String *str, enum_query_type query_type)
@@ -2212,8 +2213,8 @@ void Item::split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array,
if (!(item_ref= (new (thd->mem_root)
Item_direct_ref(thd,
&thd->lex->current_select->context,
- &ref_pointer_array[el], 0,
- &name))))
+ &ref_pointer_array[el],
+ null_clex_str, name))))
return; // fatal_error is set
}
else
@@ -2221,8 +2222,8 @@ void Item::split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array,
if (!(item_ref= (new (thd->mem_root)
Item_aggregate_ref(thd,
&thd->lex->current_select->context,
- &ref_pointer_array[el], 0,
- &name))))
+ &ref_pointer_array[el],
+ null_clex_str, name))))
return; // fatal_error is set
}
if (type() == SUM_FUNC_ITEM)
@@ -2770,7 +2771,8 @@ Item_sp::execute_impl(THD *thd, Item **args, uint arg_count)
(m_sp->agg_type() == NOT_AGGREGATE && !func_ctx));
if (!func_ctx)
{
- init_sql_alloc(&sp_mem_root, "Item_sp", MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
+ init_sql_alloc(key_memory_sp_head_call_root, &sp_mem_root,
+ MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
*sp_query_arena= Query_arena(&sp_mem_root,
Query_arena::STMT_INITIALIZED_FOR_SP);
}
@@ -2888,9 +2890,10 @@ Item* Item_ref::build_clone(THD *thd)
/**********************************************/
Item_field::Item_field(THD *thd, Field *f)
- :Item_ident(thd, 0, NullS, *f->table_name, &f->field_name),
+ :Item_ident(thd, 0, null_clex_str,
+ Lex_cstring_strlen(*f->table_name), f->field_name),
item_equal(0),
- have_privileges(0), any_privileges(0)
+ have_privileges(NO_ACL), any_privileges(0)
{
set_field(f);
/*
@@ -2912,10 +2915,10 @@ Item_field::Item_field(THD *thd, Field *f)
Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
Field *f)
- :Item_ident(thd, context_arg, f->table->s->db.str, *f->table_name,
- &f->field_name),
+ :Item_ident(thd, context_arg, f->table->s->db,
+ Lex_cstring_strlen(*f->table_name), f->field_name),
item_equal(0),
- have_privileges(0), any_privileges(0)
+ have_privileges(NO_ACL), any_privileges(0)
{
/*
We always need to provide Item_field with a fully qualified field
@@ -2935,13 +2938,12 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
procedures).
*/
{
- if (db_name)
- orig_db_name= thd->strdup(db_name);
- if (table_name)
- orig_table_name= thd->strdup(table_name);
+ if (db_name.str)
+ orig_db_name= thd->strmake_lex_cstring(db_name);
+ if (table_name.str)
+ orig_table_name= thd->strmake_lex_cstring(table_name);
if (field_name.str)
- thd->make_lex_string(&orig_field_name, field_name.str,
- field_name.length);
+ orig_field_name= thd->strmake_lex_cstring(field_name);
/*
We don't restore 'name' in cleanup because it's not changed
during execution. Still we need it to point to persistent
@@ -2955,11 +2957,12 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
- const char *db_arg,const char *table_name_arg,
- const LEX_CSTRING *field_name_arg)
+ const LEX_CSTRING &db_arg,
+ const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg)
:Item_ident(thd, context_arg, db_arg, table_name_arg, field_name_arg),
field(0), item_equal(0),
- have_privileges(0), any_privileges(0)
+ have_privileges(NO_ACL), any_privileges(0)
{
SELECT_LEX *select= thd->lex->current_select;
collation.set(DERIVATION_IMPLICIT);
@@ -2989,9 +2992,9 @@ void Item_field::set_field(Field *field_par)
field=result_field=field_par; // for easy coding with fields
maybe_null=field->maybe_null();
Type_std_attributes::set(field_par->type_std_attributes());
- table_name= *field_par->table_name;
+ table_name= Lex_cstring_strlen(*field_par->table_name);
field_name= field_par->field_name;
- db_name= field_par->table->s->db.str;
+ db_name= field_par->table->s->db;
alias_name_used= field_par->table->alias_name_used;
fixed= 1;
@@ -3074,24 +3077,24 @@ bool Item_field::switch_to_nullable_fields_processor(void *arg)
const char *Item_ident::full_name() const
{
char *tmp;
- if (!table_name || !field_name.str)
+ if (!table_name.str || !field_name.str)
return field_name.str ? field_name.str : name.str ? name.str : "tmp_field";
- if (db_name && db_name[0])
+ if (db_name.str && db_name.str[0])
{
THD *thd= current_thd;
- tmp=(char*) thd->alloc((uint) strlen(db_name)+(uint) strlen(table_name)+
+ tmp=(char*) thd->alloc((uint) db_name.length+ (uint) table_name.length +
(uint) field_name.length+3);
- strxmov(tmp,db_name,".",table_name,".",field_name.str,NullS);
+ strxmov(tmp,db_name.str,".",table_name.str,".",field_name.str,NullS);
}
else
{
- if (table_name[0])
+ if (table_name.str[0])
{
THD *thd= current_thd;
- tmp= (char*) thd->alloc((uint) strlen(table_name) +
+ tmp= (char*) thd->alloc((uint) table_name.length +
field_name.length + 2);
- strxmov(tmp, table_name, ".", field_name.str, NullS);
+ strxmov(tmp, table_name.str, ".", field_name.str, NullS);
}
else
return field_name.str;
@@ -3103,12 +3106,14 @@ void Item_ident::print(String *str, enum_query_type query_type)
{
THD *thd= current_thd;
char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME];
- const char *d_name= db_name, *t_name= table_name;
- bool use_table_name= table_name && table_name[0];
- bool use_db_name= use_table_name && db_name && db_name[0] && !alias_name_used;
+ LEX_CSTRING d_name= db_name;
+ LEX_CSTRING t_name= table_name;
+ bool use_table_name= table_name.str && table_name.str[0];
+ bool use_db_name= use_table_name && db_name.str && db_name.str[0] &&
+ !alias_name_used;
if (use_db_name && (query_type & QT_ITEM_IDENT_SKIP_DB_NAMES))
- use_db_name= !thd->db.str || strcmp(thd->db.str, db_name);
+ use_db_name= !thd->db.str || strcmp(thd->db.str, db_name.str);
if (use_db_name)
use_db_name= !(cached_table && cached_table->belong_to_view &&
@@ -3142,27 +3147,27 @@ void Item_ident::print(String *str, enum_query_type query_type)
{
if (use_table_name)
{
- strmov(t_name_buff, table_name);
+ strmov(t_name_buff, table_name.str);
my_casedn_str(files_charset_info, t_name_buff);
- t_name= t_name_buff;
+ t_name= Lex_cstring_strlen(t_name_buff);
}
if (use_db_name)
{
- strmov(d_name_buff, db_name);
+ strmov(d_name_buff, db_name.str);
my_casedn_str(files_charset_info, d_name_buff);
- d_name= d_name_buff;
+ d_name= Lex_cstring_strlen(d_name_buff);
}
}
if (use_db_name)
{
- append_identifier(thd, str, d_name, (uint)strlen(d_name));
+ append_identifier(thd, str, d_name.str, (uint) d_name.length);
str->append('.');
DBUG_ASSERT(use_table_name);
}
if (use_table_name)
{
- append_identifier(thd, str, t_name, (uint) strlen(t_name));
+ append_identifier(thd, str, t_name.str, (uint) t_name.length);
str->append('.');
}
append_identifier(thd, str, &field_name);
@@ -3311,12 +3316,12 @@ bool Item_field::eq(const Item *item, bool binary_cmp) const
*/
return (!lex_string_cmp(system_charset_info, &item_field->name,
&field_name) &&
- (!item_field->table_name || !table_name ||
- (!my_strcasecmp(table_alias_charset, item_field->table_name,
- table_name) &&
- (!item_field->db_name || !db_name ||
- (item_field->db_name && !strcmp(item_field->db_name,
- db_name))))));
+ (!item_field->table_name.str || !table_name.str ||
+ (!my_strcasecmp(table_alias_charset, item_field->table_name.str,
+ table_name.str) &&
+ (!item_field->db_name.str || !db_name.str ||
+ (item_field->db_name.str && !strcmp(item_field->db_name.str,
+ db_name.str))))));
}
@@ -3333,6 +3338,16 @@ table_map Item_field::all_used_tables() const
}
+bool Item_field::find_not_null_fields(table_map allowed)
+{
+ if (field->table->const_table)
+ return false;
+ if (!get_depended_from() && field->real_maybe_null())
+ bitmap_set_bit(&field->table->tmp_set, field->field_index);
+ return false;
+}
+
+
/*
@Note thd->fatal_error can be set in case of OOM
*/
@@ -3889,7 +3904,6 @@ void Item_param::sync_clones()
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;
@@ -3935,7 +3949,7 @@ void Item_param::set_int(longlong i, uint32 max_length_arg)
DBUG_ASSERT(value.type_handler()->cmp_type() == INT_RESULT);
value.integer= (longlong) i;
state= SHORT_DATA_VALUE;
- collation.set_numeric();
+ collation= DTCollation_numeric();
max_length= max_length_arg;
decimals= 0;
maybe_null= 0;
@@ -3949,7 +3963,7 @@ void Item_param::set_double(double d)
DBUG_ASSERT(value.type_handler()->cmp_type() == REAL_RESULT);
value.real= d;
state= SHORT_DATA_VALUE;
- collation.set_numeric();
+ collation= DTCollation_numeric();
max_length= DBL_DIG + 8;
decimals= NOT_FIXED_DEC;
maybe_null= 0;
@@ -3980,7 +3994,7 @@ void Item_param::set_decimal(const char *str, ulong length)
str2my_decimal(E_DEC_FATAL_ERROR, str, &value.m_decimal, &end);
state= SHORT_DATA_VALUE;
decimals= value.m_decimal.frac;
- collation.set_numeric();
+ collation= DTCollation_numeric();
max_length=
my_decimal_precision_to_length_no_truncation(value.m_decimal.precision(),
decimals, unsigned_flag);
@@ -3997,7 +4011,7 @@ void Item_param::set_decimal(const my_decimal *dv, bool unsigned_arg)
my_decimal2decimal(dv, &value.m_decimal);
decimals= (uint8) value.m_decimal.frac;
- collation.set_numeric();
+ collation= DTCollation_numeric();
unsigned_flag= unsigned_arg;
max_length= my_decimal_precision_to_length(value.m_decimal.intg + decimals,
decimals, unsigned_flag);
@@ -4009,7 +4023,7 @@ void Item_param::set_decimal(const my_decimal *dv, bool unsigned_arg)
void Item_param::fix_temporal(uint32 max_length_arg, uint decimals_arg)
{
state= SHORT_DATA_VALUE;
- collation.set_numeric();
+ collation= DTCollation_numeric();
max_length= max_length_arg;
decimals= decimals_arg;
maybe_null= 0;
@@ -4116,12 +4130,12 @@ bool Item_param::set_longdata(const char *str, ulong length)
(here), and first have to concatenate all pieces together,
write query to the binary log and only then perform conversion.
*/
- if (value.m_string.length() + length > max_long_data_size)
+ if (value.m_string.length() + length > current_thd->variables.max_allowed_packet)
{
my_message(ER_UNKNOWN_ERROR,
"Parameter of prepared statement which is set through "
"mysql_send_long_data() is longer than "
- "'max_long_data_size' bytes",
+ "'max_allowed_packet' bytes",
MYF(0));
DBUG_RETURN(true);
}
@@ -4575,9 +4589,9 @@ Item *Item_param::value_clone_item(THD *thd)
case DECIMAL_RESULT:
return 0; // Should create Item_decimal. See MDEV-11361.
case STRING_RESULT:
- return new (mem_root) Item_string(thd, name.str,
- value.m_string.c_ptr_quick(),
- value.m_string.length(),
+ return new (mem_root) Item_string(thd, name,
+ Lex_cstring(value.m_string.c_ptr_quick(),
+ value.m_string.length()),
value.m_string.charset(),
collation.derivation,
collation.repertoire);
@@ -4813,16 +4827,16 @@ double Item_copy_string::val_real()
int err_not_used;
char *end_not_used;
return (null_value ? 0.0 :
- my_strntod(str_value.charset(), (char*) str_value.ptr(),
- str_value.length(), &end_not_used, &err_not_used));
+ str_value.charset()->strntod((char*) str_value.ptr(), str_value.length(),
+ &end_not_used, &err_not_used));
}
longlong Item_copy_string::val_int()
{
int err;
- return null_value ? 0 : my_strntoll(str_value.charset(),str_value.ptr(),
- str_value.length(), 10, (char**) 0,
- &err);
+ return null_value ? 0 : str_value.charset()->strntoll(str_value.ptr(),
+ str_value.length(), 10, (char**) 0,
+ &err);
}
@@ -4958,10 +4972,10 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
DBUG_RETURN(TRUE);
if (thd->lex->describe & DESCRIBE_EXTENDED)
{
- const char *db_name= (resolved_item->db_name ?
- resolved_item->db_name : "");
- const char *table_name= (resolved_item->table_name ?
- resolved_item->table_name : "");
+ const char *db_name= (resolved_item->db_name.str ?
+ resolved_item->db_name.str : "");
+ const char *table_name= (resolved_item->table_name.str ?
+ resolved_item->table_name.str : "");
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_WARN_FIELD_RESOLVED,
ER_THD(thd,ER_WARN_FIELD_RESOLVED),
@@ -4994,8 +5008,7 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
resolved identifier.
*/
-void mark_select_range_as_dependent(THD *thd,
- SELECT_LEX *last_select,
+void mark_select_range_as_dependent(THD *thd, SELECT_LEX *last_select,
SELECT_LEX *current_sel,
Field *found_field, Item *found_item,
Item_ident *resolved_item)
@@ -5007,34 +5020,33 @@ void mark_select_range_as_dependent(THD *thd,
resolving)
*/
SELECT_LEX *previous_select= current_sel;
- for (; previous_select->outer_select() != last_select;
- previous_select= previous_select->outer_select())
+ for (; previous_select->context.outer_select() != last_select;
+ previous_select= previous_select->context.outer_select())
{
Item_subselect *prev_subselect_item=
previous_select->master_unit()->item;
prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
prev_subselect_item->const_item_cache= 0;
}
+
+ Item_subselect *prev_subselect_item=
+ previous_select->master_unit()->item;
+ Item_ident *dependent= resolved_item;
+ if (found_field == view_ref_found)
{
- Item_subselect *prev_subselect_item=
- previous_select->master_unit()->item;
- Item_ident *dependent= resolved_item;
- if (found_field == view_ref_found)
- {
- Item::Type type= found_item->type();
- prev_subselect_item->used_tables_cache|=
- found_item->used_tables();
- dependent= ((type == Item::REF_ITEM || type == Item::FIELD_ITEM) ?
- (Item_ident*) found_item :
- 0);
- }
- else
- prev_subselect_item->used_tables_cache|=
- found_field->table->map;
- prev_subselect_item->const_item_cache= 0;
- mark_as_dependent(thd, last_select, current_sel, resolved_item,
- dependent);
+ Item::Type type= found_item->type();
+ prev_subselect_item->used_tables_cache|=
+ found_item->used_tables();
+ dependent= ((type == Item::REF_ITEM || type == Item::FIELD_ITEM) ?
+ (Item_ident*) found_item :
+ 0);
}
+ else
+ prev_subselect_item->used_tables_cache|=
+ found_field->table->map;
+ prev_subselect_item->const_item_cache= 0;
+ mark_as_dependent(thd, last_select, current_sel, resolved_item,
+ dependent);
}
@@ -5055,9 +5067,9 @@ void mark_select_range_as_dependent(THD *thd,
static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
{
- const char *db_name;
- const char *table_name;
- LEX_CSTRING *field_name;
+ LEX_CSTRING db_name;
+ LEX_CSTRING table_name;
+ LEX_CSTRING field_name;
ORDER *found_group= NULL;
int found_match_degree= 0;
char name_buff[SAFE_NAME_LEN+1];
@@ -5067,30 +5079,30 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
{
db_name= ((Item_ident*) find_item)->db_name;
table_name= ((Item_ident*) find_item)->table_name;
- field_name= &((Item_ident*) find_item)->field_name;
+ field_name= ((Item_ident*) find_item)->field_name;
}
else
return NULL;
- if (db_name && lower_case_table_names)
+ if (db_name.str && lower_case_table_names)
{
/* Convert database to lower case for comparison */
- strmake_buf(name_buff, db_name);
+ strmake_buf(name_buff, db_name.str);
my_casedn_str(files_charset_info, name_buff);
- db_name= name_buff;
+ db_name= Lex_cstring_strlen(name_buff);
}
- DBUG_ASSERT(field_name->str != 0);
+ DBUG_ASSERT(field_name.str != 0);
for (ORDER *cur_group= group_list ; cur_group ; cur_group= cur_group->next)
{
int cur_match_degree= 0;
/* SELECT list element with explicit alias */
- if ((*(cur_group->item))->name.str && !table_name &&
- !(*(cur_group->item))->is_autogenerated_name &&
+ if ((*(cur_group->item))->name.str && !table_name.str &&
+ !(*(cur_group->item))->is_autogenerated_name() &&
!lex_string_cmp(system_charset_info,
- &(*(cur_group->item))->name, field_name))
+ &(*(cur_group->item))->name, &field_name))
{
++cur_match_degree;
}
@@ -5099,30 +5111,30 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
(*(cur_group->item))->type() == Item::REF_ITEM )
{
Item_ident *cur_field= (Item_ident*) *cur_group->item;
- const char *l_db_name= cur_field->db_name;
- const char *l_table_name= cur_field->table_name;
+ const char *l_db_name= cur_field->db_name.str;
+ const char *l_table_name= cur_field->table_name.str;
LEX_CSTRING *l_field_name= &cur_field->field_name;
DBUG_ASSERT(l_field_name->str != 0);
if (!lex_string_cmp(system_charset_info,
- l_field_name, field_name))
+ l_field_name, &field_name))
++cur_match_degree;
else
continue;
- if (l_table_name && table_name)
+ if (l_table_name && table_name.str)
{
/* If field_name is qualified by a table name. */
- if (my_strcasecmp(table_alias_charset, l_table_name, table_name))
+ if (my_strcasecmp(table_alias_charset, l_table_name, table_name.str))
/* Same field names, different tables. */
return NULL;
++cur_match_degree;
- if (l_db_name && db_name)
+ if (l_db_name && db_name.str)
{
/* If field_name is also qualified by a database name. */
- if (strcmp(l_db_name, db_name))
+ if (strcmp(l_db_name, db_name.str))
/* Same field names, different databases. */
return NULL;
++cur_match_degree;
@@ -5591,14 +5603,14 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
rf= (place == IN_HAVING ?
new (thd->mem_root)
Item_ref(thd, context, ref, table_name,
- &field_name, alias_name_used) :
+ field_name, alias_name_used) :
(!select->group_list.elements ?
new (thd->mem_root)
Item_direct_ref(thd, context, ref, table_name,
- &field_name, alias_name_used) :
+ field_name, alias_name_used) :
new (thd->mem_root)
Item_outer_ref(thd, context, ref, table_name,
- &field_name, alias_name_used)));
+ field_name, alias_name_used)));
*ref= save;
if (!rf)
return -1;
@@ -5643,9 +5655,9 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
{
Item_ref *rf;
rf= new (thd->mem_root) Item_ref(thd, context,
- (*from_field)->table->s->db.str,
- (*from_field)->table->alias.c_ptr(),
- &field_name);
+ (*from_field)->table->s->db,
+ Lex_cstring_strlen((*from_field)->table->alias.c_ptr()),
+ field_name);
if (!rf)
return -1;
thd->change_item_tree(reference, rf);
@@ -5793,7 +5805,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
Item_field created by the parser with the new Item_ref.
*/
Item_ref *rf= new (thd->mem_root)
- Item_ref(thd, context, db_name, table_name, &field_name);
+ Item_ref(thd, context, db_name, table_name, field_name);
if (!rf)
return 1;
bool err= rf->fix_fields(thd, (Item **) &rf) || rf->check_cols(1);
@@ -5976,7 +5988,7 @@ bool Item_field::post_fix_fields_part_expr_processor(void *int_arg)
/*
Update table_name to be real table name, not the alias. Because alias is
reallocated for every statement, and this item has a long life time */
- table_name= field->table->s->table_name.str;
+ table_name= field->table->s->table_name;
return FALSE;
}
@@ -6173,10 +6185,10 @@ Item *Item_field::replace_equal_field(THD *thd, uchar *arg)
void Item::init_make_send_field(Send_field *tmp_field,
const Type_handler *h)
{
- tmp_field->db_name= "";
- tmp_field->org_table_name= "";
+ tmp_field->db_name= empty_clex_str;
+ tmp_field->org_table_name= empty_clex_str;
tmp_field->org_col_name= empty_clex_str;
- tmp_field->table_name= "";
+ tmp_field->table_name= empty_clex_str;
tmp_field->col_name= name;
tmp_field->flags= (maybe_null ? 0 : NOT_NULL_FLAG) |
(my_binary_compare(charset_for_protocol()) ?
@@ -6186,6 +6198,9 @@ void Item::init_make_send_field(Send_field *tmp_field,
tmp_field->decimals=decimals;
if (unsigned_flag)
tmp_field->flags |= UNSIGNED_FLAG;
+ static_cast<Send_field_extended_metadata>(*tmp_field)=
+ Send_field_extended_metadata();
+ h->Item_append_extended_type_info(tmp_field, this);
}
void Item::make_send_field(THD *thd, Send_field *tmp_field)
@@ -6274,7 +6289,7 @@ String_copier_for_item::copy_with_warn(CHARSET_INFO *dstcs, String *dst,
if (unlikely(pos= cannot_convert_error_pos()))
{
char buf[16];
- int mblen= my_charlen(srccs, pos, src + src_length);
+ int mblen= srccs->charlen(pos, src + src_length);
DBUG_ASSERT(mblen > 0 && mblen * 2 + 1 <= (int) sizeof(buf));
octet2hex(buf, pos, mblen);
push_warning_printf(m_thd, Sql_condition::WARN_LEVEL_WARN,
@@ -6335,15 +6350,15 @@ bool Item::eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs)
void Item_field::make_send_field(THD *thd, Send_field *tmp_field)
{
field->make_send_field(tmp_field);
- DBUG_ASSERT(tmp_field->table_name != 0);
+ DBUG_ASSERT(tmp_field->table_name.str != 0);
if (name.str)
{
DBUG_ASSERT(name.length == strlen(name.str));
tmp_field->col_name= name; // Use user supplied name
}
- if (table_name)
+ if (table_name.str)
tmp_field->table_name= table_name;
- if (db_name)
+ if (db_name.str)
tmp_field->db_name= db_name;
}
@@ -6569,8 +6584,7 @@ int Item_string::save_in_field(Field *field, bool no_conversions)
Item *Item_string::clone_item(THD *thd)
{
return new (thd->mem_root)
- Item_string(thd, name.str, str_value.ptr(),
- str_value.length(), collation.collation);
+ Item_string(thd, name, str_value.lex_cstring(), collation.collation);
}
@@ -6800,8 +6814,7 @@ Item_float::Item_float(THD *thd, const char *str_arg, size_t length):
{
int error;
char *end_not_used;
- value= my_strntod(&my_charset_bin, (char*) str_arg, length, &end_not_used,
- &error);
+ value= my_charset_bin.strntod((char*) str_arg, length, &end_not_used, &error);
if (unlikely(error))
{
char tmp[NAME_LEN + 1];
@@ -7179,7 +7192,7 @@ Item *Item_field::update_value_transformer(THD *thd, uchar *select_arg)
all_fields->push_front((Item*)this, thd->mem_root);
ref= new (thd->mem_root)
Item_ref(thd, &select->context, &ref_pointer_array[el],
- table_name, &field_name);
+ table_name, field_name);
return ref;
}
return this;
@@ -7405,8 +7418,7 @@ Item *get_field_item_for_having(THD *thd, Item *item, st_select_lex *sel)
if (field_item)
{
Item_ref *ref= new (thd->mem_root) Item_ref(thd, &sel->context,
- NullS, NullS,
- &field_item->field_name);
+ field_item->field_name);
return ref;
}
DBUG_ASSERT(0);
@@ -7568,10 +7580,10 @@ void Item_temptable_field::print(String *str, enum_query_type query_type)
Item_ref::Item_ref(THD *thd, Name_resolution_context *context_arg,
- Item **item, const char *table_name_arg,
- const LEX_CSTRING *field_name_arg,
+ Item **item, const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg,
bool alias_name_used_arg):
- Item_ident(thd, context_arg, NullS, table_name_arg, field_name_arg),
+ Item_ident(thd, context_arg, null_clex_str, table_name_arg, field_name_arg),
ref(item), reference_trough_name(0)
{
alias_name_used= alias_name_used_arg;
@@ -7618,7 +7630,7 @@ public:
};
Item_ref::Item_ref(THD *thd, TABLE_LIST *view_arg, Item **item,
- const LEX_CSTRING *field_name_arg,
+ const LEX_CSTRING &field_name_arg,
bool alias_name_used_arg):
Item_ident(thd, view_arg, field_name_arg),
ref(item), reference_trough_name(0)
@@ -8052,7 +8064,7 @@ void Item_ref::print(String *str, enum_query_type query_type)
if ((*ref)->type() != Item::CACHE_ITEM &&
(*ref)->type() != Item::WINDOW_FUNC_ITEM &&
ref_type() != VIEW_REF &&
- !table_name && name.str && alias_name_used)
+ !table_name.str && name.str && alias_name_used)
{
THD *thd= current_thd;
append_identifier(thd, str, &(*ref)->real_item()->name);
@@ -8286,13 +8298,13 @@ void Item_ref::make_send_field(THD *thd, Send_field *field)
/* Non-zero in case of a view */
if (name.str)
field->col_name= name;
- if (table_name)
+ if (table_name.str)
field->table_name= table_name;
- if (db_name)
+ if (db_name.str)
field->db_name= db_name;
if (orig_field_name.str)
field->org_col_name= orig_field_name;
- if (orig_table_name)
+ if (orig_table_name.str)
field->org_table_name= orig_table_name;
}
diff --git a/sql/item.h b/sql/item.h
index 990ca0ec887..5eab1d049f0 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -624,6 +624,13 @@ class st_select_lex_unit;
class Item_func_not;
class Item_splocal;
+/* Item::common_flags */
+/* Indicates that name of this Item autogenerated or set by user */
+#define IS_AUTO_GENERATED_NAME 1
+/* Indicates that this item is in CYCLE clause of WITH */
+#define IS_IN_WITH_CYCLE 2
+
+
/**
String_copier that sends Item specific warnings.
*/
@@ -784,10 +791,11 @@ protected:
/**
Create a field based on the exact data type handler.
*/
- Field *create_table_field_from_handler(TABLE *table)
+ Field *create_table_field_from_handler(MEM_ROOT *root, TABLE *table)
{
const Type_handler *h= type_handler();
- return h->make_and_init_table_field(&name, Record_addr(maybe_null),
+ return h->make_and_init_table_field(root, &name,
+ Record_addr(maybe_null),
*this, table);
}
/**
@@ -800,11 +808,12 @@ protected:
@retval NULL error
@retval !NULL on success
*/
- Field *tmp_table_field_from_field_type(TABLE *table)
+ Field *tmp_table_field_from_field_type(MEM_ROOT *root, TABLE *table)
{
DBUG_ASSERT(is_fixed());
const Type_handler *h= type_handler()->type_handler_for_tmp_table(this);
- return h->make_and_init_table_field(&name, Record_addr(maybe_null),
+ return h->make_and_init_table_field(root, &name,
+ Record_addr(maybe_null),
*this, table);
}
/**
@@ -816,17 +825,20 @@ protected:
- does not need to set Field::is_created_from_null_item for the result
See create_tmp_field_ex() for details on parameters and return values.
*/
- Field *create_tmp_field_ex_simple(TABLE *table,
+ Field *create_tmp_field_ex_simple(MEM_ROOT *root,
+ TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(!param->make_copy_field());
DBUG_ASSERT(!is_result_field());
DBUG_ASSERT(type() != NULL_ITEM);
- return tmp_table_field_from_field_type(table);
+ return tmp_table_field_from_field_type(root, table);
}
- Field *create_tmp_field_int(TABLE *table, uint convert_int_length);
- Field *tmp_table_field_from_field_type_maybe_null(TABLE *table,
+ Field *create_tmp_field_int(MEM_ROOT *root, TABLE *table,
+ uint convert_int_length);
+ Field *tmp_table_field_from_field_type_maybe_null(MEM_ROOT *root,
+ TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param,
bool is_explicit_null);
@@ -926,8 +938,9 @@ public:
True if any item except Item_sum contains a field. Set during parsing.
*/
bool with_field;
- bool is_autogenerated_name; /* indicate was name of this Item
- autogenerated or set by user */
+ uint8 common_flags;
+ bool is_autogenerated_name()
+ { return (common_flags & IS_AUTO_GENERATED_NAME); }
// alloc & destruct is done as start of select on THD::mem_root
Item(THD *thd);
/*
@@ -947,6 +960,11 @@ public:
#endif
} /*lint -e1509 */
void set_name(THD *thd, const char *str, size_t length, CHARSET_INFO *cs);
+ void set_name(THD *thd, const LEX_CSTRING &str,
+ CHARSET_INFO *cs= system_charset_info)
+ {
+ set_name(thd, str.str, str.length, cs);
+ }
void set_name_no_truncate(THD *thd, const char *str, uint length,
CHARSET_INFO *cs);
void init_make_send_field(Send_field *tmp_field, const Type_handler *h);
@@ -1110,9 +1128,9 @@ public:
{
return type_handler()->max_display_length(this);
}
- TYPELIB *get_typelib() const { return NULL; }
+ const TYPELIB *get_typelib() const { return NULL; }
void set_maybe_null(bool maybe_null_arg) { maybe_null= maybe_null_arg; }
- void set_typelib(TYPELIB *typelib)
+ void set_typelib(const TYPELIB *typelib)
{
// Non-field Items (e.g. hybrid functions) never have ENUM/SET types yet.
DBUG_ASSERT(0);
@@ -1459,7 +1477,6 @@ public:
{
return type_handler()->Item_val_bool(this);
}
- virtual String *val_raw(String*) { return 0; }
bool eval_const_cond()
{
@@ -1527,8 +1544,7 @@ public:
int save_str_value_in_field(Field *field, String *result);
virtual Field *get_tmp_table_field() { return 0; }
- virtual Field *create_field_for_create_select(TABLE *table);
- virtual Field *create_field_for_schema(THD *thd, TABLE *table);
+ virtual Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table);
virtual const char *full_name() const { return name.str ? name.str : "???"; }
const char *field_name_or_null()
{ return real_item()->type() == Item::FIELD_ITEM ? name.str : NULL; }
@@ -1807,6 +1823,15 @@ public:
virtual bool need_parentheses_in_default() { return false; }
virtual void save_in_result_field(bool no_conversions) {}
/*
+ Data type format implied by the CHECK CONSTRAINT,
+ to be sent to the client in the result set metadata.
+ */
+ virtual bool set_format_by_check_constraint(Send_field_extended_metadata *)
+ const
+ {
+ return false;
+ }
+ /*
set value of aggregate function in case of no rows for grouping were found
*/
virtual void no_rows_in_result() {}
@@ -2031,6 +2056,44 @@ public:
virtual bool check_index_dependence(void *arg) { return 0; }
/*============== End of Item processor list ======================*/
+ /*
+ Given a condition P from the WHERE clause or from an ON expression of
+ the processed SELECT S and a set of join tables from S marked in the
+ parameter 'allowed'={T} a call of P->find_not_null_fields({T}) has to
+ find the set fields {F} of the tables from 'allowed' such that:
+ - each field from {F} is declared as nullable
+ - each record of table t from {T} that contains NULL as the value for at
+ at least one field from {F} can be ignored when building the result set
+ for S
+ It is assumed here that the condition P is conjunctive and all its column
+ references belong to T.
+
+ Examples:
+ CREATE TABLE t1 (a int, b int);
+ CREATE TABLE t2 (a int, b int);
+
+ SELECT * FROM t1,t2 WHERE t1.a=t2.a and t1.b > 5;
+ A call of find_not_null_fields() for the whole WHERE condition and {t1,t2}
+ should find {t1.a,t1.b,t2.a}
+
+ SELECT * FROM t1 LEFT JOIN ON (t1.a=t2.a and t2.a > t2.b);
+ A call of find_not_null_fields() for the ON expression and {t2}
+ should find {t2.a,t2.b}
+
+ The function returns TRUE if it succeeds to prove that all records of
+ a table from {T} can be ignored. Otherwise it always returns FALSE.
+
+ Example:
+ SELECT * FROM t1,t2 WHERE t1.a=t2.a AND t2.a IS NULL;
+ A call of find_not_null_fields() for the WHERE condition and {t1,t2}
+ will return TRUE.
+
+ It is assumed that the implementation of this virtual function saves
+ the info on the found set of fields in the structures associates with
+ tables from {T}.
+ */
+ virtual bool find_not_null_fields(table_map allowed) { return false; }
+
virtual Item *get_copy(THD *thd)=0;
bool cache_const_expr_analyzer(uchar **arg);
@@ -2095,7 +2158,8 @@ public:
const Type_handler *type_handler_long_or_longlong() const
{
- return Type_handler::type_handler_long_or_longlong(max_char_length());
+ return Type_handler::type_handler_long_or_longlong(max_char_length(),
+ unsigned_flag);
}
/**
@@ -2106,7 +2170,8 @@ public:
@retval NULL (on error)
@retval a pointer to a newly create Field (on success)
*/
- virtual Field *create_tmp_field_ex(TABLE *table,
+ virtual Field *create_tmp_field_ex(MEM_ROOT *root,
+ TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)= 0;
virtual Item_field *field_for_view_update() { return 0; }
@@ -2232,14 +2297,6 @@ public:
is_expensive_cache= walk(&Item::is_expensive_processor, 0, NULL);
return MY_TEST(is_expensive_cache);
}
- virtual Field::geometry_type get_geometry_type() const
- { return Field::GEOM_GEOMETRY; };
- uint uint_geometry_type() const
- { return get_geometry_type(); }
- void set_geometry_type(uint type)
- {
- DBUG_ASSERT(0);
- }
String *check_well_formed_result(String *str, bool send_error= 0);
bool eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs);
bool too_big_for_varchar() const
@@ -2450,56 +2507,6 @@ public:
};
-class Type_geometry_attributes
-{
- uint m_geometry_type;
- static const uint m_geometry_type_unknown= Field::GEOM_GEOMETRYCOLLECTION + 1;
- void copy(const Type_handler *handler, const Type_all_attributes *gattr)
- {
- // Ignore implicit NULLs
- m_geometry_type= handler == &type_handler_geometry ?
- gattr->uint_geometry_type() :
- m_geometry_type_unknown;
- }
-public:
- Type_geometry_attributes()
- :m_geometry_type(m_geometry_type_unknown)
- { }
- Type_geometry_attributes(const Type_handler *handler,
- const Type_all_attributes *gattr)
- :m_geometry_type(m_geometry_type_unknown)
- {
- copy(handler, gattr);
- }
- void join(const Item *item)
- {
- // Ignore implicit NULLs
- if (m_geometry_type == m_geometry_type_unknown)
- copy(item->type_handler(), item);
- else if (item->type_handler() == &type_handler_geometry)
- {
- m_geometry_type=
- Field_geom::geometry_type_merge((Field_geom::geometry_type)
- m_geometry_type,
- (Field_geom::geometry_type)
- item->uint_geometry_type());
- }
- }
- Field::geometry_type get_geometry_type() const
- {
- return m_geometry_type == m_geometry_type_unknown ?
- Field::GEOM_GEOMETRY :
- (Field::geometry_type) m_geometry_type;
- }
- void set_geometry_type(uint type)
- {
- DBUG_ASSERT(type <= m_geometry_type_unknown);
- m_geometry_type= type;
- }
-};
-
-
-
/**
Compare two Items for List<Item>::add_unique()
*/
@@ -2739,7 +2746,8 @@ protected:
}
Item_basic_value(THD *thd): Item(thd) {}
public:
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root,
+ TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
@@ -2751,7 +2759,8 @@ public:
DECLARE c CURSOR FOR SELECT 'test';
OPEN c;
*/
- return tmp_table_field_from_field_type_maybe_null(table, src, param,
+ return tmp_table_field_from_field_type_maybe_null(root,
+ table, src, param,
type() == Item::NULL_ITEM);
}
bool eq(const Item *item, bool binary_cmp) const;
@@ -2823,10 +2832,11 @@ public:
inline bool const_item() const;
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root,
+ TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
- return create_tmp_field_ex_simple(table, src, param);
+ return create_tmp_field_ex_simple(root, table, src, param);
}
inline int save_in_field(Field *field, bool no_conversions);
inline bool send(Protocol *protocol, st_value *buffer);
@@ -2929,8 +2939,8 @@ public:
The inherited implementation would create a column
based on result_type(), which is less exact.
*/
- Field *create_field_for_create_select(TABLE *table)
- { return create_table_field_from_handler(table); }
+ Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table)
+ { return create_table_field_from_handler(root, table); }
bool is_valid_limit_clause_variable_with_error() const
{
@@ -3119,7 +3129,8 @@ public:
return TRUE;
}
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root,
+ TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
/*
@@ -3127,7 +3138,7 @@ public:
DECLARE c CURSOR FOR SELECT NAME_CONST('x','y') FROM t1;
OPEN c;
*/
- return tmp_table_field_from_field_type_maybe_null(table, src, param,
+ return tmp_table_field_from_field_type_maybe_null(root, table, src, param,
type() == Item::NULL_ITEM);
}
int save_in_field(Field *field, bool no_conversions)
@@ -3163,7 +3174,7 @@ public:
class Item_num: public Item_literal
{
public:
- Item_num(THD *thd): Item_literal(thd) { collation.set_numeric(); }
+ Item_num(THD *thd): Item_literal(thd) { collation= DTCollation_numeric(); }
Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs);
bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
@@ -3178,6 +3189,11 @@ class st_select_lex;
class Item_result_field :public Item_fixed_hybrid /* Item with result field */
{
+protected:
+ Field *create_tmp_field_ex_from_handler(MEM_ROOT *root, TABLE *table,
+ Tmp_field_src *src,
+ const Tmp_field_param *param,
+ const Type_handler *h);
public:
Field *result_field; /* Save result here */
Item_result_field(THD *thd): Item_fixed_hybrid(thd), result_field(0) {}
@@ -3187,8 +3203,13 @@ public:
{}
~Item_result_field() {} /* Required with gcc 2.95 */
Field *get_tmp_table_field() { return result_field; }
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
- const Tmp_field_param *param);
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param)
+ {
+ DBUG_ASSERT(fixed);
+ const Type_handler *h= type_handler()->type_handler_for_tmp_table(this);
+ return create_tmp_field_ex_from_handler(root, table, src, param, h);
+ }
void get_tmp_field_src(Tmp_field_src *src, const Tmp_field_param *param);
/*
This implementation of used_tables() used by Item_avg_field and
@@ -3215,14 +3236,14 @@ protected:
updated during fix_fields() to values from Field object and life-time
of those is shorter than life-time of Item_field.
*/
- const char *orig_db_name;
- const char *orig_table_name;
+ LEX_CSTRING orig_db_name;
+ LEX_CSTRING orig_table_name;
LEX_CSTRING orig_field_name;
public:
Name_resolution_context *context;
- const char *db_name;
- const char *table_name;
+ LEX_CSTRING db_name;
+ LEX_CSTRING table_name;
LEX_CSTRING field_name;
bool alias_name_used; /* true if item was resolved against alias */
/*
@@ -3252,10 +3273,10 @@ public:
*/
bool can_be_depended;
Item_ident(THD *thd, Name_resolution_context *context_arg,
- const char *db_name_arg, const char *table_name_arg,
- const LEX_CSTRING *field_name_arg);
+ const LEX_CSTRING &db_name_arg, const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg);
Item_ident(THD *thd, Item_ident *item);
- Item_ident(THD *thd, TABLE_LIST *view_arg, const LEX_CSTRING *field_name_arg);
+ Item_ident(THD *thd, TABLE_LIST *view_arg, const LEX_CSTRING &field_name_arg);
const char *full_name() const;
void cleanup();
st_select_lex *get_depended_from() const;
@@ -3286,12 +3307,19 @@ public:
if any_privileges set to TRUE then here real effective privileges will
be stored
*/
- uint have_privileges;
+ privilege_t have_privileges;
/* field need any privileges (for VIEW creation) */
bool any_privileges;
Item_field(THD *thd, Name_resolution_context *context_arg,
- const char *db_arg,const char *table_name_arg,
- const LEX_CSTRING *field_name_arg);
+ const LEX_CSTRING &db_arg, const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg);
+ Item_field(THD *thd, Name_resolution_context *context_arg,
+ const LEX_CSTRING &field_name_arg)
+ :Item_field(thd, context_arg, null_clex_str, null_clex_str, field_name_arg)
+ { }
+ Item_field(THD *thd, Name_resolution_context *context_arg)
+ :Item_field(thd, context_arg, null_clex_str, null_clex_str, null_clex_str)
+ { }
/*
Constructor needed to process subselect with temporary tables (see Item)
*/
@@ -3368,12 +3396,13 @@ public:
return &type_handler_null;
return field->type_handler();
}
- Field *create_tmp_field_from_item_field(TABLE *new_table,
+ Field *create_tmp_field_from_item_field(MEM_ROOT *root, TABLE *new_table,
Item_ref *orig_item,
const Tmp_field_param *param);
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root,
+ TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param);
- TYPELIB *get_typelib() const { return field->get_typelib(); }
+ const TYPELIB *get_typelib() const { return field->get_typelib(); }
enum_monotonicity_info get_monotonicity_info() const
{
return MONOTONIC_STRICT_INCREASING;
@@ -3425,6 +3454,7 @@ public:
bool is_result_field() { return false; }
void save_in_result_field(bool no_conversions);
Item *get_tmp_table_item(THD *thd);
+ bool find_not_null_fields(table_map allowed);
bool collect_item_field_processor(void * arg);
bool add_field_to_set_processor(void * arg);
bool find_item_in_field_list_processor(void *arg);
@@ -3490,11 +3520,6 @@ public:
DBUG_ASSERT(fixed);
return field->table->pos_in_table_list->outer_join;
}
- Field::geometry_type get_geometry_type() const
- {
- DBUG_ASSERT(field_type() == MYSQL_TYPE_GEOMETRY);
- return field->get_geometry_type();
- }
bool check_index_dependence(void *arg);
friend class Item_default_value;
friend class Item_insert_value;
@@ -3625,7 +3650,7 @@ public:
{
return result_field->type();
}
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(0);
@@ -3672,8 +3697,7 @@ public:
class Item_param :public Item_basic_value,
private Settable_routine_parameter,
public Rewritable_query_parameter,
- private Type_handler_hybrid_field_type,
- public Type_geometry_attributes
+ private Type_handler_hybrid_field_type
{
/*
NO_VALUE is a special value meaning that the parameter has not been
@@ -3832,12 +3856,6 @@ public:
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
- Field::geometry_type get_geometry_type() const
- { return Type_geometry_attributes::get_geometry_type(); };
-
- void set_geometry_type(uint type)
- { Type_geometry_attributes::set_geometry_type(type); }
-
Item_param(THD *thd, const LEX_CSTRING *name_arg,
uint pos_in_query_arg, uint len_in_query_arg);
@@ -3980,7 +3998,7 @@ public:
bool set_limit_clause_param(longlong nr)
{
- value.set_handler(&type_handler_longlong);
+ value.set_handler(&type_handler_slonglong);
set_int(nr, MY_INT64_NUM_DECIMAL_DIGITS);
return !unsigned_flag && value.integer < 0;
}
@@ -4100,8 +4118,8 @@ public:
Item_int(THD *thd, const char *str_arg, size_t length=64);
const Type_handler *type_handler() const
{ return type_handler_long_or_longlong(); }
- Field *create_field_for_create_select(TABLE *table)
- { return tmp_table_field_from_field_type(table); }
+ Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table)
+ { return tmp_table_field_from_field_type(root, table); }
const longlong *const_ptr_longlong() const { return &value; }
longlong val_int() { return value; }
longlong val_int_min() const { return value; }
@@ -4295,7 +4313,7 @@ protected:
const Metadata metadata)
{
fix_from_value(dv, metadata);
- set_name(thd, str_value.ptr(), str_value.length(), str_value.charset());
+ set_name(thd, str_value.lex_cstring(), str_value.charset());
}
protected:
/* Just create an item and do not fill string representation */
@@ -4342,21 +4360,21 @@ public:
fix_and_set_name_from_value(thd, dv, Metadata(&str_value, repertoire));
}
// Constructors with an externally provided item name
- Item_string(THD *thd, const char *name_par, const char *str, size_t length,
+ Item_string(THD *thd, const LEX_CSTRING &name_par, const LEX_CSTRING &str,
CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE)
:Item_literal(thd)
{
- str_value.set_or_copy_aligned(str, length, cs);
+ str_value.set_or_copy_aligned(str.str, str.length, cs);
fix_from_value(dv, Metadata(&str_value));
- set_name(thd, name_par,safe_strlen(name_par), system_charset_info);
+ set_name(thd, name_par);
}
- Item_string(THD *thd, const char *name_par, const char *str, size_t length,
+ Item_string(THD *thd, const LEX_CSTRING &name_par, const LEX_CSTRING &str,
CHARSET_INFO *cs, Derivation dv, uint repertoire)
:Item_literal(thd)
{
- str_value.set_or_copy_aligned(str, length, cs);
+ str_value.set_or_copy_aligned(str.str, str.length, cs);
fix_from_value(dv, Metadata(&str_value, repertoire));
- set_name(thd, name_par, safe_strlen(name_par), system_charset_info);
+ set_name(thd, name_par);
}
void print_value(String *to) const
{
@@ -4431,13 +4449,13 @@ public:
class Item_string_with_introducer :public Item_string
{
public:
- Item_string_with_introducer(THD *thd, const char *str, uint length,
+ Item_string_with_introducer(THD *thd, const LEX_CSTRING &str,
CHARSET_INFO *cs):
- Item_string(thd, str, length, cs)
+ Item_string(thd, str.str, str.length, cs)
{ }
- Item_string_with_introducer(THD *thd, const char *name_arg,
- const char *str, uint length, CHARSET_INFO *tocs):
- Item_string(thd, name_arg, str, length, tocs)
+ Item_string_with_introducer(THD *thd, const LEX_CSTRING &name_arg,
+ const LEX_CSTRING &str, CHARSET_INFO *tocs):
+ Item_string(thd, name_arg, str, tocs)
{ }
virtual bool is_cs_specified() const
{
@@ -4474,14 +4492,14 @@ public:
class Item_static_string_func :public Item_string
{
- const char *func_name;
+ const LEX_CSTRING func_name;
public:
- Item_static_string_func(THD *thd, const char *name_par, const char *str,
- uint length, CHARSET_INFO *cs,
+ Item_static_string_func(THD *thd, const LEX_CSTRING &name_par,
+ const LEX_CSTRING &str, CHARSET_INFO *cs,
Derivation dv= DERIVATION_COERCIBLE):
- Item_string(thd, NullS, str, length, cs, dv), func_name(name_par)
+ Item_string(thd, LEX_CSTRING({NullS,0}), str, cs, dv), func_name(name_par)
{}
- Item_static_string_func(THD *thd, const char *name_par,
+ Item_static_string_func(THD *thd, const LEX_CSTRING &name_par,
const String *str,
CHARSET_INFO *tocs, uint *conv_errors,
Derivation dv, uint repertoire):
@@ -4490,7 +4508,7 @@ public:
{}
Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
{
- return const_charset_converter(thd, tocs, true, func_name);
+ return const_charset_converter(thd, tocs, true, func_name.str);
}
virtual inline void print(String *str, enum_query_type query_type)
@@ -4503,7 +4521,7 @@ public:
bool check_vcol_func_processor(void *arg)
{ // VCOL_TIME_FUNC because the value is not constant, but does not
// require fix_fields() to be re-run for every statement.
- return mark_unsupported_function(func_name, arg, VCOL_TIME_FUNC);
+ return mark_unsupported_function(func_name.str, arg, VCOL_TIME_FUNC);
}
};
@@ -4512,53 +4530,16 @@ public:
class Item_partition_func_safe_string: public Item_string
{
public:
- Item_partition_func_safe_string(THD *thd, const char *name_arg, uint length,
- CHARSET_INFO *cs= NULL):
- Item_string(thd, name_arg, length, cs)
- {}
- bool check_vcol_func_processor(void *arg)
- {
- return mark_unsupported_function("safe_string", arg, VCOL_IMPOSSIBLE);
- }
-};
-
-
-class Item_return_date_time :public Item_partition_func_safe_string
-{
- enum_field_types date_time_field_type;
-public:
- Item_return_date_time(THD *thd, const char *name_arg, uint length_arg,
- enum_field_types field_type_arg, uint dec_arg= 0):
- Item_partition_func_safe_string(thd, name_arg, length_arg, &my_charset_bin),
- date_time_field_type(field_type_arg)
- { decimals= dec_arg; }
- const Type_handler *type_handler() const
- {
- return Type_handler::get_handler_by_field_type(date_time_field_type);
- }
-};
-
-
-class Item_blob :public Item_partition_func_safe_string
-{
-public:
- Item_blob(THD *thd, const char *name_arg, uint length):
- Item_partition_func_safe_string(thd, name_arg, (uint) safe_strlen(name_arg),
- &my_charset_bin)
- { max_length= length; }
- enum Type type() const { return TYPE_HOLDER; }
- const Type_handler *type_handler() const
+ Item_partition_func_safe_string(THD *thd, const LEX_CSTRING &name_arg,
+ uint length, CHARSET_INFO *cs):
+ Item_string(thd, name_arg, LEX_CSTRING({0,0}), cs)
{
- return Type_handler::blob_type_handler(max_length);
+ max_length= length;
}
- const Type_handler *real_type_handler() const
+ bool check_vcol_func_processor(void *arg)
{
- // Should not be called, Item_blob is used for SHOW purposes only.
- DBUG_ASSERT(0);
- return &type_handler_varchar;
+ return mark_unsupported_function("safe_string", arg, VCOL_IMPOSSIBLE);
}
- Field *create_field_for_schema(THD *thd, TABLE *table)
- { return tmp_table_field_from_field_type(table); }
};
@@ -4571,15 +4552,15 @@ public:
class Item_empty_string :public Item_partition_func_safe_string
{
public:
- Item_empty_string(THD *thd, const char *header,uint length,
- CHARSET_INFO *cs= NULL):
- Item_partition_func_safe_string(thd, "", 0,
- cs ? cs : &my_charset_utf8_general_ci)
- {
- name.str= header;
- name.length= strlen(name.str);
- max_length= length * collation.collation->mbmaxlen;
- }
+ Item_empty_string(THD *thd, const LEX_CSTRING &header, uint length,
+ CHARSET_INFO *cs= &my_charset_utf8mb3_general_ci)
+ :Item_partition_func_safe_string(thd, header, length * cs->mbmaxlen, cs)
+ { }
+ Item_empty_string(THD *thd, const char *header, uint length,
+ CHARSET_INFO *cs= &my_charset_utf8mb3_general_ci)
+ :Item_partition_func_safe_string(thd, LEX_CSTRING({header, strlen(header)}),
+ length * cs->mbmaxlen, cs)
+ { }
void make_send_field(THD *thd, Send_field *field);
};
@@ -4596,7 +4577,9 @@ public:
}
const Type_handler *type_handler() const
{
- return Type_handler::get_handler_by_field_type(int_field_type);
+ const Type_handler *h=
+ Type_handler::get_handler_by_field_type(int_field_type);
+ return unsigned_flag ? h->type_handler_unsigned() : h;
}
};
@@ -4776,14 +4759,14 @@ public:
Item_temporal_literal(THD *thd, const MYSQL_TIME *ltime)
:Item_literal(thd)
{
- collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII);
+ collation= DTCollation_numeric();
decimals= 0;
cached_time= *ltime;
}
Item_temporal_literal(THD *thd, const MYSQL_TIME *ltime, uint dec_arg):
Item_literal(thd)
{
- collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII);
+ collation= DTCollation_numeric();
decimals= dec_arg;
cached_time= *ltime;
}
@@ -5173,10 +5156,14 @@ public:
Item **ref;
bool reference_trough_name;
Item_ref(THD *thd, Name_resolution_context *context_arg,
- const char *db_arg, const char *table_name_arg,
- const LEX_CSTRING *field_name_arg):
+ const LEX_CSTRING &db_arg, const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg):
Item_ident(thd, context_arg, db_arg, table_name_arg, field_name_arg),
set_properties_only(0), ref(0), reference_trough_name(1) {}
+ Item_ref(THD *thd, Name_resolution_context *context_arg,
+ const LEX_CSTRING &field_name_arg)
+ :Item_ref(thd, context_arg, null_clex_str, null_clex_str, field_name_arg)
+ { }
/*
This constructor is used in two scenarios:
A) *item = NULL
@@ -5192,10 +5179,10 @@ public:
with Bar, and if we have a more broader set of problems like this.
*/
Item_ref(THD *thd, Name_resolution_context *context_arg, Item **item,
- const char *table_name_arg, const LEX_CSTRING *field_name_arg,
+ const LEX_CSTRING &table_name_arg, const LEX_CSTRING &field_name_arg,
bool alias_name_used_arg= FALSE);
Item_ref(THD *thd, TABLE_LIST *view_arg, Item **item,
- const LEX_CSTRING *field_name_arg, bool alias_name_used_arg= FALSE);
+ const LEX_CSTRING &field_name_arg, bool alias_name_used_arg= FALSE);
/* Constructor need to process subselect with temporary tables (see Item) */
Item_ref(THD *thd, Item_ref *item)
@@ -5242,7 +5229,7 @@ public:
Field *get_tmp_table_field()
{ return result_field ? result_field : (*ref)->get_tmp_table_field(); }
Item *get_tmp_table_item(THD *thd);
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param);
Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *);
table_map used_tables() const;
@@ -5271,6 +5258,10 @@ public:
{
return depended_from ? 0 : (*ref)->not_null_tables();
}
+ bool find_not_null_fields(table_map allowed)
+ {
+ return depended_from ? false : (*ref)->find_not_null_fields(allowed);
+ }
void save_in_result_field(bool no_conversions)
{
(*ref)->save_in_field(result_field, no_conversions);
@@ -5279,7 +5270,7 @@ public:
{
return ref ? (*ref)->real_item() : this;
}
- TYPELIB *get_typelib() const
+ const TYPELIB *get_typelib() const
{
return ref ? (*ref)->get_typelib() : NULL;
}
@@ -5412,8 +5403,8 @@ class Item_direct_ref :public Item_ref
{
public:
Item_direct_ref(THD *thd, Name_resolution_context *context_arg, Item **item,
- const char *table_name_arg,
- const LEX_CSTRING *field_name_arg,
+ const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg,
bool alias_name_used_arg= FALSE):
Item_ref(thd, context_arg, item, table_name_arg,
field_name_arg, alias_name_used_arg)
@@ -5421,7 +5412,7 @@ public:
/* Constructor need to process subselect with temporary tables (see Item) */
Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {}
Item_direct_ref(THD *thd, TABLE_LIST *view_arg, Item **item,
- const LEX_CSTRING *field_name_arg,
+ const LEX_CSTRING &field_name_arg,
bool alias_name_used_arg= FALSE):
Item_ref(thd, view_arg, item, field_name_arg,
alias_name_used_arg)
@@ -5461,7 +5452,7 @@ class Item_direct_ref_to_ident :public Item_direct_ref
public:
Item_direct_ref_to_ident(THD *thd, Item_ident *item):
Item_direct_ref(thd, item->context, (Item**)&item, item->table_name,
- &item->field_name, FALSE)
+ item->field_name, FALSE)
{
ident= item;
ref= (Item**)&ident;
@@ -5653,8 +5644,8 @@ class Item_direct_view_ref :public Item_direct_ref
public:
Item_direct_view_ref(THD *thd, Name_resolution_context *context_arg,
Item **item,
- const char *table_name_arg,
- LEX_CSTRING *field_name_arg,
+ LEX_CSTRING &table_name_arg,
+ LEX_CSTRING &field_name_arg,
TABLE_LIST *view_arg):
Item_direct_ref(thd, context_arg, item, table_name_arg, field_name_arg),
item_equal(0), view(view_arg),
@@ -5836,7 +5827,7 @@ public:
Item_outer_ref(THD *thd, Name_resolution_context *context_arg,
Item_field *outer_field_arg):
Item_direct_ref(thd, context_arg, 0, outer_field_arg->table_name,
- &outer_field_arg->field_name),
+ outer_field_arg->field_name),
outer_ref(outer_field_arg), in_sum_func(0),
found_in_select_list(0), found_in_group_by(0)
{
@@ -5845,7 +5836,7 @@ public:
fixed= 0; /* reset flag set in set_properties() */
}
Item_outer_ref(THD *thd, Name_resolution_context *context_arg, Item **item,
- const char *table_name_arg, LEX_CSTRING *field_name_arg,
+ const LEX_CSTRING &table_name_arg, LEX_CSTRING &field_name_arg,
bool alias_name_used_arg):
Item_direct_ref(thd, context_arg, item, table_name_arg, field_name_arg,
alias_name_used_arg),
@@ -5886,8 +5877,8 @@ protected:
public:
Item_ref_null_helper(THD *thd, Name_resolution_context *context_arg,
Item_in_subselect* master, Item **item,
- const char *table_name_arg,
- const LEX_CSTRING *field_name_arg):
+ const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg):
Item_ref(thd, context_arg, item, table_name_arg, field_name_arg),
owner(master) {}
void save_val(Field *to);
@@ -5931,14 +5922,11 @@ public:
};
#ifdef MYSQL_SERVER
-#include "gstream.h"
-#include "spatial.h"
#include "item_sum.h"
#include "item_func.h"
#include "item_row.h"
#include "item_cmpfunc.h"
#include "item_strfunc.h"
-#include "item_geofunc.h"
#include "item_timefunc.h"
#include "item_subselect.h"
#include "item_xmlfunc.h"
@@ -6015,7 +6003,7 @@ public:
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(0);
@@ -6255,16 +6243,13 @@ class Item_default_value : public Item_field
public:
Item *arg;
Item_default_value(THD *thd, Name_resolution_context *context_arg)
- :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
- &null_clex_str),
+ :Item_field(thd, context_arg),
arg(NULL) {}
Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a)
- :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
- &null_clex_str),
+ :Item_field(thd, context_arg),
arg(a) {}
Item_default_value(THD *thd, Name_resolution_context *context_arg, Field *a)
- :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
- &null_clex_str),
+ :Item_field(thd, context_arg),
arg(NULL) {}
enum Type type() const { return DEFAULT_VALUE_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
@@ -6351,8 +6336,7 @@ class Item_insert_value : public Item_field
public:
Item *arg;
Item_insert_value(THD *thd, Name_resolution_context *context_arg, Item *a)
- :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
- &null_clex_str),
+ :Item_field(thd, context_arg),
arg(a) {}
bool eq(const Item *item, bool binary_cmp) const;
bool fix_fields(THD *, Item **);
@@ -6413,10 +6397,9 @@ public:
Item_trigger_field(THD *thd, Name_resolution_context *context_arg,
row_version_type row_ver_arg,
- const LEX_CSTRING *field_name_arg,
- ulong priv, const bool ro)
- :Item_field(thd, context_arg,
- (const char *)NULL, (const char *)NULL, field_name_arg),
+ const LEX_CSTRING &field_name_arg,
+ privilege_t priv, const bool ro)
+ :Item_field(thd, context_arg, field_name_arg),
row_version(row_ver_arg), field_idx((uint)-1), original_privilege(priv),
want_privilege(priv), table_grants(NULL), read_only (ro)
{}
@@ -6457,8 +6440,8 @@ private:
want_privilege and cleanup() is responsible for restoring of
original want_privilege once parameter's value is updated).
*/
- ulong original_privilege;
- ulong want_privilege;
+ privilege_t original_privilege;
+ privilege_t want_privilege;
GRANT_INFO *table_grants;
/*
Trigger field is read-only unless it belongs to the NEW row in a
@@ -6538,10 +6521,10 @@ public:
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
- return create_tmp_field_ex_simple(table, src, param);
+ return create_tmp_field_ex_simple(root, table, src, param);
}
virtual void keep_array() {}
@@ -6641,8 +6624,6 @@ class Item_cache_int: public Item_cache
protected:
longlong value;
public:
- Item_cache_int(THD *thd): Item_cache(thd, &type_handler_longlong),
- value(0) {}
Item_cache_int(THD *thd, const Type_handler *handler):
Item_cache(thd, handler), value(0) {}
@@ -7039,11 +7020,10 @@ public:
single SP/PS execution.
*/
class Item_type_holder: public Item,
- public Type_handler_hybrid_field_type,
- public Type_geometry_attributes
+ public Type_handler_hybrid_field_type
{
protected:
- TYPELIB *enum_set_typelib;
+ const TYPELIB *enum_set_typelib;
public:
Item_type_holder(THD *thd, Item *item)
:Item(thd, item),
@@ -7060,12 +7040,12 @@ public:
bool maybe_null_arg)
:Item(thd),
Type_handler_hybrid_field_type(handler),
- Type_geometry_attributes(handler, attr),
enum_set_typelib(attr->get_typelib())
{
name= item->name;
Type_std_attributes::set(*attr);
maybe_null= maybe_null_arg;
+ common_flags= item->common_flags;
}
const Type_handler *type_handler() const
@@ -7079,27 +7059,19 @@ public:
}
enum Type type() const { return TYPE_HOLDER; }
- TYPELIB *get_typelib() const { return enum_set_typelib; }
+ const TYPELIB *get_typelib() const { return enum_set_typelib; }
double val_real();
longlong val_int();
my_decimal *val_decimal(my_decimal *);
String *val_str(String*);
bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
return Item_type_holder::real_type_handler()->
- make_and_init_table_field(&name, Record_addr(maybe_null),
+ make_and_init_table_field(root, &name, Record_addr(maybe_null),
*this, table);
}
- Field::geometry_type get_geometry_type() const
- {
- return Type_geometry_attributes::get_geometry_type();
- }
- void set_geometry_type(uint type)
- {
- Type_geometry_attributes::set_geometry_type(type);
- }
Item* get_copy(THD *thd) { return 0; }
};
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index b23aca2c5f3..7fe16848082 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2009, 2019, MariaDB
+ Copyright (c) 2009, 2020, 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
@@ -33,6 +33,8 @@
#include "sql_parse.h" // check_stack_overrun
#include "sql_base.h" // dynamic_column_error_message
+#define PCRE2_STATIC 1 /* Important on Windows */
+#include "pcre2.h" /* pcre2 header file */
/*
Compare row signature of two expressions
@@ -1230,6 +1232,15 @@ bool Item_in_optimizer::eval_not_null_tables(void *opt_arg)
}
+bool Item_in_optimizer::find_not_null_fields(table_map allowed)
+{
+ if (!(~allowed & used_tables()) && is_top_level_item())
+ {
+ return args[0]->find_not_null_fields(allowed);
+ }
+ return false;
+}
+
void Item_in_optimizer::print(String *str, enum_query_type query_type)
{
if (query_type & QT_PARSABLE)
@@ -2076,7 +2087,17 @@ bool Item_func_between::eval_not_null_tables(void *opt_arg)
(args[1]->not_null_tables() &
args[2]->not_null_tables()));
return 0;
-}
+}
+
+
+bool Item_func_between::find_not_null_fields(table_map allowed)
+{
+ if (negated || !is_top_level_item() || (~allowed & used_tables()))
+ return false;
+ return args[0]->find_not_null_fields(allowed) ||
+ args[1]->find_not_null_fields(allowed) ||
+ args[2]->find_not_null_fields(allowed);
+}
bool Item_func_between::count_sargable_conds(void *arg)
@@ -2134,7 +2155,7 @@ bool Item_func_between::fix_length_and_dec_numeric(THD *thd)
if (cvt_arg1 && cvt_arg2)
{
// Works for all types
- m_comparator.set_handler(&type_handler_longlong);
+ m_comparator.set_handler(&type_handler_slonglong);
}
}
}
@@ -4342,6 +4363,15 @@ Item_func_in::eval_not_null_tables(void *opt_arg)
}
+bool
+Item_func_in::find_not_null_fields(table_map allowed)
+{
+ if (negated || !is_top_level_item() || (~allowed & used_tables()))
+ return 0;
+ return args[0]->find_not_null_fields(allowed);
+}
+
+
void Item_func_in::fix_after_pullout(st_select_lex *new_parent, Item **ref,
bool merge)
{
@@ -4476,7 +4506,7 @@ bool Item_func_in::value_list_convert_const_to_int(THD *thd)
all_converted= false;
}
if (all_converted)
- m_comparator.set_handler(&type_handler_longlong);
+ m_comparator.set_handler(&type_handler_slonglong);
}
}
return thd->is_fatal_error; // Catch errrors in convert_const_to_int
@@ -4945,6 +4975,82 @@ Item_cond::eval_not_null_tables(void *opt_arg)
}
+/**
+ @note
+ This implementation of the virtual function find_not_null_fields()
+ infers null-rejectedness if fields from tables marked in 'allowed' from
+ this condition.
+ Currently only top level AND conjuncts that are not disjunctions are used
+ for the inference. Usage of any top level and-or formula with l OR levels
+ would require a stack of bitmaps for fields of the height h=2*l+1 So we
+ would have to allocate h-1 additional field bitmaps for each table marked
+ in 'allowed'.
+*/
+
+bool
+Item_cond::find_not_null_fields(table_map allowed)
+{
+ Item *item;
+ bool is_and_cond= functype() == Item_func::COND_AND_FUNC;
+ if (!is_and_cond)
+ {
+ /* Now only fields of top AND level conjuncts are taken into account */
+ return false;
+ }
+ uint isnull_func_cnt= 0;
+ List_iterator<Item> li(list);
+ while ((item=li++))
+ {
+ bool is_mult_eq= item->type() == Item::FUNC_ITEM &&
+ ((Item_func *) item)->functype() == Item_func::MULT_EQUAL_FUNC;
+ if (is_mult_eq)
+ {
+ if (!item->find_not_null_fields(allowed))
+ continue;
+ }
+
+ if (~allowed & item->used_tables())
+ continue;
+
+ /* It is assumed that all constant conjuncts are already eliminated */
+
+ /*
+ First infer null-rejectedness of fields from all conjuncts but
+ IS NULL predicates
+ */
+ bool isnull_func= item->type() == Item::FUNC_ITEM &&
+ ((Item_func *) item)->functype() == Item_func::ISNULL_FUNC;
+ if (isnull_func)
+ {
+ isnull_func_cnt++;
+ continue;
+ }
+ if (!item->find_not_null_fields(allowed))
+ continue;
+ }
+
+ /* Now try no get contradictions using IS NULL conjuncts */
+ if (isnull_func_cnt)
+ {
+ li.rewind();
+ while ((item=li++) && isnull_func_cnt)
+ {
+ if (~allowed & item->used_tables())
+ continue;
+
+ bool isnull_func= item->type() == Item::FUNC_ITEM &&
+ ((Item_func *) item)->functype() == Item_func::ISNULL_FUNC;
+ if (isnull_func)
+ {
+ if (item->find_not_null_fields(allowed))
+ return true;
+ isnull_func_cnt--;
+ }
+ }
+ }
+ return false;
+}
+
void Item_cond::fix_after_pullout(st_select_lex *new_parent, Item **ref,
bool merge)
{
@@ -5390,6 +5496,19 @@ longlong Item_func_isnull::val_int()
}
+bool Item_func_isnull::find_not_null_fields(table_map allowed)
+{
+ if (!(~allowed & used_tables()) &&
+ args[0]->real_item()->type() == Item::FIELD_ITEM)
+ {
+ Field *field= ((Item_field *)(args[0]->real_item()))->field;
+ if (bitmap_is_set(&field->table->tmp_set, field->field_index))
+ return true;
+ }
+ return false;
+}
+
+
void Item_func_isnull::print(String *str, enum_query_type query_type)
{
if (const_item() && !args[0]->maybe_null &&
@@ -5484,7 +5603,7 @@ longlong Item_func_like::val_int()
null_value=0;
if (canDoTurboBM)
return turboBM_matches(res->ptr(), res->length()) ? !negated : negated;
- return my_wildcmp(cmp_collation.collation,
+ return cmp_collation.collation->wildcmp(
res->ptr(),res->ptr()+res->length(),
res2->ptr(),res2->ptr()+res2->length(),
escape,wild_one,wild_many) ? negated : !negated;
@@ -5577,14 +5696,14 @@ bool fix_escape_item(THD *thd, Item *escape_item, String *tmp_str,
return TRUE;
}
- if (use_mb(cmp_cs))
+ if (cmp_cs->use_mb())
{
CHARSET_INFO *cs= escape_str->charset();
my_wc_t wc;
- int rc= cs->cset->mb_wc(cs, &wc,
- (const uchar*) escape_str_ptr,
- (const uchar*) escape_str_ptr +
- escape_str->length());
+ int rc= cs->mb_wc(&wc,
+ (const uchar*) escape_str_ptr,
+ (const uchar*) escape_str_ptr +
+ escape_str->length());
*escape= (int) (rc > 0 ? wc : '\\');
}
else
@@ -5652,7 +5771,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
{
const char* tmp = first + 1;
for (; *tmp != wild_many && *tmp != wild_one && *tmp != escape; tmp++) ;
- canDoTurboBM = (tmp == last) && !use_mb(args[0]->collation.collation);
+ canDoTurboBM = (tmp == last) && !args[0]->collation.collation->use_mb();
}
if (canDoTurboBM)
{
@@ -5710,15 +5829,28 @@ int Regexp_processor_pcre::default_regex_flags()
return default_regex_flags_pcre(current_thd);
}
-void Regexp_processor_pcre::set_recursion_limit(THD *thd)
+void Regexp_processor_pcre::cleanup()
{
- long stack_used;
- DBUG_ASSERT(thd == current_thd);
- stack_used= available_stack_size(thd->thread_stack, &stack_used);
- m_pcre_extra.match_limit_recursion=
- (ulong)((my_thread_stack_size - STACK_MIN_SIZE - stack_used)/my_pcre_frame_size);
+ pcre2_match_data_free(m_pcre_match_data);
+ pcre2_code_free(m_pcre);
+ reset();
}
+void Regexp_processor_pcre::init(CHARSET_INFO *data_charset, int extra_flags)
+{
+ m_library_flags= default_regex_flags() | extra_flags |
+ (data_charset != &my_charset_bin ?
+ (PCRE2_UTF | PCRE2_UCP) : 0) |
+ ((data_charset->state &
+ (MY_CS_BINSORT | MY_CS_CSSORT)) ? 0 : PCRE2_CASELESS);
+
+ // Convert text data to utf-8.
+ m_library_charset= data_charset == &my_charset_bin ?
+ &my_charset_bin : &my_charset_utf8mb3_general_ci;
+
+ m_conversion_is_needed= (data_charset != &my_charset_bin) &&
+ !my_charset_same(data_charset, m_library_charset);
+}
/**
Convert string to lib_charset, if needed.
@@ -5752,8 +5884,8 @@ String *Regexp_processor_pcre::convert_if_needed(String *str, String *converter)
bool Regexp_processor_pcre::compile(String *pattern, bool send_error)
{
- const char *pcreErrorStr;
- int pcreErrorOffset;
+ int pcreErrorNumber;
+ PCRE2_SIZE pcreErrorOffset;
if (is_compiled())
{
@@ -5766,19 +5898,39 @@ bool Regexp_processor_pcre::compile(String *pattern, bool send_error)
if (!(pattern= convert_if_needed(pattern, &pattern_converter)))
return true;
- m_pcre= pcre_compile(pattern->c_ptr_safe(), m_library_flags,
- &pcreErrorStr, &pcreErrorOffset, NULL);
+ pcre2_compile_context *cctx= NULL;
+#ifndef pcre2_set_depth_limit
+ // old pcre2 uses stack - put a limit on that (new pcre2 prefers heap)
+ cctx= pcre2_compile_context_create(NULL);
+ pcre2_set_compile_recursion_guard(cctx, [](uint32_t cur, void *end) -> int
+ { return available_stack_size(&cur, end) < STACK_MIN_SIZE; },
+ current_thd->mysys_var->stack_ends_here);
+#endif
+ m_pcre= pcre2_compile((PCRE2_SPTR8) pattern->ptr(), pattern->length(),
+ m_library_flags,
+ &pcreErrorNumber, &pcreErrorOffset, cctx);
+ pcre2_compile_context_free(cctx); // NULL is ok here
if (unlikely(m_pcre == NULL))
{
if (send_error)
{
char buff[MAX_FIELD_WIDTH];
- my_snprintf(buff, sizeof(buff), "%s at offset %d", pcreErrorStr, pcreErrorOffset);
+ int lmsg= pcre2_get_error_message(pcreErrorNumber,
+ (PCRE2_UCHAR8 *)buff, sizeof(buff));
+ if (lmsg >= 0)
+ my_snprintf(buff+lmsg, sizeof(buff)-lmsg,
+ " at offset %d", pcreErrorOffset);
my_error(ER_REGEXP_ERROR, MYF(0), buff);
}
return true;
}
+ m_pcre_match_data= pcre2_match_data_create_from_pattern(m_pcre, NULL);
+ if (m_pcre_match_data == NULL)
+ {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ return true;
+ }
return false;
}
@@ -5799,124 +5951,54 @@ bool Regexp_processor_pcre::compile(Item *item, bool send_error)
*/
void Regexp_processor_pcre::pcre_exec_warn(int rc) const
{
- char buf[64];
- const char *errmsg= NULL;
+ PCRE2_UCHAR8 buf[128];
THD *thd= current_thd;
- /*
- Make a descriptive message only for those pcre_exec() error codes
- that can actually happen in MariaDB.
- */
- switch (rc)
+ int errlen= pcre2_get_error_message(rc, buf, sizeof(buf));
+ if (errlen <= 0)
{
- case PCRE_ERROR_NULL:
- errmsg= "pcre_exec: null argument passed";
- break;
- case PCRE_ERROR_BADOPTION:
- errmsg= "pcre_exec: bad option";
- break;
- case PCRE_ERROR_BADMAGIC:
- errmsg= "pcre_exec: bad magic - not a compiled regex";
- break;
- case PCRE_ERROR_UNKNOWN_OPCODE:
- errmsg= "pcre_exec: error in compiled regex";
- break;
- case PCRE_ERROR_NOMEMORY:
- errmsg= "pcre_exec: Out of memory";
- break;
- case PCRE_ERROR_NOSUBSTRING:
- errmsg= "pcre_exec: no substring";
- break;
- case PCRE_ERROR_MATCHLIMIT:
- errmsg= "pcre_exec: match limit exceeded";
- break;
- case PCRE_ERROR_CALLOUT:
- errmsg= "pcre_exec: callout error";
- break;
- case PCRE_ERROR_BADUTF8:
- errmsg= "pcre_exec: Invalid utf8 byte sequence in the subject string";
- break;
- case PCRE_ERROR_BADUTF8_OFFSET:
- errmsg= "pcre_exec: Started at invalid location within utf8 byte sequence";
- break;
- case PCRE_ERROR_PARTIAL:
- errmsg= "pcre_exec: partial match";
- break;
- case PCRE_ERROR_INTERNAL:
- errmsg= "pcre_exec: internal error";
- break;
- case PCRE_ERROR_BADCOUNT:
- errmsg= "pcre_exec: ovesize is negative";
- break;
- case PCRE_ERROR_RECURSIONLIMIT:
- my_snprintf(buf, sizeof(buf), "pcre_exec: recursion limit of %ld exceeded",
- m_pcre_extra.match_limit_recursion);
- errmsg= buf;
- break;
- case PCRE_ERROR_BADNEWLINE:
- errmsg= "pcre_exec: bad newline options";
- break;
- case PCRE_ERROR_BADOFFSET:
- errmsg= "pcre_exec: start offset negative or greater than string length";
- break;
- case PCRE_ERROR_SHORTUTF8:
- errmsg= "pcre_exec: ended in middle of utf8 sequence";
- break;
- case PCRE_ERROR_JIT_STACKLIMIT:
- errmsg= "pcre_exec: insufficient stack memory for JIT compile";
- break;
- case PCRE_ERROR_RECURSELOOP:
- errmsg= "pcre_exec: Recursion loop detected";
- break;
- case PCRE_ERROR_BADMODE:
- errmsg= "pcre_exec: compiled pattern passed to wrong bit library function";
- break;
- case PCRE_ERROR_BADENDIANNESS:
- errmsg= "pcre_exec: compiled pattern passed to wrong endianness processor";
- break;
- case PCRE_ERROR_JIT_BADOPTION:
- errmsg= "pcre_exec: bad jit option";
- break;
- case PCRE_ERROR_BADLENGTH:
- errmsg= "pcre_exec: negative length";
- break;
- default:
- /*
- As other error codes should normally not happen,
- we just report the error code without textual description
- of the code.
- */
- my_snprintf(buf, sizeof(buf), "pcre_exec: Internal error (%d)", rc);
- errmsg= buf;
+ my_snprintf((char *)buf, sizeof(buf), "pcre_exec: Internal error (%d)", rc);
}
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_REGEXP_ERROR, ER_THD(thd, ER_REGEXP_ERROR), errmsg);
+ ER_REGEXP_ERROR, ER_THD(thd, ER_REGEXP_ERROR), buf);
}
/**
Call pcre_exec() and send a warning if pcre_exec() returned with an error.
*/
-int Regexp_processor_pcre::pcre_exec_with_warn(const pcre *code,
- const pcre_extra *extra,
+int Regexp_processor_pcre::pcre_exec_with_warn(const pcre2_code *code,
+ pcre2_match_data *data,
const char *subject,
int length, int startoffset,
- int options, int *ovector,
- int ovecsize)
-{
- int rc= pcre_exec(code, extra, subject, length,
- startoffset, options, ovector, ovecsize);
+ int options)
+{
+ pcre2_match_context *mctx= NULL;
+#ifndef pcre2_set_depth_limit
+ // old pcre2 uses stack - put a limit on that (new pcre2 prefers heap)
+ mctx= pcre2_match_context_create(NULL);
+ pcre2_set_recursion_limit(mctx,
+ available_stack_size(&mctx, current_thd->mysys_var->stack_ends_here)/544);
+#endif
+ int rc= pcre2_match(code, (PCRE2_SPTR8) subject, (PCRE2_SIZE) length,
+ (PCRE2_SIZE) startoffset, options, data, mctx);
+ pcre2_match_context_free(mctx); // NULL is ok here
DBUG_EXECUTE_IF("pcre_exec_error_123", rc= -123;);
- if (unlikely(rc < PCRE_ERROR_NOMATCH))
+ if (unlikely(rc < PCRE2_ERROR_NOMATCH))
+ {
+ m_SubStrVec= NULL;
pcre_exec_warn(rc);
+ }
+ else
+ m_SubStrVec= pcre2_get_ovector_pointer(data);
return rc;
}
bool Regexp_processor_pcre::exec(const char *str, size_t length, size_t offset)
{
- m_pcre_exec_rc= pcre_exec_with_warn(m_pcre, &m_pcre_extra, str, (int)length, (int)offset, 0,
- m_SubStrVec, array_elements(m_SubStrVec));
+ m_pcre_exec_rc= pcre_exec_with_warn(m_pcre, m_pcre_match_data,
+ str, (int)length, (int)offset, 0);
return false;
}
@@ -5926,10 +6008,8 @@ bool Regexp_processor_pcre::exec(String *str, int offset,
{
if (!(str= convert_if_needed(str, &subject_converter)))
return true;
- m_pcre_exec_rc= pcre_exec_with_warn(m_pcre, &m_pcre_extra,
- str->c_ptr_safe(), str->length(),
- offset, 0,
- m_SubStrVec, array_elements(m_SubStrVec));
+ m_pcre_exec_rc= pcre_exec_with_warn(m_pcre, m_pcre_match_data,
+ str->ptr(), str->length(), offset, 0);
if (m_pcre_exec_rc > 0)
{
uint i;
@@ -5938,10 +6018,9 @@ bool Regexp_processor_pcre::exec(String *str, int offset,
/*
Convert byte offset into character offset.
*/
- m_SubStrVec[i]= (int) str->charset()->cset->numchars(str->charset(),
- str->ptr(),
- str->ptr() +
- m_SubStrVec[i]);
+ m_SubStrVec[i]= (int) str->charset()->numchars(str->ptr(),
+ str->ptr() +
+ m_SubStrVec[i]);
}
}
return false;
@@ -5979,12 +6058,6 @@ void Regexp_processor_pcre::fix_owner(Item_func *owner,
}
-bool Item_func_regex::fix_fields(THD *thd, Item **ref)
-{
- re.set_recursion_limit(thd);
- return Item_bool_func::fix_fields(thd, ref);
-}
-
bool
Item_func_regex::fix_length_and_dec()
{
@@ -6011,13 +6084,6 @@ longlong Item_func_regex::val_int()
}
-bool Item_func_regexp_instr::fix_fields(THD *thd, Item **ref)
-{
- re.set_recursion_limit(thd);
- return Item_int_func::fix_fields(thd, ref);
-}
-
-
bool
Item_func_regexp_instr::fix_length_and_dec()
{
@@ -6040,7 +6106,7 @@ longlong Item_func_regexp_instr::val_int()
if ((null_value= re.exec(args[0], 0, 1)))
return 0;
- return re.match() ? re.subpattern_start(0) + 1 : 0;
+ return re.match() ? (longlong) (re.subpattern_start(0) + 1) : 0;
}
@@ -6415,6 +6481,21 @@ Item *Item_cond_and::neg_transformer(THD *thd) /* NOT(a AND b AND ...) -> */
}
+bool
+Item_cond_and::set_format_by_check_constraint(
+ Send_field_extended_metadata *to) const
+{
+ List_iterator_fast<Item> li(const_cast<List<Item>&>(list));
+ Item *item;
+ while ((item= li++))
+ {
+ if (item->set_format_by_check_constraint(to))
+ return true;
+ }
+ return false;
+}
+
+
Item *Item_cond_or::neg_transformer(THD *thd) /* NOT(a OR b OR ...) -> */
/* NOT a AND NOT b AND ... */
{
@@ -6976,6 +7057,48 @@ void Item_equal::update_used_tables()
}
+/**
+ @note
+ This multiple equality can contains elements belonging not to tables {T}
+ marked in 'allowed' . So we can ascertain null-rejectedness of field f
+ belonging to table t from {T} only if one of the following equality
+ predicate can be extracted from this multiple equality:
+ - f=const
+ - f=f' where f' is a field of some table from {T}
+*/
+
+bool Item_equal::find_not_null_fields(table_map allowed)
+{
+ if (!(allowed & used_tables()))
+ return false;
+ bool checked= false;
+ Item_equal_fields_iterator it(*this);
+ Item *item;
+ while ((item= it++))
+ {
+ if (~allowed & item->used_tables())
+ continue;
+ if ((with_const || checked) && !item->find_not_null_fields(allowed))
+ continue;
+ Item_equal_fields_iterator it1(*this);
+ Item *item1;
+ while ((item1= it1++) && item1 != item)
+ {
+ if (~allowed & item1->used_tables())
+ continue;
+ if (!item->find_not_null_fields(allowed) &&
+ !item1->find_not_null_fields(allowed))
+ {
+ checked= true;
+ break;
+ }
+ }
+ }
+ return false;
+}
+
+
+
bool Item_equal::count_sargable_conds(void *arg)
{
SELECT_LEX *sel= (SELECT_LEX *) arg;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 178ed8360dd..8d5cfb359ec 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -24,8 +24,6 @@
#endif
#include "item_func.h" /* Item_int_func, Item_bool_func */
-#define PCRE_STATIC 1 /* Important on Windows */
-#include "pcre.h" /* pcre header file */
#include "item.h"
extern Item_result item_cmp_type(Item_result a,Item_result b);
@@ -292,6 +290,7 @@ public:
Item_func_truth(thd, a, true, false) {}
~Item_func_isnottrue() {}
virtual const char* func_name() const { return "isnottrue"; }
+ bool find_not_null_fields(table_map allowed) { return false; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_isnottrue>(thd, this); }
bool eval_not_null_tables(void *) { not_null_tables_cache= 0; return false; }
@@ -324,6 +323,7 @@ public:
Item_func_truth(thd, a, false, false) {}
~Item_func_isnotfalse() {}
virtual const char* func_name() const { return "isnotfalse"; }
+ bool find_not_null_fields(table_map allowed) { return false; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_isnotfalse>(thd, this); }
bool eval_not_null_tables(void *) { not_null_tables_cache= 0; return false; }
@@ -386,6 +386,7 @@ public:
virtual void get_cache_parameters(List<Item> &parameters);
bool is_top_level_item();
bool eval_not_null_tables(void *opt_arg);
+ bool find_not_null_fields(table_map allowed);
void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge);
bool invisible_mode();
void reset_cache() { cache= NULL; }
@@ -582,6 +583,7 @@ public:
void print(String *str, enum_query_type query_type)
{ Item_func::print_op(str, query_type); }
longlong val_int();
+ bool find_not_null_fields(table_map allowed) { return false; }
Item *neg_transformer(THD *thd);
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
{
@@ -603,6 +605,7 @@ public:
longlong val_int();
enum Functype functype() const { return NOT_FUNC; }
const char *func_name() const { return "not"; }
+ bool find_not_null_fields(table_map allowed) { return false; }
enum precedence precedence() const { return BANG_PRECEDENCE; }
Item *neg_transformer(THD *thd);
bool fix_fields(THD *, Item **);
@@ -747,6 +750,7 @@ public:
longlong val_int();
bool fix_length_and_dec();
table_map not_null_tables() const { return 0; }
+ bool find_not_null_fields(table_map allowed) { return false; }
enum Functype functype() const { return EQUAL_FUNC; }
enum Functype rev_functype() const { return EQUAL_FUNC; }
cond_result eq_cmp_result() const { return COND_TRUE; }
@@ -924,6 +928,7 @@ public:
bool fix_length_and_dec_numeric(THD *);
virtual void print(String *str, enum_query_type query_type);
bool eval_not_null_tables(void *opt_arg);
+ bool find_not_null_fields(table_map allowed);
void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge);
bool count_sargable_conds(void *arg);
void add_key_fields(JOIN *join, KEY_FIELD **key_fields,
@@ -1425,7 +1430,7 @@ public:
((Item_int*) item)->unsigned_flag= (bool)
((packed_longlong*) base)[pos].unsigned_flag;
}
- const Type_handler *type_handler() const { return &type_handler_longlong; }
+ const Type_handler *type_handler() const { return &type_handler_slonglong; }
friend int cmp_longlong(void *cmp_arg, packed_longlong *a,packed_longlong *b);
};
@@ -2449,6 +2454,7 @@ public:
const char *func_name() const { return "in"; }
enum precedence precedence() const { return CMP_PRECEDENCE; }
bool eval_not_null_tables(void *opt_arg);
+ bool find_not_null_fields(table_map allowed);
void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge);
bool count_sargable_conds(void *arg);
Item *get_copy(THD *thd)
@@ -2593,6 +2599,7 @@ public:
COND *remove_eq_conds(THD *thd, Item::cond_result *cond_value,
bool top_level);
table_map not_null_tables() const { return 0; }
+ bool find_not_null_fields(table_map allowed);
Item *neg_transformer(THD *thd);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_isnull>(thd, this); }
@@ -2793,53 +2800,38 @@ public:
};
+typedef struct pcre2_real_code_8 pcre2_code;
+typedef struct pcre2_real_match_data_8 pcre2_match_data;
+#define PCRE2_SIZE size_t
class Regexp_processor_pcre
{
- pcre *m_pcre;
- pcre_extra m_pcre_extra;
+ pcre2_code *m_pcre;
+ pcre2_match_data *m_pcre_match_data;
bool m_conversion_is_needed;
bool m_is_const;
int m_library_flags;
- CHARSET_INFO *m_data_charset;
CHARSET_INFO *m_library_charset;
String m_prev_pattern;
int m_pcre_exec_rc;
- int m_SubStrVec[30];
+ PCRE2_SIZE *m_SubStrVec;
void pcre_exec_warn(int rc) const;
- int pcre_exec_with_warn(const pcre *code, const pcre_extra *extra,
+ int pcre_exec_with_warn(const pcre2_code *code,
+ pcre2_match_data *data,
const char *subject, int length, int startoffset,
- int options, int *ovector, int ovecsize);
+ int options);
public:
String *convert_if_needed(String *src, String *converter);
String subject_converter;
String pattern_converter;
String replace_converter;
Regexp_processor_pcre() :
- m_pcre(NULL), m_conversion_is_needed(true), m_is_const(0),
+ m_pcre(NULL), m_pcre_match_data(NULL),
+ m_conversion_is_needed(true), m_is_const(0),
m_library_flags(0),
- m_data_charset(&my_charset_utf8_general_ci),
- m_library_charset(&my_charset_utf8_general_ci)
- {
- m_pcre_extra.flags= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
- m_pcre_extra.match_limit_recursion= 100L;
- }
+ m_library_charset(&my_charset_utf8mb3_general_ci)
+ {}
int default_regex_flags();
- void set_recursion_limit(THD *);
- void init(CHARSET_INFO *data_charset, int extra_flags)
- {
- m_library_flags= default_regex_flags() | extra_flags |
- (data_charset != &my_charset_bin ?
- (PCRE_UTF8 | PCRE_UCP) : 0) |
- ((data_charset->state &
- (MY_CS_BINSORT | MY_CS_CSSORT)) ? 0 : PCRE_CASELESS);
-
- // Convert text data to utf-8.
- m_library_charset= data_charset == &my_charset_bin ?
- &my_charset_bin : &my_charset_utf8_general_ci;
-
- m_conversion_is_needed= (data_charset != &my_charset_bin) &&
- !my_charset_same(data_charset, m_library_charset);
- }
+ void init(CHARSET_INFO *data_charset, int extra_flags);
void fix_owner(Item_func *owner, Item *subject_arg, Item *pattern_arg);
bool compile(String *pattern, bool send_error);
bool compile(Item *item, bool send_error);
@@ -2852,28 +2844,25 @@ public:
bool exec(Item *item, int offset, uint n_result_offsets_to_convert);
bool match() const { return m_pcre_exec_rc < 0 ? 0 : 1; }
int nsubpatterns() const { return m_pcre_exec_rc <= 0 ? 0 : m_pcre_exec_rc; }
- int subpattern_start(int n) const
+ size_t subpattern_start(int n) const
{
return m_pcre_exec_rc <= 0 ? 0 : m_SubStrVec[n * 2];
}
- int subpattern_end(int n) const
+ size_t subpattern_end(int n) const
{
return m_pcre_exec_rc <= 0 ? 0 : m_SubStrVec[n * 2 + 1];
}
- int subpattern_length(int n) const
+ size_t subpattern_length(int n) const
{
return subpattern_end(n) - subpattern_start(n);
}
void reset()
{
m_pcre= NULL;
+ m_pcre_match_data= NULL;
m_prev_pattern.length(0);
}
- void cleanup()
- {
- pcre_free(m_pcre);
- reset();
- }
+ void cleanup();
bool is_compiled() const { return m_pcre != NULL; }
bool is_const() const { return m_is_const; }
void set_const(bool arg) { m_is_const= arg; }
@@ -2896,7 +2885,6 @@ public:
DBUG_VOID_RETURN;
}
longlong val_int();
- bool fix_fields(THD *thd, Item **ref);
bool fix_length_and_dec();
const char *func_name() const { return "regexp"; }
enum precedence precedence() const { return CMP_PRECEDENCE; }
@@ -2937,7 +2925,6 @@ public:
DBUG_VOID_RETURN;
}
longlong val_int();
- 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 0; }
@@ -3017,6 +3004,7 @@ public:
Item *compile(THD *thd, Item_analyzer analyzer, uchar **arg_p,
Item_transformer transformer, uchar *arg_t);
bool eval_not_null_tables(void *opt_arg);
+ bool find_not_null_fields(table_map allowed);
Item *build_clone(THD *thd);
bool excl_dep_on_table(table_map tab_map);
bool excl_dep_on_grouping_fields(st_select_lex *sel);
@@ -3182,6 +3170,7 @@ public:
eval_item= NULL;
}
void update_used_tables();
+ bool find_not_null_fields(table_map allowed);
COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
bool link_item_fields,
COND_EQUAL **cond_equal_ref);
@@ -3360,6 +3349,7 @@ public:
COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
bool link_item_fields,
COND_EQUAL **cond_equal_ref);
+ bool set_format_by_check_constraint(Send_field_extended_metadata *to) const;
void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
table_map usable_tables, SARGABLE_PARAM **sargables);
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 9b949835e27..edf44fc3cd3 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -33,118 +33,46 @@
#include "set_var.h"
#include "sp_head.h"
#include "sp.h"
-#include "item_inetfunc.h"
#include "sql_time.h"
+#include "sql_type_geom.h"
+#include <mysql/plugin_function.h>
-/*
-=============================================================================
- LOCAL DECLARATIONS
-=============================================================================
-*/
-
-/**
- Adapter for functions that takes exactly zero arguments.
-*/
-
-class Create_func_arg0 : public Create_func
-{
-public:
- virtual Item *create_func(THD *thd, LEX_CSTRING *name,
- List<Item> *item_list);
- /**
- Builder method, with no arguments.
- @param thd The current thread
- @return An item representing the function call
- */
- virtual Item *create_builder(THD *thd) = 0;
-
-protected:
- /** Constructor. */
- Create_func_arg0() {}
- /** Destructor. */
- virtual ~Create_func_arg0() {}
-};
-
-
-/**
- Adapter for functions that takes exactly one argument.
-*/
-
-class Create_func_arg1 : public Create_func
+extern "C" uchar*
+get_native_fct_hash_key(const uchar *buff, size_t *length,
+ my_bool /* unused */)
{
-public:
- virtual Item *create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
-
- /**
- Builder method, with one argument.
- @param thd The current thread
- @param arg1 The first argument of the function
- @return An item representing the function call
- */
- virtual Item *create_1_arg(THD *thd, Item *arg1) = 0;
-
-protected:
- /** Constructor. */
- Create_func_arg1() {}
- /** Destructor. */
- virtual ~Create_func_arg1() {}
-};
-
+ Native_func_registry *func= (Native_func_registry*) buff;
+ *length= func->name.length;
+ return (uchar*) func->name.str;
+}
-/**
- Adapter for functions that takes exactly two arguments.
-*/
-class Create_func_arg2 : public Create_func
+bool Native_func_registry_array::append_to_hash(HASH *hash) const
{
-public:
- virtual Item *create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+ DBUG_ENTER("Native_func_registry_array::append_to_hash");
+ for (size_t i= 0; i < count(); i++)
+ {
+ const Native_func_registry &func= element(i);
+ DBUG_ASSERT(func.builder != NULL);
+ if (my_hash_insert(hash, (uchar*) &func))
+ DBUG_RETURN(true);
+ }
+ DBUG_RETURN(false);
+}
- /**
- Builder method, with two arguments.
- @param thd The current thread
- @param arg1 The first argument of the function
- @param arg2 The second argument of the function
- @return An item representing the function call
- */
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) = 0;
-protected:
- /** Constructor. */
- Create_func_arg2() {}
- /** Destructor. */
- virtual ~Create_func_arg2() {}
-};
+#ifdef HAVE_SPATIAL
+extern Native_func_registry_array native_func_registry_array_geom;
+#endif
-/**
- Adapter for functions that takes exactly three arguments.
+/*
+=============================================================================
+ LOCAL DECLARATIONS
+=============================================================================
*/
-class Create_func_arg3 : public Create_func
-{
-public:
- virtual Item *create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
-
- /**
- Builder method, with three arguments.
- @param thd The current thread
- @param arg1 The first argument of the function
- @param arg2 The second argument of the function
- @param arg3 The third argument of the function
- @return An item representing the function call
- */
- virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3) = 0;
-
-protected:
- /** Constructor. */
- Create_func_arg3() {}
- /** Destructor. */
- virtual ~Create_func_arg3() {}
-};
-
-
/**
Function builder for Stored Functions.
*/
@@ -165,30 +93,6 @@ protected:
};
-#ifndef HAVE_SPATIAL
-/**
- Common (non) builder for geometry functions.
- This builder is used in <code>--without-geometry</code> builds only,
- to report an error.
-*/
-
-class Create_func_no_geom : public Create_func
-{
-public:
- virtual Item *create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
-
- /** Singleton. */
- static Create_func_no_geom s_singleton;
-
-protected:
- /** Constructor. */
- Create_func_no_geom() {}
- /** Destructor. */
- virtual ~Create_func_no_geom() {}
-};
-#endif
-
-
/*
Concrete functions builders (native functions).
Please keep this list sorted in alphabetical order,
@@ -260,51 +164,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_area : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_area s_singleton;
-
-protected:
- Create_func_area() {}
- virtual ~Create_func_area() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_as_wkb : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_as_wkb s_singleton;
-
-protected:
- Create_func_as_wkb() {}
- virtual ~Create_func_as_wkb() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_as_wkt : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_as_wkt s_singleton;
-
-protected:
- Create_func_as_wkt() {}
- virtual ~Create_func_as_wkt() {}
-};
-#endif
-
-
class Create_func_asin : public Create_func_arg1
{
public:
@@ -409,20 +268,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_centroid : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_centroid s_singleton;
-
-protected:
- Create_func_centroid() {}
- virtual ~Create_func_centroid() {}
-};
-
-
class Create_func_chr : public Create_func_arg1
{
public:
@@ -436,35 +281,6 @@ protected:
};
-class Create_func_convexhull : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_convexhull s_singleton;
-
-protected:
- Create_func_convexhull() {}
- virtual ~Create_func_convexhull() {}
-};
-
-
-class Create_func_pointonsurface : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_pointonsurface s_singleton;
-
-protected:
- Create_func_pointonsurface() {}
- virtual ~Create_func_pointonsurface() {}
-};
-
-
-#endif /*HAVE_SPATIAL*/
-
-
class Create_func_char_length : public Create_func_arg1
{
public:
@@ -630,34 +446,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_mbr_contains : public Create_func_arg2
-{
- public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_mbr_contains s_singleton;
-
- protected:
- Create_func_mbr_contains() {}
- virtual ~Create_func_mbr_contains() {}
-};
-
-
-class Create_func_contains : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_contains s_singleton;
-
-protected:
- Create_func_contains() {}
- virtual ~Create_func_contains() {}
-};
-#endif
-
-
class Create_func_nvl2 : public Create_func_arg3
{
public:
@@ -736,21 +524,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_crosses : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_crosses s_singleton;
-
-protected:
- Create_func_crosses() {}
- virtual ~Create_func_crosses() {}
-};
-#endif
-
-
class Create_func_datediff : public Create_func_arg2
{
public:
@@ -855,62 +628,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_dimension : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_dimension s_singleton;
-
-protected:
- Create_func_dimension() {}
- virtual ~Create_func_dimension() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_mbr_disjoint : public Create_func_arg2
-{
- public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_mbr_disjoint s_singleton;
-
- protected:
- Create_func_mbr_disjoint() {}
- virtual ~Create_func_mbr_disjoint() {}
-};
-
-
-class Create_func_disjoint : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_disjoint s_singleton;
-
-protected:
- Create_func_disjoint() {}
- virtual ~Create_func_disjoint() {}
-};
-
-
-class Create_func_distance : public Create_func_arg2
-{
- public:
- virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_distance s_singleton;
-
- protected:
- Create_func_distance() {}
- virtual ~Create_func_distance() {}
-};
-#endif
-
-
class Create_func_elt : public Create_native_func
{
public:
@@ -950,76 +667,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_endpoint : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_endpoint s_singleton;
-
-protected:
- Create_func_endpoint() {}
- virtual ~Create_func_endpoint() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_envelope : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_envelope s_singleton;
-
-protected:
- Create_func_envelope() {}
- virtual ~Create_func_envelope() {}
-};
-
-class Create_func_boundary : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_boundary s_singleton;
-
-protected:
- Create_func_boundary() {}
- virtual ~Create_func_boundary() {}
-};
-#endif /*HAVE_SPATIAL*/
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_mbr_equals : public Create_func_arg2
-{
- public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_mbr_equals s_singleton;
-
- protected:
- Create_func_mbr_equals() {}
- virtual ~Create_func_mbr_equals() {}
-};
-
-
-class Create_func_equals : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_equals s_singleton;
-
-protected:
- Create_func_equals() {}
- virtual ~Create_func_equals() {}
-};
-#endif
-
-
class Create_func_exp : public Create_func_arg1
{
public:
@@ -1046,21 +693,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_exteriorring : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_exteriorring s_singleton;
-
-protected:
- Create_func_exteriorring() {}
- virtual ~Create_func_exteriorring() {}
-};
-#endif
-
-
class Create_func_field : public Create_native_func
{
public:
@@ -1165,94 +797,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_geometry_from_text : public Create_native_func
-{
-public:
- virtual Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
-
- static Create_func_geometry_from_text s_singleton;
-
-protected:
- Create_func_geometry_from_text() {}
- virtual ~Create_func_geometry_from_text() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_geometry_from_wkb : public Create_native_func
-{
-public:
- virtual Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
-
- static Create_func_geometry_from_wkb s_singleton;
-
-protected:
- Create_func_geometry_from_wkb() {}
- virtual ~Create_func_geometry_from_wkb() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_geometry_from_json : public Create_native_func
-{
-public:
- virtual Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
-
- static Create_func_geometry_from_json s_singleton;
-
-protected:
- Create_func_geometry_from_json() {}
- virtual ~Create_func_geometry_from_json() {}
-};
-
-
-class Create_func_as_geojson : public Create_native_func
-{
-public:
- virtual Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
-
- static Create_func_as_geojson s_singleton;
-
-protected:
- Create_func_as_geojson() {}
- virtual ~Create_func_as_geojson() {}
-};
-#endif /*HAVE_SPATIAL*/
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_geometry_type : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_geometry_type s_singleton;
-
-protected:
- Create_func_geometry_type() {}
- virtual ~Create_func_geometry_type() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_geometryn : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_geometryn s_singleton;
-
-protected:
- Create_func_geometryn() {}
- virtual ~Create_func_geometryn() {}
-};
-#endif
-
-
class Create_func_get_lock : public Create_func_arg2
{
public:
@@ -1266,36 +810,6 @@ protected:
};
-#if defined(HAVE_SPATIAL) && !defined(DBUG_OFF)
-class Create_func_gis_debug : public Create_func_arg1
-{
- public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_gis_debug s_singleton;
-
- protected:
- Create_func_gis_debug() {}
- virtual ~Create_func_gis_debug() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_glength : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_glength s_singleton;
-
-protected:
- Create_func_glength() {}
- virtual ~Create_func_glength() {}
-};
-#endif
-
-
class Create_func_greatest : public Create_native_func
{
public:
@@ -1335,110 +849,6 @@ protected:
};
-class Create_func_inet_ntoa : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_inet_ntoa s_singleton;
-
-protected:
- Create_func_inet_ntoa() {}
- virtual ~Create_func_inet_ntoa() {}
-};
-
-
-class Create_func_inet_aton : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_inet_aton s_singleton;
-
-protected:
- Create_func_inet_aton() {}
- virtual ~Create_func_inet_aton() {}
-};
-
-
-class Create_func_inet6_aton : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_inet6_aton s_singleton;
-
-protected:
- Create_func_inet6_aton() {}
- virtual ~Create_func_inet6_aton() {}
-};
-
-
-class Create_func_inet6_ntoa : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_inet6_ntoa s_singleton;
-
-protected:
- Create_func_inet6_ntoa() {}
- virtual ~Create_func_inet6_ntoa() {}
-};
-
-
-class Create_func_is_ipv4 : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_is_ipv4 s_singleton;
-
-protected:
- Create_func_is_ipv4() {}
- virtual ~Create_func_is_ipv4() {}
-};
-
-
-class Create_func_is_ipv6 : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_is_ipv6 s_singleton;
-
-protected:
- Create_func_is_ipv6() {}
- virtual ~Create_func_is_ipv6() {}
-};
-
-
-class Create_func_is_ipv4_compat : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_is_ipv4_compat s_singleton;
-
-protected:
- Create_func_is_ipv4_compat() {}
- virtual ~Create_func_is_ipv4_compat() {}
-};
-
-
-class Create_func_is_ipv4_mapped : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_is_ipv4_mapped s_singleton;
-
-protected:
- Create_func_is_ipv4_mapped() {}
- virtual ~Create_func_is_ipv4_mapped() {}
-};
-
-
class Create_func_instr : public Create_func_arg2
{
public:
@@ -1452,127 +862,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_interiorringn : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_interiorringn s_singleton;
-
-protected:
- Create_func_interiorringn() {}
- virtual ~Create_func_interiorringn() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_relate : public Create_func_arg3
-{
-public:
- virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
-
- static Create_func_relate s_singleton;
-
-protected:
- Create_func_relate() {}
- virtual ~Create_func_relate() {}
-};
-
-
-class Create_func_mbr_intersects : public Create_func_arg2
-{
- public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_mbr_intersects s_singleton;
-
- protected:
- Create_func_mbr_intersects() {}
- virtual ~Create_func_mbr_intersects() {}
-};
-
-
-class Create_func_intersects : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_intersects s_singleton;
-
-protected:
- Create_func_intersects() {}
- virtual ~Create_func_intersects() {}
-};
-
-
-class Create_func_intersection : public Create_func_arg2
-{
-public:
- virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_intersection s_singleton;
-
-protected:
- Create_func_intersection() {}
- virtual ~Create_func_intersection() {}
-};
-
-
-class Create_func_difference : public Create_func_arg2
-{
-public:
- virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_difference s_singleton;
-
-protected:
- Create_func_difference() {}
- virtual ~Create_func_difference() {}
-};
-
-
-class Create_func_union : public Create_func_arg2
-{
-public:
- virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_union s_singleton;
-
-protected:
- Create_func_union() {}
- virtual ~Create_func_union() {}
-};
-
-
-class Create_func_symdifference : public Create_func_arg2
-{
-public:
- virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_symdifference s_singleton;
-
-protected:
- Create_func_symdifference() {}
- virtual ~Create_func_symdifference() {}
-};
-
-
-class Create_func_buffer : public Create_func_arg2
-{
-public:
- virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_buffer s_singleton;
-
-protected:
- Create_func_buffer() {}
- virtual ~Create_func_buffer() {}
-};
-#endif /*HAVE_SPATIAL*/
-
-
class Create_func_is_free_lock : public Create_func_arg1
{
public:
@@ -1599,49 +888,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_isclosed : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_isclosed s_singleton;
-
-protected:
- Create_func_isclosed() {}
- virtual ~Create_func_isclosed() {}
-};
-
-
-class Create_func_isring : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_isring s_singleton;
-
-protected:
- Create_func_isring() {}
- virtual ~Create_func_isring() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_isempty : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_isempty s_singleton;
-
-protected:
- Create_func_isempty() {}
- virtual ~Create_func_isempty() {}
-};
-#endif
-
-
class Create_func_isnull : public Create_func_arg1
{
public:
@@ -1655,21 +901,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_issimple : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_issimple s_singleton;
-
-protected:
- Create_func_issimple() {}
- virtual ~Create_func_issimple() {}
-};
-#endif
-
-
class Create_func_json_exists : public Create_func_arg2
{
public:
@@ -2378,51 +1609,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_numgeometries : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_numgeometries s_singleton;
-
-protected:
- Create_func_numgeometries() {}
- virtual ~Create_func_numgeometries() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_numinteriorring : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_numinteriorring s_singleton;
-
-protected:
- Create_func_numinteriorring() {}
- virtual ~Create_func_numinteriorring() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_numpoints : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_numpoints s_singleton;
-
-protected:
- Create_func_numpoints() {}
- virtual ~Create_func_numpoints() {}
-};
-#endif
-
-
class Create_func_oct : public Create_func_arg1
{
public:
@@ -2449,34 +1635,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_mbr_overlaps : public Create_func_arg2
-{
- public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_mbr_overlaps s_singleton;
-
- protected:
- Create_func_mbr_overlaps() {}
- virtual ~Create_func_mbr_overlaps() {}
-};
-
-
-class Create_func_overlaps : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_overlaps s_singleton;
-
-protected:
- Create_func_overlaps() {}
- virtual ~Create_func_overlaps() {}
-};
-#endif
-
-
class Create_func_period_add : public Create_func_arg2
{
public:
@@ -2516,21 +1674,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_pointn : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_pointn s_singleton;
-
-protected:
- Create_func_pointn() {}
- virtual ~Create_func_pointn() {}
-};
-#endif
-
-
class Create_func_pow : public Create_func_arg2
{
public:
@@ -2622,6 +1765,15 @@ protected:
};
+class Create_func_release_all_locks : public Create_func_arg0
+{
+public:
+ virtual Item *create_builder(THD *thd);
+
+ static Create_func_release_all_locks s_singleton;
+};
+
+
class Create_func_release_lock : public Create_func_arg1
{
public:
@@ -2848,36 +2000,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_srid : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_srid s_singleton;
-
-protected:
- Create_func_srid() {}
- virtual ~Create_func_srid() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_startpoint : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_startpoint s_singleton;
-
-protected:
- Create_func_startpoint() {}
- virtual ~Create_func_startpoint() {}
-};
-#endif
-
-
class Create_func_str_to_date : public Create_func_arg2
{
public:
@@ -3034,21 +2156,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_touches : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_touches s_singleton;
-
-protected:
- Create_func_touches() {}
- virtual ~Create_func_touches() {}
-};
-#endif
-
-
class Create_func_ucase : public Create_func_arg1
{
public:
@@ -3179,33 +2286,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_mbr_within : public Create_func_arg2
-{
- public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_mbr_within s_singleton;
-
- protected:
- Create_func_mbr_within() {}
- virtual ~Create_func_mbr_within() {}
-};
-
-
-class Create_func_within : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_within s_singleton;
-
-protected:
- Create_func_within() {}
- virtual ~Create_func_within() {}
-};
-#endif
-
#ifdef WITH_WSREP
class Create_func_wsrep_last_written_gtid : public Create_func_arg0
{
@@ -3246,20 +2326,6 @@ protected:
};
#endif /* WITH_WSREP */
-#ifdef HAVE_SPATIAL
-class Create_func_x : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_x s_singleton;
-
-protected:
- Create_func_x() {}
- virtual ~Create_func_x() {}
-};
-#endif
-
class Create_func_xml_extractvalue : public Create_func_arg2
{
@@ -3287,21 +2353,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_y : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_y s_singleton;
-
-protected:
- Create_func_y() {}
- virtual ~Create_func_y() {}
-};
-#endif
-
-
class Create_func_year_week : public Create_native_func
{
public:
@@ -3336,7 +2387,7 @@ static bool has_named_parameters(List<Item> *params)
List_iterator<Item> it(*params);
while ((param= it++))
{
- if (! param->is_autogenerated_name)
+ if (! param->is_autogenerated_name())
return true;
}
}
@@ -3344,21 +2395,6 @@ static bool has_named_parameters(List<Item> *params)
return false;
}
-#ifndef HAVE_SPATIAL
-Create_func_no_geom Create_func_no_geom::s_singleton;
-
-Item*
-Create_func_no_geom::create_func(THD * /* unused */,
- LEX_CSTRING /* unused */,
- List<Item> * /* unused */)
-{
- /* FIXME: error message can't be translated. */
- my_error(ER_FEATURE_DISABLED, MYF(0),
- sym_group_geom.name, sym_group_geom.needed_define);
- return NULL;
-}
-#endif
-
Item*
Create_qfunc::create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list)
@@ -3597,7 +2633,7 @@ Create_func_arg1::create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list
Item *param_1= item_list->pop();
- if (unlikely(! param_1->is_autogenerated_name))
+ if (unlikely(! param_1->is_autogenerated_name()))
{
my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), name->str);
return NULL;
@@ -3624,8 +2660,8 @@ Create_func_arg2::create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list
Item *param_1= item_list->pop();
Item *param_2= item_list->pop();
- if (unlikely(!param_1->is_autogenerated_name ||
- !param_2->is_autogenerated_name))
+ if (unlikely(!param_1->is_autogenerated_name() ||
+ !param_2->is_autogenerated_name()))
{
my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), name->str);
return NULL;
@@ -3653,9 +2689,9 @@ Create_func_arg3::create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list
Item *param_2= item_list->pop();
Item *param_3= item_list->pop();
- if (unlikely(!param_1->is_autogenerated_name ||
- !param_2->is_autogenerated_name ||
- !param_3->is_autogenerated_name))
+ if (unlikely(!param_1->is_autogenerated_name() ||
+ !param_2->is_autogenerated_name() ||
+ !param_3->is_autogenerated_name()))
{
my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), name->str);
return NULL;
@@ -3710,39 +2746,6 @@ Create_func_aes_decrypt::create_2_arg(THD *thd, Item *arg1, Item *arg2)
}
-#ifdef HAVE_SPATIAL
-Create_func_area Create_func_area::s_singleton;
-
-Item*
-Create_func_area::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_area(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_as_wkb Create_func_as_wkb::s_singleton;
-
-Item*
-Create_func_as_wkb::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_as_wkb(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_as_wkt Create_func_as_wkt::s_singleton;
-
-Item*
-Create_func_as_wkt::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_as_wkt(thd, arg1);
-}
-#endif
-
-
Create_func_asin Create_func_asin::s_singleton;
Item*
@@ -3854,16 +2857,6 @@ Create_func_ceiling::create_1_arg(THD *thd, Item *arg1)
}
-#ifdef HAVE_SPATIAL
-Create_func_centroid Create_func_centroid::s_singleton;
-
-Item*
-Create_func_centroid::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_centroid(thd, arg1);
-}
-
-
Create_func_chr Create_func_chr::s_singleton;
Item*
@@ -3874,25 +2867,6 @@ Create_func_chr::create_1_arg(THD *thd, Item *arg1)
}
-Create_func_convexhull Create_func_convexhull::s_singleton;
-
-Item*
-Create_func_convexhull::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_convexhull(thd, arg1);
-}
-
-
-Create_func_pointonsurface Create_func_pointonsurface::s_singleton;
-
-Item*
-Create_func_pointonsurface::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_pointonsurface(thd, arg1);
-}
-#endif /*HAVE_SPATIAL*/
-
-
Create_func_char_length Create_func_char_length::s_singleton;
Item*
@@ -4050,28 +3024,6 @@ Create_func_connection_id::create_builder(THD *thd)
}
-#ifdef HAVE_SPATIAL
-Create_func_mbr_contains Create_func_mbr_contains::s_singleton;
-
-Item*
-Create_func_mbr_contains::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
- Item_func::SP_CONTAINS_FUNC);
-}
-
-
-Create_func_contains Create_func_contains::s_singleton;
-
-Item*
-Create_func_contains::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
- Item_func::SP_CONTAINS_FUNC);
-}
-#endif
-
-
Create_func_nvl2 Create_func_nvl2::s_singleton;
Item*
@@ -4125,19 +3077,6 @@ Create_func_crc32::create_1_arg(THD *thd, Item *arg1)
return new (thd->mem_root) Item_func_crc32(thd, arg1);
}
-
-#ifdef HAVE_SPATIAL
-Create_func_crosses Create_func_crosses::s_singleton;
-
-Item*
-Create_func_crosses::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
- Item_func::SP_CROSSES_FUNC);
-}
-#endif
-
-
Create_func_datediff Create_func_datediff::s_singleton;
Item*
@@ -4270,48 +3209,6 @@ Create_func_des_encrypt::create_native(THD *thd, LEX_CSTRING *name,
}
-#ifdef HAVE_SPATIAL
-Create_func_dimension Create_func_dimension::s_singleton;
-
-Item*
-Create_func_dimension::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_dimension(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_mbr_disjoint Create_func_mbr_disjoint::s_singleton;
-
-Item*
-Create_func_mbr_disjoint::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
- Item_func::SP_DISJOINT_FUNC);
-}
-
-
-Create_func_disjoint Create_func_disjoint::s_singleton;
-
-Item*
-Create_func_disjoint::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
- Item_func::SP_DISJOINT_FUNC);
-}
-
-
-Create_func_distance Create_func_distance::s_singleton;
-
-Item*
-Create_func_distance::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_distance(thd, arg1, arg2);
-}
-#endif
-
-
Create_func_elt Create_func_elt::s_singleton;
Item*
@@ -4380,60 +3277,6 @@ Create_func_encrypt::create_native(THD *thd, LEX_CSTRING *name,
}
-#ifdef HAVE_SPATIAL
-Create_func_endpoint Create_func_endpoint::s_singleton;
-
-Item*
-Create_func_endpoint::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
- Item_func::SP_ENDPOINT);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_envelope Create_func_envelope::s_singleton;
-
-Item*
-Create_func_envelope::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_envelope(thd, arg1);
-}
-
-
-Create_func_boundary Create_func_boundary::s_singleton;
-
-Item*
-Create_func_boundary::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_boundary(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_mbr_equals Create_func_mbr_equals::s_singleton;
-
-Item*
-Create_func_mbr_equals::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
- Item_func::SP_EQUALS_FUNC);
-}
-
-
-Create_func_equals Create_func_equals::s_singleton;
-
-Item*
-Create_func_equals::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
- Item_func::SP_EQUALS_FUNC);
-}
-#endif
-
-
Create_func_exp Create_func_exp::s_singleton;
Item*
@@ -4496,18 +3339,6 @@ Create_func_export_set::create_native(THD *thd, LEX_CSTRING *name,
}
-#ifdef HAVE_SPATIAL
-Create_func_exteriorring Create_func_exteriorring::s_singleton;
-
-Item*
-Create_func_exteriorring::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
- Item_func::SP_EXTERIORRING);
-}
-#endif
-
-
Create_func_field Create_func_field::s_singleton;
Item*
@@ -4650,203 +3481,6 @@ Create_func_from_unixtime::create_native(THD *thd, LEX_CSTRING *name,
}
-#ifdef HAVE_SPATIAL
-Create_func_geometry_from_text Create_func_geometry_from_text::s_singleton;
-
-Item*
-Create_func_geometry_from_text::create_native(THD *thd, LEX_CSTRING *name,
- List<Item> *item_list)
-{
- Item *func= NULL;
- int arg_count= 0;
-
- if (item_list != NULL)
- arg_count= item_list->elements;
-
- switch (arg_count) {
- case 1:
- {
- Item *param_1= item_list->pop();
- func= new (thd->mem_root) Item_func_geometry_from_text(thd, param_1);
- thd->lex->uncacheable(UNCACHEABLE_RAND);
- break;
- }
- case 2:
- {
- Item *param_1= item_list->pop();
- Item *param_2= item_list->pop();
- func= new (thd->mem_root) Item_func_geometry_from_text(thd, param_1, param_2);
- break;
- }
- default:
- {
- my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
- break;
- }
- }
-
- return func;
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_geometry_from_wkb Create_func_geometry_from_wkb::s_singleton;
-
-Item*
-Create_func_geometry_from_wkb::create_native(THD *thd, LEX_CSTRING *name,
- List<Item> *item_list)
-{
- Item *func= NULL;
- int arg_count= 0;
-
- if (item_list != NULL)
- arg_count= item_list->elements;
-
- switch (arg_count) {
- case 1:
- {
- Item *param_1= item_list->pop();
- func= new (thd->mem_root) Item_func_geometry_from_wkb(thd, param_1);
- thd->lex->uncacheable(UNCACHEABLE_RAND);
- break;
- }
- case 2:
- {
- Item *param_1= item_list->pop();
- Item *param_2= item_list->pop();
- func= new (thd->mem_root) Item_func_geometry_from_wkb(thd, param_1, param_2);
- break;
- }
- default:
- {
- my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
- break;
- }
- }
-
- return func;
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_geometry_from_json Create_func_geometry_from_json::s_singleton;
-
-Item*
-Create_func_geometry_from_json::create_native(THD *thd, LEX_CSTRING *name,
- List<Item> *item_list)
-{
- Item *func= NULL;
- int arg_count= 0;
-
- if (item_list != NULL)
- arg_count= item_list->elements;
-
- switch (arg_count) {
- case 1:
- {
- Item *json= item_list->pop();
- func= new (thd->mem_root) Item_func_geometry_from_json(thd, json);
- thd->lex->uncacheable(UNCACHEABLE_RAND);
- break;
- }
- case 2:
- {
- Item *json= item_list->pop();
- Item *options= item_list->pop();
- func= new (thd->mem_root) Item_func_geometry_from_json(thd, json, options);
- break;
- }
- case 3:
- {
- Item *json= item_list->pop();
- Item *options= item_list->pop();
- Item *srid= item_list->pop();
- func= new (thd->mem_root) Item_func_geometry_from_json(thd, json, options,
- srid);
- break;
- }
- default:
- {
- my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
- break;
- }
- }
-
- return func;
-}
-
-
-Create_func_as_geojson Create_func_as_geojson::s_singleton;
-
-Item*
-Create_func_as_geojson::create_native(THD *thd, LEX_CSTRING *name,
- List<Item> *item_list)
-{
- Item *func= NULL;
- int arg_count= 0;
-
- if (item_list != NULL)
- arg_count= item_list->elements;
-
- switch (arg_count) {
- case 1:
- {
- Item *geom= item_list->pop();
- func= new (thd->mem_root) Item_func_as_geojson(thd, geom);
- thd->lex->uncacheable(UNCACHEABLE_RAND);
- break;
- }
- case 2:
- {
- Item *geom= item_list->pop();
- Item *max_dec= item_list->pop();
- func= new (thd->mem_root) Item_func_as_geojson(thd, geom, max_dec);
- break;
- }
- case 3:
- {
- Item *geom= item_list->pop();
- Item *max_dec= item_list->pop();
- Item *options= item_list->pop();
- func= new (thd->mem_root) Item_func_as_geojson(thd, geom, max_dec, options);
- break;
- }
- default:
- {
- my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
- break;
- }
- }
-
- return func;
-}
-#endif /*HAVE_SPATIAL*/
-
-
-#ifdef HAVE_SPATIAL
-Create_func_geometry_type Create_func_geometry_type::s_singleton;
-
-Item*
-Create_func_geometry_type::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_geometry_type(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_geometryn Create_func_geometryn::s_singleton;
-
-Item*
-Create_func_geometryn::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
- Item_func::SP_GEOMETRYN);
-}
-#endif
-
Create_func_get_lock Create_func_get_lock::s_singleton;
@@ -4859,28 +3493,6 @@ Create_func_get_lock::create_2_arg(THD *thd, Item *arg1, Item *arg2)
}
-#if defined(HAVE_SPATIAL) && !defined(DBUG_OFF)
-Create_func_gis_debug Create_func_gis_debug::s_singleton;
-
-Item*
-Create_func_gis_debug::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_gis_debug(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_glength Create_func_glength::s_singleton;
-
-Item*
-Create_func_glength::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_glength(thd, arg1);
-}
-#endif
-
-
Create_func_greatest Create_func_greatest::s_singleton;
Item*
@@ -4920,78 +3532,6 @@ Create_func_ifnull::create_2_arg(THD *thd, Item *arg1, Item *arg2)
}
-Create_func_inet_ntoa Create_func_inet_ntoa::s_singleton;
-
-Item*
-Create_func_inet_ntoa::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_inet_ntoa(thd, arg1);
-}
-
-
-Create_func_inet6_aton Create_func_inet6_aton::s_singleton;
-
-Item*
-Create_func_inet6_aton::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_inet6_aton(thd, arg1);
-}
-
-
-Create_func_inet6_ntoa Create_func_inet6_ntoa::s_singleton;
-
-Item*
-Create_func_inet6_ntoa::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_inet6_ntoa(thd, arg1);
-}
-
-
-Create_func_inet_aton Create_func_inet_aton::s_singleton;
-
-Item*
-Create_func_inet_aton::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_inet_aton(thd, arg1);
-}
-
-
-Create_func_is_ipv4 Create_func_is_ipv4::s_singleton;
-
-Item*
-Create_func_is_ipv4::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_is_ipv4(thd, arg1);
-}
-
-
-Create_func_is_ipv6 Create_func_is_ipv6::s_singleton;
-
-Item*
-Create_func_is_ipv6::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_is_ipv6(thd, arg1);
-}
-
-
-Create_func_is_ipv4_compat Create_func_is_ipv4_compat::s_singleton;
-
-Item*
-Create_func_is_ipv4_compat::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_is_ipv4_compat(thd, arg1);
-}
-
-
-Create_func_is_ipv4_mapped Create_func_is_ipv4_mapped::s_singleton;
-
-Item*
-Create_func_is_ipv4_mapped::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_is_ipv4_mapped(thd, arg1);
-}
-
-
Create_func_instr Create_func_instr::s_singleton;
Item*
@@ -5001,98 +3541,6 @@ Create_func_instr::create_2_arg(THD *thd, Item *arg1, Item *arg2)
}
-#ifdef HAVE_SPATIAL
-Create_func_interiorringn Create_func_interiorringn::s_singleton;
-
-Item*
-Create_func_interiorringn::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
- Item_func::SP_INTERIORRINGN);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_relate Create_func_relate::s_singleton;
-
-Item*
-Create_func_relate::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *matrix)
-{
- return new (thd->mem_root) Item_func_spatial_relate(thd, arg1, arg2, matrix);
-}
-
-
-Create_func_mbr_intersects Create_func_mbr_intersects::s_singleton;
-
-Item*
-Create_func_mbr_intersects::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
- Item_func::SP_INTERSECTS_FUNC);
-}
-
-
-Create_func_intersects Create_func_intersects::s_singleton;
-
-Item*
-Create_func_intersects::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
- Item_func::SP_INTERSECTS_FUNC);
-}
-
-
-Create_func_intersection Create_func_intersection::s_singleton;
-
-Item*
-Create_func_intersection::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
- Gcalc_function::op_intersection);
-}
-
-
-Create_func_difference Create_func_difference::s_singleton;
-
-Item*
-Create_func_difference::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
- Gcalc_function::op_difference);
-}
-
-
-Create_func_union Create_func_union::s_singleton;
-
-Item*
-Create_func_union::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
- Gcalc_function::op_union);
-}
-
-
-Create_func_symdifference Create_func_symdifference::s_singleton;
-
-Item*
-Create_func_symdifference::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
- Gcalc_function::op_symdifference);
-}
-
-
-Create_func_buffer Create_func_buffer::s_singleton;
-
-Item*
-Create_func_buffer::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_buffer(thd, arg1, arg2);
-}
-#endif /*HAVE_SPATAI*/
-
-
Create_func_is_free_lock Create_func_is_free_lock::s_singleton;
Item*
@@ -5115,35 +3563,6 @@ Create_func_is_used_lock::create_1_arg(THD *thd, Item *arg1)
}
-#ifdef HAVE_SPATIAL
-Create_func_isclosed Create_func_isclosed::s_singleton;
-
-Item*
-Create_func_isclosed::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_isclosed(thd, arg1);
-}
-
-
-Create_func_isring Create_func_isring::s_singleton;
-
-Item*
-Create_func_isring::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_isring(thd, arg1);
-}
-
-
-Create_func_isempty Create_func_isempty::s_singleton;
-
-Item*
-Create_func_isempty::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_isempty(thd, arg1);
-}
-#endif /*HAVE_SPATIAL*/
-
-
Create_func_isnull Create_func_isnull::s_singleton;
Item*
@@ -5153,17 +3572,6 @@ Create_func_isnull::create_1_arg(THD *thd, Item *arg1)
}
-#ifdef HAVE_SPATIAL
-Create_func_issimple Create_func_issimple::s_singleton;
-
-Item*
-Create_func_issimple::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_issimple(thd, arg1);
-}
-#endif
-
-
Create_func_json_exists Create_func_json_exists::s_singleton;
Item*
@@ -6211,39 +4619,6 @@ Create_func_nullif::create_2_arg(THD *thd, Item *arg1, Item *arg2)
}
-#ifdef HAVE_SPATIAL
-Create_func_numgeometries Create_func_numgeometries::s_singleton;
-
-Item*
-Create_func_numgeometries::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_numgeometries(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_numinteriorring Create_func_numinteriorring::s_singleton;
-
-Item*
-Create_func_numinteriorring::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_numinteriorring(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_numpoints Create_func_numpoints::s_singleton;
-
-Item*
-Create_func_numpoints::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_numpoints(thd, arg1);
-}
-#endif
-
-
Create_func_oct Create_func_oct::s_singleton;
Item*
@@ -6264,28 +4639,6 @@ Create_func_ord::create_1_arg(THD *thd, Item *arg1)
}
-#ifdef HAVE_SPATIAL
-Create_func_mbr_overlaps Create_func_mbr_overlaps::s_singleton;
-
-Item*
-Create_func_mbr_overlaps::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
- Item_func::SP_OVERLAPS_FUNC);
-}
-
-
-Create_func_overlaps Create_func_overlaps::s_singleton;
-
-Item*
-Create_func_overlaps::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
- Item_func::SP_OVERLAPS_FUNC);
-}
-#endif
-
-
Create_func_period_add Create_func_period_add::s_singleton;
Item*
@@ -6313,18 +4666,6 @@ Create_func_pi::create_builder(THD *thd)
}
-#ifdef HAVE_SPATIAL
-Create_func_pointn Create_func_pointn::s_singleton;
-
-Item*
-Create_func_pointn::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
- Item_func::SP_POINTN);
-}
-#endif
-
-
Create_func_pow Create_func_pow::s_singleton;
Item*
@@ -6430,6 +4771,17 @@ Create_func_rand::create_native(THD *thd, LEX_CSTRING *name,
}
+Create_func_release_all_locks Create_func_release_all_locks::s_singleton;
+
+Item*
+Create_func_release_all_locks::create_builder(THD *thd)
+{
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
+ thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
+ return new (thd->mem_root) Item_func_release_all_locks(thd);
+}
+
+
Create_func_release_lock Create_func_release_lock::s_singleton;
Item*
@@ -6663,29 +5015,6 @@ Create_func_sqrt::create_1_arg(THD *thd, Item *arg1)
}
-#ifdef HAVE_SPATIAL
-Create_func_srid Create_func_srid::s_singleton;
-
-Item*
-Create_func_srid::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_srid(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_startpoint Create_func_startpoint::s_singleton;
-
-Item*
-Create_func_startpoint::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
- Item_func::SP_STARTPOINT);
-}
-#endif
-
-
Create_func_str_to_date Create_func_str_to_date::s_singleton;
Item*
@@ -6819,18 +5148,6 @@ Create_func_to_seconds::create_1_arg(THD *thd, Item *arg1)
}
-#ifdef HAVE_SPATIAL
-Create_func_touches Create_func_touches::s_singleton;
-
-Item*
-Create_func_touches::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
- Item_func::SP_TOUCHES_FUNC);
-}
-#endif
-
-
Create_func_ucase Create_func_ucase::s_singleton;
Item*
@@ -6933,9 +5250,9 @@ Item*
Create_func_version::create_builder(THD *thd)
{
thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
- return new (thd->mem_root) Item_static_string_func(thd, "version()",
- server_version,
- (uint) strlen(server_version),
+ static Lex_cstring name(STRING_WITH_LEN("version()"));
+ return new (thd->mem_root) Item_static_string_func(thd, name,
+ Lex_cstring_strlen(server_version),
system_charset_info,
DERIVATION_SYSCONST);
}
@@ -6960,27 +5277,6 @@ Create_func_weekofyear::create_1_arg(THD *thd, Item *arg1)
}
-#ifdef HAVE_SPATIAL
-Create_func_mbr_within Create_func_mbr_within::s_singleton;
-
-Item*
-Create_func_mbr_within::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
- Item_func::SP_WITHIN_FUNC);
-}
-
-
-Create_func_within Create_func_within::s_singleton;
-
-Item*
-Create_func_within::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
- Item_func::SP_WITHIN_FUNC);
-}
-#endif
-
#ifdef WITH_WSREP
Create_func_wsrep_last_written_gtid
Create_func_wsrep_last_written_gtid::s_singleton;
@@ -7039,17 +5335,6 @@ Create_func_wsrep_sync_wait_upto::create_native(THD *thd,
}
#endif /* WITH_WSREP */
-#ifdef HAVE_SPATIAL
-Create_func_x Create_func_x::s_singleton;
-
-Item*
-Create_func_x::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_x(thd, arg1);
-}
-#endif
-
-
Create_func_xml_extractvalue Create_func_xml_extractvalue::s_singleton;
Item*
@@ -7068,17 +5353,6 @@ Create_func_xml_update::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg
}
-#ifdef HAVE_SPATIAL
-Create_func_y Create_func_y::s_singleton;
-
-Item*
-Create_func_y::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_y(thd, arg1);
-}
-#endif
-
-
Create_func_year_week Create_func_year_week::s_singleton;
Item*
@@ -7119,12 +5393,6 @@ Create_func_year_week::create_native(THD *thd, LEX_CSTRING *name,
#define BUILDER(F) & F::s_singleton
-#ifdef HAVE_SPATIAL
- #define GEOM_BUILDER(F) & F::s_singleton
-#else
- #define GEOM_BUILDER(F) & Create_func_no_geom::s_singleton
-#endif
-
/*
MySQL native functions.
MAINTAINER:
@@ -7143,12 +5411,7 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("ADDTIME") }, BUILDER(Create_func_addtime)},
{ { STRING_WITH_LEN("AES_DECRYPT") }, BUILDER(Create_func_aes_decrypt)},
{ { STRING_WITH_LEN("AES_ENCRYPT") }, BUILDER(Create_func_aes_encrypt)},
- { { STRING_WITH_LEN("AREA") }, GEOM_BUILDER(Create_func_area)},
- { { STRING_WITH_LEN("ASBINARY") }, GEOM_BUILDER(Create_func_as_wkb)},
{ { STRING_WITH_LEN("ASIN") }, BUILDER(Create_func_asin)},
- { { STRING_WITH_LEN("ASTEXT") }, GEOM_BUILDER(Create_func_as_wkt)},
- { { STRING_WITH_LEN("ASWKB") }, GEOM_BUILDER(Create_func_as_wkb)},
- { { STRING_WITH_LEN("ASWKT") }, GEOM_BUILDER(Create_func_as_wkt)},
{ { STRING_WITH_LEN("ATAN") }, BUILDER(Create_func_atan)},
{ { STRING_WITH_LEN("ATAN2") }, BUILDER(Create_func_atan)},
{ { STRING_WITH_LEN("BENCHMARK") }, BUILDER(Create_func_benchmark)},
@@ -7156,11 +5419,8 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("BINLOG_GTID_POS") }, BUILDER(Create_func_binlog_gtid_pos)},
{ { STRING_WITH_LEN("BIT_COUNT") }, BUILDER(Create_func_bit_count)},
{ { STRING_WITH_LEN("BIT_LENGTH") }, BUILDER(Create_func_bit_length)},
- { { STRING_WITH_LEN("BOUNDARY") }, GEOM_BUILDER(Create_func_boundary)},
- { { STRING_WITH_LEN("BUFFER") }, GEOM_BUILDER(Create_func_buffer)},
{ { STRING_WITH_LEN("CEIL") }, BUILDER(Create_func_ceiling)},
{ { STRING_WITH_LEN("CEILING") }, BUILDER(Create_func_ceiling)},
- { { STRING_WITH_LEN("CENTROID") }, GEOM_BUILDER(Create_func_centroid)},
{ { STRING_WITH_LEN("CHARACTER_LENGTH") }, BUILDER(Create_func_char_length)},
{ { STRING_WITH_LEN("CHAR_LENGTH") }, BUILDER(Create_func_char_length)},
{ { STRING_WITH_LEN("CHR") }, BUILDER(Create_func_chr)},
@@ -7176,11 +5436,9 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("CONNECTION_ID") }, BUILDER(Create_func_connection_id)},
{ { STRING_WITH_LEN("CONV") }, BUILDER(Create_func_conv)},
{ { STRING_WITH_LEN("CONVERT_TZ") }, BUILDER(Create_func_convert_tz)},
- { { STRING_WITH_LEN("CONVEXHULL") }, GEOM_BUILDER(Create_func_convexhull)},
{ { STRING_WITH_LEN("COS") }, BUILDER(Create_func_cos)},
{ { STRING_WITH_LEN("COT") }, BUILDER(Create_func_cot)},
{ { STRING_WITH_LEN("CRC32") }, BUILDER(Create_func_crc32)},
- { { STRING_WITH_LEN("CROSSES") }, GEOM_BUILDER(Create_func_crosses)},
{ { STRING_WITH_LEN("DATEDIFF") }, BUILDER(Create_func_datediff)},
{ { STRING_WITH_LEN("DAYNAME") }, BUILDER(Create_func_dayname)},
{ { STRING_WITH_LEN("DAYOFMONTH") }, BUILDER(Create_func_dayofmonth)},
@@ -7191,17 +5449,11 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("DECODE_ORACLE") }, BUILDER(Create_func_decode_oracle)},
{ { STRING_WITH_LEN("DES_DECRYPT") }, BUILDER(Create_func_des_decrypt)},
{ { STRING_WITH_LEN("DES_ENCRYPT") }, BUILDER(Create_func_des_encrypt)},
- { { STRING_WITH_LEN("DIMENSION") }, GEOM_BUILDER(Create_func_dimension)},
- { { STRING_WITH_LEN("DISJOINT") }, GEOM_BUILDER(Create_func_mbr_disjoint)},
{ { STRING_WITH_LEN("ELT") }, BUILDER(Create_func_elt)},
{ { STRING_WITH_LEN("ENCODE") }, BUILDER(Create_func_encode)},
{ { STRING_WITH_LEN("ENCRYPT") }, BUILDER(Create_func_encrypt)},
- { { STRING_WITH_LEN("ENDPOINT") }, GEOM_BUILDER(Create_func_endpoint)},
- { { STRING_WITH_LEN("ENVELOPE") }, GEOM_BUILDER(Create_func_envelope)},
- { { STRING_WITH_LEN("EQUALS") }, GEOM_BUILDER(Create_func_equals)},
{ { STRING_WITH_LEN("EXP") }, BUILDER(Create_func_exp)},
{ { STRING_WITH_LEN("EXPORT_SET") }, BUILDER(Create_func_export_set)},
- { { STRING_WITH_LEN("EXTERIORRING") }, GEOM_BUILDER(Create_func_exteriorring)},
{ { STRING_WITH_LEN("EXTRACTVALUE") }, BUILDER(Create_func_xml_extractvalue)},
{ { STRING_WITH_LEN("FIELD") }, BUILDER(Create_func_field)},
{ { STRING_WITH_LEN("FIND_IN_SET") }, BUILDER(Create_func_find_in_set)},
@@ -7211,37 +5463,12 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("FROM_BASE64") }, BUILDER(Create_func_from_base64)},
{ { STRING_WITH_LEN("FROM_DAYS") }, BUILDER(Create_func_from_days)},
{ { STRING_WITH_LEN("FROM_UNIXTIME") }, BUILDER(Create_func_from_unixtime)},
- { { STRING_WITH_LEN("GEOMCOLLFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("GEOMCOLLFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("GEOMETRYCOLLECTIONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("GEOMETRYCOLLECTIONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("GEOMETRYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("GEOMETRYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("GEOMETRYN") }, GEOM_BUILDER(Create_func_geometryn)},
- { { STRING_WITH_LEN("GEOMETRYTYPE") }, GEOM_BUILDER(Create_func_geometry_type)},
- { { STRING_WITH_LEN("GEOMFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("GEOMFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("GET_LOCK") }, BUILDER(Create_func_get_lock)},
- { { STRING_WITH_LEN("GLENGTH") }, GEOM_BUILDER(Create_func_glength)},
{ { STRING_WITH_LEN("GREATEST") }, BUILDER(Create_func_greatest)},
{ { STRING_WITH_LEN("HEX") }, BUILDER(Create_func_hex)},
{ { STRING_WITH_LEN("IFNULL") }, BUILDER(Create_func_ifnull)},
- { { STRING_WITH_LEN("INET_ATON") }, BUILDER(Create_func_inet_aton)},
- { { STRING_WITH_LEN("INET_NTOA") }, BUILDER(Create_func_inet_ntoa)},
- { { STRING_WITH_LEN("INET6_ATON") }, BUILDER(Create_func_inet6_aton)},
- { { STRING_WITH_LEN("INET6_NTOA") }, BUILDER(Create_func_inet6_ntoa)},
- { { STRING_WITH_LEN("IS_IPV4") }, BUILDER(Create_func_is_ipv4)},
- { { STRING_WITH_LEN("IS_IPV6") }, BUILDER(Create_func_is_ipv6)},
- { { STRING_WITH_LEN("IS_IPV4_COMPAT") }, BUILDER(Create_func_is_ipv4_compat)},
- { { STRING_WITH_LEN("IS_IPV4_MAPPED") }, BUILDER(Create_func_is_ipv4_mapped)},
{ { STRING_WITH_LEN("INSTR") }, BUILDER(Create_func_instr)},
- { { STRING_WITH_LEN("INTERIORRINGN") }, GEOM_BUILDER(Create_func_interiorringn)},
- { { STRING_WITH_LEN("INTERSECTS") }, GEOM_BUILDER(Create_func_mbr_intersects)},
- { { STRING_WITH_LEN("ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)},
- { { STRING_WITH_LEN("ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)},
{ { STRING_WITH_LEN("ISNULL") }, BUILDER(Create_func_isnull)},
- { { STRING_WITH_LEN("ISRING") }, GEOM_BUILDER(Create_func_isring)},
- { { STRING_WITH_LEN("ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)},
{ { STRING_WITH_LEN("IS_FREE_LOCK") }, BUILDER(Create_func_is_free_lock)},
{ { STRING_WITH_LEN("IS_USED_LOCK") }, BUILDER(Create_func_is_used_lock)},
{ { STRING_WITH_LEN("JSON_ARRAY") }, BUILDER(Create_func_json_array)},
@@ -7282,10 +5509,6 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("LIKE_RANGE_MIN") }, BUILDER(Create_func_like_range_min)},
{ { STRING_WITH_LEN("LIKE_RANGE_MAX") }, BUILDER(Create_func_like_range_max)},
#endif
- { { STRING_WITH_LEN("LINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("LINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("LINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("LINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("LN") }, BUILDER(Create_func_ln)},
{ { STRING_WITH_LEN("LOAD_FILE") }, BUILDER(Create_func_load_file)},
{ { STRING_WITH_LEN("LOCATE") }, BUILDER(Create_func_locate)},
@@ -7302,50 +5525,18 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("MAKE_SET") }, BUILDER(Create_func_make_set)},
{ { STRING_WITH_LEN("MASTER_GTID_WAIT") }, BUILDER(Create_func_master_gtid_wait)},
{ { STRING_WITH_LEN("MASTER_POS_WAIT") }, BUILDER(Create_func_master_pos_wait)},
- { { STRING_WITH_LEN("MBRCONTAINS") }, GEOM_BUILDER(Create_func_mbr_contains)},
- { { STRING_WITH_LEN("MBRDISJOINT") }, GEOM_BUILDER(Create_func_mbr_disjoint)},
- { { STRING_WITH_LEN("MBREQUAL") }, GEOM_BUILDER(Create_func_mbr_equals)},
- { { STRING_WITH_LEN("MBREQUALS") }, GEOM_BUILDER(Create_func_mbr_equals)},
- { { STRING_WITH_LEN("MBRINTERSECTS") }, GEOM_BUILDER(Create_func_mbr_intersects)},
- { { STRING_WITH_LEN("MBROVERLAPS") }, GEOM_BUILDER(Create_func_mbr_overlaps)},
- { { STRING_WITH_LEN("MBRTOUCHES") }, GEOM_BUILDER(Create_func_touches)},
- { { STRING_WITH_LEN("MBRWITHIN") }, GEOM_BUILDER(Create_func_mbr_within)},
{ { STRING_WITH_LEN("MD5") }, BUILDER(Create_func_md5)},
- { { STRING_WITH_LEN("MLINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("MLINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("MONTHNAME") }, BUILDER(Create_func_monthname)},
- { { STRING_WITH_LEN("MPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("MPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("MPOLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("MPOLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("MULTILINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("MULTILINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("MULTIPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("MULTIPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("MULTIPOLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("MULTIPOLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("NAME_CONST") }, BUILDER(Create_func_name_const)},
{ { STRING_WITH_LEN("NVL") }, BUILDER(Create_func_ifnull)},
{ { STRING_WITH_LEN("NVL2") }, BUILDER(Create_func_nvl2)},
{ { STRING_WITH_LEN("NULLIF") }, BUILDER(Create_func_nullif)},
- { { STRING_WITH_LEN("NUMGEOMETRIES") }, GEOM_BUILDER(Create_func_numgeometries)},
- { { STRING_WITH_LEN("NUMINTERIORRINGS") }, GEOM_BUILDER(Create_func_numinteriorring)},
- { { STRING_WITH_LEN("NUMPOINTS") }, GEOM_BUILDER(Create_func_numpoints)},
{ { STRING_WITH_LEN("OCT") }, BUILDER(Create_func_oct)},
{ { STRING_WITH_LEN("OCTET_LENGTH") }, BUILDER(Create_func_octet_length)},
{ { STRING_WITH_LEN("ORD") }, BUILDER(Create_func_ord)},
- { { STRING_WITH_LEN("OVERLAPS") }, GEOM_BUILDER(Create_func_mbr_overlaps)},
{ { STRING_WITH_LEN("PERIOD_ADD") }, BUILDER(Create_func_period_add)},
{ { STRING_WITH_LEN("PERIOD_DIFF") }, BUILDER(Create_func_period_diff)},
{ { STRING_WITH_LEN("PI") }, BUILDER(Create_func_pi)},
- { { STRING_WITH_LEN("POINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("POINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("POINTN") }, GEOM_BUILDER(Create_func_pointn)},
- { { STRING_WITH_LEN("POINTONSURFACE") }, GEOM_BUILDER(Create_func_pointonsurface)},
- { { STRING_WITH_LEN("POLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("POLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("POLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("POLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("POW") }, BUILDER(Create_func_pow)},
{ { STRING_WITH_LEN("POWER") }, BUILDER(Create_func_pow)},
{ { STRING_WITH_LEN("QUOTE") }, BUILDER(Create_func_quote)},
@@ -7354,6 +5545,8 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("REGEXP_SUBSTR") }, BUILDER(Create_func_regexp_substr)},
{ { STRING_WITH_LEN("RADIANS") }, BUILDER(Create_func_radians)},
{ { STRING_WITH_LEN("RAND") }, BUILDER(Create_func_rand)},
+ { { STRING_WITH_LEN("RELEASE_ALL_LOCKS") },
+ BUILDER(Create_func_release_all_locks)},
{ { STRING_WITH_LEN("RELEASE_LOCK") }, BUILDER(Create_func_release_lock)},
{ { STRING_WITH_LEN("REPLACE_ORACLE") },
BUILDER(Create_func_replace_oracle)},
@@ -7373,90 +5566,8 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("SOUNDEX") }, BUILDER(Create_func_soundex)},
{ { STRING_WITH_LEN("SPACE") }, BUILDER(Create_func_space)},
{ { STRING_WITH_LEN("SQRT") }, BUILDER(Create_func_sqrt)},
- { { STRING_WITH_LEN("SRID") }, GEOM_BUILDER(Create_func_srid)},
- { { STRING_WITH_LEN("STARTPOINT") }, GEOM_BUILDER(Create_func_startpoint)},
{ { STRING_WITH_LEN("STRCMP") }, BUILDER(Create_func_strcmp)},
{ { STRING_WITH_LEN("STR_TO_DATE") }, BUILDER(Create_func_str_to_date)},
- { { STRING_WITH_LEN("ST_AREA") }, GEOM_BUILDER(Create_func_area)},
- { { STRING_WITH_LEN("ST_ASBINARY") }, GEOM_BUILDER(Create_func_as_wkb)},
- { { STRING_WITH_LEN("ST_ASGEOJSON") }, GEOM_BUILDER(Create_func_as_geojson)},
- { { STRING_WITH_LEN("ST_ASTEXT") }, GEOM_BUILDER(Create_func_as_wkt)},
- { { STRING_WITH_LEN("ST_ASWKB") }, GEOM_BUILDER(Create_func_as_wkb)},
- { { STRING_WITH_LEN("ST_ASWKT") }, GEOM_BUILDER(Create_func_as_wkt)},
- { { STRING_WITH_LEN("ST_BOUNDARY") }, GEOM_BUILDER(Create_func_boundary)},
- { { STRING_WITH_LEN("ST_BUFFER") }, GEOM_BUILDER(Create_func_buffer)},
- { { STRING_WITH_LEN("ST_CENTROID") }, GEOM_BUILDER(Create_func_centroid)},
- { { STRING_WITH_LEN("ST_CONTAINS") }, GEOM_BUILDER(Create_func_contains)},
- { { STRING_WITH_LEN("ST_CONVEXHULL") }, GEOM_BUILDER(Create_func_convexhull)},
- { { STRING_WITH_LEN("ST_CROSSES") }, GEOM_BUILDER(Create_func_crosses)},
- { { STRING_WITH_LEN("ST_DIFFERENCE") }, GEOM_BUILDER(Create_func_difference)},
- { { STRING_WITH_LEN("ST_DIMENSION") }, GEOM_BUILDER(Create_func_dimension)},
- { { STRING_WITH_LEN("ST_DISJOINT") }, GEOM_BUILDER(Create_func_disjoint)},
- { { STRING_WITH_LEN("ST_DISTANCE") }, GEOM_BUILDER(Create_func_distance)},
- { { STRING_WITH_LEN("ST_ENDPOINT") }, GEOM_BUILDER(Create_func_endpoint)},
- { { STRING_WITH_LEN("ST_ENVELOPE") }, GEOM_BUILDER(Create_func_envelope)},
- { { STRING_WITH_LEN("ST_EQUALS") }, GEOM_BUILDER(Create_func_equals)},
- { { STRING_WITH_LEN("ST_EXTERIORRING") }, GEOM_BUILDER(Create_func_exteriorring)},
- { { STRING_WITH_LEN("ST_GEOMCOLLFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_GEOMCOLLFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_GEOMETRYCOLLECTIONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_GEOMETRYCOLLECTIONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_GEOMETRYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_GEOMETRYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_GEOMETRYN") }, GEOM_BUILDER(Create_func_geometryn)},
- { { STRING_WITH_LEN("ST_GEOMETRYTYPE") }, GEOM_BUILDER(Create_func_geometry_type)},
- { { STRING_WITH_LEN("ST_GEOMFROMGEOJSON") }, GEOM_BUILDER(Create_func_geometry_from_json)},
- { { STRING_WITH_LEN("ST_GEOMFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_GEOMFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
-#ifndef DBUG_OFF
- { { STRING_WITH_LEN("ST_GIS_DEBUG") }, GEOM_BUILDER(Create_func_gis_debug)},
-#endif
- { { STRING_WITH_LEN("ST_EQUALS") }, GEOM_BUILDER(Create_func_equals)},
- { { STRING_WITH_LEN("ST_INTERIORRINGN") }, GEOM_BUILDER(Create_func_interiorringn)},
- { { STRING_WITH_LEN("ST_INTERSECTS") }, GEOM_BUILDER(Create_func_intersects)},
- { { STRING_WITH_LEN("ST_INTERSECTION") }, GEOM_BUILDER(Create_func_intersection)},
- { { STRING_WITH_LEN("ST_ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)},
- { { STRING_WITH_LEN("ST_ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)},
- { { STRING_WITH_LEN("ST_ISRING") }, GEOM_BUILDER(Create_func_isring)},
- { { STRING_WITH_LEN("ST_ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)},
- { { STRING_WITH_LEN("ST_LENGTH") }, GEOM_BUILDER(Create_func_glength)},
- { { STRING_WITH_LEN("ST_LINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_LINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_LINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_LINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_MLINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_MLINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_MPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_MPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_MPOLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_MPOLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_MULTILINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_MULTILINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_MULTIPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_MULTIPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_MULTIPOLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_MULTIPOLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_NUMGEOMETRIES") }, GEOM_BUILDER(Create_func_numgeometries)},
- { { STRING_WITH_LEN("ST_NUMINTERIORRINGS") }, GEOM_BUILDER(Create_func_numinteriorring)},
- { { STRING_WITH_LEN("ST_NUMPOINTS") }, GEOM_BUILDER(Create_func_numpoints)},
- { { STRING_WITH_LEN("ST_OVERLAPS") }, GEOM_BUILDER(Create_func_overlaps)},
- { { STRING_WITH_LEN("ST_POINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_POINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_POINTN") }, GEOM_BUILDER(Create_func_pointn)},
- { { STRING_WITH_LEN("ST_POINTONSURFACE") }, GEOM_BUILDER(Create_func_pointonsurface)},
- { { STRING_WITH_LEN("ST_POLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_POLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_POLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_POLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_RELATE") }, GEOM_BUILDER(Create_func_relate)},
- { { STRING_WITH_LEN("ST_SRID") }, GEOM_BUILDER(Create_func_srid)},
- { { STRING_WITH_LEN("ST_STARTPOINT") }, GEOM_BUILDER(Create_func_startpoint)},
- { { STRING_WITH_LEN("ST_SYMDIFFERENCE") }, GEOM_BUILDER(Create_func_symdifference)},
- { { STRING_WITH_LEN("ST_TOUCHES") }, GEOM_BUILDER(Create_func_touches)},
- { { STRING_WITH_LEN("ST_UNION") }, GEOM_BUILDER(Create_func_union)},
- { { STRING_WITH_LEN("ST_WITHIN") }, GEOM_BUILDER(Create_func_within)},
- { { STRING_WITH_LEN("ST_X") }, GEOM_BUILDER(Create_func_x)},
- { { STRING_WITH_LEN("ST_Y") }, GEOM_BUILDER(Create_func_y)},
{ { STRING_WITH_LEN("SUBSTR_ORACLE") },
BUILDER(Create_func_substr_oracle)},
{ { STRING_WITH_LEN("SUBSTRING_INDEX") }, BUILDER(Create_func_substr_index)},
@@ -7465,7 +5576,6 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("TIMEDIFF") }, BUILDER(Create_func_timediff)},
{ { STRING_WITH_LEN("TIME_FORMAT") }, BUILDER(Create_func_time_format)},
{ { STRING_WITH_LEN("TIME_TO_SEC") }, BUILDER(Create_func_time_to_sec)},
- { { STRING_WITH_LEN("TOUCHES") }, GEOM_BUILDER(Create_func_touches)},
{ { STRING_WITH_LEN("TO_BASE64") }, BUILDER(Create_func_to_base64)},
{ { STRING_WITH_LEN("TO_DAYS") }, BUILDER(Create_func_to_days)},
{ { STRING_WITH_LEN("TO_SECONDS") }, BUILDER(Create_func_to_seconds)},
@@ -7481,29 +5591,18 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("VERSION") }, BUILDER(Create_func_version)},
{ { STRING_WITH_LEN("WEEKDAY") }, BUILDER(Create_func_weekday)},
{ { STRING_WITH_LEN("WEEKOFYEAR") }, BUILDER(Create_func_weekofyear)},
- { { STRING_WITH_LEN("WITHIN") }, GEOM_BUILDER(Create_func_within)},
#ifdef WITH_WSREP
{ { STRING_WITH_LEN("WSREP_LAST_WRITTEN_GTID") }, BUILDER(Create_func_wsrep_last_written_gtid)},
{ { STRING_WITH_LEN("WSREP_LAST_SEEN_GTID") }, BUILDER(Create_func_wsrep_last_seen_gtid)},
{ { STRING_WITH_LEN("WSREP_SYNC_WAIT_UPTO_GTID") }, BUILDER(Create_func_wsrep_sync_wait_upto)},
#endif /* WITH_WSREP */
- { { STRING_WITH_LEN("X") }, GEOM_BUILDER(Create_func_x)},
- { { STRING_WITH_LEN("Y") }, GEOM_BUILDER(Create_func_y)},
- { { STRING_WITH_LEN("YEARWEEK") }, BUILDER(Create_func_year_week)},
-
- { {0, 0}, NULL}
+ { { STRING_WITH_LEN("YEARWEEK") }, BUILDER(Create_func_year_week)}
};
-static HASH native_functions_hash;
+Native_func_registry_array
+ native_func_registry_array(func_array, array_elements(func_array));
-extern "C" uchar*
-get_native_fct_hash_key(const uchar *buff, size_t *length,
- my_bool /* unused */)
-{
- Native_func_registry *func= (Native_func_registry*) buff;
- *length= func->name.length;
- return (uchar*) func->name.str;
-}
+static HASH native_functions_hash;
/*
Load the hash table for native functions.
@@ -7514,20 +5613,42 @@ get_native_fct_hash_key(const uchar *buff, size_t *length,
int item_create_init()
{
DBUG_ENTER("item_create_init");
+ size_t count= native_func_registry_array.count();
+#ifdef HAVE_SPATIAL
+ count+= native_func_registry_array_geom.count();
+#endif
+ if (my_hash_init(key_memory_native_functions, & native_functions_hash,
+ system_charset_info, (ulong) count, 0, 0, (my_hash_get_key)
+ get_native_fct_hash_key, NULL, MYF(0)))
+ DBUG_RETURN(1);
- if (my_hash_init(& native_functions_hash,
- system_charset_info,
- array_elements(func_array),
- 0,
- 0,
- (my_hash_get_key) get_native_fct_hash_key,
- NULL, /* Nothing to free */
- MYF(0)))
+ if (native_func_registry_array.append_to_hash(&native_functions_hash))
+ DBUG_RETURN(1);
+
+#ifdef HAVE_SPATIAL
+ if (native_func_registry_array_geom.append_to_hash(&native_functions_hash))
DBUG_RETURN(1);
+#endif
+
+#ifndef DBUG_OFF
+ for (uint i=0 ; i < native_functions_hash.records ; i++)
+ {
+ Native_func_registry *func;
+ func= (Native_func_registry*) my_hash_element(& native_functions_hash, i);
+ DBUG_PRINT("info", ("native function: %s length: %u",
+ func->name.str, (uint) func->name.length));
+ }
+#endif
- DBUG_RETURN(item_create_append(func_array));
+ DBUG_RETURN(0);
}
+
+/*
+ This function is used (dangerously) by plugin/versioning/versioning.cc
+ TODO: MDEV-20842 Wrap SQL functions defined in
+ plugin/versioning/versioning.cc into MariaDB_FUNCTION_PLUGIN
+*/
int item_create_append(Native_func_registry array[])
{
Native_func_registry *func;
@@ -7540,15 +5661,6 @@ int item_create_append(Native_func_registry array[])
DBUG_RETURN(1);
}
-#ifndef DBUG_OFF
- for (uint i=0 ; i < native_functions_hash.records ; i++)
- {
- func= (Native_func_registry*) my_hash_element(& native_functions_hash, i);
- DBUG_PRINT("info", ("native function: %s length: %u",
- func->name.str, (uint) func->name.length));
- }
-#endif
-
DBUG_RETURN(0);
}
@@ -7565,6 +5677,24 @@ void item_create_cleanup()
DBUG_VOID_RETURN;
}
+
+static Create_func *
+function_plugin_find_native_function_builder(THD *thd, const LEX_CSTRING &name)
+{
+ plugin_ref plugin;
+ if ((plugin= my_plugin_lock_by_name(thd, &name, MariaDB_FUNCTION_PLUGIN)))
+ {
+ Create_func *builder=
+ reinterpret_cast<Plugin_function*>(plugin_decl(plugin)->info)->
+ create_func();
+ // TODO: MDEV-20846 Add proper unlocking for MariaDB_FUNCTION_PLUGIN
+ plugin_unlock(thd, plugin);
+ return builder;
+ }
+ return NULL;
+}
+
+
Create_func *
find_native_function_builder(THD *thd, const LEX_CSTRING *name)
{
@@ -7576,12 +5706,13 @@ find_native_function_builder(THD *thd, const LEX_CSTRING *name)
(uchar*) name->str,
name->length);
- if (func)
- {
- builder= func->builder;
- }
+ if (func && (builder= func->builder))
+ return builder;
- return builder;
+ if ((builder= function_plugin_find_native_function_builder(thd, *name)))
+ return builder;
+
+ return NULL;
}
Create_qfunc *
diff --git a/sql/item_create.h b/sql/item_create.h
index 5890e8ad057..c9bdb23dffe 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -69,6 +69,111 @@ protected:
/**
+ Adapter for functions that takes exactly zero arguments.
+*/
+
+class Create_func_arg0 : public Create_func
+{
+public:
+ virtual Item *create_func(THD *thd, LEX_CSTRING *name,
+ List<Item> *item_list);
+
+ /**
+ Builder method, with no arguments.
+ @param thd The current thread
+ @return An item representing the function call
+ */
+ virtual Item *create_builder(THD *thd) = 0;
+
+protected:
+ /** Constructor. */
+ Create_func_arg0() {}
+ /** Destructor. */
+ virtual ~Create_func_arg0() {}
+};
+
+
+/**
+ Adapter for functions that takes exactly one argument.
+*/
+
+class Create_func_arg1 : public Create_func
+{
+public:
+ virtual Item *create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+ /**
+ Builder method, with one argument.
+ @param thd The current thread
+ @param arg1 The first argument of the function
+ @return An item representing the function call
+ */
+ virtual Item *create_1_arg(THD *thd, Item *arg1) = 0;
+
+protected:
+ /** Constructor. */
+ Create_func_arg1() {}
+ /** Destructor. */
+ virtual ~Create_func_arg1() {}
+};
+
+
+/**
+ Adapter for functions that takes exactly two arguments.
+*/
+
+class Create_func_arg2 : public Create_func
+{
+public:
+ virtual Item *create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+ /**
+ Builder method, with two arguments.
+ @param thd The current thread
+ @param arg1 The first argument of the function
+ @param arg2 The second argument of the function
+ @return An item representing the function call
+ */
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) = 0;
+
+protected:
+ /** Constructor. */
+ Create_func_arg2() {}
+ /** Destructor. */
+ virtual ~Create_func_arg2() {}
+};
+
+
+/**
+ Adapter for functions that takes exactly three arguments.
+*/
+
+class Create_func_arg3 : public Create_func
+{
+public:
+ virtual Item *create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+ /**
+ Builder method, with three arguments.
+ @param thd The current thread
+ @param arg1 The first argument of the function
+ @param arg2 The second argument of the function
+ @param arg3 The third argument of the function
+ @return An item representing the function call
+ */
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3) = 0;
+
+protected:
+ /** Constructor. */
+ Create_func_arg3() {}
+ /** Destructor. */
+ virtual ~Create_func_arg3() {}
+};
+
+
+
+
+/**
Adapter for native functions with a variable number of arguments.
The main use of this class is to discard the following calls:
<code>foo(expr1 AS name1, expr2 AS name2, ...)</code>
@@ -210,5 +315,30 @@ Item *create_func_dyncol_get(THD *thd, Item *num, Item *str,
const char *c_len, const char *c_dec,
CHARSET_INFO *cs);
Item *create_func_dyncol_json(THD *thd, Item *str);
+
+
+class Native_func_registry_array
+{
+ const Native_func_registry *m_elements;
+ size_t m_count;
+public:
+ Native_func_registry_array()
+ :m_elements(NULL),
+ m_count(0)
+ { }
+ Native_func_registry_array(const Native_func_registry *elements, size_t count)
+ :m_elements(elements),
+ m_count(count)
+ { }
+ const Native_func_registry& element(size_t i) const
+ {
+ DBUG_ASSERT(i < m_count);
+ return m_elements[i];
+ }
+ size_t count() const { return m_count; }
+ bool append_to_hash(HASH *hash) const;
+};
+
+
#endif
diff --git a/sql/item_func.cc b/sql/item_func.cc
index c1350fd1818..b75bae596e8 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2009, 2019, MariaDB
+ Copyright (c) 2009, 2020, 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
@@ -405,6 +405,25 @@ Item_func::eval_not_null_tables(void *opt_arg)
}
+bool
+Item_func::find_not_null_fields(table_map allowed)
+{
+ if (~allowed & used_tables())
+ return false;
+
+ Item **arg,**arg_end;
+ if (arg_count)
+ {
+ for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
+ {
+ if (!(*arg)->find_not_null_fields(allowed))
+ continue;
+ }
+ }
+ return false;
+}
+
+
void Item_func::fix_after_pullout(st_select_lex *new_parent, Item **ref,
bool merge)
{
@@ -657,16 +676,6 @@ bool Item_func::is_expensive_processor(uchar *arg)
}
*/
-my_decimal *Item_func::val_decimal(my_decimal *decimal_value)
-{
- DBUG_ASSERT(fixed);
- longlong nr= val_int();
- if (null_value)
- return 0; /* purecov: inspected */
- int2my_decimal(E_DEC_FATAL_ERROR, nr, unsigned_flag, decimal_value);
- return decimal_value;
-}
-
bool Item_hybrid_func::fix_attributes(Item **items, uint nitems)
{
@@ -1208,7 +1217,10 @@ void Item_func_minus::fix_unsigned_flag()
{
if (unsigned_flag &&
(current_thd->variables.sql_mode & MODE_NO_UNSIGNED_SUBTRACTION))
+ {
unsigned_flag=0;
+ set_handler(Item_func_minus::type_handler()->type_handler_signed());
+ }
}
@@ -1224,9 +1236,8 @@ bool Item_func_minus::fix_length_and_dec()
if (Item_func_minus::type_handler()->Item_func_minus_fix_length_and_dec(this))
DBUG_RETURN(TRUE);
DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr()));
- if ((m_depends_on_sql_mode_no_unsigned_subtraction= unsigned_flag) &&
- (current_thd->variables.sql_mode & MODE_NO_UNSIGNED_SUBTRACTION))
- unsigned_flag= false;
+ m_depends_on_sql_mode_no_unsigned_subtraction= unsigned_flag;
+ fix_unsigned_flag();
DBUG_RETURN(FALSE);
}
@@ -1729,9 +1740,9 @@ static void calc_hash_for_unique(ulong &nr1, ulong &nr2, String *str)
uchar l[4];
int4store(l, str->length());
cs= str->charset();
- cs->coll->hash_sort(cs, l, sizeof(l), &nr1, &nr2);
+ cs->hash_sort(l, sizeof(l), &nr1, &nr2);
cs= str->charset();
- cs->coll->hash_sort(cs, (uchar *)str->ptr(), str->length(), &nr1, &nr2);
+ cs->hash_sort((uchar *)str->ptr(), str->length(), &nr1, &nr2);
}
longlong Item_func_hash::val_int()
@@ -1829,7 +1840,7 @@ void Item_func_neg::fix_length_and_dec_int()
Ensure that result is converted to DECIMAL, as longlong can't hold
the negated number
*/
- set_handler_by_result_type(DECIMAL_RESULT);
+ set_handler(&type_handler_newdecimal);
DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT"));
}
}
@@ -2938,11 +2949,10 @@ longlong Item_func_locate::val_int()
if (!b->length()) // Found empty string at start
return start + 1;
- if (!cmp_collation.collation->coll->instr(cmp_collation.collation,
- a->ptr()+start,
- (uint) (a->length()-start),
- b->ptr(), b->length(),
- &match, 1))
+ if (!cmp_collation.collation->instr(a->ptr() + start,
+ (uint) (a->length() - start),
+ b->ptr(), b->length(),
+ &match, 1))
return 0;
return (longlong) match.mb_len + start0 + 1;
}
@@ -3055,7 +3065,7 @@ longlong Item_func_ord::val_int()
null_value=0;
if (!res->length()) return 0;
#ifdef USE_MB
- if (use_mb(res->charset()))
+ if (res->use_mb())
{
const char *str=res->ptr();
uint32 n=0, l=my_ismbchar(res->charset(),str,str+res->length());
@@ -3141,14 +3151,14 @@ longlong Item_func_find_in_set::val_int()
const char *str_begin= buffer->ptr();
const char *str_end= buffer->ptr();
const char *real_end= str_end+buffer->length();
- const uchar *find_str= (const uchar *) find->ptr();
+ const char *find_str= find->ptr();
uint find_str_len= find->length();
int position= 0;
while (1)
{
int symbol_len;
- if ((symbol_len= cs->cset->mb_wc(cs, &wc, (uchar*) str_end,
- (uchar*) real_end)) > 0)
+ if ((symbol_len= cs->mb_wc(&wc, (uchar*) str_end,
+ (uchar*) real_end)) > 0)
{
const char *substr_end= str_end + symbol_len;
bool is_last_item= (substr_end == real_end);
@@ -3158,9 +3168,8 @@ longlong Item_func_find_in_set::val_int()
position++;
if (is_last_item && !is_separator)
str_end= substr_end;
- if (!my_strnncoll(cs, (const uchar *) str_begin,
- (uint) (str_end - str_begin),
- find_str, find_str_len))
+ if (!cs->strnncoll(str_begin, (uint) (str_end - str_begin),
+ find_str, find_str_len))
return (longlong) position;
else
str_begin= substr_end;
@@ -3997,16 +4006,17 @@ longlong Item_func_get_lock::val_int()
DBUG_PRINT("enter", ("lock: %.*s", res->length(), res->ptr()));
/* HASH entries are of type User_level_lock. */
if (! my_hash_inited(&thd->ull_hash) &&
- my_hash_init(&thd->ull_hash, &my_charset_bin,
- 16 /* small hash */, 0, 0, ull_get_key, NULL, 0))
+ my_hash_init(key_memory_User_level_lock, &thd->ull_hash,
+ &my_charset_bin, 16 /* small hash */, 0, 0, ull_get_key,
+ NULL, 0))
{
DBUG_RETURN(0);
}
MDL_request ull_request;
- ull_request.init(MDL_key::USER_LOCK, res->c_ptr_safe(), "",
+ MDL_REQUEST_INIT(&ull_request, MDL_key::USER_LOCK, res->c_ptr_safe(), "",
MDL_SHARED_NO_WRITE, MDL_EXPLICIT);
- MDL_key *ull_key = &ull_request.key;
+ MDL_key *ull_key= &ull_request.key;
if ((ull= (User_level_lock*)
@@ -4014,7 +4024,7 @@ longlong Item_func_get_lock::val_int()
{
/* Recursive lock */
ull->refs++;
- null_value = 0;
+ null_value= 0;
DBUG_PRINT("info", ("recursive lock, ref-count: %d", (int) ull->refs));
DBUG_RETURN(1);
}
@@ -4030,7 +4040,8 @@ longlong Item_func_get_lock::val_int()
DBUG_RETURN(0);
}
- ull= (User_level_lock*) my_malloc(sizeof(User_level_lock),
+ ull= (User_level_lock*) my_malloc(key_memory_User_level_lock,
+ sizeof(User_level_lock),
MYF(MY_WME|MY_THREAD_SPECIFIC));
if (ull == NULL)
{
@@ -4054,6 +4065,30 @@ longlong Item_func_get_lock::val_int()
/**
+ Release all user level locks.
+ @return
+ - N if N-lock released
+ - 0 if lock wasn't held
+*/
+longlong Item_func_release_all_locks::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ THD *thd= current_thd;
+ ulong num_unlocked= 0;
+ DBUG_ENTER("Item_func_release_all_locks::val_int");
+ for (size_t i= 0; i < thd->ull_hash.records; i++)
+ {
+ auto ull= (User_level_lock *) my_hash_element(&thd->ull_hash, i);
+ thd->mdl_context.release_lock(ull->lock);
+ num_unlocked+= ull->refs;
+ my_free(ull);
+ }
+ my_hash_free(&thd->ull_hash);
+ DBUG_RETURN(num_unlocked);
+}
+
+
+/**
Release a user level lock.
@return
- 1 if lock released
@@ -4253,7 +4288,7 @@ static PSI_mutex_key key_LOCK_item_func_sleep;
static PSI_mutex_info item_func_sleep_mutexes[]=
{
- { &key_LOCK_item_func_sleep, "LOCK_user_locks", PSI_FLAG_GLOBAL}
+ { &key_LOCK_item_func_sleep, "LOCK_item_func_sleep", PSI_FLAG_GLOBAL}
};
@@ -4374,7 +4409,7 @@ user_var_entry *get_variable(HASH *hash, LEX_CSTRING *name,
size_t size=ALIGN_SIZE(sizeof(user_var_entry))+name->length+1+extra_size;
if (!my_hash_inited(hash))
return 0;
- if (!(entry = (user_var_entry*) my_malloc(size,
+ if (!(entry = (user_var_entry*) my_malloc(key_memory_user_var_entry, size,
MYF(MY_WME | ME_FATAL |
MY_THREAD_SPECIFIC))))
return 0;
@@ -4466,8 +4501,10 @@ bool Item_func_set_user_var::fix_fields(THD *thd, Item **ref)
null_item= (args[0]->type() == NULL_ITEM);
if (!m_var_entry->charset() || !null_item)
m_var_entry->set_charset(args[0]->collation.derivation == DERIVATION_NUMERIC ?
- default_charset() : args[0]->collation.collation);
- collation.set(m_var_entry->charset(), DERIVATION_IMPLICIT);
+ &my_charset_numeric : args[0]->collation.collation);
+ collation.set(m_var_entry->charset(),
+ args[0]->collation.derivation == DERIVATION_NUMERIC ?
+ DERIVATION_NUMERIC : DERIVATION_IMPLICIT);
switch (args[0]->result_type()) {
case STRING_RESULT:
case TIME_RESULT:
@@ -4479,7 +4516,8 @@ bool Item_func_set_user_var::fix_fields(THD *thd, Item **ref)
set_handler(&type_handler_double);
break;
case INT_RESULT:
- set_handler(Type_handler::type_handler_long_or_longlong(max_char_length()));
+ set_handler(Type_handler::type_handler_long_or_longlong(max_char_length(),
+ unsigned_flag));
break;
case DECIMAL_RESULT:
set_handler(&type_handler_newdecimal);
@@ -4519,11 +4557,14 @@ Item_func_set_user_var::fix_length_and_dec()
{
maybe_null=args[0]->maybe_null;
decimals=args[0]->decimals;
- collation.set(DERIVATION_IMPLICIT);
if (args[0]->collation.derivation == DERIVATION_NUMERIC)
- fix_length_and_charset(args[0]->max_char_length(), default_charset());
+ {
+ collation.set(DERIVATION_NUMERIC);
+ fix_length_and_charset(args[0]->max_char_length(), &my_charset_numeric);
+ }
else
{
+ collation.set(DERIVATION_IMPLICIT);
fix_length_and_charset(args[0]->max_char_length(),
args[0]->collation.collation);
}
@@ -4628,10 +4669,10 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, size_t length,
char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry));
if (entry->value == pos)
entry->value=0;
- entry->value= (char*) my_realloc(entry->value, length,
+ entry->value= (char*) my_realloc(key_memory_user_var_entry_value,
+ entry->value, length,
MYF(MY_ALLOW_ZERO_PTR | MY_WME |
- ME_FATAL |
- MY_THREAD_SPECIFIC));
+ ME_FATAL | MY_THREAD_SPECIFIC));
if (!entry->value)
return 1;
}
@@ -4649,6 +4690,10 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, size_t length,
entry->unsigned_flag= unsigned_arg;
}
entry->type=type;
+#ifndef EMBEDDED_LIBRARY
+ THD *thd= current_thd;
+ thd->session_tracker.user_variables.mark_as_changed(thd, entry);
+#endif
return 0;
}
@@ -4738,7 +4783,7 @@ longlong user_var_entry::val_int(bool *null_value) const
/** Get the value of a variable as a string. */
String *user_var_entry::val_str(bool *null_value, String *str,
- uint decimals)
+ uint decimals) const
{
if ((*null_value= (value == 0)))
return (String*) 0;
@@ -4914,13 +4959,13 @@ Item_func_set_user_var::update()
case REAL_RESULT:
{
res= update_hash((void*) &save_result.vreal,sizeof(save_result.vreal),
- REAL_RESULT, default_charset(), 0);
+ REAL_RESULT, &my_charset_numeric, 0);
break;
}
case INT_RESULT:
{
res= update_hash((void*) &save_result.vint, sizeof(save_result.vint),
- INT_RESULT, default_charset(), unsigned_flag);
+ INT_RESULT, &my_charset_numeric, unsigned_flag);
break;
}
case STRING_RESULT:
@@ -4940,7 +4985,7 @@ Item_func_set_user_var::update()
else
res= update_hash((void*) save_result.vdec,
sizeof(my_decimal), DECIMAL_RESULT,
- default_charset(), 0);
+ &my_charset_numeric, 0);
break;
}
case ROW_RESULT:
@@ -5071,7 +5116,7 @@ void Item_func_set_user_var::make_send_field(THD *thd, Send_field *tmp_field)
if (result_field)
{
result_field->make_send_field(tmp_field);
- DBUG_ASSERT(tmp_field->table_name != 0);
+ DBUG_ASSERT(tmp_field->table_name.str != 0);
if (Item::name.str)
tmp_field->col_name= Item::name; // Use user supplied name
}
@@ -5379,22 +5424,31 @@ bool Item_func_get_user_var::fix_length_and_dec()
{
unsigned_flag= m_var_entry->unsigned_flag;
max_length= (uint32)m_var_entry->length;
- collation.set(m_var_entry->charset(), DERIVATION_IMPLICIT);
- set_handler_by_result_type(m_var_entry->type);
- switch (result_type()) {
+ switch (m_var_entry->type) {
case REAL_RESULT:
+ collation.set(&my_charset_numeric, DERIVATION_NUMERIC);
fix_char_length(DBL_DIG + 8);
+ set_handler(&type_handler_double);
break;
case INT_RESULT:
+ collation.set(&my_charset_numeric, DERIVATION_NUMERIC);
fix_char_length(MAX_BIGINT_WIDTH);
decimals=0;
+ if (unsigned_flag)
+ set_handler(&type_handler_ulonglong);
+ else
+ set_handler(&type_handler_slonglong);
break;
case STRING_RESULT:
+ collation.set(m_var_entry->charset(), DERIVATION_IMPLICIT);
max_length= MAX_BLOB_WIDTH - 1;
+ set_handler(&type_handler_long_blob);
break;
case DECIMAL_RESULT:
+ collation.set(&my_charset_numeric, DERIVATION_NUMERIC);
fix_char_length(DECIMAL_MAX_STR_LENGTH);
decimals= DECIMAL_MAX_SCALE;
+ set_handler(&type_handler_newdecimal);
break;
case ROW_RESULT: // Keep compiler happy
case TIME_RESULT:
@@ -5591,7 +5645,7 @@ bool Item_func_get_system_var::fix_length_and_dec()
case SHOW_SINT:
case SHOW_SLONG:
case SHOW_SLONGLONG:
- collation.set_numeric();
+ collation= DTCollation_numeric();
fix_char_length(MY_INT64_NUM_DECIMAL_DIGITS);
decimals=0;
break;
@@ -5602,9 +5656,8 @@ bool Item_func_get_system_var::fix_length_and_dec()
(char*) var->value_ptr(current_thd, var_type, &component) :
*(char**) var->value_ptr(current_thd, var_type, &component);
if (cptr)
- max_length= (uint32)system_charset_info->cset->numchars(system_charset_info,
- cptr,
- cptr + strlen(cptr));
+ max_length= (uint32) system_charset_info->numchars(cptr,
+ cptr + strlen(cptr));
mysql_mutex_unlock(&LOCK_global_system_variables);
collation.set(system_charset_info, DERIVATION_SYSCONST);
max_length*= system_charset_info->mbmaxlen;
@@ -5614,9 +5667,8 @@ bool Item_func_get_system_var::fix_length_and_dec()
{
mysql_mutex_lock(&LOCK_global_system_variables);
LEX_STRING *ls= ((LEX_STRING*)var->value_ptr(current_thd, var_type, &component));
- max_length= (uint32)system_charset_info->cset->numchars(system_charset_info,
- ls->str,
- ls->str + ls->length);
+ max_length= (uint32) system_charset_info->numchars(ls->str,
+ ls->str + ls->length);
mysql_mutex_unlock(&LOCK_global_system_variables);
collation.set(system_charset_info, DERIVATION_SYSCONST);
max_length*= system_charset_info->mbmaxlen;
@@ -5625,13 +5677,13 @@ bool Item_func_get_system_var::fix_length_and_dec()
break;
case SHOW_BOOL:
case SHOW_MY_BOOL:
- collation.set_numeric();
+ collation= DTCollation_numeric();
fix_char_length(1);
decimals=0;
break;
case SHOW_DOUBLE:
decimals= 6;
- collation.set_numeric();
+ collation= DTCollation_numeric();
fix_char_length(DBL_DIG + 6);
break;
default:
@@ -5677,11 +5729,12 @@ const Type_handler *Item_func_get_system_var::type_handler() const
case SHOW_SINT:
case SHOW_SLONG:
case SHOW_SLONGLONG:
+ return &type_handler_slonglong;
case SHOW_UINT:
case SHOW_ULONG:
case SHOW_ULONGLONG:
case SHOW_HA_ROWS:
- return &type_handler_longlong;
+ return &type_handler_ulonglong;
case SHOW_CHAR:
case SHOW_CHAR_PTR:
case SHOW_LEX_STRING:
@@ -6730,7 +6783,7 @@ longlong Item_func_nextval::val_int()
if (!(entry= ((SEQUENCE_LAST_VALUE*)
my_hash_search(&thd->sequences, (uchar*) key, length))))
{
- if (!(key= (char*) my_memdup(key, length, MYF(MY_WME))) ||
+ if (!(key= (char*) my_memdup(PSI_INSTRUMENT_ME, key, length, MYF(MY_WME))) ||
!(entry= new SEQUENCE_LAST_VALUE((uchar*) key, length)))
{
/* EOM, error given */
diff --git a/sql/item_func.h b/sql/item_func.h
index 996a445617b..3771992d617 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1,7 +1,7 @@
#ifndef ITEM_FUNC_INCLUDED
#define ITEM_FUNC_INCLUDED
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2009, 2016, MariaDB
+ Copyright (c) 2009, 2020, 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
@@ -188,12 +188,10 @@ public:
void signal_divide_by_null();
friend class udf_handler;
- Field *create_field_for_create_select(TABLE *table)
- { return tmp_table_field_from_field_type(table); }
+ Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table)
+ { return tmp_table_field_from_field_type(root, table); }
Item *get_tmp_table_item(THD *thd);
- my_decimal *val_decimal(my_decimal *);
-
void fix_char_length_ulonglong(ulonglong max_char_length_arg)
{
ulonglong max_result_length= max_char_length_arg *
@@ -212,6 +210,7 @@ public:
void traverse_cond(Cond_traverser traverser,
void * arg, traverse_order order);
bool eval_not_null_tables(void *opt_arg);
+ bool find_not_null_fields(table_map allowed);
// bool is_expensive_processor(void *arg);
// virtual bool is_expensive() { return 0; }
inline void raise_numeric_overflow(const char *type_name)
@@ -406,13 +405,13 @@ public:
class Item_real_func :public Item_func
{
public:
- Item_real_func(THD *thd): Item_func(thd) { collation.set_numeric(); }
+ Item_real_func(THD *thd): Item_func(thd) { collation= DTCollation_numeric(); }
Item_real_func(THD *thd, Item *a): Item_func(thd, a)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
Item_real_func(THD *thd, Item *a, Item *b): Item_func(thd, a, b)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
Item_real_func(THD *thd, List<Item> &list): Item_func(thd, list)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
String *val_str(String*str);
my_decimal *val_decimal(my_decimal *decimal_value);
longlong val_int()
@@ -436,8 +435,7 @@ public:
Functions whose returned field type is determined at fix_fields() time.
*/
class Item_hybrid_func: public Item_func,
- public Type_handler_hybrid_field_type,
- public Type_geometry_attributes
+ public Type_handler_hybrid_field_type
{
protected:
bool fix_attributes(Item **item, uint nitems);
@@ -452,12 +450,6 @@ public:
:Item_func(thd, item), Type_handler_hybrid_field_type(item) { }
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
- Field::geometry_type get_geometry_type() const
- { return Type_geometry_attributes::get_geometry_type(); };
- void set_geometry_type(uint type)
- {
- Type_geometry_attributes::set_geometry_type(type);
- }
};
@@ -474,10 +466,48 @@ public:
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(THD *thd, Item_handled_func *, MYSQL_TIME *, date_mode_t fuzzydate) const= 0;
- virtual const Type_handler *return_type_handler() const= 0;
+ virtual const Type_handler *
+ return_type_handler(const Item_handled_func *item) const= 0;
+ virtual const Type_handler *
+ type_handler_for_create_select(const Item_handled_func *item) const
+ {
+ return return_type_handler(item);
+ }
virtual bool fix_length_and_dec(Item_handled_func *) const= 0;
};
+ class Handler_str: public Handler
+ {
+ public:
+ String *val_str_ascii(Item_handled_func *item, String *str) const
+ {
+ return item->Item::val_str_ascii(str);
+ }
+ double val_real(Item_handled_func *item) const
+ {
+ DBUG_ASSERT(item->is_fixed());
+ StringBuffer<64> tmp;
+ String *res= item->val_str(&tmp);
+ return res ? item->double_from_string_with_check(res) : 0.0;
+ }
+ longlong val_int(Item_handled_func *item) const
+ {
+ DBUG_ASSERT(item->is_fixed());
+ StringBuffer<22> tmp;
+ String *res= item->val_str(&tmp);
+ return res ? item->longlong_from_string_with_check(res) : 0;
+ }
+ my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const
+ {
+ return item->val_decimal_from_string(to);
+ }
+ bool get_date(THD *thd, Item_handled_func *item, MYSQL_TIME *to,
+ date_mode_t fuzzydate) const
+ {
+ return item->get_date_from_string(thd, to, fuzzydate);
+ }
+ };
+
/**
Abstract class for functions returning TIME, DATE, DATETIME or string values,
whose data type depends on parameters and is set at fix_fields time.
@@ -500,10 +530,15 @@ public:
class Handler_temporal_string: public Handler_temporal
{
public:
- const Type_handler *return_type_handler() const
+ const Type_handler *return_type_handler(const Item_handled_func *) const
{
return &type_handler_string;
}
+ const Type_handler *
+ type_handler_for_create_select(const Item_handled_func *item) const
+ {
+ return return_type_handler(item)->type_handler_for_tmp_table(item);
+ }
double val_real(Item_handled_func *item) const
{
return Temporal_hybrid(item).to_double();
@@ -526,7 +561,7 @@ public:
class Handler_date: public Handler_temporal
{
public:
- const Type_handler *return_type_handler() const
+ const Type_handler *return_type_handler(const Item_handled_func *) const
{
return &type_handler_newdate;
}
@@ -557,7 +592,7 @@ public:
class Handler_time: public Handler_temporal
{
public:
- const Type_handler *return_type_handler() const
+ const Type_handler *return_type_handler(const Item_handled_func *) const
{
return &type_handler_time2;
}
@@ -583,7 +618,7 @@ public:
class Handler_datetime: public Handler_temporal
{
public:
- const Type_handler *return_type_handler() const
+ const Type_handler *return_type_handler(const Item_handled_func *) const
{
return &type_handler_datetime2;
}
@@ -619,7 +654,15 @@ public:
}
const Type_handler *type_handler() const
{
- return m_func_handler->return_type_handler();
+ return m_func_handler->return_type_handler(this);
+ }
+ Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table)
+ {
+ DBUG_ASSERT(fixed);
+ const Type_handler *h= m_func_handler->type_handler_for_create_select(this);
+ return h->make_and_init_table_field(root, &name,
+ Record_addr(maybe_null),
+ *this, table);
}
String *val_str(String *to)
{
@@ -730,19 +773,19 @@ public:
public:
Item_func_hybrid_field_type(THD *thd):
Item_hybrid_func(thd)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
Item_func_hybrid_field_type(THD *thd, Item *a):
Item_hybrid_func(thd, a)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
Item_func_hybrid_field_type(THD *thd, Item *a, Item *b):
Item_hybrid_func(thd, a, b)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
Item_func_hybrid_field_type(THD *thd, Item *a, Item *b, Item *c):
Item_hybrid_func(thd, a, b, c)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
Item_func_hybrid_field_type(THD *thd, List<Item> &list):
Item_hybrid_func(thd, list)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
double val_real()
{
@@ -882,6 +925,7 @@ public:
Item_func_case_expression(THD *thd, List<Item> &list):
Item_func_hybrid_field_type(thd, list)
{ }
+ bool find_not_null_fields(table_map allowed) { return false; }
};
@@ -943,7 +987,12 @@ public:
/* Base class for operations like '+', '-', '*' */
class Item_num_op :public Item_func_numhybrid
{
- public:
+protected:
+ bool check_arguments() const
+ {
+ return false; // Checked by aggregate_for_num_op()
+ }
+public:
Item_num_op(THD *thd, Item *a, Item *b): Item_func_numhybrid(thd, a, b) {}
virtual void result_precision()= 0;
@@ -954,7 +1003,7 @@ class Item_num_op :public Item_func_numhybrid
bool fix_type_handler(const Type_aggregator *aggregator);
void fix_length_and_dec_double()
{
- count_real_length(args, arg_count);
+ aggregate_numeric_attributes_real(args, arg_count);
max_length= float_length(decimals);
}
void fix_length_and_dec_decimal()
@@ -991,22 +1040,26 @@ public:
Min signed = -9,223,372,036,854,775,808 = 19 digits, 20 characters
*/
Item_int_func(THD *thd): Item_func(thd)
- { collation.set_numeric(); fix_char_length(21); }
+ { collation= DTCollation_numeric(); fix_char_length(21); }
Item_int_func(THD *thd, Item *a): Item_func(thd, a)
- { collation.set_numeric(); fix_char_length(21); }
+ { collation= DTCollation_numeric(); fix_char_length(21); }
Item_int_func(THD *thd, Item *a, Item *b): Item_func(thd, a, b)
- { collation.set_numeric(); fix_char_length(21); }
+ { collation= DTCollation_numeric(); fix_char_length(21); }
Item_int_func(THD *thd, Item *a, Item *b, Item *c): Item_func(thd, a, b, c)
- { collation.set_numeric(); fix_char_length(21); }
+ { collation= DTCollation_numeric(); fix_char_length(21); }
Item_int_func(THD *thd, Item *a, Item *b, Item *c, Item *d):
Item_func(thd, a, b, c, d)
- { collation.set_numeric(); fix_char_length(21); }
+ { collation= DTCollation_numeric(); fix_char_length(21); }
Item_int_func(THD *thd, List<Item> &list): Item_func(thd, list)
- { collation.set_numeric(); fix_char_length(21); }
+ { collation= DTCollation_numeric(); fix_char_length(21); }
Item_int_func(THD *thd, Item_int_func *item) :Item_func(thd, item)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
double val_real();
String *val_str(String*str);
+ my_decimal *val_decimal(my_decimal *decimal_value)
+ {
+ return val_decimal_from_int(decimal_value);
+ }
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;
@@ -1023,7 +1076,12 @@ public:
Item_long_func(THD *thd, Item *a, Item *b, Item *c): Item_int_func(thd, a, b, c) {}
Item_long_func(THD *thd, List<Item> &list): Item_int_func(thd, list) { }
Item_long_func(THD *thd, Item_long_func *item) :Item_int_func(thd, item) {}
- const Type_handler *type_handler() const { return &type_handler_long; }
+ const Type_handler *type_handler() const
+ {
+ if (unsigned_flag)
+ return &type_handler_ulong;
+ return &type_handler_slong;
+ }
bool fix_length_and_dec() { max_length= 11; return FALSE; }
};
@@ -1035,7 +1093,7 @@ public:
{}
longlong val_int();
bool fix_length_and_dec();
- const Type_handler *type_handler() const { return &type_handler_long; }
+ const Type_handler *type_handler() const { return &type_handler_slong; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_hash>(thd, this); }
const char *func_name() const { return "<hash>"; }
@@ -1052,7 +1110,12 @@ public:
Item_int_func(thd, a, b, c, d) {}
Item_longlong_func(THD *thd, List<Item> &list): Item_int_func(thd, list) { }
Item_longlong_func(THD *thd, Item_longlong_func *item) :Item_int_func(thd, item) {}
- const Type_handler *type_handler() const { return &type_handler_longlong; }
+ const Type_handler *type_handler() const
+ {
+ if (unsigned_flag)
+ return &type_handler_ulonglong;
+ return &type_handler_slonglong;
+ }
};
@@ -1120,7 +1183,10 @@ public:
}
const char *func_name() const { return "cast_as_signed"; }
const Type_handler *type_handler() const
- { return type_handler_long_or_longlong(); }
+ {
+ return Type_handler::type_handler_long_or_longlong(max_char_length(),
+ false);
+ }
longlong val_int()
{
longlong value= args[0]->val_int_signed_typecast();
@@ -1179,8 +1245,8 @@ public:
const Type_handler *type_handler() const
{
if (max_char_length() <= MY_INT32_NUM_DECIMAL_DIGITS - 1)
- return &type_handler_long;
- return &type_handler_longlong;
+ return &type_handler_ulong;
+ return &type_handler_ulonglong;
}
longlong val_int()
{
@@ -1207,7 +1273,7 @@ public:
:Item_func(thd, a)
{
decimals= (uint8) dec;
- collation.set_numeric();
+ collation= DTCollation_numeric();
fix_char_length(my_decimal_precision_to_length_no_truncation(len, dec,
unsigned_flag));
}
@@ -1823,6 +1889,10 @@ class Item_func_min_max :public Item_hybrid_func
String tmp_value;
int cmp_sign;
protected:
+ bool check_arguments() const
+ {
+ return false; // Checked by aggregate_for_min_max()
+ }
bool fix_attributes(Item **item, uint nitems);
public:
Item_func_min_max(THD *thd, List<Item> &list, int cmp_sign_arg):
@@ -1940,9 +2010,7 @@ public:
const Type_handler *type_handler() const { return args[0]->type_handler(); }
bool fix_length_and_dec()
{
- collation= args[0]->collation;
- max_length= args[0]->max_length;
- decimals=args[0]->decimals;
+ Type_std_attributes::set(*args[0]);
return FALSE;
}
Item *get_copy(THD *thd)
@@ -2012,6 +2080,10 @@ public:
not_null_tables_cache= 0;
return false;
}
+ bool find_not_null_fields(table_map allowed)
+ {
+ return false;
+ }
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
{ return this; }
bool const_item() const { return true; }
@@ -2384,6 +2456,10 @@ public:
not_null_tables_cache= 0;
return 0;
}
+ bool find_not_null_fields(table_map allowed)
+ {
+ return false;
+ }
bool is_expensive() { return 1; }
virtual void print(String *str, enum_query_type query_type);
bool check_vcol_func_processor(void *arg)
@@ -2440,8 +2516,17 @@ public:
Item_udf_func(thd, udf_arg, list) {}
longlong val_int();
double val_real() { return (double) Item_func_udf_int::val_int(); }
+ my_decimal *val_decimal(my_decimal *decimal_value)
+ {
+ return val_decimal_from_int(decimal_value);
+ }
String *val_str(String *str);
- const Type_handler *type_handler() const { return &type_handler_longlong; }
+ const Type_handler *type_handler() const
+ {
+ if (unsigned_flag)
+ return &type_handler_ulonglong;
+ return &type_handler_slonglong;
+ }
bool fix_length_and_dec() { decimals= 0; max_length= 21; return FALSE; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_udf_int>(thd, this); }
@@ -2489,15 +2574,15 @@ public:
char *end_not_used;
String *res;
res= val_str(&str_value);
- return res ? my_strntod(res->charset(),(char*) res->ptr(),
- res->length(), &end_not_used, &err_not_used) : 0.0;
+ return res ? res->charset()->strntod((char*) res->ptr(), res->length(),
+ &end_not_used, &err_not_used) : 0.0;
}
longlong val_int()
{
int err_not_used;
String *res; res=val_str(&str_value);
- return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10,
- (char**) 0, &err_not_used) : (longlong) 0;
+ return res ? res->charset()->strntoll(res->ptr(),res->length(),10,
+ (char**) 0, &err_not_used) : (longlong) 0;
}
my_decimal *val_decimal(my_decimal *dec_buf)
{
@@ -2533,7 +2618,7 @@ public:
Item_int_func(thd) {}
Item_func_udf_int(THD *thd, udf_func *udf_arg, List<Item> &list):
Item_int_func(thd, list) {}
- const Type_handler *type_handler() const { return &type_handler_longlong; }
+ const Type_handler *type_handler() const { return &type_handler_slonglong; }
longlong val_int() { DBUG_ASSERT(fixed == 1); return 0; }
};
@@ -2545,7 +2630,7 @@ public:
Item_int_func(thd) {}
Item_func_udf_decimal(THD *thd, udf_func *udf_arg, List<Item> &list):
Item_int_func(thd, list) {}
- const Type_handler *type_handler() const { return &type_handler_longlong; }
+ const Type_handler *type_handler() const { return &type_handler_slonglong; }
my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; }
};
@@ -2569,19 +2654,13 @@ public:
void mysql_ull_cleanup(THD *thd);
void mysql_ull_set_explicit_lock_duration(THD *thd);
-class Item_func_get_lock :public Item_long_func
+
+class Item_func_lock :public Item_long_func
{
- bool check_arguments() const
- {
- return args[0]->check_type_general_purpose_string(func_name()) ||
- args[1]->check_type_can_return_real(func_name());
- }
- String value;
public:
- Item_func_get_lock(THD *thd, Item *a, Item *b) :Item_long_func(thd, a, b) {}
- longlong val_int();
- const char *func_name() const { return "get_lock"; }
- bool fix_length_and_dec() { max_length=1; maybe_null=1; return FALSE; }
+ Item_func_lock(THD *thd): Item_long_func(thd) { }
+ Item_func_lock(THD *thd, Item *a): Item_long_func(thd, a) {}
+ Item_func_lock(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) {}
table_map used_tables() const
{
return used_tables_cache | RAND_TABLE_BIT;
@@ -2592,34 +2671,54 @@ class Item_func_get_lock :public Item_long_func
{
return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE);
}
- Item *get_copy(THD *thd)
+};
+
+
+class Item_func_get_lock final :public Item_func_lock
+{
+ bool check_arguments() const
+ {
+ return args[0]->check_type_general_purpose_string(func_name()) ||
+ args[1]->check_type_can_return_real(func_name());
+ }
+ String value;
+ public:
+ Item_func_get_lock(THD *thd, Item *a, Item *b) :Item_func_lock(thd, a, b) {}
+ longlong val_int() final;
+ const char *func_name() const final { return "get_lock"; }
+ bool fix_length_and_dec() { max_length= 1; maybe_null= 1; return FALSE; }
+ Item *get_copy(THD *thd) final
{ return get_item_copy<Item_func_get_lock>(thd, this); }
};
-class Item_func_release_lock :public Item_long_func
+
+class Item_func_release_all_locks final :public Item_func_lock
+{
+public:
+ Item_func_release_all_locks(THD *thd): Item_func_lock(thd)
+ { unsigned_flag= 1; }
+ longlong val_int() final;
+ const char *func_name() const final { return "release_all_locks"; }
+ Item *get_copy(THD *thd) final
+ { return get_item_copy<Item_func_release_all_locks>(thd, this); }
+};
+
+
+class Item_func_release_lock final :public Item_func_lock
{
bool check_arguments() const
{ return args[0]->check_type_general_purpose_string(func_name()); }
String value;
public:
- Item_func_release_lock(THD *thd, Item *a): Item_long_func(thd, a) {}
- longlong val_int();
+ Item_func_release_lock(THD *thd, Item *a): Item_func_lock(thd, a) {}
+ longlong val_int() final;
const char *func_name() const { return "release_lock"; }
bool fix_length_and_dec() { max_length= 1; maybe_null= 1; return FALSE; }
- table_map used_tables() const
- {
- return used_tables_cache | RAND_TABLE_BIT;
- }
- bool const_item() const { return 0; }
- bool is_expensive() { return 1; }
- bool check_vcol_func_processor(void *arg)
- {
- return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE);
- }
- Item *get_copy(THD *thd)
+ Item *get_copy(THD *thd) final
{ return get_item_copy<Item_func_release_lock>(thd, this); }
};
+
/* replication functions */
class Item_master_pos_wait :public Item_longlong_func
@@ -2698,10 +2797,15 @@ public:
Item_func_user_var(THD *thd, Item_func_user_var *item)
:Item_hybrid_func(thd, item),
m_var_entry(item->m_var_entry), name(item->name) { }
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
- const Tmp_field_param *param);
- Field *create_field_for_create_select(TABLE *table)
- { return create_table_field_from_handler(table); }
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param)
+ {
+ DBUG_ASSERT(fixed);
+ return create_tmp_field_ex_from_handler(root, table, src, param,
+ type_handler());
+ }
+ Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table)
+ { return create_table_field_from_handler(root, table); }
bool check_vcol_func_processor(void *arg);
bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
@@ -2876,7 +2980,7 @@ public:
{
return 0;
}
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(0);
@@ -2995,6 +3099,10 @@ public:
not_null_tables_cache= 0;
return 0;
}
+ bool find_not_null_fields(table_map allowed)
+ {
+ return false;
+ }
bool fix_fields(THD *thd, Item **ref);
bool eq(const Item *, bool binary_cmp) const;
/* The following should be safe, even if we compare doubles */
@@ -3128,12 +3236,15 @@ public:
set(handler, 0, 0);
}
const Type_handler *type_handler() const { return m_type_handler; }
- Item *create_typecast_item(THD *thd, Item *item, CHARSET_INFO *cs= NULL)
+ Item *create_typecast_item(THD *thd, Item *item,
+ CHARSET_INFO *cs= NULL) const
{
return m_type_handler->
create_typecast_item(thd, item,
Type_cast_attributes(length(), dec(), cs));
}
+ Item *create_typecast_item_or_error(THD *thd, Item *item,
+ CHARSET_INFO *cs= NULL) const;
};
@@ -3195,13 +3306,13 @@ public:
const Type_handler *type_handler() const;
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param);
- Field *create_field_for_create_select(TABLE *table)
+ Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table)
{
return result_type() != STRING_RESULT ?
sp_result_field :
- create_table_field_from_handler(table);
+ create_table_field_from_handler(root, table);
}
void make_send_field(THD *thd, Send_field *tmp_field);
@@ -3295,6 +3406,10 @@ public:
}
bool excl_dep_on_grouping_fields(st_select_lex *sel)
{ return false; }
+ bool find_not_null_fields(table_map allowed)
+ {
+ return false;
+ }
};
@@ -3399,6 +3514,10 @@ public:
not_null_tables_cache= 0;
return 0;
}
+ bool find_not_null_fields(table_map allowed)
+ {
+ return false;
+ }
bool const_item() const { return 0; }
void evaluate_sideeffects();
void update_used_tables()
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 9e6c8ea9008..c107c93d584 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -38,6 +38,8 @@
#ifdef HAVE_SPATIAL
#include <m_ctype.h>
#include "opt_range.h"
+#include "item_geofunc.h"
+#include "item_create.h"
bool Item_geometry_func::fix_length_and_dec()
@@ -324,12 +326,6 @@ String *Item_func_geometry_type::val_str_ascii(String *str)
}
-Field::geometry_type Item_func_envelope::get_geometry_type() const
-{
- return Field::GEOM_POLYGON;
-}
-
-
String *Item_func_envelope::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -478,12 +474,6 @@ mem_error:
}
-Field::geometry_type Item_func_centroid::get_geometry_type() const
-{
- return Field::GEOM_POINT;
-}
-
-
String *Item_func_centroid::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -901,12 +891,6 @@ err:
*/
-Field::geometry_type Item_func_point::get_geometry_type() const
-{
- return Field::GEOM_POINT;
-}
-
-
String *Item_func_point::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -1080,9 +1064,17 @@ Item_func_spatial_rel::get_mm_leaf(RANGE_OPT_PARAM *param,
if (param->using_real_indexes &&
!field->optimize_range(param->real_keynr[key_part->key],
key_part->part))
- DBUG_RETURN(0);
+ DBUG_RETURN(0);
- if (value->save_in_field_no_warnings(field, 1))
+ Field_geom *field_geom= dynamic_cast<Field_geom*>(field);
+ DBUG_ASSERT(field_geom);
+ const Type_handler_geometry *sav_geom_type= field_geom->type_handler_geom();
+ // We have to be able to store all sorts of spatial features here
+ field_geom->set_type_handler(&type_handler_geometry);
+ bool rc= value->save_in_field_no_warnings(field, 1);
+ field_geom->set_type_handler(sav_geom_type);
+
+ if (rc)
DBUG_RETURN(&sel_arg_impossible); // Bad GEOMETRY value
DBUG_ASSERT(!field->real_maybe_null()); // SPATIAL keys do not support NULL
@@ -2631,12 +2623,6 @@ mem_error:
}
-Field::geometry_type Item_func_pointonsurface::get_geometry_type() const
-{
- return Field::GEOM_POINT;
-}
-
-
#ifndef DBUG_OFF
longlong Item_func_gis_debug::val_int()
{
@@ -2645,4 +2631,1274 @@ longlong Item_func_gis_debug::val_int()
}
#endif
+
+/**********************************************************************/
+
+
+class Create_func_area : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_area(thd, arg1);
+ }
+
+ static Create_func_area s_singleton;
+
+protected:
+ Create_func_area() {}
+ virtual ~Create_func_area() {}
+};
+
+
+class Create_func_as_wkb : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_as_wkb(thd, arg1);
+ }
+
+ static Create_func_as_wkb s_singleton;
+
+protected:
+ Create_func_as_wkb() {}
+ virtual ~Create_func_as_wkb() {}
+};
+
+
+class Create_func_as_wkt : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_as_wkt(thd, arg1);
+ }
+
+ static Create_func_as_wkt s_singleton;
+
+protected:
+ Create_func_as_wkt() {}
+ virtual ~Create_func_as_wkt() {}
+};
+
+
+
+class Create_func_centroid : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_centroid(thd, arg1);
+ }
+
+ static Create_func_centroid s_singleton;
+
+protected:
+ Create_func_centroid() {}
+ virtual ~Create_func_centroid() {}
+};
+
+
+class Create_func_convexhull : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_convexhull(thd, arg1);
+ }
+
+ static Create_func_convexhull s_singleton;
+
+protected:
+ Create_func_convexhull() {}
+ virtual ~Create_func_convexhull() {}
+};
+
+
+class Create_func_pointonsurface : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_pointonsurface(thd, arg1);
+ }
+
+ static Create_func_pointonsurface s_singleton;
+
+protected:
+ Create_func_pointonsurface() {}
+ virtual ~Create_func_pointonsurface() {}
+};
+
+
+class Create_func_mbr_contains : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
+ Item_func::SP_CONTAINS_FUNC);
+ }
+
+ static Create_func_mbr_contains s_singleton;
+
+protected:
+ Create_func_mbr_contains() {}
+ virtual ~Create_func_mbr_contains() {}
+};
+
+
+class Create_func_contains : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
+ Item_func::SP_CONTAINS_FUNC);
+ }
+ static Create_func_contains s_singleton;
+
+protected:
+ Create_func_contains() {}
+ virtual ~Create_func_contains() {}
+};
+
+
+class Create_func_crosses : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
+ Item_func::SP_CROSSES_FUNC);
+ }
+ static Create_func_crosses s_singleton;
+
+protected:
+ Create_func_crosses() {}
+ virtual ~Create_func_crosses() {}
+};
+
+
+class Create_func_dimension : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_dimension(thd, arg1);
+ }
+
+ static Create_func_dimension s_singleton;
+
+protected:
+ Create_func_dimension() {}
+ virtual ~Create_func_dimension() {}
+};
+
+
+class Create_func_mbr_disjoint : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
+ Item_func::SP_DISJOINT_FUNC);
+ }
+
+ static Create_func_mbr_disjoint s_singleton;
+
+protected:
+ Create_func_mbr_disjoint() {}
+ virtual ~Create_func_mbr_disjoint() {}
+};
+
+
+class Create_func_disjoint : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
+ Item_func::SP_DISJOINT_FUNC);
+ }
+ static Create_func_disjoint s_singleton;
+
+protected:
+ Create_func_disjoint() {}
+ virtual ~Create_func_disjoint() {}
+};
+
+
+class Create_func_distance : public Create_func_arg2
+{
+public:
+ Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_distance(thd, arg1, arg2);
+ }
+
+ static Create_func_distance s_singleton;
+
+protected:
+ Create_func_distance() {}
+ virtual ~Create_func_distance() {}
+};
+
+
+
+class Create_func_endpoint : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
+ Item_func::SP_ENDPOINT);
+ }
+
+ static Create_func_endpoint s_singleton;
+
+protected:
+ Create_func_endpoint() {}
+ virtual ~Create_func_endpoint() {}
+};
+
+
+class Create_func_envelope : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_envelope(thd, arg1);
+ }
+
+ static Create_func_envelope s_singleton;
+
+protected:
+ Create_func_envelope() {}
+ virtual ~Create_func_envelope() {}
+};
+
+class Create_func_boundary : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_boundary(thd, arg1);
+ }
+
+ static Create_func_boundary s_singleton;
+
+protected:
+ Create_func_boundary() {}
+ virtual ~Create_func_boundary() {}
+};
+
+
+class Create_func_mbr_equals : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
+ Item_func::SP_EQUALS_FUNC);
+ }
+
+ static Create_func_mbr_equals s_singleton;
+
+protected:
+ Create_func_mbr_equals() {}
+ virtual ~Create_func_mbr_equals() {}
+};
+
+
+class Create_func_equals : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
+ Item_func::SP_EQUALS_FUNC);
+ }
+
+ static Create_func_equals s_singleton;
+
+protected:
+ Create_func_equals() {}
+ virtual ~Create_func_equals() {}
+};
+
+
+class Create_func_exteriorring : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
+ Item_func::SP_EXTERIORRING);
+ }
+
+ static Create_func_exteriorring s_singleton;
+
+protected:
+ Create_func_exteriorring() {}
+ virtual ~Create_func_exteriorring() {}
+};
+
+
+
+class Create_func_geometry_from_text : public Create_native_func
+{
+public:
+ Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+ static Create_func_geometry_from_text s_singleton;
+
+protected:
+ Create_func_geometry_from_text() {}
+ virtual ~Create_func_geometry_from_text() {}
+};
+
+
+Item*
+Create_func_geometry_from_text::create_native(THD *thd, LEX_CSTRING *name,
+ List<Item> *item_list)
+{
+ Item *func= NULL;
+ int arg_count= 0;
+
+ if (item_list != NULL)
+ arg_count= item_list->elements;
+
+ switch (arg_count) {
+ case 1:
+ {
+ Item *param_1= item_list->pop();
+ func= new (thd->mem_root) Item_func_geometry_from_text(thd, param_1);
+ thd->lex->uncacheable(UNCACHEABLE_RAND);
+ break;
+ }
+ case 2:
+ {
+ Item *param_1= item_list->pop();
+ Item *param_2= item_list->pop();
+ func= new (thd->mem_root) Item_func_geometry_from_text(thd, param_1, param_2);
+ break;
+ }
+ default:
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
+ break;
+ }
+ }
+
+ return func;
+}
+
+
+class Create_func_geometry_from_wkb : public Create_native_func
+{
+public:
+ Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+ static Create_func_geometry_from_wkb s_singleton;
+
+protected:
+ Create_func_geometry_from_wkb() {}
+ virtual ~Create_func_geometry_from_wkb() {}
+};
+
+
+Item*
+Create_func_geometry_from_wkb::create_native(THD *thd, LEX_CSTRING *name,
+ List<Item> *item_list)
+{
+ Item *func= NULL;
+ int arg_count= 0;
+
+ if (item_list != NULL)
+ arg_count= item_list->elements;
+
+ switch (arg_count) {
+ case 1:
+ {
+ Item *param_1= item_list->pop();
+ func= new (thd->mem_root) Item_func_geometry_from_wkb(thd, param_1);
+ thd->lex->uncacheable(UNCACHEABLE_RAND);
+ break;
+ }
+ case 2:
+ {
+ Item *param_1= item_list->pop();
+ Item *param_2= item_list->pop();
+ func= new (thd->mem_root) Item_func_geometry_from_wkb(thd, param_1, param_2);
+ break;
+ }
+ default:
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
+ break;
+ }
+ }
+
+ return func;
+}
+
+
+class Create_func_geometry_from_json : public Create_native_func
+{
+public:
+ Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+ static Create_func_geometry_from_json s_singleton;
+
+protected:
+ Create_func_geometry_from_json() {}
+ virtual ~Create_func_geometry_from_json() {}
+};
+
+
+Item*
+Create_func_geometry_from_json::create_native(THD *thd, LEX_CSTRING *name,
+ List<Item> *item_list)
+{
+ Item *func= NULL;
+ int arg_count= 0;
+
+ if (item_list != NULL)
+ arg_count= item_list->elements;
+
+ switch (arg_count) {
+ case 1:
+ {
+ Item *json= item_list->pop();
+ func= new (thd->mem_root) Item_func_geometry_from_json(thd, json);
+ thd->lex->uncacheable(UNCACHEABLE_RAND);
+ break;
+ }
+ case 2:
+ {
+ Item *json= item_list->pop();
+ Item *options= item_list->pop();
+ func= new (thd->mem_root) Item_func_geometry_from_json(thd, json, options);
+ break;
+ }
+ case 3:
+ {
+ Item *json= item_list->pop();
+ Item *options= item_list->pop();
+ Item *srid= item_list->pop();
+ func= new (thd->mem_root) Item_func_geometry_from_json(thd, json, options,
+ srid);
+ break;
+ }
+ default:
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
+ break;
+ }
+ }
+
+ return func;
+}
+
+
+class Create_func_as_geojson : public Create_native_func
+{
+public:
+ Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+ static Create_func_as_geojson s_singleton;
+
+protected:
+ Create_func_as_geojson() {}
+ virtual ~Create_func_as_geojson() {}
+};
+
+
+Item*
+Create_func_as_geojson::create_native(THD *thd, LEX_CSTRING *name,
+ List<Item> *item_list)
+{
+ Item *func= NULL;
+ int arg_count= 0;
+
+ if (item_list != NULL)
+ arg_count= item_list->elements;
+
+ switch (arg_count) {
+ case 1:
+ {
+ Item *geom= item_list->pop();
+ func= new (thd->mem_root) Item_func_as_geojson(thd, geom);
+ thd->lex->uncacheable(UNCACHEABLE_RAND);
+ break;
+ }
+ case 2:
+ {
+ Item *geom= item_list->pop();
+ Item *max_dec= item_list->pop();
+ func= new (thd->mem_root) Item_func_as_geojson(thd, geom, max_dec);
+ break;
+ }
+ case 3:
+ {
+ Item *geom= item_list->pop();
+ Item *max_dec= item_list->pop();
+ Item *options= item_list->pop();
+ func= new (thd->mem_root) Item_func_as_geojson(thd, geom, max_dec, options);
+ break;
+ }
+ default:
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
+ break;
+ }
+ }
+
+ return func;
+}
+
+
+class Create_func_geometry_type : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_geometry_type(thd, arg1);
+ }
+
+ static Create_func_geometry_type s_singleton;
+
+protected:
+ Create_func_geometry_type() {}
+ virtual ~Create_func_geometry_type() {}
+};
+
+
+class Create_func_geometryn : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
+ Item_func::SP_GEOMETRYN);
+ }
+
+ static Create_func_geometryn s_singleton;
+
+protected:
+ Create_func_geometryn() {}
+ virtual ~Create_func_geometryn() {}
+};
+
+
+#if !defined(DBUG_OFF)
+class Create_func_gis_debug : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_gis_debug(thd, arg1);
+ }
+
+ static Create_func_gis_debug s_singleton;
+
+protected:
+ Create_func_gis_debug() {}
+ virtual ~Create_func_gis_debug() {}
+};
+#endif
+
+
+class Create_func_glength : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_glength(thd, arg1);
+ }
+
+ static Create_func_glength s_singleton;
+
+protected:
+ Create_func_glength() {}
+ virtual ~Create_func_glength() {}
+};
+
+
+class Create_func_interiorringn : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
+ Item_func::SP_INTERIORRINGN);
+ }
+
+ static Create_func_interiorringn s_singleton;
+
+protected:
+ Create_func_interiorringn() {}
+ virtual ~Create_func_interiorringn() {}
+};
+
+
+class Create_func_relate : public Create_func_arg3
+{
+public:
+ Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3) override
+ {
+ return new (thd->mem_root) Item_func_spatial_relate(thd, arg1, arg2, arg3);
+ }
+
+ static Create_func_relate s_singleton;
+
+protected:
+ Create_func_relate() {}
+ virtual ~Create_func_relate() {}
+};
+
+
+class Create_func_mbr_intersects : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
+ Item_func::SP_INTERSECTS_FUNC);
+ }
+
+ static Create_func_mbr_intersects s_singleton;
+
+protected:
+ Create_func_mbr_intersects() {}
+ virtual ~Create_func_mbr_intersects() {}
+};
+
+
+class Create_func_intersects : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
+ Item_func::SP_INTERSECTS_FUNC);
+ }
+
+ static Create_func_intersects s_singleton;
+
+protected:
+ Create_func_intersects() {}
+ virtual ~Create_func_intersects() {}
+};
+
+
+class Create_func_intersection : public Create_func_arg2
+{
+public:
+ Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
+ Gcalc_function::op_intersection);
+ }
+
+ static Create_func_intersection s_singleton;
+
+protected:
+ Create_func_intersection() {}
+ virtual ~Create_func_intersection() {}
+};
+
+
+class Create_func_difference : public Create_func_arg2
+{
+public:
+ Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
+ Gcalc_function::op_difference);
+ }
+
+ static Create_func_difference s_singleton;
+
+protected:
+ Create_func_difference() {}
+ virtual ~Create_func_difference() {}
+};
+
+
+class Create_func_union : public Create_func_arg2
+{
+public:
+ Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
+ Gcalc_function::op_union);
+ }
+
+ static Create_func_union s_singleton;
+
+protected:
+ Create_func_union() {}
+ virtual ~Create_func_union() {}
+};
+
+
+class Create_func_symdifference : public Create_func_arg2
+{
+public:
+ Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
+ Gcalc_function::op_symdifference);
+ }
+
+ static Create_func_symdifference s_singleton;
+
+protected:
+ Create_func_symdifference() {}
+ virtual ~Create_func_symdifference() {}
+};
+
+
+class Create_func_buffer : public Create_func_arg2
+{
+public:
+ Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_buffer(thd, arg1, arg2);
+ }
+
+ static Create_func_buffer s_singleton;
+
+protected:
+ Create_func_buffer() {}
+ virtual ~Create_func_buffer() {}
+};
+
+
+class Create_func_isclosed : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_isclosed(thd, arg1);
+ }
+
+ static Create_func_isclosed s_singleton;
+
+protected:
+ Create_func_isclosed() {}
+ virtual ~Create_func_isclosed() {}
+};
+
+
+class Create_func_isring : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_isring(thd, arg1);
+ }
+
+ static Create_func_isring s_singleton;
+
+protected:
+ Create_func_isring() {}
+ virtual ~Create_func_isring() {}
+};
+
+
+class Create_func_isempty : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_isempty(thd, arg1);
+ }
+
+ static Create_func_isempty s_singleton;
+
+protected:
+ Create_func_isempty() {}
+ virtual ~Create_func_isempty() {}
+};
+
+
+class Create_func_issimple : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_issimple(thd, arg1);
+ }
+
+ static Create_func_issimple s_singleton;
+
+protected:
+ Create_func_issimple() {}
+ virtual ~Create_func_issimple() {}
+};
+
+
+
+class Create_func_numgeometries : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_numgeometries(thd, arg1);
+ }
+
+ static Create_func_numgeometries s_singleton;
+
+protected:
+ Create_func_numgeometries() {}
+ virtual ~Create_func_numgeometries() {}
+};
+
+
+class Create_func_numinteriorring : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_numinteriorring(thd, arg1);
+ }
+
+ static Create_func_numinteriorring s_singleton;
+
+protected:
+ Create_func_numinteriorring() {}
+ virtual ~Create_func_numinteriorring() {}
+};
+
+
+class Create_func_numpoints : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_numpoints(thd, arg1);
+ }
+
+ static Create_func_numpoints s_singleton;
+
+protected:
+ Create_func_numpoints() {}
+ virtual ~Create_func_numpoints() {}
+};
+
+
+class Create_func_mbr_overlaps : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
+ Item_func::SP_OVERLAPS_FUNC);
+ }
+
+ static Create_func_mbr_overlaps s_singleton;
+
+protected:
+ Create_func_mbr_overlaps() {}
+ virtual ~Create_func_mbr_overlaps() {}
+};
+
+
+class Create_func_overlaps : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
+ Item_func::SP_OVERLAPS_FUNC);
+ }
+
+ static Create_func_overlaps s_singleton;
+
+protected:
+ Create_func_overlaps() {}
+ virtual ~Create_func_overlaps() {}
+};
+
+
+
+
+
+class Create_func_pointn : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
+ Item_func::SP_POINTN);
+ }
+ static Create_func_pointn s_singleton;
+
+protected:
+ Create_func_pointn() {}
+ virtual ~Create_func_pointn() {}
+};
+
+
+
+
+class Create_func_srid : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_srid(thd, arg1);
+ }
+
+ static Create_func_srid s_singleton;
+
+protected:
+ Create_func_srid() {}
+ virtual ~Create_func_srid() {}
+};
+
+
+class Create_func_startpoint : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
+ Item_func::SP_STARTPOINT);
+ }
+
+ static Create_func_startpoint s_singleton;
+
+protected:
+ Create_func_startpoint() {}
+ virtual ~Create_func_startpoint() {}
+};
+
+
+
+class Create_func_touches : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
+ Item_func::SP_TOUCHES_FUNC);
+ }
+
+ static Create_func_touches s_singleton;
+
+protected:
+ Create_func_touches() {}
+ virtual ~Create_func_touches() {}
+};
+
+
+class Create_func_mbr_within : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
+ Item_func::SP_WITHIN_FUNC);
+ }
+
+ static Create_func_mbr_within s_singleton;
+
+protected:
+ Create_func_mbr_within() {}
+ virtual ~Create_func_mbr_within() {}
+};
+
+
+class Create_func_within : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
+ Item_func::SP_WITHIN_FUNC);
+ }
+
+ static Create_func_within s_singleton;
+
+protected:
+ Create_func_within() {}
+ virtual ~Create_func_within() {}
+};
+
+
+class Create_func_x : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_x(thd, arg1);
+ }
+
+ static Create_func_x s_singleton;
+
+protected:
+ Create_func_x() {}
+ virtual ~Create_func_x() {}
+};
+
+
+class Create_func_y : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_y(thd, arg1);
+ }
+
+ static Create_func_y s_singleton;
+
+protected:
+ Create_func_y() {}
+ virtual ~Create_func_y() {}
+};
+
+
+/*****************************************************************/
+
+
+
+
+
+
+
+/*************************************************************************/
+
+#if !defined(DBUG_OFF)
+Create_func_gis_debug Create_func_gis_debug::s_singleton;
+#endif
+
+Create_func_area Create_func_area::s_singleton;
+Create_func_as_geojson Create_func_as_geojson::s_singleton;
+Create_func_as_wkb Create_func_as_wkb::s_singleton;
+Create_func_as_wkt Create_func_as_wkt::s_singleton;
+Create_func_boundary Create_func_boundary::s_singleton;
+Create_func_buffer Create_func_buffer::s_singleton;
+Create_func_centroid Create_func_centroid::s_singleton;
+Create_func_contains Create_func_contains::s_singleton;
+Create_func_convexhull Create_func_convexhull::s_singleton;
+Create_func_crosses Create_func_crosses::s_singleton;
+Create_func_difference Create_func_difference::s_singleton;
+Create_func_dimension Create_func_dimension::s_singleton;
+Create_func_disjoint Create_func_disjoint::s_singleton;
+Create_func_distance Create_func_distance::s_singleton;
+Create_func_endpoint Create_func_endpoint::s_singleton;
+Create_func_envelope Create_func_envelope::s_singleton;
+Create_func_equals Create_func_equals::s_singleton;
+Create_func_exteriorring Create_func_exteriorring::s_singleton;
+Create_func_geometry_from_json Create_func_geometry_from_json::s_singleton;
+Create_func_geometry_from_text Create_func_geometry_from_text::s_singleton;
+Create_func_geometry_from_wkb Create_func_geometry_from_wkb::s_singleton;
+Create_func_geometryn Create_func_geometryn::s_singleton;
+Create_func_geometry_type Create_func_geometry_type::s_singleton;
+Create_func_glength Create_func_glength::s_singleton;
+Create_func_interiorringn Create_func_interiorringn::s_singleton;
+Create_func_intersection Create_func_intersection::s_singleton;
+Create_func_intersects Create_func_intersects::s_singleton;
+Create_func_isclosed Create_func_isclosed::s_singleton;
+Create_func_isempty Create_func_isempty::s_singleton;
+Create_func_isring Create_func_isring::s_singleton;
+Create_func_issimple Create_func_issimple::s_singleton;
+Create_func_mbr_contains Create_func_mbr_contains::s_singleton;
+Create_func_mbr_disjoint Create_func_mbr_disjoint::s_singleton;
+Create_func_mbr_equals Create_func_mbr_equals::s_singleton;
+Create_func_mbr_intersects Create_func_mbr_intersects::s_singleton;
+Create_func_mbr_overlaps Create_func_mbr_overlaps::s_singleton;
+Create_func_mbr_within Create_func_mbr_within::s_singleton;
+Create_func_numgeometries Create_func_numgeometries::s_singleton;
+Create_func_numinteriorring Create_func_numinteriorring::s_singleton;
+Create_func_numpoints Create_func_numpoints::s_singleton;
+Create_func_overlaps Create_func_overlaps::s_singleton;
+Create_func_pointn Create_func_pointn::s_singleton;
+Create_func_pointonsurface Create_func_pointonsurface::s_singleton;
+Create_func_relate Create_func_relate::s_singleton;
+Create_func_srid Create_func_srid::s_singleton;
+Create_func_startpoint Create_func_startpoint::s_singleton;
+Create_func_symdifference Create_func_symdifference::s_singleton;
+Create_func_touches Create_func_touches::s_singleton;
+Create_func_union Create_func_union::s_singleton;
+Create_func_within Create_func_within::s_singleton;
+Create_func_x Create_func_x::s_singleton;
+Create_func_y Create_func_y::s_singleton;
+
+/*************************************************************************/
+
+
+#define GEOM_BUILDER(F) & F::s_singleton
+
+
+static Native_func_registry func_array_geom[] =
+{
+#ifndef DBUG_OFF
+ { { STRING_WITH_LEN("ST_GIS_DEBUG") }, GEOM_BUILDER(Create_func_gis_debug)},
+#endif
+ { { STRING_WITH_LEN("AREA") }, GEOM_BUILDER(Create_func_area)},
+ { { STRING_WITH_LEN("ASBINARY") }, GEOM_BUILDER(Create_func_as_wkb)},
+ { { STRING_WITH_LEN("ASTEXT") }, GEOM_BUILDER(Create_func_as_wkt)},
+ { { STRING_WITH_LEN("ASWKB") }, GEOM_BUILDER(Create_func_as_wkb)},
+ { { STRING_WITH_LEN("ASWKT") }, GEOM_BUILDER(Create_func_as_wkt)},
+ { { STRING_WITH_LEN("BOUNDARY") }, GEOM_BUILDER(Create_func_boundary)},
+ { { STRING_WITH_LEN("BUFFER") }, GEOM_BUILDER(Create_func_buffer)},
+ { { STRING_WITH_LEN("CENTROID") }, GEOM_BUILDER(Create_func_centroid)},
+ { { STRING_WITH_LEN("CONTAINS") }, GEOM_BUILDER(Create_func_contains)},
+ { { STRING_WITH_LEN("CONVEXHULL") }, GEOM_BUILDER(Create_func_convexhull)},
+ { { STRING_WITH_LEN("CROSSES") }, GEOM_BUILDER(Create_func_crosses)},
+ { { STRING_WITH_LEN("DIMENSION") }, GEOM_BUILDER(Create_func_dimension)},
+ { { STRING_WITH_LEN("DISJOINT") }, GEOM_BUILDER(Create_func_mbr_disjoint)},
+ { { STRING_WITH_LEN("ENDPOINT") }, GEOM_BUILDER(Create_func_endpoint)},
+ { { STRING_WITH_LEN("ENVELOPE") }, GEOM_BUILDER(Create_func_envelope)},
+ { { STRING_WITH_LEN("EQUALS") }, GEOM_BUILDER(Create_func_equals)},
+ { { STRING_WITH_LEN("EXTERIORRING") }, GEOM_BUILDER(Create_func_exteriorring)},
+ { { STRING_WITH_LEN("GEOMCOLLFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("GEOMCOLLFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("GEOMETRYCOLLECTIONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("GEOMETRYCOLLECTIONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("GEOMETRYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("GEOMETRYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("GEOMETRYN") }, GEOM_BUILDER(Create_func_geometryn)},
+ { { STRING_WITH_LEN("GEOMETRYTYPE") }, GEOM_BUILDER(Create_func_geometry_type)},
+ { { STRING_WITH_LEN("GEOMFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("GEOMFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("GLENGTH") }, GEOM_BUILDER(Create_func_glength)},
+ { { STRING_WITH_LEN("INTERIORRINGN") }, GEOM_BUILDER(Create_func_interiorringn)},
+ { { STRING_WITH_LEN("INTERSECTS") }, GEOM_BUILDER(Create_func_mbr_intersects)},
+ { { STRING_WITH_LEN("ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)},
+ { { STRING_WITH_LEN("ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)},
+ { { STRING_WITH_LEN("ISRING") }, GEOM_BUILDER(Create_func_isring)},
+ { { STRING_WITH_LEN("ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)},
+ { { STRING_WITH_LEN("LINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("LINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("LINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("LINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("MBRCONTAINS") }, GEOM_BUILDER(Create_func_mbr_contains)},
+ { { STRING_WITH_LEN("MBRDISJOINT") }, GEOM_BUILDER(Create_func_mbr_disjoint)},
+ { { STRING_WITH_LEN("MBREQUAL") }, GEOM_BUILDER(Create_func_mbr_equals)},
+ { { STRING_WITH_LEN("MBREQUALS") }, GEOM_BUILDER(Create_func_mbr_equals)},
+ { { STRING_WITH_LEN("MBRINTERSECTS") }, GEOM_BUILDER(Create_func_mbr_intersects)},
+ { { STRING_WITH_LEN("MBROVERLAPS") }, GEOM_BUILDER(Create_func_mbr_overlaps)},
+ { { STRING_WITH_LEN("MBRTOUCHES") }, GEOM_BUILDER(Create_func_touches)},
+ { { STRING_WITH_LEN("MBRWITHIN") }, GEOM_BUILDER(Create_func_mbr_within)},
+ { { STRING_WITH_LEN("MLINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("MLINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("MPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("MPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("MPOLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("MPOLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("MULTILINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("MULTILINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("MULTIPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("MULTIPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("MULTIPOLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("MULTIPOLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("NUMGEOMETRIES") }, GEOM_BUILDER(Create_func_numgeometries)},
+ { { STRING_WITH_LEN("NUMINTERIORRINGS") }, GEOM_BUILDER(Create_func_numinteriorring)},
+ { { STRING_WITH_LEN("NUMPOINTS") }, GEOM_BUILDER(Create_func_numpoints)},
+ { { STRING_WITH_LEN("OVERLAPS") }, GEOM_BUILDER(Create_func_mbr_overlaps)},
+ { { STRING_WITH_LEN("POINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("POINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("POINTN") }, GEOM_BUILDER(Create_func_pointn)},
+ { { STRING_WITH_LEN("POINTONSURFACE") }, GEOM_BUILDER(Create_func_pointonsurface)},
+ { { STRING_WITH_LEN("POLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("POLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("POLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("POLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("SRID") }, GEOM_BUILDER(Create_func_srid)},
+ { { STRING_WITH_LEN("ST_AREA") }, GEOM_BUILDER(Create_func_area)},
+ { { STRING_WITH_LEN("STARTPOINT") }, GEOM_BUILDER(Create_func_startpoint)},
+ { { STRING_WITH_LEN("ST_ASBINARY") }, GEOM_BUILDER(Create_func_as_wkb)},
+ { { STRING_WITH_LEN("ST_ASGEOJSON") }, GEOM_BUILDER(Create_func_as_geojson)},
+ { { STRING_WITH_LEN("ST_ASTEXT") }, GEOM_BUILDER(Create_func_as_wkt)},
+ { { STRING_WITH_LEN("ST_ASWKB") }, GEOM_BUILDER(Create_func_as_wkb)},
+ { { STRING_WITH_LEN("ST_ASWKT") }, GEOM_BUILDER(Create_func_as_wkt)},
+ { { STRING_WITH_LEN("ST_BOUNDARY") }, GEOM_BUILDER(Create_func_boundary)},
+ { { STRING_WITH_LEN("ST_BUFFER") }, GEOM_BUILDER(Create_func_buffer)},
+ { { STRING_WITH_LEN("ST_CENTROID") }, GEOM_BUILDER(Create_func_centroid)},
+ { { STRING_WITH_LEN("ST_CONTAINS") }, GEOM_BUILDER(Create_func_contains)},
+ { { STRING_WITH_LEN("ST_CONVEXHULL") }, GEOM_BUILDER(Create_func_convexhull)},
+ { { STRING_WITH_LEN("ST_CROSSES") }, GEOM_BUILDER(Create_func_crosses)},
+ { { STRING_WITH_LEN("ST_DIFFERENCE") }, GEOM_BUILDER(Create_func_difference)},
+ { { STRING_WITH_LEN("ST_DIMENSION") }, GEOM_BUILDER(Create_func_dimension)},
+ { { STRING_WITH_LEN("ST_DISJOINT") }, GEOM_BUILDER(Create_func_disjoint)},
+ { { STRING_WITH_LEN("ST_DISTANCE") }, GEOM_BUILDER(Create_func_distance)},
+ { { STRING_WITH_LEN("ST_ENDPOINT") }, GEOM_BUILDER(Create_func_endpoint)},
+ { { STRING_WITH_LEN("ST_ENVELOPE") }, GEOM_BUILDER(Create_func_envelope)},
+ { { STRING_WITH_LEN("ST_EQUALS") }, GEOM_BUILDER(Create_func_equals)},
+ { { STRING_WITH_LEN("ST_EQUALS") }, GEOM_BUILDER(Create_func_equals)},
+ { { STRING_WITH_LEN("ST_EXTERIORRING") }, GEOM_BUILDER(Create_func_exteriorring)},
+ { { STRING_WITH_LEN("ST_GEOMCOLLFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_GEOMCOLLFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_GEOMETRYCOLLECTIONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_GEOMETRYCOLLECTIONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_GEOMETRYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_GEOMETRYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_GEOMETRYN") }, GEOM_BUILDER(Create_func_geometryn)},
+ { { STRING_WITH_LEN("ST_GEOMETRYTYPE") }, GEOM_BUILDER(Create_func_geometry_type)},
+ { { STRING_WITH_LEN("ST_GEOMFROMGEOJSON") }, GEOM_BUILDER(Create_func_geometry_from_json)},
+ { { STRING_WITH_LEN("ST_GEOMFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_GEOMFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_INTERIORRINGN") }, GEOM_BUILDER(Create_func_interiorringn)},
+ { { STRING_WITH_LEN("ST_INTERSECTION") }, GEOM_BUILDER(Create_func_intersection)},
+ { { STRING_WITH_LEN("ST_INTERSECTS") }, GEOM_BUILDER(Create_func_intersects)},
+ { { STRING_WITH_LEN("ST_ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)},
+ { { STRING_WITH_LEN("ST_ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)},
+ { { STRING_WITH_LEN("ST_ISRING") }, GEOM_BUILDER(Create_func_isring)},
+ { { STRING_WITH_LEN("ST_ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)},
+ { { STRING_WITH_LEN("ST_LENGTH") }, GEOM_BUILDER(Create_func_glength)},
+ { { STRING_WITH_LEN("ST_LINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_LINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_LINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_LINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_MLINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_MLINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_MPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_MPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_MPOLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_MPOLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_MULTILINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_MULTILINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_MULTIPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_MULTIPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_MULTIPOLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_MULTIPOLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_NUMGEOMETRIES") }, GEOM_BUILDER(Create_func_numgeometries)},
+ { { STRING_WITH_LEN("ST_NUMINTERIORRINGS") }, GEOM_BUILDER(Create_func_numinteriorring)},
+ { { STRING_WITH_LEN("ST_NUMPOINTS") }, GEOM_BUILDER(Create_func_numpoints)},
+ { { STRING_WITH_LEN("ST_OVERLAPS") }, GEOM_BUILDER(Create_func_overlaps)},
+ { { STRING_WITH_LEN("ST_POINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_POINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_POINTN") }, GEOM_BUILDER(Create_func_pointn)},
+ { { STRING_WITH_LEN("ST_POINTONSURFACE") }, GEOM_BUILDER(Create_func_pointonsurface)},
+ { { STRING_WITH_LEN("ST_POLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_POLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_POLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_POLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_RELATE") }, GEOM_BUILDER(Create_func_relate)},
+ { { STRING_WITH_LEN("ST_SRID") }, GEOM_BUILDER(Create_func_srid)},
+ { { STRING_WITH_LEN("ST_STARTPOINT") }, GEOM_BUILDER(Create_func_startpoint)},
+ { { STRING_WITH_LEN("ST_SYMDIFFERENCE") }, GEOM_BUILDER(Create_func_symdifference)},
+ { { STRING_WITH_LEN("ST_TOUCHES") }, GEOM_BUILDER(Create_func_touches)},
+ { { STRING_WITH_LEN("ST_UNION") }, GEOM_BUILDER(Create_func_union)},
+ { { STRING_WITH_LEN("ST_WITHIN") }, GEOM_BUILDER(Create_func_within)},
+ { { STRING_WITH_LEN("ST_X") }, GEOM_BUILDER(Create_func_x)},
+ { { STRING_WITH_LEN("ST_Y") }, GEOM_BUILDER(Create_func_y)},
+ { { STRING_WITH_LEN("TOUCHES") }, GEOM_BUILDER(Create_func_touches)},
+ { { STRING_WITH_LEN("WITHIN") }, GEOM_BUILDER(Create_func_within)},
+ { { STRING_WITH_LEN("X") }, GEOM_BUILDER(Create_func_x)},
+ { { STRING_WITH_LEN("Y") }, GEOM_BUILDER(Create_func_y)},
+};
+
+
+Native_func_registry_array
+ native_func_registry_array_geom(func_array_geom,
+ array_elements(func_array_geom));
+
#endif /*HAVE_SPATIAL*/
diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h
index 4e7cda137c2..c38d0b986f1 100644
--- a/sql/item_geofunc.h
+++ b/sql/item_geofunc.h
@@ -26,6 +26,10 @@
#pragma interface /* gcc class implementation */
#endif
+#include "sql_type_geom.h"
+#include "item.h"
+#include "gstream.h"
+#include "spatial.h"
#include "gcalc_slicescan.h"
#include "gcalc_tools.h"
@@ -53,7 +57,8 @@ protected:
bool check_arguments() const
{
DBUG_ASSERT(arg_count == 1);
- return args[0]->check_type_or_binary(func_name(), &type_handler_geometry);
+ return Type_handler_geometry::check_type_geom_or_binary(func_name(),
+ args[0]);
}
public:
Item_real_func_args_geometry(THD *thd, Item *a)
@@ -69,7 +74,8 @@ class Item_long_func_args_geometry: public Item_long_func
bool check_arguments() const
{
DBUG_ASSERT(arg_count == 1);
- return args[0]->check_type_or_binary(func_name(), &type_handler_geometry);
+ return Type_handler_geometry::check_type_geom_or_binary(func_name(),
+ args[0]);
}
protected:
String value;
@@ -89,7 +95,8 @@ protected:
bool check_arguments() const
{
DBUG_ASSERT(arg_count == 1);
- return args[0]->check_type_or_binary(func_name(), &type_handler_geometry);
+ return Type_handler_geometry::check_type_geom_or_binary(func_name(),
+ args[0]);
}
public:
Item_bool_func_args_geometry(THD *thd, Item *a)
@@ -106,7 +113,8 @@ protected:
bool check_arguments() const
{
DBUG_ASSERT(arg_count >= 1);
- return args[0]->check_type_or_binary(func_name(), &type_handler_geometry);
+ return Type_handler_geometry::check_type_geom_or_binary(func_name(),
+ args[0]);
}
public:
Item_str_ascii_func_args_geometry(THD *thd, Item *a)
@@ -127,7 +135,8 @@ protected:
bool check_arguments() const
{
DBUG_ASSERT(arg_count >= 1);
- return args[0]->check_type_or_binary(func_name(), &type_handler_geometry);
+ return Type_handler_geometry::check_type_geom_or_binary(func_name(),
+ args[0]);
}
public:
Item_binary_func_args_geometry(THD *thd, Item *a)
@@ -144,7 +153,8 @@ protected:
bool check_arguments() const
{
DBUG_ASSERT(arg_count >= 1);
- return args[0]->check_type_or_binary(func_name(), &type_handler_geometry);
+ return Type_handler_geometry::check_type_geom_or_binary(func_name(),
+ args[0]);
}
public:
Item_geometry_func_args_geometry(THD *thd, Item *a)
@@ -163,7 +173,8 @@ protected:
bool check_arguments() const
{
DBUG_ASSERT(arg_count >= 2);
- return check_argument_types_or_binary(&type_handler_geometry, 0, 2);
+ return Type_handler_geometry::check_types_geom_or_binary(func_name(),
+ args, 0, 2);
}
public:
Item_real_func_args_geometry_geometry(THD *thd, Item *a, Item *b)
@@ -181,7 +192,8 @@ protected:
bool check_arguments() const
{
DBUG_ASSERT(arg_count >= 2);
- return check_argument_types_or_binary(&type_handler_geometry, 0, 2);
+ return Type_handler_geometry::check_types_geom_or_binary(func_name(),
+ args, 0, 2);
}
public:
Item_bool_func_args_geometry_geometry(THD *thd, Item *a, Item *b, Item *c)
@@ -210,8 +222,9 @@ class Item_func_geometry_from_wkb: public Item_geometry_func
{
bool check_arguments() const
{
- return args[0]->check_type_or_binary(func_name(), &type_handler_geometry) ||
- check_argument_types_can_return_int(1, MY_MIN(2, arg_count));
+ return
+ Type_handler_geometry::check_type_geom_or_binary(func_name(), args[0]) ||
+ check_argument_types_can_return_int(1, MY_MIN(2, arg_count));
}
public:
Item_func_geometry_from_wkb(THD *thd, Item *a): Item_geometry_func(thd, a) {}
@@ -363,7 +376,10 @@ public:
:Item_geometry_func_args_geometry(thd, a) {}
const char *func_name() const { return "st_centroid"; }
String *val_str(String *);
- Field::geometry_type get_geometry_type() const;
+ const Type_handler *type_handler() const
+ {
+ return &type_handler_point;
+ }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_centroid>(thd, this); }
};
@@ -375,7 +391,10 @@ public:
:Item_geometry_func_args_geometry(thd, a) {}
const char *func_name() const { return "st_envelope"; }
String *val_str(String *);
- Field::geometry_type get_geometry_type() const;
+ const Type_handler *type_handler() const
+ {
+ return &type_handler_polygon;
+ }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_envelope>(thd, this); }
};
@@ -425,7 +444,10 @@ public:
Item_geometry_func(thd, a, b, srid) {}
const char *func_name() const { return "point"; }
String *val_str(String *);
- Field::geometry_type get_geometry_type() const;
+ const Type_handler *type_handler() const
+ {
+ return &type_handler_point;
+ }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_point>(thd, this); }
};
@@ -493,7 +515,8 @@ class Item_func_spatial_collection: public Item_geometry_func
{
bool check_arguments() const
{
- return check_argument_types_or_binary(&type_handler_geometry, 0, arg_count);
+ return Type_handler_geometry::check_types_geom_or_binary(func_name(), args,
+ 0, arg_count);
}
enum Geometry::wkbType coll_type;
enum Geometry::wkbType item_type;
@@ -524,13 +547,112 @@ public:
}
return FALSE;
}
-
+};
+
+
+class Item_func_geometrycollection: public Item_func_spatial_collection
+{
+public:
+ Item_func_geometrycollection(THD *thd, List<Item> &list)
+ :Item_func_spatial_collection(thd, list,
+ Geometry::wkb_geometrycollection,
+ Geometry::wkb_point)
+ { }
+ const Type_handler *type_handler() const
+ {
+ return &type_handler_geometrycollection;
+ }
const char *func_name() const { return "geometrycollection"; }
Item *get_copy(THD *thd)
- { return get_item_copy<Item_func_spatial_collection>(thd, this); }
+ { return get_item_copy<Item_func_geometrycollection>(thd, this); }
};
+class Item_func_linestring: public Item_func_spatial_collection
+{
+public:
+ Item_func_linestring(THD *thd, List<Item> &list)
+ :Item_func_spatial_collection(thd, list,
+ Geometry::wkb_linestring,
+ Geometry::wkb_point)
+ { }
+ const Type_handler *type_handler() const { return &type_handler_linestring; }
+ const char *func_name() const { return "linestring"; }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_linestring>(thd, this); }
+};
+
+
+class Item_func_polygon: public Item_func_spatial_collection
+{
+public:
+ Item_func_polygon(THD *thd, List<Item> &list)
+ :Item_func_spatial_collection(thd, list,
+ Geometry::wkb_polygon,
+ Geometry::wkb_linestring)
+ { }
+ const Type_handler *type_handler() const { return &type_handler_polygon; }
+ const char *func_name() const { return "polygon"; }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_polygon>(thd, this); }
+};
+
+
+class Item_func_multilinestring: public Item_func_spatial_collection
+{
+public:
+ Item_func_multilinestring(THD *thd, List<Item> &list)
+ :Item_func_spatial_collection(thd, list,
+ Geometry::wkb_multilinestring,
+ Geometry::wkb_linestring)
+ { }
+ const Type_handler *type_handler() const
+ {
+ return &type_handler_multilinestring;
+ }
+ const char *func_name() const { return "multilinestring"; }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_multilinestring>(thd, this); }
+};
+
+
+class Item_func_multipoint: public Item_func_spatial_collection
+{
+public:
+ Item_func_multipoint(THD *thd, List<Item> &list)
+ :Item_func_spatial_collection(thd, list,
+ Geometry::wkb_multipoint,
+ Geometry::wkb_point)
+ { }
+ const Type_handler *type_handler() const
+ {
+ return &type_handler_multipoint;
+ }
+ const char *func_name() const { return "multipoint"; }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_multipoint>(thd, this); }
+};
+
+
+class Item_func_multipolygon: public Item_func_spatial_collection
+{
+public:
+ Item_func_multipolygon(THD *thd, List<Item> &list)
+ :Item_func_spatial_collection(thd, list,
+ Geometry::wkb_multipolygon,
+ Geometry::wkb_polygon)
+ { }
+ const Type_handler *type_handler() const
+ {
+ return &type_handler_multipolygon;
+ }
+ const char *func_name() const { return "multipolygon"; }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_multipolygon>(thd, this); }
+};
+
+
+
/*
Spatial relations
*/
@@ -546,7 +668,8 @@ protected:
bool check_arguments() const
{
DBUG_ASSERT(arg_count >= 2);
- return check_argument_types_or_binary(&type_handler_geometry, 0, 2);
+ return Type_handler_geometry::check_types_geom_or_binary(func_name(),
+ args, 0, 2);
}
public:
Item_func_spatial_rel(THD *thd, Item *a, Item *b, enum Functype sp_rel):
@@ -641,7 +764,8 @@ class Item_func_spatial_operation: public Item_geometry_func
bool check_arguments() const
{
DBUG_ASSERT(arg_count >= 2);
- return check_argument_types_or_binary(&type_handler_geometry, 0, 2);
+ return Type_handler_geometry::check_types_geom_or_binary(func_name(),
+ args, 0, 2);
}
public:
Gcalc_function::op_type spatial_op;
@@ -945,7 +1069,10 @@ public:
:Item_geometry_func_args_geometry(thd, a) {}
const char *func_name() const { return "st_pointonsurface"; }
String *val_str(String *);
- Field::geometry_type get_geometry_type() const;
+ const Type_handler *type_handler() const
+ {
+ return &type_handler_point;
+ }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_pointonsurface>(thd, this); }
};
@@ -971,10 +1098,12 @@ class Item_func_gis_debug: public Item_long_func
#define GEOM_NEW(thd, obj_constructor) new (thd->mem_root) obj_constructor
+#define GEOM_TYPE(x) (x)
#else /*HAVE_SPATIAL*/
#define GEOM_NEW(thd, obj_constructor) NULL
+#define GEOM_TYPE(x) NULL
#endif /*HAVE_SPATIAL*/
#endif /* ITEM_GEOFUNC_INCLUDED */
diff --git a/sql/item_inetfunc.cc b/sql/item_inetfunc.cc
deleted file mode 100644
index 082584181a4..00000000000
--- a/sql/item_inetfunc.cc
+++ /dev/null
@@ -1,967 +0,0 @@
-/* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
- Copyright (c) 2014 MariaDB Foundation
-
- 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-1335 USA */
-
-#include "mariadb.h"
-#include "item_inetfunc.h"
-
-#include "my_net.h"
-
-///////////////////////////////////////////////////////////////////////////
-
-static const size_t IN_ADDR_SIZE= 4;
-static const size_t IN_ADDR_MAX_CHAR_LENGTH= 15;
-
-static const size_t IN6_ADDR_SIZE= 16;
-static const size_t IN6_ADDR_NUM_WORDS= IN6_ADDR_SIZE / 2;
-
-/**
- Non-abbreviated syntax is 8 groups, up to 4 digits each,
- plus 7 delimiters between the groups.
- Abbreviated syntax is even shorter.
-*/
-static const uint IN6_ADDR_MAX_CHAR_LENGTH= 8 * 4 + 7;
-
-static const char HEX_DIGITS[]= "0123456789abcdef";
-
-///////////////////////////////////////////////////////////////////////////
-
-longlong Item_func_inet_aton::val_int()
-{
- DBUG_ASSERT(fixed);
-
- uint byte_result= 0;
- ulonglong result= 0; // We are ready for 64 bit addresses
- const char *p,* end;
- char c= '.'; // we mark c to indicate invalid IP in case length is 0
- int dot_count= 0;
-
- StringBuffer<36> tmp;
- String *s= args[0]->val_str_ascii(&tmp);
-
- if (!s) // If null value
- goto err;
-
- null_value= 0;
-
- end= (p = s->ptr()) + s->length();
- while (p < end)
- {
- c= *p++;
- int digit= (int) (c - '0');
- if (digit >= 0 && digit <= 9)
- {
- if ((byte_result= byte_result * 10 + digit) > 255)
- goto err; // Wrong address
- }
- else if (c == '.')
- {
- dot_count++;
- result= (result << 8) + (ulonglong) byte_result;
- byte_result= 0;
- }
- else
- goto err; // Invalid character
- }
- if (c != '.') // IP number can't end on '.'
- {
- /*
- Attempt to support short forms of IP-addresses. It's however pretty
- basic one comparing to the BSD support.
- Examples:
- 127 -> 0.0.0.127
- 127.255 -> 127.0.0.255
- 127.256 -> NULL (should have been 127.0.1.0)
- 127.2.1 -> 127.2.0.1
- */
- switch (dot_count) {
- case 1: result<<= 8; /* Fall through */
- case 2: result<<= 8; /* Fall through */
- }
- return (result << 8) + (ulonglong) byte_result;
- }
-
-err:
- null_value=1;
- return 0;
-}
-
-
-String* Item_func_inet_ntoa::val_str(String* str)
-{
- DBUG_ASSERT(fixed);
-
- ulonglong n= (ulonglong) args[0]->val_int();
-
- /*
- We do not know if args[0] is NULL until we have called
- some val function on it if args[0] is not a constant!
-
- Also return null if n > 255.255.255.255
- */
- if ((null_value= (args[0]->null_value || n > 0xffffffff)))
- return 0; // Null value
-
- str->set_charset(collation.collation);
- str->length(0);
-
- uchar buf[8];
- int4store(buf, n);
-
- /* Now we can assume little endian. */
-
- char num[4];
- num[3]= '.';
-
- for (uchar *p= buf + 4; p-- > buf;)
- {
- uint c= *p;
- uint n1, n2; // Try to avoid divisions
- n1= c / 100; // 100 digits
- c-= n1 * 100;
- n2= c / 10; // 10 digits
- c-= n2 * 10; // last digit
- num[0]= (char) n1 + '0';
- num[1]= (char) n2 + '0';
- num[2]= (char) c + '0';
- uint length= (n1 ? 4 : n2 ? 3 : 2); // Remove pre-zero
- uint dot_length= (p <= buf) ? 1 : 0;
- (void) str->append(num + 4 - length, length - dot_length,
- &my_charset_latin1);
- }
-
- return str;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-
-class Inet4
-{
- char m_buffer[IN_ADDR_SIZE];
-protected:
- bool ascii_to_ipv4(const char *str, size_t length);
- bool character_string_to_ipv4(const char *str, size_t str_length,
- CHARSET_INFO *cs)
- {
- if (cs->state & MY_CS_NONASCII)
- {
- char tmp[IN_ADDR_MAX_CHAR_LENGTH];
- String_copier copier;
- uint length= copier.well_formed_copy(&my_charset_latin1, tmp, sizeof(tmp),
- cs, str, str_length);
- return ascii_to_ipv4(tmp, length);
- }
- return ascii_to_ipv4(str, str_length);
- }
- bool binary_to_ipv4(const char *str, size_t length)
- {
- if (length != sizeof(m_buffer))
- return true;
- memcpy(m_buffer, str, length);
- return false;
- }
- // Non-initializing constructor
- Inet4() { }
-public:
- void to_binary(char *dst, size_t dstsize) const
- {
- DBUG_ASSERT(dstsize >= sizeof(m_buffer));
- memcpy(dst, m_buffer, sizeof(m_buffer));
- }
- bool to_binary(String *to) const
- {
- return to->copy(m_buffer, sizeof(m_buffer), &my_charset_bin);
- }
- size_t to_string(char *dst, size_t dstsize) const;
- bool to_string(String *to) const
- {
- to->set_charset(&my_charset_latin1);
- if (to->alloc(INET_ADDRSTRLEN))
- return true;
- to->length((uint32) to_string((char*) to->ptr(), INET_ADDRSTRLEN));
- return false;
- }
-};
-
-
-class Inet4_null: public Inet4, public Null_flag
-{
-public:
- // Initialize from a text representation
- Inet4_null(const char *str, size_t length, CHARSET_INFO *cs)
- :Null_flag(character_string_to_ipv4(str, length, cs))
- { }
- Inet4_null(const String &str)
- :Inet4_null(str.ptr(), str.length(), str.charset())
- { }
- // Initialize from a binary representation
- Inet4_null(const char *str, size_t length)
- :Null_flag(binary_to_ipv4(str, length))
- { }
- Inet4_null(const Binary_string &str)
- :Inet4_null(str.ptr(), str.length())
- { }
-public:
- const Inet4& to_inet4() const
- {
- DBUG_ASSERT(!is_null());
- return *this;
- }
- void to_binary(char *dst, size_t dstsize) const
- {
- to_inet4().to_binary(dst, dstsize);
- }
- bool to_binary(String *to) const
- {
- return to_inet4().to_binary(to);
- }
- size_t to_string(char *dst, size_t dstsize) const
- {
- return to_inet4().to_string(dst, dstsize);
- }
- bool to_string(String *to) const
- {
- return to_inet4().to_string(to);
- }
-};
-
-
-class Inet6
-{
- char m_buffer[IN6_ADDR_SIZE];
-protected:
- bool make_from_item(Item *item);
- bool ascii_to_ipv6(const char *str, size_t str_length);
- bool character_string_to_ipv6(const char *str, size_t str_length,
- CHARSET_INFO *cs)
- {
- if (cs->state & MY_CS_NONASCII)
- {
- char tmp[IN6_ADDR_MAX_CHAR_LENGTH];
- String_copier copier;
- uint length= copier.well_formed_copy(&my_charset_latin1, tmp, sizeof(tmp),
- cs, str, str_length);
- return ascii_to_ipv6(tmp, length);
- }
- return ascii_to_ipv6(str, str_length);
- }
- bool binary_to_ipv6(const char *str, size_t length)
- {
- if (length != sizeof(m_buffer))
- return true;
- memcpy(m_buffer, str, length);
- return false;
- }
- // Non-initializing constructor
- Inet6() { }
-public:
- bool to_binary(String *to) const
- {
- return to->copy(m_buffer, sizeof(m_buffer), &my_charset_bin);
- }
- size_t to_string(char *dst, size_t dstsize) const;
- bool to_string(String *to) const
- {
- to->set_charset(&my_charset_latin1);
- if (to->alloc(INET6_ADDRSTRLEN))
- return true;
- to->length((uint32) to_string((char*) to->ptr(), INET6_ADDRSTRLEN));
- return false;
- }
- bool is_v4compat() const
- {
- static_assert(sizeof(in6_addr) == IN6_ADDR_SIZE, "unexpected in6_addr size");
- return IN6_IS_ADDR_V4COMPAT((struct in6_addr *) m_buffer);
- }
- bool is_v4mapped() const
- {
- static_assert(sizeof(in6_addr) == IN6_ADDR_SIZE, "unexpected in6_addr size");
- return IN6_IS_ADDR_V4MAPPED((struct in6_addr *) m_buffer);
- }
-};
-
-
-class Inet6_null: public Inet6, public Null_flag
-{
-public:
- // Initialize from a text representation
- Inet6_null(const char *str, size_t length, CHARSET_INFO *cs)
- :Null_flag(character_string_to_ipv6(str, length, cs))
- { }
- Inet6_null(const String &str)
- :Inet6_null(str.ptr(), str.length(), str.charset())
- { }
- // Initialize from a binary representation
- Inet6_null(const char *str, size_t length)
- :Null_flag(binary_to_ipv6(str, length))
- { }
- Inet6_null(const Binary_string &str)
- :Inet6_null(str.ptr(), str.length())
- { }
- // Initialize from an Item
- Inet6_null(Item *item)
- :Null_flag(make_from_item(item))
- { }
-public:
- const Inet6& to_inet6() const
- {
- DBUG_ASSERT(!is_null());
- return *this;
- }
- bool to_binary(String *to) const
- {
- DBUG_ASSERT(!is_null());
- return to_inet6().to_binary(to);
- }
- size_t to_string(char *dst, size_t dstsize) const
- {
- return to_inet6().to_string(dst, dstsize);
- }
- bool to_string(String *to) const
- {
- return to_inet6().to_string(to);
- }
- bool is_v4compat() const
- {
- return to_inet6().is_v4compat();
- }
- bool is_v4mapped() const
- {
- return to_inet6().is_v4mapped();
- }
-};
-
-
-bool Inet6::make_from_item(Item *item)
-{
- String tmp(m_buffer, sizeof(m_buffer), &my_charset_bin);
- String *str= item->val_str(&tmp);
- /*
- Charset could be tested in item->collation.collation before the val_str()
- call, but traditionally Inet6 functions still call item->val_str()
- for non-binary arguments and therefore execute side effects.
- */
- if (!str || str->length() != sizeof(m_buffer) ||
- str->charset() != &my_charset_bin)
- return true;
- if (str->ptr() != m_buffer)
- memcpy(m_buffer, str->ptr(), sizeof(m_buffer));
- return false;
-};
-
-
-/**
- Tries to convert given string to binary IPv4-address representation.
- This is a portable alternative to inet_pton(AF_INET).
-
- @param str String to convert.
- @param str_length String length.
-
- @return Completion status.
- @retval true - error, the given string does not represent an IPv4-address.
- @retval false - ok, the string has been converted sucessfully.
-
- @note The problem with inet_pton() is that it treats leading zeros in
- IPv4-part differently on different platforms.
-*/
-
-bool Inet4::ascii_to_ipv4(const char *str, size_t str_length)
-{
- if (str_length < 7)
- {
- DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): "
- "invalid IPv4 address: too short.",
- (int) str_length, str));
- return true;
- }
-
- if (str_length > IN_ADDR_MAX_CHAR_LENGTH)
- {
- DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): "
- "invalid IPv4 address: too long.",
- (int) str_length, str));
- return true;
- }
-
- unsigned char *ipv4_bytes= (unsigned char *) &m_buffer;
- const char *str_end= str + str_length;
- const char *p= str;
- int byte_value= 0;
- int chars_in_group= 0;
- int dot_count= 0;
- char c= 0;
-
- while (p < str_end && *p)
- {
- c= *p++;
-
- if (my_isdigit(&my_charset_latin1, c))
- {
- ++chars_in_group;
-
- if (chars_in_group > 3)
- {
- DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
- "too many characters in a group.",
- (int) str_length, str));
- return true;
- }
-
- byte_value= byte_value * 10 + (c - '0');
-
- if (byte_value > 255)
- {
- DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
- "invalid byte value.",
- (int) str_length, str));
- return true;
- }
- }
- else if (c == '.')
- {
- if (chars_in_group == 0)
- {
- DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
- "too few characters in a group.",
- (int) str_length, str));
- return true;
- }
-
- ipv4_bytes[dot_count]= (unsigned char) byte_value;
-
- ++dot_count;
- byte_value= 0;
- chars_in_group= 0;
-
- if (dot_count > 3)
- {
- DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
- "too many dots.", (int) str_length, str));
- return true;
- }
- }
- else
- {
- DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
- "invalid character at pos %d.",
- (int) str_length, str, (int) (p - str)));
- return true;
- }
- }
-
- if (c == '.')
- {
- DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
- "ending at '.'.", (int) str_length, str));
- return true;
- }
-
- if (dot_count != 3)
- {
- DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
- "too few groups.",
- (int) str_length, str));
- return true;
- }
-
- ipv4_bytes[3]= (unsigned char) byte_value;
-
- DBUG_PRINT("info", ("ascii_to_ipv4(%.*s): valid IPv4 address: %d.%d.%d.%d",
- (int) str_length, str,
- ipv4_bytes[0], ipv4_bytes[1],
- ipv4_bytes[2], ipv4_bytes[3]));
- return false;
-}
-
-
-/**
- Tries to convert given string to binary IPv6-address representation.
- This is a portable alternative to inet_pton(AF_INET6).
-
- @param str String to convert.
- @param str_length String length.
-
- @return Completion status.
- @retval true - error, the given string does not represent an IPv6-address.
- @retval false - ok, the string has been converted sucessfully.
-
- @note The problem with inet_pton() is that it treats leading zeros in
- IPv4-part differently on different platforms.
-*/
-
-bool Inet6::ascii_to_ipv6(const char *str, size_t str_length)
-{
- if (str_length < 2)
- {
- DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: too short.",
- (int) str_length, str));
- return true;
- }
-
- if (str_length > IN6_ADDR_MAX_CHAR_LENGTH)
- {
- DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: too long.",
- (int) str_length, str));
- return true;
- }
-
- memset(m_buffer, 0, sizeof(m_buffer));
-
- const char *p= str;
-
- if (*p == ':')
- {
- ++p;
-
- if (*p != ':')
- {
- DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
- "can not start with ':x'.", (int) str_length, str));
- return true;
- }
- }
-
- const char *str_end= str + str_length;
- char *ipv6_bytes_end= m_buffer + sizeof(m_buffer);
- char *dst= m_buffer;
- char *gap_ptr= NULL;
- const char *group_start_ptr= p;
- int chars_in_group= 0;
- int group_value= 0;
-
- while (p < str_end && *p)
- {
- char c= *p++;
-
- if (c == ':')
- {
- group_start_ptr= p;
-
- if (!chars_in_group)
- {
- if (gap_ptr)
- {
- DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
- "too many gaps(::).", (int) str_length, str));
- return true;
- }
-
- gap_ptr= dst;
- continue;
- }
-
- if (!*p || p >= str_end)
- {
- DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
- "ending at ':'.", (int) str_length, str));
- return true;
- }
-
- if (dst + 2 > ipv6_bytes_end)
- {
- DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
- "too many groups (1).", (int) str_length, str));
- return true;
- }
-
- dst[0]= (unsigned char) (group_value >> 8) & 0xff;
- dst[1]= (unsigned char) group_value & 0xff;
- dst += 2;
-
- chars_in_group= 0;
- group_value= 0;
- }
- else if (c == '.')
- {
- if (dst + IN_ADDR_SIZE > ipv6_bytes_end)
- {
- DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
- "unexpected IPv4-part.", (int) str_length, str));
- return true;
- }
-
- Inet4_null tmp(group_start_ptr, (size_t) (str_end - group_start_ptr),
- &my_charset_latin1);
- if (tmp.is_null())
- {
- DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
- "invalid IPv4-part.", (int) str_length, str));
- return true;
- }
-
- tmp.to_binary(dst, IN_ADDR_SIZE);
- dst += IN_ADDR_SIZE;
- chars_in_group= 0;
-
- break;
- }
- else
- {
- const char *hdp= strchr(HEX_DIGITS, my_tolower(&my_charset_latin1, c));
-
- if (!hdp)
- {
- DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
- "invalid character at pos %d.",
- (int) str_length, str, (int) (p - str)));
- return true;
- }
-
- if (chars_in_group >= 4)
- {
- DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
- "too many digits in group.",
- (int) str_length, str));
- return true;
- }
-
- group_value <<= 4;
- group_value |= hdp - HEX_DIGITS;
-
- DBUG_ASSERT(group_value <= 0xffff);
-
- ++chars_in_group;
- }
- }
-
- if (chars_in_group > 0)
- {
- if (dst + 2 > ipv6_bytes_end)
- {
- DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
- "too many groups (2).", (int) str_length, str));
- return true;
- }
-
- dst[0]= (unsigned char) (group_value >> 8) & 0xff;
- dst[1]= (unsigned char) group_value & 0xff;
- dst += 2;
- }
-
- if (gap_ptr)
- {
- if (dst == ipv6_bytes_end)
- {
- DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
- "no room for a gap (::).", (int) str_length, str));
- return true;
- }
-
- int bytes_to_move= (int)(dst - gap_ptr);
-
- for (int i= 1; i <= bytes_to_move; ++i)
- {
- ipv6_bytes_end[-i]= gap_ptr[bytes_to_move - i];
- gap_ptr[bytes_to_move - i]= 0;
- }
-
- dst= ipv6_bytes_end;
- }
-
- if (dst < ipv6_bytes_end)
- {
- DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
- "too few groups.", (int) str_length, str));
- return true;
- }
-
- return false;
-}
-
-
-/**
- Converts IPv4-binary-address to a string. This function is a portable
- alternative to inet_ntop(AF_INET).
-
- @param[in] ipv4 IPv4-address data (byte array)
- @param[out] dst A buffer to store string representation of IPv4-address.
- @param[in] dstsize Number of bytes avaiable in "dst"
-
- @note The problem with inet_ntop() is that it is available starting from
- Windows Vista, but the minimum supported version is Windows 2000.
-*/
-
-size_t Inet4::to_string(char *dst, size_t dstsize) const
-{
- return (size_t) my_snprintf(dst, dstsize, "%d.%d.%d.%d",
- (uchar) m_buffer[0], (uchar) m_buffer[1],
- (uchar) m_buffer[2], (uchar) m_buffer[3]);
-}
-
-
-/**
- Converts IPv6-binary-address to a string. This function is a portable
- alternative to inet_ntop(AF_INET6).
-
- @param[in] ipv6 IPv6-address data (byte array)
- @param[out] dst A buffer to store string representation of IPv6-address.
- It must be at least of INET6_ADDRSTRLEN.
- @param[in] dstsize Number of bytes available dst.
-
- @note The problem with inet_ntop() is that it is available starting from
- Windows Vista, but out the minimum supported version is Windows 2000.
-*/
-
-size_t Inet6::to_string(char *dst, size_t dstsize) const
-{
- struct Region
- {
- int pos;
- int length;
- };
-
- const char *ipv6= m_buffer;
- char *dstend= dst + dstsize;
- const unsigned char *ipv6_bytes= (const unsigned char *) ipv6;
-
- // 1. Translate IPv6-address bytes to words.
- // We can't just cast to short, because it's not guaranteed
- // that sizeof (short) == 2. So, we have to make a copy.
-
- uint16 ipv6_words[IN6_ADDR_NUM_WORDS];
-
- DBUG_ASSERT(dstsize > 0); // Need a space at least for the trailing '\0'
- for (size_t i= 0; i < IN6_ADDR_NUM_WORDS; ++i)
- ipv6_words[i]= (ipv6_bytes[2 * i] << 8) + ipv6_bytes[2 * i + 1];
-
- // 2. Find "the gap" -- longest sequence of zeros in IPv6-address.
-
- Region gap= { -1, -1 };
-
- {
- Region rg= { -1, -1 };
-
- for (size_t i= 0; i < IN6_ADDR_NUM_WORDS; ++i)
- {
- if (ipv6_words[i] != 0)
- {
- if (rg.pos >= 0)
- {
- if (rg.length > gap.length)
- gap= rg;
-
- rg.pos= -1;
- rg.length= -1;
- }
- }
- else
- {
- if (rg.pos >= 0)
- {
- ++rg.length;
- }
- else
- {
- rg.pos= (int) i;
- rg.length= 1;
- }
- }
- }
-
- if (rg.pos >= 0)
- {
- if (rg.length > gap.length)
- gap= rg;
- }
- }
-
- // 3. Convert binary data to string.
-
- char *p= dst;
-
- for (int i= 0; i < (int) IN6_ADDR_NUM_WORDS; ++i)
- {
- DBUG_ASSERT(dstend >= p);
- size_t dstsize_available= dstend - p;
- if (dstsize_available < 5)
- break;
- if (i == gap.pos)
- {
- // We're at the gap position. We should put trailing ':' and jump to
- // the end of the gap.
-
- if (i == 0)
- {
- // The gap starts from the beginning of the data -- leading ':'
- // should be put additionally.
-
- *p= ':';
- ++p;
- }
-
- *p= ':';
- ++p;
-
- i += gap.length - 1;
- }
- else if (i == 6 && gap.pos == 0 &&
- (gap.length == 6 || // IPv4-compatible
- (gap.length == 5 && ipv6_words[5] == 0xffff) // IPv4-mapped
- ))
- {
- // The data represents either IPv4-compatible or IPv4-mapped address.
- // The IPv6-part (zeros or zeros + ffff) has been already put into
- // the string (dst). Now it's time to dump IPv4-part.
-
- return (size_t) (p - dst) +
- Inet4_null((const char *) (ipv6_bytes + 12), 4).
- to_string(p, dstsize_available);
- }
- else
- {
- // Usual IPv6-address-field. Print it out using lower-case
- // hex-letters without leading zeros (recommended IPv6-format).
- //
- // If it is not the last field, append closing ':'.
-
- p += sprintf(p, "%x", ipv6_words[i]);
-
- if (i + 1 != IN6_ADDR_NUM_WORDS)
- {
- *p= ':';
- ++p;
- }
- }
- }
-
- *p= 0;
- return (size_t) (p - dst);
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
- Converts IP-address-string to IP-address-data.
-
- ipv4-string -> varbinary(4)
- ipv6-string -> varbinary(16)
-
- @return Completion status.
- @retval NULL Given string does not represent an IP-address.
- @retval !NULL The string has been converted sucessfully.
-*/
-
-String *Item_func_inet6_aton::val_str(String *buffer)
-{
- DBUG_ASSERT(fixed);
-
- Ascii_ptr_and_buffer<STRING_BUFFER_USUAL_SIZE> tmp(args[0]);
- if ((null_value= tmp.is_null()))
- return NULL;
-
- Inet4_null ipv4(*tmp.string());
- if (!ipv4.is_null())
- {
- ipv4.to_binary(buffer);
- return buffer;
- }
-
- Inet6_null ipv6(*tmp.string());
- if (!ipv6.is_null())
- {
- ipv6.to_binary(buffer);
- return buffer;
- }
-
- null_value= true;
- return NULL;
-}
-
-
-/**
- Converts IP-address-data to IP-address-string.
-*/
-
-String *Item_func_inet6_ntoa::val_str_ascii(String *buffer)
-{
- DBUG_ASSERT(fixed);
-
- // Binary string argument expected
- if (unlikely(args[0]->result_type() != STRING_RESULT ||
- args[0]->collation.collation != &my_charset_bin))
- {
- null_value= true;
- return NULL;
- }
-
- String_ptr_and_buffer<STRING_BUFFER_USUAL_SIZE> tmp(args[0]);
- if ((null_value= tmp.is_null()))
- return NULL;
-
- Inet4_null ipv4(static_cast<const Binary_string&>(*tmp.string()));
- if (!ipv4.is_null())
- {
- ipv4.to_string(buffer);
- return buffer;
- }
-
- Inet6_null ipv6(static_cast<const Binary_string&>(*tmp.string()));
- if (!ipv6.is_null())
- {
- ipv6.to_string(buffer);
- return buffer;
- }
-
- DBUG_PRINT("info", ("INET6_NTOA(): varbinary(4) or varbinary(16) expected."));
- null_value= true;
- return NULL;
-}
-
-
-/**
- Checks if the passed string represents an IPv4-address.
-*/
-
-longlong Item_func_is_ipv4::val_int()
-{
- DBUG_ASSERT(fixed);
- String_ptr_and_buffer<STRING_BUFFER_USUAL_SIZE> tmp(args[0]);
- return !tmp.is_null() && !Inet4_null(*tmp.string()).is_null();
-}
-
-
-/**
- Checks if the passed string represents an IPv6-address.
-*/
-
-longlong Item_func_is_ipv6::val_int()
-{
- DBUG_ASSERT(fixed);
- String_ptr_and_buffer<STRING_BUFFER_USUAL_SIZE> tmp(args[0]);
- return !tmp.is_null() && !Inet6_null(*tmp.string()).is_null();
-}
-
-
-/**
- Checks if the passed IPv6-address is an IPv4-compat IPv6-address.
-*/
-
-longlong Item_func_is_ipv4_compat::val_int()
-{
- Inet6_null ip6(args[0]);
- return !ip6.is_null() && ip6.is_v4compat();
-}
-
-
-/**
- Checks if the passed IPv6-address is an IPv4-mapped IPv6-address.
-*/
-
-longlong Item_func_is_ipv4_mapped::val_int()
-{
- Inet6_null ip6(args[0]);
- return !ip6.is_null() && ip6.is_v4mapped();
-}
diff --git a/sql/item_inetfunc.h b/sql/item_inetfunc.h
deleted file mode 100644
index 8cfb4cd278c..00000000000
--- a/sql/item_inetfunc.h
+++ /dev/null
@@ -1,226 +0,0 @@
-#ifndef ITEM_INETFUNC_INCLUDED
-#define ITEM_INETFUNC_INCLUDED
-
-/* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
- Copyright (c) 2014 MariaDB Foundation
-
- 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-1335 USA */
-
-
-#include "item.h"
-
-/*************************************************************************
- Item_func_inet_aton implements INET_ATON() SQL-function.
-*************************************************************************/
-
-class Item_func_inet_aton : public Item_longlong_func
-{
- bool check_arguments() const
- { return check_argument_types_can_return_text(0, arg_count); }
-public:
- Item_func_inet_aton(THD *thd, Item *a): Item_longlong_func(thd, a) {}
- longlong val_int();
- const char *func_name() const { return "inet_aton"; }
- bool fix_length_and_dec()
- {
- decimals= 0;
- max_length= 21;
- maybe_null= 1;
- unsigned_flag= 1;
- return FALSE;
- }
- Item *get_copy(THD *thd)
- { return get_item_copy<Item_func_inet_aton>(thd, this); }
-};
-
-
-/*************************************************************************
- Item_func_inet_ntoa implements INET_NTOA() SQL-function.
-*************************************************************************/
-
-class Item_func_inet_ntoa : public Item_str_func
-{
-public:
- Item_func_inet_ntoa(THD *thd, Item *a): Item_str_func(thd, a)
- { }
- String* val_str(String* str);
- const char *func_name() const { return "inet_ntoa"; }
- bool fix_length_and_dec()
- {
- decimals= 0;
- fix_length_and_charset(3 * 8 + 7, default_charset());
- maybe_null= 1;
- return FALSE;
- }
- Item *get_copy(THD *thd)
- { return get_item_copy<Item_func_inet_ntoa>(thd, this); }
-};
-
-
-/*************************************************************************
- Item_func_inet_bool_base implements common code for INET6/IP-related
- functions returning boolean value.
-*************************************************************************/
-
-class Item_func_inet_bool_base : public Item_bool_func
-{
-public:
- inline Item_func_inet_bool_base(THD *thd, Item *ip_addr):
- Item_bool_func(thd, ip_addr)
- {
- null_value= false;
- }
- bool need_parentheses_in_default() { return false; }
-};
-
-
-/*************************************************************************
- Item_func_inet6_aton implements INET6_ATON() SQL-function.
-*************************************************************************/
-
-class Item_func_inet6_aton : public Item_str_func
-{
-public:
- inline Item_func_inet6_aton(THD *thd, Item *ip_addr):
- Item_str_func(thd, ip_addr)
- { }
-
-public:
- virtual const char *func_name() const
- { return "inet6_aton"; }
-
- virtual bool fix_length_and_dec()
- {
- decimals= 0;
- fix_length_and_charset(16, &my_charset_bin);
- maybe_null= 1;
- return FALSE;
- }
- Item *get_copy(THD *thd)
- { return get_item_copy<Item_func_inet6_aton>(thd, this); }
-
- String *val_str(String *to);
-};
-
-
-/*************************************************************************
- Item_func_inet6_ntoa implements INET6_NTOA() SQL-function.
-*************************************************************************/
-
-class Item_func_inet6_ntoa : public Item_str_ascii_func
-{
-public:
- inline Item_func_inet6_ntoa(THD *thd, Item *ip_addr):
- Item_str_ascii_func(thd, ip_addr)
- { }
-
-public:
- virtual const char *func_name() const
- { return "inet6_ntoa"; }
-
- virtual bool fix_length_and_dec()
- {
- decimals= 0;
-
- // max length: IPv6-address -- 16 bytes
- // 16 bytes / 2 bytes per group == 8 groups => 7 delimiter
- // 4 symbols per group
- fix_length_and_charset(8 * 4 + 7, default_charset());
-
- maybe_null= 1;
- return FALSE;
- }
- String *val_str_ascii(String *to);
- Item *get_copy(THD *thd)
- { return get_item_copy<Item_func_inet6_ntoa>(thd, this); }
-};
-
-
-/*************************************************************************
- Item_func_is_ipv4 implements IS_IPV4() SQL-function.
-*************************************************************************/
-
-class Item_func_is_ipv4 : public Item_func_inet_bool_base
-{
-public:
- inline Item_func_is_ipv4(THD *thd, Item *ip_addr):
- Item_func_inet_bool_base(thd, ip_addr)
- { }
-
-public:
- virtual const char *func_name() const
- { return "is_ipv4"; }
- Item *get_copy(THD *thd)
- { return get_item_copy<Item_func_is_ipv4>(thd, this); }
-
- longlong val_int();
-};
-
-
-/*************************************************************************
- Item_func_is_ipv6 implements IS_IPV6() SQL-function.
-*************************************************************************/
-
-class Item_func_is_ipv6 : public Item_func_inet_bool_base
-{
-public:
- inline Item_func_is_ipv6(THD *thd, Item *ip_addr):
- Item_func_inet_bool_base(thd, ip_addr)
- { }
-
- virtual const char *func_name() const
- { return "is_ipv6"; }
- Item *get_copy(THD *thd)
- { return get_item_copy<Item_func_is_ipv6>(thd, this); }
-
- longlong val_int();
-};
-
-
-/*************************************************************************
- Item_func_is_ipv4_compat implements IS_IPV4_COMPAT() SQL-function.
-*************************************************************************/
-
-class Item_func_is_ipv4_compat : public Item_func_inet_bool_base
-{
-public:
- inline Item_func_is_ipv4_compat(THD *thd, Item *ip_addr):
- Item_func_inet_bool_base(thd, ip_addr)
- { }
- virtual const char *func_name() const
- { return "is_ipv4_compat"; }
- Item *get_copy(THD *thd)
- { return get_item_copy<Item_func_is_ipv4_compat>(thd, this); }
- longlong val_int();
-};
-
-
-/*************************************************************************
- Item_func_is_ipv4_mapped implements IS_IPV4_MAPPED() SQL-function.
-*************************************************************************/
-
-class Item_func_is_ipv4_mapped : public Item_func_inet_bool_base
-{
-public:
- inline Item_func_is_ipv4_mapped(THD *thd, Item *ip_addr):
- Item_func_inet_bool_base(thd, ip_addr)
- { }
- virtual const char *func_name() const
- { return "is_ipv4_mapped"; }
- Item *get_copy(THD *thd)
- { return get_item_copy<Item_func_is_ipv4_mapped>(thd, this); }
- longlong val_int();
-};
-
-#endif // ITEM_INETFUNC_INCLUDED
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc
index a90e7fb3a1a..a3b5d3b7fac 100644
--- a/sql/item_jsonfunc.cc
+++ b/sql/item_jsonfunc.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, Monty Program Ab.
+/* Copyright (c) 2016, 2020, 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
@@ -36,7 +36,7 @@ static bool eq_ascii_string(const CHARSET_INFO *cs,
my_wc_t wc;
int wc_len;
- wc_len= cs->cset->mb_wc(cs, &wc, (uchar *) s, (uchar *) s_end);
+ wc_len= cs->mb_wc(&wc, (uchar *) s, (uchar *) s_end);
if (wc_len <= 0 || (wc | 0x20) != (my_wc_t) *ascii)
return 0;
@@ -439,7 +439,17 @@ bool Item_func_json_value::fix_length_and_dec()
{
collation.set(args[0]->collation);
max_length= args[0]->max_length;
- path.set_constant_flag(args[1]->const_item());
+ set_constant_flag(args[1]->const_item());
+ maybe_null= 1;
+ return FALSE;
+}
+
+
+bool Item_func_json_query::fix_length_and_dec()
+{
+ collation.set(args[0]->collation);
+ max_length= args[0]->max_length;
+ set_constant_flag(args[1]->const_item());
maybe_null= 1;
return FALSE;
}
@@ -449,115 +459,100 @@ bool Item_func_json_value::fix_length_and_dec()
Returns NULL, not an error if the found value
is not a scalar.
*/
-String *Item_func_json_value::val_str(String *str)
+bool Json_path_extractor::extract(String *str, Item *item_js, Item *item_jp,
+ CHARSET_INFO *cs)
{
- json_engine_t je;
- String *js= args[0]->val_json(&tmp_js);
+ String *js= item_js->val_json(&tmp_js);
int error= 0;
uint array_counters[JSON_DEPTH_LIMIT];
- if (!path.parsed)
+ if (!parsed)
{
- String *s_p= args[1]->val_str(&tmp_path);
+ String *s_p= item_jp->val_str(&tmp_path);
if (s_p &&
- json_path_setup(&path.p, s_p->charset(), (const uchar *) s_p->ptr(),
+ json_path_setup(&p, s_p->charset(), (const uchar *) s_p->ptr(),
(const uchar *) s_p->ptr() + s_p->length()))
- goto err_return;
- path.parsed= path.constant;
+ return true;
+ parsed= constant;
}
- if ((null_value= args[0]->null_value || args[1]->null_value))
- return NULL;
-
- json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
- (const uchar *) js->ptr() + js->length());
+ if (item_js->null_value || item_jp->null_value)
+ return true;
+ Json_engine_scan je(*js);
str->length(0);
- str->set_charset(collation.collation);
+ str->set_charset(cs);
- path.cur_step= path.p.steps;
+ cur_step= p.steps;
continue_search:
- if (json_find_path(&je, &path.p, &path.cur_step, array_counters))
- {
- if (je.s.error)
- goto err_return;
-
- null_value= 1;
- return 0;
- }
+ if (json_find_path(&je, &p, &cur_step, array_counters))
+ return true;
if (json_read_value(&je))
- goto err_return;
+ return true;
if (unlikely(check_and_get_value(&je, str, &error)))
{
if (error)
- goto err_return;
+ return true;
goto continue_search;
}
- return str;
-
-err_return:
- null_value= 1;
- return 0;
+ return false;
}
-bool Item_func_json_value::check_and_get_value(json_engine_t *je, String *res,
- int *error)
+bool Json_engine_scan::check_and_get_value_scalar(String *res, int *error)
{
CHARSET_INFO *json_cs;
const uchar *js;
uint js_len;
- if (!json_value_scalar(je))
+ if (!json_value_scalar(this))
{
/* We only look for scalar values! */
- if (json_skip_level(je) || json_scan_next(je))
+ if (json_skip_level(this) || json_scan_next(this))
*error= 1;
return true;
}
- if (je->value_type == JSON_VALUE_TRUE ||
- je->value_type == JSON_VALUE_FALSE)
+ if (value_type == JSON_VALUE_TRUE ||
+ value_type == JSON_VALUE_FALSE)
{
json_cs= &my_charset_utf8mb4_bin;
- js= (const uchar *) ((je->value_type == JSON_VALUE_TRUE) ? "1" : "0");
+ js= (const uchar *) ((value_type == JSON_VALUE_TRUE) ? "1" : "0");
js_len= 1;
}
else
{
- json_cs= je->s.cs;
- js= je->value;
- js_len= je->value_len;
+ json_cs= s.cs;
+ js= value;
+ js_len= value_len;
}
- return st_append_json(res, json_cs, js, js_len);
+ return st_append_json(res, json_cs, js, js_len);
}
-bool Item_func_json_query::check_and_get_value(json_engine_t *je, String *res,
- int *error)
+bool Json_engine_scan::check_and_get_value_complex(String *res, int *error)
{
- const uchar *value;
- if (json_value_scalar(je))
+ if (json_value_scalar(this))
{
/* We skip scalar values. */
- if (json_scan_next(je))
+ if (json_scan_next(this))
*error= 1;
return true;
}
- value= je->value;
- if (json_skip_level(je))
+ const uchar *tmp_value= value;
+ if (json_skip_level(this))
{
*error= 1;
return true;
}
- res->set((const char *) je->value, (uint32)(je->s.c_str - value), je->s.cs);
+ res->set((const char *) value, (uint32)(s.c_str - tmp_value), s.cs);
return false;
}
@@ -600,7 +595,7 @@ String *Item_func_json_quote::val_str(String *str)
bool Item_func_json_unquote::fix_length_and_dec()
{
- collation.set(&my_charset_utf8_general_ci,
+ collation.set(&my_charset_utf8mb3_general_ci,
DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
max_length= args[0]->max_length;
maybe_null= 1;
@@ -645,12 +640,12 @@ String *Item_func_json_unquote::val_str(String *str)
return js;
str->length(0);
- str->set_charset(&my_charset_utf8_general_ci);
+ str->set_charset(&my_charset_utf8mb3_general_ci);
if (str->realloc_with_extra_if_needed(je.value_len) ||
(c_len= json_unescape(js->charset(),
je.value, je.value + je.value_len,
- &my_charset_utf8_general_ci,
+ &my_charset_utf8mb3_general_ci,
(uchar *) str->ptr(), (uchar *) (str->ptr() + je.value_len))) < 0)
goto error;
@@ -680,7 +675,7 @@ static int alloc_tmp_paths(THD *thd, uint n_paths,
return 1;
for (uint c_path=0; c_path < n_paths; c_path++)
- (*tmp_paths)[c_path].set_charset(&my_charset_utf8_general_ci);
+ (*tmp_paths)[c_path].set_charset(&my_charset_utf8mb3_general_ci);
}
return 0;
@@ -910,7 +905,7 @@ longlong Item_func_json_extract::val_int()
{
char *end;
int err;
- i= my_strntoll(collation.collation, value, value_len, 10, &end, &err);
+ i= collation.collation->strntoll(value, value_len, 10, &end, &err);
break;
}
case JSON_VALUE_TRUE:
@@ -941,7 +936,7 @@ double Item_func_json_extract::val_real()
{
char *end;
int err;
- d= my_strntod(collation.collation, value, value_len, &end, &err);
+ d= collation.collation->strntod(value, value_len, &end, &err);
break;
}
case JSON_VALUE_TRUE:
@@ -1097,10 +1092,8 @@ static int check_contains(json_engine_t *js, json_engine_t *value)
char *end;
int err;
- d_j= my_strntod(js->s.cs, (char *) js->value, js->value_len,
- &end, &err);;
- d_v= my_strntod(value->s.cs, (char *) value->value, value->value_len,
- &end, &err);;
+ d_j= js->s.cs->strntod((char *) js->value, js->value_len, &end, &err);;
+ d_v= value->s.cs->strntod((char *) value->value, value->value_len, &end, &err);;
return (fabs(d_j - d_v) < 1e-12);
}
@@ -2619,7 +2612,7 @@ longlong Item_func_json_depth::val_int()
bool Item_func_json_type::fix_length_and_dec()
{
- collation.set(&my_charset_utf8_general_ci);
+ collation.set(&my_charset_utf8mb3_general_ci);
max_length= 12;
maybe_null= 1;
return FALSE;
@@ -2665,7 +2658,7 @@ String *Item_func_json_type::val_str(String *str)
break;
}
- str->set(type, strlen(type), &my_charset_utf8_general_ci);
+ str->set(type, strlen(type), &my_charset_utf8mb3_general_ci);
return str;
error:
@@ -3321,7 +3314,7 @@ int Item_func_json_search::compare_json_value_wild(json_engine_t *je,
const String *cmp_str)
{
if (je->value_type != JSON_VALUE_STRING || !je->value_escaped)
- return my_wildcmp(collation.collation,
+ return collation.collation->wildcmp(
(const char *) je->value, (const char *) (je->value + je->value_len),
cmp_str->ptr(), cmp_str->end(), escape, wild_one, wild_many) ? 0 : 1;
@@ -3338,7 +3331,7 @@ int Item_func_json_search::compare_json_value_wild(json_engine_t *je,
if (esc_len <= 0)
return 0;
- return my_wildcmp(collation.collation,
+ return collation.collation->wildcmp(
esc_value.ptr(), esc_value.ptr() + esc_len,
cmp_str->ptr(), cmp_str->end(), escape, wild_one, wild_many) ? 0 : 1;
}
@@ -3567,7 +3560,7 @@ int Arg_comparator::compare_json_str_basic(Item *j, Item *s)
if (value2.realloc_with_extra_if_needed(je.value_len) ||
(c_len= json_unescape(js->charset(), je.value,
je.value + je.value_len,
- &my_charset_utf8_general_ci,
+ &my_charset_utf8mb3_general_ci,
(uchar *) value2.ptr(),
(uchar *) (value2.ptr() + je.value_len))) < 0)
goto error;
@@ -3616,7 +3609,7 @@ int Arg_comparator::compare_e_json_str_basic(Item *j, Item *s)
if (value1.realloc_with_extra_if_needed(value_len) ||
(c_len= json_unescape(value1.charset(), (uchar *) value,
(uchar *) value+value_len,
- &my_charset_utf8_general_ci,
+ &my_charset_utf8mb3_general_ci,
(uchar *) value1.ptr(),
(uchar *) (value1.ptr() + value_len))) < 0)
return 1;
@@ -3626,3 +3619,141 @@ int Arg_comparator::compare_e_json_str_basic(Item *j, Item *s)
return MY_TEST(sortcmp(res1, res2, compare_collation()) == 0);
}
+
+
+String* Item_func_json_arrayagg::convert_to_json(Item *item, String *res)
+{
+ String tmp;
+ res->length(0);
+ append_json_value(res, item, &tmp);
+ return res;
+}
+
+
+String* Item_func_json_arrayagg::val_str(String *str)
+{
+ str= Item_func_group_concat::val_str(str);
+ String s;
+ s.append('[');
+ s.swap(*str);
+ str->append(s);
+ str->append(']');
+
+ return str;
+}
+
+
+Item_func_json_objectagg::
+Item_func_json_objectagg(THD *thd, Item_func_json_objectagg *item)
+ :Item_sum(thd, item)
+{
+ result.set_charset(collation.collation);
+ result.append("{");
+}
+
+
+bool
+Item_func_json_objectagg::fix_fields(THD *thd, Item **ref)
+{
+ uint i; /* for loop variable */
+ DBUG_ASSERT(fixed == 0);
+
+ if (init_sum_func_check(thd))
+ return TRUE;
+
+ maybe_null= 1;
+
+ /*
+ Fix fields for select list and ORDER clause
+ */
+
+ for (i=0 ; i < arg_count ; i++)
+ {
+ if (args[i]->fix_fields_if_needed_for_scalar(thd, &args[i]))
+ return TRUE;
+ m_with_subquery|= args[i]->with_subquery();
+ with_param|= args[i]->with_param;
+ with_window_func|= args[i]->with_window_func;
+ }
+
+ /* skip charset aggregation for order columns */
+ if (agg_arg_charsets_for_string_result(collation, args, arg_count))
+ return 1;
+
+ result.set_charset(collation.collation);
+ result_field= 0;
+ null_value= 1;
+ max_length= (uint32)(thd->variables.group_concat_max_len
+ / collation.collation->mbminlen
+ * collation.collation->mbmaxlen);
+
+ if (check_sum_func(thd, ref))
+ return TRUE;
+
+ fixed= 1;
+ return FALSE;
+}
+
+
+void Item_func_json_objectagg::cleanup()
+{
+ DBUG_ENTER("Item_func_json_objectagg::cleanup");
+ Item_sum::cleanup();
+
+ result.length(1);
+ DBUG_VOID_RETURN;
+}
+
+
+Item *Item_func_json_objectagg::copy_or_same(THD* thd)
+{
+ return new (thd->mem_root) Item_func_json_objectagg(thd, this);
+}
+
+
+void Item_func_json_objectagg::clear()
+{
+ result.length(1);
+ null_value= 1;
+}
+
+
+bool Item_func_json_objectagg::add()
+{
+ StringBuffer<MAX_FIELD_WIDTH> buf;
+ String *key;
+
+ key= args[0]->val_str(&buf);
+ if (args[0]->is_null())
+ return 0;
+
+ null_value= 0;
+ if (result.length() > 1)
+ result.append(", ");
+
+ result.append("\"");
+ result.append(*key);
+ result.append("\":");
+
+ buf.length(0);
+ append_json_value(&result, args[1], &buf);
+
+ return 0;
+}
+
+
+String* Item_func_json_objectagg::val_str(String* str)
+{
+ DBUG_ASSERT(fixed == 1);
+ if (null_value)
+ return 0;
+
+ result.append("}");
+ return &result;
+}
+
+
+void Item_func_json_objectagg::print(String *str, enum_query_type query_type)
+{
+}
+
diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h
index e9b77502e80..44f9e8146c2 100644
--- a/sql/item_jsonfunc.h
+++ b/sql/item_jsonfunc.h
@@ -23,6 +23,7 @@
#include <json_lib.h>
#include "item_cmpfunc.h" // Item_bool_func
#include "item_strfunc.h" // Item_str_func
+#include "item_sum.h"
class json_path_with_flags
@@ -40,6 +41,33 @@ public:
};
+class Json_engine_scan: public json_engine_t
+{
+public:
+ Json_engine_scan(CHARSET_INFO *i_cs, const uchar *str, const uchar *end)
+ {
+ json_scan_start(this, i_cs, str, end);
+ }
+ Json_engine_scan(const String &str)
+ :Json_engine_scan(str.charset(), (const uchar *) str.ptr(),
+ (const uchar *) str.end())
+ { }
+ bool check_and_get_value_scalar(String *res, int *error);
+ bool check_and_get_value_complex(String *res, int *error);
+};
+
+
+class Json_path_extractor: public json_path_with_flags
+{
+protected:
+ String tmp_js, tmp_path;
+ virtual ~Json_path_extractor() { }
+ virtual bool check_and_get_value(Json_engine_scan *je,
+ String *to, int *error)=0;
+ bool extract(String *to, Item *js, Item *jp, CHARSET_INFO *cs);
+};
+
+
class Item_func_json_valid: public Item_bool_func
{
protected:
@@ -56,6 +84,11 @@ public:
maybe_null= 1;
return FALSE;
}
+ bool set_format_by_check_constraint(Send_field_extended_metadata *to) const
+ {
+ static const Lex_cstring fmt(STRING_WITH_LEN("json"));
+ return to->set_format_name(fmt);
+ }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_json_valid>(thd, this); }
};
@@ -78,33 +111,72 @@ public:
};
-class Item_func_json_value: public Item_str_func
+class Item_json_func: public Item_str_func
+{
+public:
+ Item_json_func(THD *thd)
+ :Item_str_func(thd) { }
+ Item_json_func(THD *thd, Item *a)
+ :Item_str_func(thd, a) { }
+ Item_json_func(THD *thd, Item *a, Item *b)
+ :Item_str_func(thd, a, b) { }
+ Item_json_func(THD *thd, List<Item> &list)
+ :Item_str_func(thd, list) { }
+ bool is_json_type() { return true; }
+ void make_send_field(THD *thd, Send_field *tmp_field)
+ {
+ Item_str_func::make_send_field(thd, tmp_field);
+ static const Lex_cstring fmt(STRING_WITH_LEN("json"));
+ tmp_field->set_format_name(fmt);
+ }
+};
+
+
+class Item_func_json_value: public Item_str_func,
+ public Json_path_extractor
{
-protected:
- json_path_with_flags path;
- String tmp_js, tmp_path;
public:
Item_func_json_value(THD *thd, Item *js, Item *i_path):
Item_str_func(thd, js, i_path) {}
- const char *func_name() const { return "json_value"; }
- bool fix_length_and_dec();
- String *val_str(String *);
- virtual bool check_and_get_value(json_engine_t *je, String *res, int *error);
- Item *get_copy(THD *thd)
+ const char *func_name() const override { return "json_value"; }
+ bool fix_length_and_dec() override ;
+ String *val_str(String *to) override
+ {
+ null_value= Json_path_extractor::extract(to, args[0], args[1],
+ collation.collation);
+ return null_value ? NULL : to;
+ }
+ bool check_and_get_value(Json_engine_scan *je,
+ String *res, int *error) override
+ {
+ return je->check_and_get_value_scalar(res, error);
+ }
+ Item *get_copy(THD *thd) override
{ return get_item_copy<Item_func_json_value>(thd, this); }
};
-class Item_func_json_query: public Item_func_json_value
+class Item_func_json_query: public Item_json_func,
+ public Json_path_extractor
{
public:
Item_func_json_query(THD *thd, Item *js, Item *i_path):
- Item_func_json_value(thd, js, i_path) {}
- bool is_json_type() { return true; }
- const char *func_name() const { return "json_query"; }
- bool check_and_get_value(json_engine_t *je, String *res, int *error);
- Item *get_copy(THD *thd)
+ Item_json_func(thd, js, i_path) {}
+ const char *func_name() const override { return "json_query"; }
+ bool fix_length_and_dec() override;
+ String *val_str(String *to) override
+ {
+ null_value= Json_path_extractor::extract(to, args[0], args[1],
+ collation.collation);
+ return null_value ? NULL : to;
+ }
+ bool check_and_get_value(Json_engine_scan *je,
+ String *res, int *error) override
+ {
+ return je->check_and_get_value_complex(res, error);
+ }
+ Item *get_copy(THD *thd) override
{ return get_item_copy<Item_func_json_query>(thd, this); }
};
@@ -139,18 +211,17 @@ public:
};
-class Item_json_str_multipath: public Item_str_func
+class Item_json_str_multipath: public Item_json_func
{
protected:
json_path_with_flags *paths;
String *tmp_paths;
public:
Item_json_str_multipath(THD *thd, List<Item> &list):
- Item_str_func(thd, list), tmp_paths(0) {}
+ Item_json_func(thd, list), tmp_paths(0) {}
bool fix_fields(THD *thd, Item **ref);
void cleanup();
virtual uint get_n_paths() const = 0;
- bool is_json_type() { return true; }
};
@@ -217,18 +288,17 @@ public:
};
-class Item_func_json_array: public Item_str_func
+class Item_func_json_array: public Item_json_func
{
protected:
String tmp_val;
ulong result_limit;
public:
Item_func_json_array(THD *thd):
- Item_str_func(thd) {}
+ Item_json_func(thd) {}
Item_func_json_array(THD *thd, List<Item> &list):
- Item_str_func(thd, list) {}
+ Item_json_func(thd, list) {}
String *val_str(String *);
- bool is_json_type() { return true; }
bool fix_length_and_dec();
const char *func_name() const { return "json_array"; }
Item *get_copy(THD *thd)
@@ -273,7 +343,6 @@ public:
Item_func_json_object(THD *thd, List<Item> &list):
Item_func_json_array(thd, list) {}
String *val_str(String *);
- bool is_json_type() { return true; }
const char *func_name() const { return "json_object"; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_json_object>(thd, this); }
@@ -288,7 +357,6 @@ public:
Item_func_json_merge(THD *thd, List<Item> &list):
Item_func_json_array(thd, list) {}
String *val_str(String *);
- bool is_json_type() { return true; }
const char *func_name() const { return "json_merge_preserve"; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_json_merge>(thd, this); }
@@ -439,7 +507,7 @@ public:
};
-class Item_func_json_format: public Item_str_func
+class Item_func_json_format: public Item_json_func
{
public:
enum formats
@@ -454,18 +522,97 @@ protected:
String tmp_js;
public:
Item_func_json_format(THD *thd, Item *js, formats format):
- Item_str_func(thd, js), fmt(format) {}
+ Item_json_func(thd, js), fmt(format) {}
Item_func_json_format(THD *thd, List<Item> &list):
- Item_str_func(thd, list), fmt(DETAILED) {}
+ Item_json_func(thd, list), fmt(DETAILED) {}
const char *func_name() const;
bool fix_length_and_dec();
String *val_str(String *str);
String *val_json(String *str);
- bool is_json_type() { return true; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_json_format>(thd, this); }
};
+class Item_func_json_arrayagg : public Item_func_group_concat
+{
+public:
+ Item_func_json_arrayagg(THD *thd, Name_resolution_context *context_arg,
+ bool is_distinct, List<Item> *is_select,
+ const SQL_I_List<ORDER> &is_order, String *is_separator,
+ bool limit_clause, Item *row_limit, Item *offset_limit):
+ Item_func_group_concat(thd, context_arg, is_distinct, is_select, is_order,
+ is_separator, limit_clause, row_limit, offset_limit)
+ {
+ }
+ Item_func_json_arrayagg(THD *thd, Item_func_json_arrayagg *item);
+ bool is_json_type() { return true; }
+
+ const char *func_name() const { return "json_arrayagg("; }
+ enum Sumfunctype sum_func() const {return JSON_ARRAYAGG_FUNC;}
+
+ String* convert_to_json(Item *item, String *str);
+ String* val_str(String *str);
+
+ /* Overrides Item_func_group_concat::add() */
+ bool add()
+ {
+ return Item_func_group_concat::add(false);
+ }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_json_arrayagg>(thd, this); }
+};
+
+
+class Item_func_json_objectagg : public Item_sum
+{
+ String result;
+public:
+ Item_func_json_objectagg(THD *thd, Item *key, Item *value) :
+ Item_sum(thd, key, value)
+ {
+ result.append("{");
+ }
+
+ Item_func_json_objectagg(THD *thd, Item_func_json_objectagg *item);
+ bool is_json_type() { return true; }
+ void cleanup();
+
+ enum Sumfunctype sum_func () const {return GROUP_CONCAT_FUNC;}
+ const char *func_name() const { return "json_objectagg("; }
+ const Type_handler *type_handler() const
+ {
+ if (too_big_for_varchar())
+ return &type_handler_blob;
+ return &type_handler_varchar;
+ }
+ void clear();
+ bool add();
+ void reset_field() { DBUG_ASSERT(0); } // not used
+ void update_field() { DBUG_ASSERT(0); } // not used
+ bool fix_fields(THD *,Item **);
+
+ double val_real()
+ { return 0.0; }
+ longlong val_int()
+ { return 0; }
+ my_decimal *val_decimal(my_decimal *decimal_value)
+ {
+ my_decimal_set_zero(decimal_value);
+ return decimal_value;
+ }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ {
+ return get_date_from_string(thd, ltime, fuzzydate);
+ }
+ String* val_str(String* str);
+ Item *copy_or_same(THD* thd);
+ void no_rows_in_result() {}
+ void print(String *str, enum_query_type query_type);
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_json_objectagg>(thd, this); }
+};
+
+
#endif /* ITEM_JSONFUNC_INCLUDED */
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 150d57263b6..def1458df1b 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -87,6 +87,25 @@ Item_row::eval_not_null_tables(void *opt_arg)
}
+bool
+Item_row::find_not_null_fields(table_map allowed)
+{
+ if (~allowed & used_tables())
+ return false;
+
+ Item **arg,**arg_end;
+ if (arg_count)
+ {
+ for (arg= args, arg_end= args + arg_count; arg != arg_end ; arg++)
+ {
+ if (!(*arg)->find_not_null_fields(allowed))
+ continue;
+ }
+ }
+ return false;
+}
+
+
void Item_row::cleanup()
{
DBUG_ENTER("Item_row::cleanup");
diff --git a/sql/item_row.h b/sql/item_row.h
index ea5a0f21d8b..2872a498d55 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -60,7 +60,7 @@ public:
bool with_subquery() const { DBUG_ASSERT(fixed); return m_with_subquery; }
enum Type type() const { return ROW_ITEM; };
const Type_handler *type_handler() const { return &type_handler_row; }
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
return NULL; // Check with Vicentiu why it's called for Item_row
@@ -121,6 +121,7 @@ public:
}
Item *transform(THD *thd, Item_transformer transformer, uchar *arg);
bool eval_not_null_tables(void *opt_arg);
+ bool find_not_null_fields(table_map allowed);
uint cols() const { return arg_count; }
Item* element_index(uint i) { return args[i]; }
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 0baa762d25f..bcc041ae9c6 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2017, Oracle and/or its affiliates.
- Copyright (c) 2009, 2019, MariaDB Corporation
+ Copyright (c) 2009, 2020, 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
@@ -43,7 +43,6 @@
#include "set_var.h"
#include "sql_base.h"
#include "sql_time.h"
-#include "sql_acl.h" // SUPER_ACL
#include "des_key_file.h" // st_des_keyschedule, st_des_keyblock
#include "password.h" // my_make_scrambled_password,
// my_make_scrambled_password_323
@@ -58,25 +57,21 @@ C_MODE_END
size_t username_char_length= 80;
+/*
+ Calculate max length of string from length argument to LEFT and RIGHT
+*/
-class Repeat_count
+static uint32 max_length_for_string(Item *item)
{
- ulonglong m_count;
-public:
- Repeat_count(Item *item)
- :m_count(0)
+ ulonglong length= item->val_int();
+ /* Note that if value is NULL, val_int() returned 0 */
+ if (length > (ulonglong) INT_MAX32)
{
- Longlong_hybrid nr= item->to_longlong_hybrid();
- if (!item->null_value && !nr.neg())
- {
- // Assume that the maximum length of a String is < INT_MAX32
- m_count= (ulonglong) nr.value();
- if (m_count > (ulonglong) INT_MAX32)
- m_count= (ulonglong) INT_MAX32;
- }
+ /* Limit string length to maxium string length in MariaDB (2G) */
+ length= item->unsigned_flag ? (ulonglong) INT_MAX32 : 0;
}
- ulonglong count() const { return m_count; }
-};
+ return (uint32) length;
+}
/*
@@ -842,7 +837,7 @@ String *Item_func_des_decrypt::val_str(String *str)
{
uint key_number=(uint) (*res)[0] & 127;
// Check if automatic key and that we have privilege to uncompress using it
- if (!(current_thd->security_ctx->master_access & SUPER_ACL) ||
+ if (!(current_thd->security_ctx->master_access & PRIV_DES_DECRYPT_ONE_ARG) ||
key_number > 9)
goto error;
@@ -1103,7 +1098,7 @@ String *Item_func_reverse::val_str(String *str)
end= res->end();
tmp= (char *) str->end();
#ifdef USE_MB
- if (use_mb(res->charset()))
+ if (res->use_mb())
{
uint32 l;
while (ptr < end)
@@ -1176,7 +1171,7 @@ String *Item_func_replace::val_str_internal(String *str,
res->set_charset(collation.collation);
#ifdef USE_MB
- binary_cmp = ((res->charset()->state & MY_CS_BINSORT) || !use_mb(res->charset()));
+ binary_cmp = ((res->charset()->state & MY_CS_BINSORT) || !res->use_mb());
#endif
if (res2->length() == 0)
@@ -1306,13 +1301,6 @@ bool Item_func_replace::fix_length_and_dec()
/*********************************************************************/
-bool Item_func_regexp_replace::fix_fields(THD *thd, Item **ref)
-{
- re.set_recursion_limit(thd);
- return Item_str_func::fix_fields(thd, ref);
-}
-
-
bool Item_func_regexp_replace::fix_length_and_dec()
{
if (agg_arg_charsets_for_string_result_with_comparison(collation, args, 3))
@@ -1342,8 +1330,8 @@ bool Item_func_regexp_replace::append_replacement(String *str,
my_wc_t wc;
int cnv, n;
- if ((cnv= cs->cset->mb_wc(cs, &wc, (const uchar *) beg,
- (const uchar *) end)) < 1)
+ if ((cnv= cs->mb_wc(&wc, (const uchar *) beg,
+ (const uchar *) end)) < 1)
break; /* End of line */
beg+= cnv;
@@ -1354,8 +1342,8 @@ bool Item_func_regexp_replace::append_replacement(String *str,
continue;
}
- if ((cnv= cs->cset->mb_wc(cs, &wc, (const uchar *) beg,
- (const uchar *) end)) < 1)
+ if ((cnv= cs->mb_wc(&wc, (const uchar *) beg,
+ (const uchar *) end)) < 1)
break; /* End of line */
beg+= cnv;
@@ -1364,7 +1352,7 @@ bool Item_func_regexp_replace::append_replacement(String *str,
if (n < re.nsubpatterns())
{
/* A valid sub-pattern reference found */
- int pbeg= re.subpattern_start(n), plength= re.subpattern_end(n) - pbeg;
+ size_t pbeg= re.subpattern_start(n), plength= re.subpattern_end(n) - pbeg;
if (str->append(source->str + pbeg, plength, cs))
return true;
}
@@ -1393,7 +1381,7 @@ String *Item_func_regexp_replace::val_str(String *str)
String *source= args[0]->val_str(&tmp0);
String *replace= args[2]->val_str(&tmp2);
LEX_CSTRING src, rpl;
- int startoffset= 0;
+ size_t startoffset= 0;
if ((null_value= (args[0]->null_value || args[2]->null_value ||
re.recompile(args[1]))))
@@ -1422,7 +1410,8 @@ String *Item_func_regexp_replace::val_str(String *str)
Append the rest of the source string
starting from startoffset until the end of the source.
*/
- if (str->append(src.str + startoffset, src.length - startoffset, re.library_charset()))
+ if (str->append(src.str + startoffset, src.length - startoffset,
+ re.library_charset()))
goto err;
return str;
}
@@ -1431,7 +1420,8 @@ String *Item_func_regexp_replace::val_str(String *str)
Append prefix, the part before the matching pattern.
starting from startoffset until the next match
*/
- if (str->append(src.str + startoffset, re.subpattern_start(0) - startoffset, re.library_charset()))
+ if (str->append(src.str + startoffset,
+ re.subpattern_start(0) - startoffset, re.library_charset()))
goto err;
// Append replacement
@@ -1449,13 +1439,6 @@ err:
}
-bool Item_func_regexp_substr::fix_fields(THD *thd, Item **ref)
-{
- re.set_recursion_limit(thd);
- return Item_str_func::fix_fields(thd, ref);
-}
-
-
bool Item_func_regexp_substr::fix_length_and_dec()
{
if (agg_arg_charsets_for_string_result_with_comparison(collation, args, 2))
@@ -1490,8 +1473,7 @@ String *Item_func_regexp_substr::val_str(String *str)
return str;
if (str->append(source->ptr() + re.subpattern_start(0),
- re.subpattern_end(0) - re.subpattern_start(0),
- re.library_charset()))
+ re.subpattern_length(0), re.library_charset()))
goto err;
return str;
@@ -1656,8 +1638,8 @@ void Item_str_func::left_right_max_length()
uint32 char_length= args[0]->max_char_length();
if (args[1]->const_item() && !args[1]->is_expensive())
{
- Repeat_count tmp(args[1]);
- set_if_smaller(char_length, (uint) tmp.count());
+ uint32 length= max_length_for_string(args[1]);
+ set_if_smaller(char_length, length);
}
fix_char_length(char_length);
}
@@ -1818,7 +1800,7 @@ String *Item_func_substr_index::val_str(String *str)
res->set_charset(collation.collation);
#ifdef USE_MB
- if (use_mb(res->charset()))
+ if (res->use_mb())
{
const char *ptr= res->ptr();
const char *strend= ptr+res->length();
@@ -2023,7 +2005,7 @@ String *Item_func_rtrim::val_str(String *str)
{
char chr=(*remove_str)[0];
#ifdef USE_MB
- if (use_mb(collation.collation))
+ if (collation.collation->use_mb())
{
while (ptr < end)
{
@@ -2040,7 +2022,7 @@ String *Item_func_rtrim::val_str(String *str)
{
const char *r_ptr=remove_str->ptr();
#ifdef USE_MB
- if (use_mb(collation.collation))
+ if (collation.collation->use_mb())
{
loop:
while (ptr + remove_length < end)
@@ -2099,7 +2081,7 @@ String *Item_func_trim::val_str(String *str)
while (ptr+remove_length <= end && !memcmp(ptr,r_ptr,remove_length))
ptr+=remove_length;
#ifdef USE_MB
- if (use_mb(collation.collation))
+ if (collation.collation->use_mb())
{
char *p=ptr;
uint32 l;
@@ -2570,10 +2552,10 @@ String *Item_func_soundex::val_str(String *str)
for ( ; ; ) /* Skip pre-space */
{
- if ((rc= cs->cset->mb_wc(cs, &wc, (uchar*) from, (uchar*) end)) <= 0)
+ if ((rc= cs->mb_wc(&wc, (uchar*) from, (uchar*) end)) <= 0)
return make_empty_result(); /* EOL or invalid byte sequence */
- if (rc == 1 && cs->ctype)
+ if (rc == 1 && cs->m_ctype)
{
/* Single byte letter found */
if (my_isalpha(cs, *from))
@@ -2592,7 +2574,7 @@ String *Item_func_soundex::val_str(String *str)
/* Multibyte letter found */
wc= soundex_toupper(wc);
last_ch= get_scode(wc); // Code of the first letter
- if ((rc= cs->cset->wc_mb(cs, wc, (uchar*) to, (uchar*) to_end)) <= 0)
+ if ((rc= cs->wc_mb(wc, (uchar*) to, (uchar*) to_end)) <= 0)
{
/* Extra safety - should not really happen */
DBUG_ASSERT(false);
@@ -2610,10 +2592,10 @@ String *Item_func_soundex::val_str(String *str)
*/
for (nchars= 1 ; ; )
{
- if ((rc= cs->cset->mb_wc(cs, &wc, (uchar*) from, (uchar*) end)) <= 0)
+ if ((rc= cs->mb_wc(&wc, (uchar*) from, (uchar*) end)) <= 0)
break; /* EOL or invalid byte sequence */
- if (rc == 1 && cs->ctype)
+ if (rc == 1 && cs->m_ctype)
{
if (!my_isalpha(cs, *from++))
continue;
@@ -2629,8 +2611,7 @@ String *Item_func_soundex::val_str(String *str)
if ((ch != '0') && (ch != last_ch)) // if not skipped or double
{
// letter, copy to output
- if ((rc= cs->cset->wc_mb(cs, (my_wc_t) ch,
- (uchar*) to, (uchar*) to_end)) <= 0)
+ if ((rc= cs->wc_mb((my_wc_t) ch, (uchar*) to, (uchar*) to_end)) <= 0)
{
// Extra safety - should not really happen
DBUG_ASSERT(false);
@@ -2646,7 +2627,7 @@ String *Item_func_soundex::val_str(String *str)
if (nchars < 4)
{
uint nbytes= (4 - nchars) * cs->mbminlen;
- cs->cset->fill(cs, to, nbytes, '0');
+ cs->fill(to, nbytes, '0');
to+= nbytes;
}
@@ -3024,8 +3005,8 @@ bool Item_func_repeat::fix_length_and_dec()
DBUG_ASSERT(collation.collation != NULL);
if (args[1]->const_item() && !args[1]->is_expensive())
{
- Repeat_count tmp(args[1]);
- ulonglong char_length= (ulonglong) args[0]->max_char_length() * tmp.count();
+ uint32 length= max_length_for_string(args[1]);
+ ulonglong char_length= (ulonglong) args[0]->max_char_length() * length;
fix_char_length_ulonglong(char_length);
return false;
}
@@ -3098,7 +3079,7 @@ bool Item_func_space::fix_length_and_dec()
collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
if (args[0]->const_item() && !args[0]->is_expensive())
{
- fix_char_length_ulonglong(Repeat_count(args[0]).count());
+ fix_char_length_ulonglong(max_length_for_string(args[0]));
return false;
}
max_length= MAX_BLOB_WIDTH;
@@ -3144,7 +3125,7 @@ String *Item_func_space::val_str(String *str)
goto err;
str->length(tot_length);
str->set_charset(cs);
- cs->cset->fill(cs, (char*) str->ptr(), tot_length, ' ');
+ cs->fill((char*) str->ptr(), tot_length, ' ');
return str;
err:
@@ -3217,7 +3198,7 @@ bool Item_func_pad::fix_length_and_dec()
DBUG_ASSERT(collation.collation->mbmaxlen > 0);
if (args[1]->const_item() && !args[1]->is_expensive())
{
- fix_char_length_ulonglong(Repeat_count(args[1]).count());
+ fix_char_length_ulonglong(max_length_for_string(args[1]));
return false;
}
max_length= MAX_BLOB_WIDTH;
@@ -3478,11 +3459,11 @@ String *Item_func_conv::val_str(String *str)
else
{
if (from_base < 0)
- dec= my_strntoll(res->charset(), res->ptr(), res->length(),
- -from_base, &endptr, &err);
+ dec= res->charset()->strntoll(res->ptr(), res->length(),
+ -from_base, &endptr, &err);
else
- dec= (longlong) my_strntoull(res->charset(), res->ptr(), res->length(),
- from_base, &endptr, &err);
+ dec= (longlong) res->charset()->strntoull(res->ptr(), res->length(),
+ from_base, &endptr, &err);
}
if (!(ptr= longlong2str(dec, ans, to_base)) ||
@@ -3604,7 +3585,7 @@ bool Item_func_weight_string::fix_length_and_dec()
size_t char_length;
char_length= ((cs->state & MY_CS_STRNXFRM_BAD_NWEIGHTS) || !nweights) ?
args[0]->max_char_length() : nweights * cs->levels_for_order;
- max_length= (uint32)cs->coll->strnxfrmlen(cs, char_length * cs->mbmaxlen);
+ max_length= (uint32) cs->strnxfrmlen(char_length * cs->mbmaxlen);
}
maybe_null= 1;
return FALSE;
@@ -3655,7 +3636,7 @@ String *Item_func_weight_string::val_str(String *str)
char_length= (flags & MY_STRXFRM_PAD_WITH_SPACE) ?
res->numchars() : (res->length() / cs->mbminlen);
}
- tmp_length= cs->coll->strnxfrmlen(cs, char_length * cs->mbmaxlen);
+ tmp_length= cs->strnxfrmlen(char_length * cs->mbmaxlen);
}
{
@@ -3674,11 +3655,10 @@ String *Item_func_weight_string::val_str(String *str)
if (str->alloc(tmp_length))
goto nl;
- frm_length= cs->coll->strnxfrm(cs,
- (uchar *) str->ptr(), tmp_length,
- nweights ? nweights : (uint)tmp_length,
- (const uchar *) res->ptr(), res->length(),
- flags);
+ frm_length= cs->strnxfrm((char*) str->ptr(), tmp_length,
+ nweights ? nweights : (uint) tmp_length,
+ res->ptr(), res->length(),
+ flags);
DBUG_ASSERT(frm_length <= tmp_length);
str->length(frm_length);
@@ -3798,10 +3778,10 @@ String *Item_func_like_range::val_str(String *str)
goto err;
null_value=0;
- if (cs->coll->like_range(cs, res->ptr(), res->length(),
- '\\', '_', '%', (size_t)nbytes,
- (char*) min_str.ptr(), (char*) max_str.ptr(),
- &min_len, &max_len))
+ if (cs->like_range(res->ptr(), res->length(),
+ '\\', '_', '%', (size_t)nbytes,
+ (char*) min_str.ptr(), (char*) max_str.ptr(),
+ &min_len, &max_len))
goto err;
min_str.set_charset(collation.collation);
@@ -4070,7 +4050,7 @@ String *Item_func_quote::val_str(String *str)
to_end= (uchar*) to + new_length;
/* Put leading quote */
- if ((mblen= cs->cset->wc_mb(cs, '\'', (uchar *) to, to_end)) <= 0)
+ if ((mblen= cs->wc_mb('\'', (uchar *) to, to_end)) <= 0)
goto toolong;
to+= mblen;
@@ -4078,7 +4058,7 @@ String *Item_func_quote::val_str(String *str)
{
my_wc_t wc;
bool escape;
- if ((mblen= cs->cset->mb_wc(cs, &wc, (uchar*) start, (uchar*) end)) <= 0)
+ if ((mblen= cs->mb_wc(&wc, (uchar*) start, (uchar*) end)) <= 0)
goto null;
start+= mblen;
switch (wc) {
@@ -4090,17 +4070,17 @@ String *Item_func_quote::val_str(String *str)
}
if (escape)
{
- if ((mblen= cs->cset->wc_mb(cs, '\\', (uchar*) to, to_end)) <= 0)
+ if ((mblen= cs->wc_mb('\\', (uchar*) to, to_end)) <= 0)
goto toolong;
to+= mblen;
}
- if ((mblen= cs->cset->wc_mb(cs, wc, (uchar*) to, to_end)) <= 0)
+ if ((mblen= cs->wc_mb(wc, (uchar*) to, to_end)) <= 0)
goto toolong;
to+= mblen;
}
/* Put trailing quote */
- if ((mblen= cs->cset->wc_mb(cs, '\'', (uchar *) to, to_end)) <= 0)
+ if ((mblen= cs->wc_mb('\'', (uchar *) to, to_end)) <= 0)
goto toolong;
to+= mblen;
new_length= (uint)(to - str->ptr());
@@ -4413,24 +4393,7 @@ bool Item_func_dyncol_create::prepare_arguments(THD *thd, bool force_names_arg)
uint valpos= i * 2 + 1;
DYNAMIC_COLUMN_TYPE type= defs[i].type;
if (type == DYN_COL_NULL)
- switch (args[valpos]->field_type())
- {
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_STRING:
- case MYSQL_TYPE_GEOMETRY:
- type= DYN_COL_STRING;
- break;
- default:
- break;
- }
-
+ type= args[valpos]->type_handler()->dyncol_type(args[valpos]);
if (type == DYN_COL_STRING &&
args[valpos]->type() == Item::FUNC_ITEM &&
((Item_func *)args[valpos])->functype() == DYNCOL_FUNC)
@@ -4447,63 +4410,7 @@ bool Item_func_dyncol_create::prepare_arguments(THD *thd, bool force_names_arg)
uint valpos= i * 2 + 1;
DYNAMIC_COLUMN_TYPE type= defs[i].type;
if (type == DYN_COL_NULL) // auto detect
- {
- /*
- We don't have a default here to ensure we get a warning if
- one adds a new not handled MYSQL_TYPE_...
- */
- switch (args[valpos]->field_type()) {
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_NEWDECIMAL:
- type= DYN_COL_DECIMAL;
- break;
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_LONGLONG:
- case MYSQL_TYPE_INT24:
- case MYSQL_TYPE_YEAR:
- case MYSQL_TYPE_BIT:
- type= args[valpos]->unsigned_flag ? DYN_COL_UINT : DYN_COL_INT;
- break;
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_DOUBLE:
- type= DYN_COL_DOUBLE;
- break;
- case MYSQL_TYPE_NULL:
- type= DYN_COL_NULL;
- break;
- case MYSQL_TYPE_TIMESTAMP:
- case MYSQL_TYPE_TIMESTAMP2:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_DATETIME2:
- type= DYN_COL_DATETIME;
- break;
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_NEWDATE:
- type= DYN_COL_DATE;
- break;
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_TIME2:
- type= DYN_COL_TIME;
- break;
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_STRING:
- case MYSQL_TYPE_GEOMETRY:
- type= DYN_COL_STRING;
- break;
- case MYSQL_TYPE_VARCHAR_COMPRESSED:
- case MYSQL_TYPE_BLOB_COMPRESSED:
- DBUG_ASSERT(0);
- }
- }
+ type= args[valpos]->type_handler()->dyncol_type(args[valpos]);
if (type == DYN_COL_STRING &&
args[valpos]->type() == Item::FUNC_ITEM &&
((Item_func *)args[valpos])->functype() == DYNCOL_FUNC)
@@ -5081,8 +4988,8 @@ double Item_dyncol_get::val_real()
{
int error;
char *end;
- double res= my_strntod(val.x.string.charset, (char*) val.x.string.value.str,
- val.x.string.value.length, &end, &error);
+ double res= val.x.string.charset->strntod((char*) val.x.string.value.str,
+ val.x.string.value.length, &end, &error);
if (end != (char*) val.x.string.value.str + val.x.string.value.length ||
error)
@@ -5326,28 +5233,33 @@ String *Item_temptable_rowid::val_str(String *str)
str_value.set((char*)(table->file->ref), max_length, &my_charset_bin);
return &str_value;
}
+
#ifdef WITH_WSREP
#include "wsrep_mysqld.h"
+/* Format is %d-%d-%llu */
+#define WSREP_MAX_WSREP_SERVER_GTID_STR_LEN 10+1+10+1+20
String *Item_func_wsrep_last_written_gtid::val_str_ascii(String *str)
{
- wsrep::gtid gtid= current_thd->wsrep_cs().last_written_gtid();
- if (gtid_str.alloc(wsrep::gtid_c_str_len()))
+ if (gtid_str.alloc(WSREP_MAX_WSREP_SERVER_GTID_STR_LEN+1))
{
- my_error(ER_OUTOFMEMORY, wsrep::gtid_c_str_len());
- null_value= true;
- return NULL;
+ my_error(ER_OUTOFMEMORY, WSREP_MAX_WSREP_SERVER_GTID_STR_LEN);
+ null_value= TRUE;
+ return 0;
}
- ssize_t gtid_len= gtid_print_to_c_str(gtid, (char*) gtid_str.ptr(),
- wsrep::gtid_c_str_len());
+ ssize_t gtid_len= my_snprintf((char*)gtid_str.ptr(),
+ WSREP_MAX_WSREP_SERVER_GTID_STR_LEN+1,
+ "%u-%u-%llu", wsrep_gtid_server.domain_id,
+ wsrep_gtid_server.server_id,
+ current_thd->wsrep_last_written_gtid_seqno);
if (gtid_len < 0)
{
my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), func_name(),
- "wsrep_gtid_print failed");
- null_value= true;
- return NULL;
+ "wsrep_gtid_print failed");
+ null_value= TRUE;
+ return 0;
}
gtid_str.length(gtid_len);
return &gtid_str;
@@ -5355,23 +5267,23 @@ String *Item_func_wsrep_last_written_gtid::val_str_ascii(String *str)
String *Item_func_wsrep_last_seen_gtid::val_str_ascii(String *str)
{
- /* TODO: Should call Wsrep_server_state.instance().last_committed_gtid()
- instead. */
- wsrep::gtid gtid= Wsrep_server_state::instance().provider().last_committed_gtid();
- if (gtid_str.alloc(wsrep::gtid_c_str_len()))
+ if (gtid_str.alloc(WSREP_MAX_WSREP_SERVER_GTID_STR_LEN+1))
{
- my_error(ER_OUTOFMEMORY, wsrep::gtid_c_str_len());
- null_value= true;
- return NULL;
+ my_error(ER_OUTOFMEMORY, WSREP_MAX_WSREP_SERVER_GTID_STR_LEN);
+ null_value= TRUE;
+ return 0;
}
- ssize_t gtid_len= wsrep::gtid_print_to_c_str(gtid, (char*) gtid_str.ptr(),
- wsrep::gtid_c_str_len());
+ ssize_t gtid_len= my_snprintf((char*)gtid_str.ptr(),
+ WSREP_MAX_WSREP_SERVER_GTID_STR_LEN+1,
+ "%u-%u-%llu", wsrep_gtid_server.domain_id,
+ wsrep_gtid_server.server_id,
+ wsrep_gtid_server.seqno());
if (gtid_len < 0)
{
my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), func_name(),
"wsrep_gtid_print failed");
- null_value= true;
- return NULL;
+ null_value= TRUE;
+ return 0;
}
gtid_str.length(gtid_len);
return &gtid_str;
@@ -5379,49 +5291,59 @@ String *Item_func_wsrep_last_seen_gtid::val_str_ascii(String *str)
longlong Item_func_wsrep_sync_wait_upto::val_int()
{
- int timeout= -1;
- String* gtid_str= args[0]->val_str(&value);
- if (gtid_str == NULL)
- {
- my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
- return 0LL;
- }
-
- if (arg_count == 2)
- {
- timeout= args[1]->val_int();
- }
+ String *gtid_str __attribute__((unused)) = args[0]->val_str(&value);
+ null_value=0;
+ uint timeout;
+ rpl_gtid *gtid_list;
+ uint32 count;
+ int wait_gtid_ret= 0;
+ int ret= 1;
- wsrep_gtid_t gtid;
- int gtid_len= wsrep_gtid_scan(gtid_str->ptr(), gtid_str->length(), &gtid);
- if (gtid_len < 0)
+ if (args[0]->null_value)
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
- return 0LL;
+ null_value= TRUE;
+ return 0;
}
- if (gtid.seqno == WSREP_SEQNO_UNDEFINED &&
- wsrep_uuid_compare(&gtid.uuid, &WSREP_UUID_UNDEFINED) == 0)
+ if (arg_count==2 && !args[1]->null_value)
+ timeout= (uint)(args[1]->val_real());
+ else
+ timeout= (uint)-1;
+
+ if (!(gtid_list= gtid_parse_string_to_list(gtid_str->ptr(), gtid_str->length(),
+ &count)))
{
- return 1LL;
+ my_error(ER_INCORRECT_GTID_STATE, MYF(0), func_name());
+ null_value= TRUE;
+ return 0;
}
-
- enum wsrep::provider::status status=
- wsrep_sync_wait_upto(current_thd, &gtid, timeout);
-
- if (status)
+ if (count == 1)
{
- int err;
- switch (status) {
- case wsrep::provider::error_transaction_missing:
- err= ER_WRONG_ARGUMENTS;
- break;
- default:
- err= ER_LOCK_WAIT_TIMEOUT;
+ if (wsrep_check_gtid_seqno(gtid_list[0].domain_id, gtid_list[0].server_id,
+ gtid_list[0].seq_no))
+ {
+ wait_gtid_ret= wsrep_gtid_server.wait_gtid_upto(gtid_list[0].seq_no, timeout);
+ if ((wait_gtid_ret == ETIMEDOUT) || (wait_gtid_ret == ETIME))
+ {
+ my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0), func_name());
+ ret= 0;
+ }
+ else if (wait_gtid_ret == ENOMEM)
+ {
+ my_error(ER_OUTOFMEMORY, MYF(0), func_name());
+ ret= 0;
+ }
}
- my_error(err, MYF(0), func_name());
- return 0LL;
}
- return 1LL;
+ else
+ {
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
+ null_value= TRUE;
+ ret= 0;
+ }
+ my_free(gtid_list);
+ return ret;
}
+
#endif /* WITH_WSREP */
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index ae0afeabeae..186efdf7fb9 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -368,13 +368,12 @@ public:
{}
void cleanup()
{
- DBUG_ENTER("Item_func_regex::cleanup");
+ DBUG_ENTER("Item_func_regexp_replace::cleanup");
Item_str_func::cleanup();
re.cleanup();
DBUG_VOID_RETURN;
}
String *val_str(String *str);
- bool fix_fields(THD *thd, Item **ref);
bool fix_length_and_dec();
const char *func_name() const { return "regexp_replace"; }
Item *get_copy(THD *thd) { return 0;}
@@ -390,13 +389,12 @@ public:
{}
void cleanup()
{
- DBUG_ENTER("Item_func_regex::cleanup");
+ DBUG_ENTER("Item_func_regexp_substr::cleanup");
Item_str_func::cleanup();
re.cleanup();
DBUG_VOID_RETURN;
}
String *val_str(String *str);
- bool fix_fields(THD *thd, Item **ref);
bool fix_length_and_dec();
const char *func_name() const { return "regexp_substr"; }
Item *get_copy(THD *thd) { return 0; }
@@ -1663,8 +1661,7 @@ public:
Item_func_uuid(THD *thd): Item_str_func(thd) {}
bool fix_length_and_dec()
{
- collation.set(system_charset_info,
- DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
+ collation.set(DTCollation_numeric());
fix_char_length(MY_UUID_STRING_LENGTH);
return FALSE;
}
@@ -1802,8 +1799,8 @@ public:
TABLE *table;
Item_temptable_rowid(TABLE *table_arg);
const Type_handler *type_handler() const { return &type_handler_string; }
- Field *create_tmp_field(bool group, TABLE *table)
- { return create_table_field_from_handler(table); }
+ Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table)
+ { return create_table_field_from_handler(root, table); }
String *val_str(String *str);
enum Functype functype() const { return TEMPTABLE_ROWID; }
const char *func_name() const { return "<rowid>"; }
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 79dcf8ecfe8..e494e9d84e1 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -47,6 +47,8 @@ double get_post_group_estimate(JOIN* join, double join_op_rows);
LEX_CSTRING exists_outer_expr_name= { STRING_WITH_LEN("<exists outer expr>") };
+LEX_CSTRING no_matter_name= {STRING_WITH_LEN("<no matter>") };
+
int check_and_do_in_subquery_rewrites(JOIN *join);
Item_subselect::Item_subselect(THD *thd_arg):
@@ -1938,8 +1940,8 @@ Item_in_subselect::single_value_transformer(JOIN *join)
*/
expr= new (thd->mem_root) Item_direct_ref(thd, &select_lex->context,
(Item**)optimizer->get_cache(),
- "<no matter>",
- &in_left_expr_name);
+ no_matter_name,
+ in_left_expr_name);
}
DBUG_RETURN(false);
@@ -2170,8 +2172,8 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
this,
&select_lex->
ref_pointer_array[0],
- (char *)"<ref>",
- &field_name));
+ {STRING_WITH_LEN("<ref>")},
+ field_name));
if (!abort_on_null && left_expr->maybe_null)
{
/*
@@ -2252,8 +2254,8 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
&select_lex->context,
this,
&select_lex->ref_pointer_array[0],
- (char *)"<no matter>",
- &field_name));
+ no_matter_name,
+ field_name));
if (!abort_on_null && left_expr->maybe_null)
{
disable_cond_guard_for_const_null_left_expr(0);
@@ -2438,21 +2440,21 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
Item_direct_ref(thd, &select_lex->context,
(*optimizer->get_cache())->
addr(i),
- (char *)"<no matter>",
- &in_left_expr_name),
+ no_matter_name,
+ in_left_expr_name),
new (thd->mem_root)
Item_ref(thd, &select_lex->context,
&select_lex->ref_pointer_array[i],
- (char *)"<no matter>",
- &list_ref));
+ no_matter_name,
+ list_ref));
Item *item_isnull=
new (thd->mem_root)
Item_func_isnull(thd,
new (thd->mem_root)
Item_ref(thd, &select_lex->context,
&select_lex->ref_pointer_array[i],
- (char *)"<no matter>",
- &list_ref));
+ no_matter_name,
+ list_ref));
Item *col_item= new (thd->mem_root)
Item_cond_or(thd, item_eq, item_isnull);
if (!abort_on_null && left_expr->element_index(i)->maybe_null &&
@@ -2472,8 +2474,8 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
Item_ref(thd, &select_lex->context,
&select_lex->
ref_pointer_array[i],
- (char *)"<no matter>",
- &list_ref));
+ no_matter_name,
+ list_ref));
if (!abort_on_null && left_expr->element_index(i)->maybe_null &&
get_cond_guard(i) )
{
@@ -2507,14 +2509,14 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
Item_direct_ref(thd, &select_lex->context,
(*optimizer->get_cache())->
addr(i),
- (char *)"<no matter>",
- &in_left_expr_name),
+ no_matter_name,
+ in_left_expr_name),
new (thd->mem_root)
Item_direct_ref(thd, &select_lex->context,
&select_lex->
ref_pointer_array[i],
- (char *)"<no matter>",
- &list_ref));
+ no_matter_name,
+ list_ref));
if (!abort_on_null && select_lex->ref_pointer_array[i]->maybe_null)
{
Item *having_col_item=
@@ -2523,8 +2525,8 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
new (thd->mem_root)
Item_ref(thd, &select_lex->context,
&select_lex->ref_pointer_array[i],
- (char *)"<no matter>",
- &list_ref));
+ no_matter_name,
+ list_ref));
item_isnull= new (thd->mem_root)
Item_func_isnull(thd,
@@ -2532,8 +2534,8 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
Item_direct_ref(thd, &select_lex->context,
&select_lex->
ref_pointer_array[i],
- (char *)"<no matter>",
- &list_ref));
+ no_matter_name,
+ list_ref));
item= new (thd->mem_root) Item_cond_or(thd, item, item_isnull);
if (left_expr->element_index(i)->maybe_null && get_cond_guard(i))
{
@@ -2742,7 +2744,7 @@ bool Item_in_subselect::inject_in_to_exists_cond(JOIN *join_arg)
join_arg->thd->change_item_tree(&unit->global_parameters()->select_limit,
new (thd->mem_root)
Item_int(thd, (int32) 1));
- unit->select_limit_cnt= 1;
+ unit->lim.set_single_row();
DBUG_RETURN(false);
}
@@ -3083,8 +3085,8 @@ bool Item_exists_subselect::exists2in_processor(void *opt_arg)
in_subs->expr= new (thd->mem_root)
Item_direct_ref(thd, &first_select->context,
(Item**)optimizer->get_cache(),
- (char *)"<no matter>",
- &in_left_expr_name);
+ no_matter_name,
+ in_left_expr_name);
if (in_subs->fix_fields(thd, optimizer->arguments() + 1))
{
res= TRUE;
@@ -3154,8 +3156,8 @@ bool Item_exists_subselect::exists2in_processor(void *opt_arg)
Item_direct_ref(thd,
&unit->outer_select()->context,
optimizer->arguments(),
- (char *)"<no matter>",
- &exists_outer_expr_name)),
+ no_matter_name,
+ exists_outer_expr_name)),
optimizer) :
(Item *)optimizer);
}
@@ -3178,8 +3180,8 @@ bool Item_exists_subselect::exists2in_processor(void *opt_arg)
Item_direct_ref(thd,
&unit->outer_select()->context,
optimizer->arguments()[0]->addr((int)i),
- (char *)"<no matter>",
- &exists_outer_expr_name)),
+ no_matter_name,
+ exists_outer_expr_name)),
thd->mem_root);
}
}
@@ -3718,7 +3720,6 @@ int subselect_single_select_engine::prepare(THD *thd)
SELECT_LEX *save_select= thd->lex->current_select;
thd->lex->current_select= select_lex;
if (join->prepare(select_lex->table_list.first,
- select_lex->with_wild,
select_lex->where,
select_lex->order_list.elements +
select_lex->group_list.elements,
@@ -4433,9 +4434,10 @@ void subselect_single_select_engine::print(String *str,
enum_query_type query_type)
{
With_clause* with_clause= select_lex->get_with_clause();
+ THD *thd= get_thd();
if (with_clause)
- with_clause->print(str, query_type);
- select_lex->print(get_thd(), str, query_type);
+ with_clause->print(thd, str, query_type);
+ select_lex->print(thd, str, query_type);
}
@@ -5806,8 +5808,9 @@ bool Ordered_key::alloc_keys_buffers()
{
DBUG_ASSERT(key_buff_elements > 0);
- if (!(key_buff= (rownum_t*) my_malloc((size_t)(key_buff_elements *
- sizeof(rownum_t)), MYF(MY_WME | MY_THREAD_SPECIFIC))))
+ if (!(key_buff= (rownum_t*) my_malloc(PSI_INSTRUMENT_ME,
+ static_cast<size_t>(key_buff_elements * sizeof(rownum_t)),
+ MYF(MY_WME | MY_THREAD_SPECIFIC))))
return TRUE;
/*
@@ -6238,8 +6241,9 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts,
sizeof(Ordered_key*))) ||
!(null_bitmaps= (MY_BITMAP**) thd->alloc(merge_keys_count *
sizeof(MY_BITMAP*))) ||
- !(row_num_to_rowid= (uchar*) my_malloc((size_t)(row_count * rowid_length),
- MYF(MY_WME | MY_THREAD_SPECIFIC))))
+ !(row_num_to_rowid= (uchar*) my_malloc(PSI_INSTRUMENT_ME,
+ static_cast<size_t>(row_count * rowid_length),
+ MYF(MY_WME | MY_THREAD_SPECIFIC))))
return TRUE;
/* Create the only non-NULL key if there is any. */
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index d68603d4ea7..052ac173747 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -42,8 +42,9 @@
size_t Item_sum::ram_limitation(THD *thd)
{
- return (size_t)MY_MIN(thd->variables.tmp_memory_table_size,
- thd->variables.max_heap_table_size);
+ return MY_MAX(1024,
+ (size_t)MY_MIN(thd->variables.tmp_memory_table_size,
+ thd->variables.max_heap_table_size));
}
@@ -1280,21 +1281,22 @@ void Item_sum_min_max::setup_hybrid(THD *thd, Item *item, Item *value_arg)
}
-Field *Item_sum_min_max::create_tmp_field(bool group, TABLE *table)
+Field *Item_sum_min_max::create_tmp_field(MEM_ROOT *root,
+ bool group, TABLE *table)
{
DBUG_ENTER("Item_sum_min_max::create_tmp_field");
if (args[0]->type() == Item::FIELD_ITEM)
{
Field *field= ((Item_field*) args[0])->field;
- if ((field= field->create_tmp_field(table->in_use->mem_root, table, true)))
+ if ((field= field->create_tmp_field(root, table, true)))
{
DBUG_ASSERT((field->flags & NOT_NULL_FLAG) == 0);
field->field_name= name;
}
DBUG_RETURN(field);
}
- DBUG_RETURN(tmp_table_field_from_field_type(table));
+ DBUG_RETURN(tmp_table_field_from_field_type(root, table));
}
/***********************************************************************
@@ -1984,7 +1986,7 @@ Item *Item_sum_avg::copy_or_same(THD* thd)
}
-Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table)
+Field *Item_sum_avg::create_tmp_field(MEM_ROOT *root, bool group, TABLE *table)
{
if (group)
@@ -1994,7 +1996,7 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table)
The easiest way is to do this is to store both value in a string
and unpack on access.
*/
- Field *field= new (table->in_use->mem_root)
+ Field *field= new (root)
Field_string(((result_type() == DECIMAL_RESULT) ?
dec_bin_size : sizeof(double)) + sizeof(longlong),
0, &name, &my_charset_bin);
@@ -2002,7 +2004,7 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table)
field->init(table);
return field;
}
- return tmp_table_field_from_field_type(table);
+ return tmp_table_field_from_field_type(root, table);
}
@@ -2226,7 +2228,8 @@ Item *Item_sum_variance::copy_or_same(THD* thd)
If we're grouping, then we need some space to serialize variables into, to
pass around.
*/
-Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table)
+Field *Item_sum_variance::create_tmp_field(MEM_ROOT *root,
+ bool group, TABLE *table)
{
Field *field;
if (group)
@@ -2236,11 +2239,12 @@ Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table)
The easiest way is to do this is to store both value in a string
and unpack on access.
*/
- field= new Field_string(Stddev::binary_size(), 0, &name, &my_charset_bin);
+ field= new (root) Field_string(Stddev::binary_size(), 0,
+ &name, &my_charset_bin);
}
else
- field= new Field_double(max_length, maybe_null, &name, decimals,
- TRUE);
+ field= new (root) Field_double(max_length, maybe_null, &name, decimals,
+ TRUE);
if (field != NULL)
field->init(table);
@@ -3669,7 +3673,19 @@ int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)),
res= (*arg)->val_str(&tmp);
}
if (res)
+ {
+ if (item->sum_func() == Item_sum::JSON_ARRAYAGG_FUNC)
+ {
+ /*
+ JSON_ARRAYAGG needs to convert the type into valid JSON before
+ appending it to the result
+ */
+ Item_func_json_arrayagg *arrayagg= (Item_func_json_arrayagg *) item_arg;
+ res= arrayagg->convert_to_json(*arg, res);
+ }
+
result->append(*res);
+ }
}
if (item->limit_clause)
@@ -3975,9 +3991,9 @@ bool Item_func_group_concat::repack_tree(THD *thd)
*/
#define GCONCAT_REPACK_FACTOR (1 << 10)
-bool Item_func_group_concat::add()
+bool Item_func_group_concat::add(bool exclude_nulls)
{
- if (always_null)
+ if (always_null && exclude_nulls)
return 0;
copy_fields(tmp_table_param);
if (copy_funcs(tmp_table_param->items_to_copy, table->in_use))
@@ -3995,7 +4011,8 @@ bool Item_func_group_concat::add()
Field *field= show_item->get_tmp_table_field();
if (field)
{
- if (field->is_null_in_record((const uchar*) table->record[0]))
+ if (field->is_null_in_record((const uchar*) table->record[0]) &&
+ exclude_nulls)
return 0; // Skip row if it contains null
if (tree && (res= field->val_str(&buf)))
row_str_len+= res->length();
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 7bf8a41f405..e221d04397d 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -1,7 +1,7 @@
#ifndef ITEM_SUM_INCLUDED
#define ITEM_SUM_INCLUDED
/* Copyright (c) 2000, 2013 Oracle and/or its affiliates.
- Copyright (c) 2008, 2013 Monty Program Ab.
+ Copyright (c) 2008, 2020, 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
@@ -355,7 +355,7 @@ public:
ROW_NUMBER_FUNC, RANK_FUNC, DENSE_RANK_FUNC, PERCENT_RANK_FUNC,
CUME_DIST_FUNC, NTILE_FUNC, FIRST_VALUE_FUNC, LAST_VALUE_FUNC,
NTH_VALUE_FUNC, LEAD_FUNC, LAG_FUNC, PERCENTILE_CONT_FUNC,
- PERCENTILE_DISC_FUNC, SP_AGGREGATE_FUNC
+ PERCENTILE_DISC_FUNC, SP_AGGREGATE_FUNC, JSON_ARRAYAGG_FUNC
};
Item **ref_by; /* pointer to a ref to the object used to register it */
@@ -428,6 +428,7 @@ public:
case SUM_BIT_FUNC:
case UDF_SUM_FUNC:
case GROUP_CONCAT_FUNC:
+ case JSON_ARRAYAGG_FUNC:
return true;
default:
return false;
@@ -513,11 +514,11 @@ public:
}
virtual void make_unique() { force_copy_fields= TRUE; }
Item *get_tmp_table_item(THD *thd);
- virtual Field *create_tmp_field(bool group, TABLE *table);
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ virtual Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table);
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
- return create_tmp_field(param->group(), table);
+ return create_tmp_field(root, param->group(), table);
}
virtual bool collect_outer_ref_processor(void *param);
bool init_sum_func_check(THD *thd);
@@ -778,7 +779,6 @@ public:
{
return get_date_from_int(thd, ltime, fuzzydate);
}
- const Type_handler *type_handler() const { return &type_handler_longlong; }
bool fix_length_and_dec()
{ decimals=0; max_length=21; maybe_null=null_value=0; return FALSE; }
};
@@ -898,6 +898,7 @@ public:
count=count_arg;
Item_sum::make_const();
}
+ const Type_handler *type_handler() const { return &type_handler_slonglong; }
longlong val_int();
void reset_field();
void update_field();
@@ -957,7 +958,7 @@ public:
return has_with_distinct() ? "avg(distinct " : "avg(";
}
Item *copy_or_same(THD* thd);
- Field *create_tmp_field(bool group, TABLE *table);
+ Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table);
void cleanup()
{
count= 0;
@@ -1041,7 +1042,7 @@ public:
const char *func_name() const
{ return sample ? "var_samp(" : "variance("; }
Item *copy_or_same(THD* thd);
- Field *create_tmp_field(bool group, TABLE *table);
+ Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table);
void cleanup()
{
m_stddev= Stddev();
@@ -1079,11 +1080,11 @@ class Item_sum_hybrid: public Item_sum,
public:
Item_sum_hybrid(THD *thd, Item *item_par):
Item_sum(thd, item_par),
- Type_handler_hybrid_field_type(&type_handler_longlong)
+ Type_handler_hybrid_field_type(&type_handler_slonglong)
{ collation.set(&my_charset_bin); }
Item_sum_hybrid(THD *thd, Item *a, Item *b):
Item_sum(thd, a, b),
- Type_handler_hybrid_field_type(&type_handler_longlong)
+ Type_handler_hybrid_field_type(&type_handler_slonglong)
{ collation.set(&my_charset_bin); }
Item_sum_hybrid(THD *thd, Item_sum_hybrid *item)
:Item_sum(thd, item),
@@ -1138,7 +1139,7 @@ public:
{
return get_arg(0)->real_type_handler();
}
- TYPELIB *get_typelib() const { return args[0]->get_typelib(); }
+ const TYPELIB *get_typelib() const { return args[0]->get_typelib(); }
void update_field();
void min_max_update_str_field();
void min_max_update_real_field();
@@ -1149,7 +1150,7 @@ public:
bool any_value() { return was_values; }
void no_rows_in_result();
void restore_to_before_no_rows_in_result();
- Field *create_tmp_field(bool group, TABLE *table);
+ Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table);
void setup_caches(THD *thd) { setup_hybrid(thd, arguments()[0], NULL); }
};
@@ -1203,6 +1204,7 @@ public:
longlong val_int();
void reset_field();
void update_field();
+ const Type_handler *type_handler() const { return &type_handler_ulonglong; }
bool fix_length_and_dec()
{
decimals= 0; max_length=21; unsigned_flag= 1; maybe_null= null_value= 0;
@@ -1311,7 +1313,7 @@ struct st_sp_security_context;
Item_sum_sp handles STORED AGGREGATE FUNCTIONS
Each Item_sum_sp represents a custom aggregate function. Inside the
- function's body, we require at least one occurence of FETCH GROUP NEXT ROW
+ function's body, we require at least one occurrence of FETCH GROUP NEXT ROW
instruction. This cursor is what makes custom stored aggregates possible.
During computation the function's add method is called. This in turn performs
@@ -1339,7 +1341,7 @@ struct st_sp_security_context;
group is already set in the argument x. This behaviour is done so when
a user writes a function, he should "logically" include FETCH GROUP NEXT ROW
before any "add" instructions in the stored function. This means however that
- internally, the first occurence doesn't stop the function. See the
+ internally, the first occurrence doesn't stop the function. See the
implementation of FETCH GROUP NEXT ROW for details as to how it happens.
Either way, one should assume that after calling "Item_sum_sp::add()" that
@@ -1372,9 +1374,9 @@ public:
{
return SP_AGGREGATE_FUNC;
}
- Field *create_field_for_create_select(TABLE *table)
+ Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table)
{
- return create_table_field_from_handler(table);
+ return create_table_field_from_handler(root, table);
}
bool fix_length_and_dec();
bool fix_fields(THD *thd, Item **ref);
@@ -1456,10 +1458,10 @@ public:
unsigned_flag= item->unsigned_flag;
}
table_map used_tables() const { return (table_map) 1L; }
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
- return create_tmp_field_ex_simple(table, src, param);
+ return create_tmp_field_ex_simple(root, table, src, param);
}
void save_in_result_field(bool no_conversions) { DBUG_ASSERT(0); }
bool check_vcol_func_processor(void *arg)
@@ -1672,7 +1674,12 @@ public:
{ DBUG_ASSERT(fixed == 1); return (double) Item_sum_udf_int::val_int(); }
String *val_str(String*str);
my_decimal *val_decimal(my_decimal *);
- const Type_handler *type_handler() const { return &type_handler_longlong; }
+ const Type_handler *type_handler() const
+ {
+ if (unsigned_flag)
+ return &type_handler_ulonglong;
+ return &type_handler_slonglong;
+ }
bool fix_length_and_dec() { decimals=0; max_length=21; return FALSE; }
Item *copy_or_same(THD* thd);
Item *get_copy(THD *thd)
@@ -1696,8 +1703,8 @@ public:
char *end_not_used;
String *res;
res=val_str(&str_value);
- return res ? my_strntod(res->charset(),(char*) res->ptr(),res->length(),
- &end_not_used, &err_not_used) : 0.0;
+ return res ? res->charset()->strntod((char*) res->ptr(),res->length(),
+ &end_not_used, &err_not_used) : 0.0;
}
longlong val_int()
{
@@ -1710,7 +1717,7 @@ public:
return 0; /* Null value */
cs= res->charset();
end= (char*) res->ptr()+res->length();
- return cs->cset->strtoll10(cs, res->ptr(), &end, &err_not_used);
+ return cs->strtoll10(res->ptr(), &end, &err_not_used);
}
my_decimal *val_decimal(my_decimal *dec);
const Type_handler *type_handler() const { return string_type_handler(); }
@@ -1843,6 +1850,7 @@ C_MODE_END
class Item_func_group_concat : public Item_sum
{
+protected:
TMP_TABLE_PARAM *tmp_table_param;
String result;
String *separator;
@@ -1888,6 +1896,12 @@ class Item_func_group_concat : public Item_sum
*/
Item_func_group_concat *original;
+ /*
+ Used by Item_func_group_concat and Item_func_json_arrayagg. The latter
+ needs null values but the former doesn't.
+ */
+ bool add(bool exclude_nulls);
+
friend int group_concat_key_cmp_with_distinct(void* arg, const void* key1,
const void* key2);
friend int group_concat_key_cmp_with_order(void* arg, const void* key1,
@@ -1925,7 +1939,10 @@ public:
return &type_handler_varchar;
}
void clear();
- bool add();
+ bool add()
+ {
+ return add(true);
+ }
void reset_field() { DBUG_ASSERT(0); } // not used
void update_field() { DBUG_ASSERT(0); } // not used
bool fix_fields(THD *,Item **);
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 924fdecffa9..a1377af08e6 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2012, Oracle and/or its affiliates.
- Copyright (c) 2009, 2016, MariaDB
+ Copyright (c) 2009, 2020, 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
@@ -157,7 +157,7 @@ static bool extract_date_time(THD *thd, DATE_TIME_FORMAT *format,
for (; ptr != end && val != val_end; ptr++)
{
/* Skip pre-space between each argument */
- if ((val+= cs->cset->scan(cs, val, val_end, MY_SEQ_SPACES)) >= val_end)
+ if ((val+= cs->scan(val, val_end, MY_SEQ_SPACES)) >= val_end)
break;
if (*ptr == '%' && ptr+1 != end)
@@ -259,13 +259,9 @@ static bool extract_date_time(THD *thd, DATE_TIME_FORMAT *format,
case 'p':
if (val_len < 2 || ! usa_time)
goto err;
- if (!my_strnncoll(&my_charset_latin1,
- (const uchar *) val, 2,
- (const uchar *) "PM", 2))
+ if (!my_charset_latin1.strnncoll(val, 2, "PM", 2))
daypart= 12;
- else if (my_strnncoll(&my_charset_latin1,
- (const uchar *) val, 2,
- (const uchar *) "AM", 2))
+ else if (my_charset_latin1.strnncoll(val, 2, "AM", 2))
goto err;
val+= 2;
break;
@@ -986,7 +982,7 @@ String* Item_func_monthname::val_str(String* str)
return (String *) 0;
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,
+ str->copy(month_name, (uint) strlen(month_name), &my_charset_utf8mb3_bin,
collation.collation, &err);
return str;
}
@@ -1132,7 +1128,7 @@ String* Item_func_dayname::val_str(String* str)
return (String*) 0;
day_name= locale->day_names->type_names[dt.weekday(false)];
- str->copy(day_name, (uint) strlen(day_name), &my_charset_utf8_bin,
+ str->copy(day_name, (uint) strlen(day_name), &my_charset_utf8mb3_bin,
collation.collation, &err);
return str;
}
@@ -1214,7 +1210,7 @@ bool Item_func_unix_timestamp::get_timestamp_value(my_time_t *seconds,
{
if ((null_value= field->is_null()))
return 1;
- *seconds= ((Field_timestamp*)field)->get_timestamp(second_part);
+ *seconds= field->get_timestamp(second_part);
return 0;
}
}
@@ -1270,7 +1266,7 @@ longlong Item_func_unix_timestamp::val_int_endpoint(bool left_endp, bool *incl_e
DBUG_ASSERT(arg_count == 1 &&
args[0]->type() == Item::FIELD_ITEM &&
args[0]->field_type() == MYSQL_TYPE_TIMESTAMP);
- Field_timestamp *field=(Field_timestamp *)(((Item_field*)args[0])->field);
+ Field *field= ((Item_field*)args[0])->field;
/* Leave the incl_endp intact */
ulong unused;
my_time_t ts= field->get_timestamp(&unused);
@@ -1644,7 +1640,7 @@ int Item_func_now_local::save_in_field(Field *field, bool no_conversions)
ulong sec_part= decimals ? thd->query_start_sec_part() : 0;
sec_part-= my_time_fraction_remainder(sec_part, decimals);
field->set_notnull();
- ((Field_timestamp*)field)->store_TIME(ts, sec_part);
+ field->store_timestamp(ts, sec_part);
return 0;
}
else
@@ -1922,7 +1918,10 @@ bool Item_func_from_unixtime::fix_length_and_dec()
THD *thd= current_thd;
thd->time_zone_used= 1;
tz= thd->variables.time_zone;
- fix_attributes_datetime_not_fixed_dec(args[0]->decimals);
+ Type_std_attributes::set(
+ Type_temporal_attributes_not_fixed_dec(MAX_DATETIME_WIDTH,
+ args[0]->decimals, false),
+ DTCollation_numeric());
maybe_null= true;
return FALSE;
}
@@ -2003,7 +2002,7 @@ bool Item_date_add_interval::fix_length_and_dec()
{
enum_field_types arg0_field_type;
- if (!args[0]->type_handler()->is_traditional_type())
+ if (!args[0]->type_handler()->is_traditional_scalar_type())
{
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
args[0]->type_handler()->name().ptr(),
@@ -2325,7 +2324,7 @@ uint Item_char_typecast::adjusted_length_with_warn(uint length)
}
-String *Item_char_typecast::val_str(String *str)
+String *Item_char_typecast::val_str_generic(String *str)
{
DBUG_ASSERT(fixed == 1);
String *res;
@@ -2381,11 +2380,75 @@ end:
}
+String *Item_char_typecast::val_str_binary_from_native(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+ DBUG_ASSERT(cast_cs == &my_charset_bin);
+ NativeBuffer<STRING_BUFFER_USUAL_SIZE> native;
+
+ if (args[0]->val_native(current_thd, &native))
+ {
+ null_value= 1;
+ return 0;
+ }
+
+ if (has_explicit_length())
+ {
+ cast_length= adjusted_length_with_warn(cast_length);
+ if (cast_length > native.length())
+ {
+ // add trailing 0x00s
+ DBUG_ASSERT(cast_length <= current_thd->variables.max_allowed_packet);
+ str->alloc(cast_length);
+ str->copy(native.ptr(), native.length(), &my_charset_bin);
+ bzero((char*) str->end(), cast_length - str->length());
+ str->length(cast_length);
+ }
+ else
+ str->copy(native.ptr(), cast_length, &my_charset_bin);
+ }
+ else
+ str->copy(native.ptr(), native.length(), &my_charset_bin);
+
+ return ((null_value= (str->length() >
+ adjusted_length_with_warn(str->length())))) ? 0 : str;
+}
+
+
+class Item_char_typecast_func_handler: public Item_handled_func::Handler_str
+{
+public:
+ const Type_handler *return_type_handler(const Item_handled_func *item) const
+ {
+ return Type_handler::string_type_handler(item->max_length);
+ }
+ const Type_handler *
+ type_handler_for_create_select(const Item_handled_func *item) const
+ {
+ return return_type_handler(item)->type_handler_for_tmp_table(item);
+ }
+
+ bool fix_length_and_dec(Item_handled_func *item) const
+ {
+ return false;
+ }
+ String *val_str(Item_handled_func *item, String *to) const
+ {
+ DBUG_ASSERT(dynamic_cast<const Item_char_typecast*>(item));
+ return static_cast<Item_char_typecast*>(item)->val_str_generic(to);
+ }
+};
+
+
+static Item_char_typecast_func_handler item_char_typecast_func_handler;
+
+
void Item_char_typecast::fix_length_and_dec_numeric()
{
fix_length_and_dec_internal(from_cs= cast_cs->mbminlen == 1 ?
cast_cs :
&my_charset_latin1);
+ set_func_handler(&item_char_typecast_func_handler);
}
@@ -2394,6 +2457,24 @@ void Item_char_typecast::fix_length_and_dec_generic()
fix_length_and_dec_internal(from_cs= args[0]->dynamic_result() ?
0 :
args[0]->collation.collation);
+ set_func_handler(&item_char_typecast_func_handler);
+}
+
+
+void Item_char_typecast::fix_length_and_dec_str()
+{
+ fix_length_and_dec_generic();
+ m_suppress_warning_to_error_escalation= true;
+ set_func_handler(&item_char_typecast_func_handler);
+}
+
+
+void
+Item_char_typecast::fix_length_and_dec_native_to_binary(uint32 octet_length)
+{
+ collation.set(&my_charset_bin, DERIVATION_IMPLICIT);
+ max_length= has_explicit_length() ? (uint32) cast_length : octet_length;
+ maybe_null|= current_thd->is_strict_mode();
}
@@ -2437,6 +2518,8 @@ void Item_char_typecast::fix_length_and_dec_internal(CHARSET_INFO *from_cs)
(cast_cs == &my_charset_bin ? 1 :
args[0]->collation.collation->mbmaxlen));
max_length= char_length * cast_cs->mbmaxlen;
+ // Add NULL-ability in strict mode. See Item_str_func::fix_fields()
+ maybe_null= maybe_null || current_thd->is_strict_mode();
}
@@ -2523,8 +2606,8 @@ bool Item_func_add_time::fix_length_and_dec()
{
enum_field_types arg0_field_type;
- if (!args[0]->type_handler()->is_traditional_type() ||
- !args[1]->type_handler()->is_traditional_type())
+ if (!args[0]->type_handler()->is_traditional_scalar_type() ||
+ !args[1]->type_handler()->is_traditional_scalar_type())
{
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
args[0]->type_handler()->name().ptr(),
@@ -2830,9 +2913,8 @@ String *Item_func_get_format::val_str_ascii(String *str)
uint format_name_len;
format_name_len= (uint) strlen(format_name);
if (val_len == format_name_len &&
- !my_strnncoll(&my_charset_latin1,
- (const uchar *) val->ptr(), val_len,
- (const uchar *) format_name, val_len))
+ !my_charset_latin1.strnncoll(val->ptr(), val_len,
+ format_name, val_len))
{
const char *format_str= get_date_time_format_str(format, type);
str->set(format_str, (uint) strlen(format_str), &my_charset_numeric);
@@ -2934,8 +3016,8 @@ get_date_time_result_type(const char *format, uint length)
bool Item_func_str_to_date::fix_length_and_dec()
{
- if (!args[0]->type_handler()->is_traditional_type() ||
- !args[1]->type_handler()->is_traditional_type())
+ if (!args[0]->type_handler()->is_traditional_scalar_type() ||
+ !args[1]->type_handler()->is_traditional_scalar_type())
{
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
args[0]->type_handler()->name().ptr(),
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index b3ecd1dfd4d..5d5f3bd4681 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -959,8 +959,8 @@ class Item_extract :public Item_int_func,
uint32 threashold)
{
if (length >= threashold)
- return &type_handler_longlong;
- return &type_handler_long;
+ return &type_handler_slonglong;
+ return &type_handler_slong;
}
void set_date_length(uint32 length)
{
@@ -991,7 +991,7 @@ class Item_extract :public Item_int_func,
const interval_type int_type; // keep it public
Item_extract(THD *thd, interval_type type_arg, Item *a):
Item_int_func(thd, a),
- Type_handler_hybrid_field_type(&type_handler_longlong),
+ Type_handler_hybrid_field_type(&type_handler_slonglong),
m_date_mode(date_mode_t(0)),
int_type(type_arg)
{ }
@@ -1053,14 +1053,16 @@ class Item_extract :public Item_int_func,
};
-class Item_char_typecast :public Item_str_func
+class Item_char_typecast :public Item_handled_func
{
uint cast_length;
CHARSET_INFO *cast_cs, *from_cs;
bool charset_conversion;
String tmp_value;
bool m_suppress_warning_to_error_escalation;
+public:
bool has_explicit_length() const { return cast_length != ~0U; }
+private:
String *reuse(String *src, size_t length);
String *copy(String *src, CHARSET_INFO *cs);
uint adjusted_length_with_warn(uint length);
@@ -1071,20 +1073,18 @@ public:
uint get_cast_length() const { return cast_length; }
public:
Item_char_typecast(THD *thd, Item *a, uint length_arg, CHARSET_INFO *cs_arg):
- Item_str_func(thd, a), cast_length(length_arg), cast_cs(cs_arg),
+ Item_handled_func(thd, a), cast_length(length_arg), cast_cs(cs_arg),
m_suppress_warning_to_error_escalation(false) {}
enum Functype functype() const { return CHAR_TYPECAST_FUNC; }
bool eq(const Item *item, bool binary_cmp) const;
const char *func_name() const { return "cast_as_char"; }
CHARSET_INFO *cast_charset() const { return cast_cs; }
- String *val_str(String *a);
+ String *val_str_generic(String *a);
+ String *val_str_binary_from_native(String *a);
void fix_length_and_dec_generic();
void fix_length_and_dec_numeric();
- void fix_length_and_dec_str()
- {
- fix_length_and_dec_generic();
- m_suppress_warning_to_error_escalation= true;
- }
+ void fix_length_and_dec_str();
+ void fix_length_and_dec_native_to_binary(uint32 octet_length);
bool fix_length_and_dec()
{
return args[0]->type_handler()->Item_char_typecast_fix_length_and_dec(this);
@@ -1537,9 +1537,11 @@ public:
{
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);
+ item->Type_std_attributes::set(
+ Type_temporal_attributes_not_fixed_dec(MAX_DATETIME_WIDTH, dec, false),
+ DTCollation(item->default_charset(),
+ DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII));
+ item->fix_char_length(item->max_length);
return false;
}
bool get_date(THD *thd, Item_handled_func *item,
@@ -1644,9 +1646,11 @@ public:
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);
+ item->Type_std_attributes::set(
+ Type_temporal_attributes_not_fixed_dec(MAX_DATETIME_WIDTH, dec, false),
+ DTCollation(item->default_charset(),
+ DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII));
+ item->fix_char_length(item->max_length);
return false;
}
bool get_date(THD *thd, Item_handled_func *item,
diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc
index 5ecb9510940..f20d20c81d6 100644
--- a/sql/item_windowfunc.cc
+++ b/sql/item_windowfunc.cc
@@ -463,7 +463,8 @@ bool Item_sum_hybrid_simple::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t f
return retval;
}
-Field *Item_sum_hybrid_simple::create_tmp_field(bool group, TABLE *table)
+Field *Item_sum_hybrid_simple::create_tmp_field(MEM_ROOT *root,
+ bool group, TABLE *table)
{
DBUG_ASSERT(0);
return NULL;
diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h
index bae487fd6f6..f38209e4bb5 100644
--- a/sql/item_windowfunc.h
+++ b/sql/item_windowfunc.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2016,2017 MariaDB
+ Copyright (c) 2016,2019 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
@@ -118,6 +118,8 @@ public:
Item_sum_row_number(THD *thd)
: Item_sum_int(thd), count(0) {}
+ const Type_handler *type_handler() const { return &type_handler_slonglong; }
+
void clear()
{
count= 0;
@@ -179,6 +181,8 @@ public:
Item_sum_rank(THD *thd) : Item_sum_int(thd), peer_tracker(NULL) {}
+ const Type_handler *type_handler() const { return &type_handler_slonglong; }
+
void clear()
{
/* This is called on partition start */
@@ -266,6 +270,7 @@ class Item_sum_dense_rank: public Item_sum_int
Item_sum_dense_rank(THD *thd)
: Item_sum_int(thd), dense_rank(0), first_add(true), peer_tracker(NULL) {}
+ const Type_handler *type_handler() const { return &type_handler_slonglong; }
enum Sumfunctype sum_func () const
{
return DENSE_RANK_FUNC;
@@ -318,7 +323,7 @@ class Item_sum_hybrid_simple : public Item_sum_hybrid
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
void update_field();
- Field *create_tmp_field(bool group, TABLE *table);
+ Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table);
void clear()
{
value->clear();
@@ -698,6 +703,8 @@ class Item_sum_ntile : public Item_sum_int,
void update_field() {}
+ const Type_handler *type_handler() const { return &type_handler_slonglong; }
+
void reset_field() { DBUG_ASSERT(0); }
void set_partition_row_count(ulonglong count)
@@ -719,7 +726,7 @@ class Item_sum_percentile_disc : public Item_sum_num,
{
public:
Item_sum_percentile_disc(THD *thd, Item* arg) : Item_sum_num(thd, arg),
- Type_handler_hybrid_field_type(&type_handler_longlong),
+ Type_handler_hybrid_field_type(&type_handler_slonglong),
value(NULL), val_calculated(FALSE), first_call(TRUE),
prev_value(0), order_item(NULL){}
diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc
index 60218c8ee74..b5eda985eb2 100644
--- a/sql/item_xmlfunc.cc
+++ b/sql/item_xmlfunc.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2005, 2019, Oracle and/or its affiliates.
- Copyright (c) 2009, 2019, MariaDB
+ Copyright (c) 2009, 2020, 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
@@ -71,15 +71,6 @@ typedef struct my_xpath_lex_st
} MY_XPATH_LEX;
-/* Structure to store nodesets */
-typedef struct my_xpath_flt_st
-{
- uint num; /* absolute position in MY_XML_NODE array */
- uint pos; /* relative position in context */
- uint size; /* context size */
-} MY_XPATH_FLT;
-
-
/* XPath function creator */
typedef struct my_xpath_function_names_st
{
@@ -105,50 +96,13 @@ typedef struct my_xpath_st
Item *item; /* current expression */
Item *context; /* last scanned context */
Item *rootelement; /* The root element */
- String *context_cache; /* last context provider */
+ Native *context_cache; /* last context provider */
String *pxml; /* Parsed XML, an array of MY_XML_NODE */
CHARSET_INFO *cs; /* character set/collation string comparison */
int error;
} MY_XPATH;
-/* Dynamic array of MY_XPATH_FLT */
-class XPathFilter :public String
-{
-public:
- XPathFilter() :String() {}
- inline bool append_element(MY_XPATH_FLT *flt)
- {
- String *str= this;
- return str->append((const char*)flt, (uint32) sizeof(MY_XPATH_FLT));
- }
- inline bool append_element(uint32 num, uint32 pos)
- {
- MY_XPATH_FLT add;
- add.num= num;
- add.pos= pos;
- add.size= 0;
- return append_element(&add);
- }
- inline bool append_element(uint32 num, uint32 pos, uint32 size)
- {
- MY_XPATH_FLT add;
- add.num= num;
- add.pos= pos;
- add.size= size;
- return append_element(&add);
- }
- inline MY_XPATH_FLT *element(uint i)
- {
- return (MY_XPATH_FLT*) (ptr() + i * sizeof(MY_XPATH_FLT));
- }
- inline uint32 numelements()
- {
- return length() / sizeof(MY_XPATH_FLT);
- }
-};
-
-
static Type_handler_long_blob type_handler_xpath_nodeset;
@@ -158,13 +112,13 @@ static Type_handler_long_blob type_handler_xpath_nodeset;
class Item_nodeset_func :public Item_str_func
{
protected:
- String tmp_value, tmp2_value;
+ NativeNodesetBuffer tmp_native_value, tmp2_native_value;
MY_XPATH_FLT *fltbeg, *fltend;
MY_XML_NODE *nodebeg, *nodeend;
uint numnodes;
public:
String *pxml;
- String context_cache;
+ NativeNodesetBuffer context_cache;
Item_nodeset_func(THD *thd, String *pxml_arg):
Item_str_func(thd), pxml(pxml_arg) {}
Item_nodeset_func(THD *thd, Item *a, String *pxml_arg):
@@ -179,12 +133,12 @@ public:
nodeend= (MY_XML_NODE*) (pxml->ptr() + pxml->length());
numnodes= (uint)(nodeend - nodebeg);
}
- void prepare(String *nodeset)
+ void prepare(THD *thd, Native *nodeset)
{
prepare_nodes();
- String *res= args[0]->val_raw(&tmp_value);
- fltbeg= (MY_XPATH_FLT*) res->ptr();
- fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
+ args[0]->val_native(thd, &tmp_native_value);
+ fltbeg= (MY_XPATH_FLT*) tmp_native_value.ptr();
+ fltend= (MY_XPATH_FLT*) tmp_native_value.end();
nodeset->length(0);
}
const Type_handler *type_handler() const
@@ -195,7 +149,7 @@ public:
{
return &type_handler_xpath_nodeset;
}
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(0);
@@ -204,9 +158,9 @@ public:
String *val_str(String *str)
{
prepare_nodes();
- String *res= val_raw(&tmp2_value);
- fltbeg= (MY_XPATH_FLT*) res->ptr();
- fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
+ val_native(current_thd, &tmp2_native_value);
+ fltbeg= (MY_XPATH_FLT*) tmp2_native_value.ptr();
+ fltend= (MY_XPATH_FLT*) tmp2_native_value.end();
String active;
active.alloc(numnodes);
bzero((char*) active.ptr(), numnodes);
@@ -235,7 +189,6 @@ public:
}
return str;
}
- enum Item_result result_type () const { return STRING_RESULT; }
bool fix_length_and_dec()
{
max_length= MAX_BLOB_WIDTH;
@@ -261,7 +214,7 @@ public:
Item_nodeset_func_rootelement(THD *thd, String *pxml):
Item_nodeset_func(thd, pxml) {}
const char *func_name() const { return "xpath_rootelement"; }
- String *val_raw(String *nodeset);
+ bool val_native(THD *thd, Native *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_rootelement>(thd, this); }
};
@@ -274,7 +227,7 @@ public:
Item_nodeset_func_union(THD *thd, Item *a, Item *b, String *pxml):
Item_nodeset_func(thd, a, b, pxml) {}
const char *func_name() const { return "xpath_union"; }
- String *val_raw(String *nodeset);
+ bool val_native(THD *thd, Native *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_union>(thd, this); }
};
@@ -308,7 +261,7 @@ public:
String *pxml):
Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml) {}
const char *func_name() const { return "xpath_selfbyname"; }
- String *val_raw(String *nodeset);
+ bool val_native(THD *thd, Native *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_selfbyname>(thd, this); }
};
@@ -322,7 +275,7 @@ public:
String *pxml):
Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml) {}
const char *func_name() const { return "xpath_childbyname"; }
- String *val_raw(String *nodeset);
+ bool val_native(THD *thd, Native *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_childbyname>(thd, this); }
};
@@ -338,7 +291,7 @@ public:
Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml),
need_self(need_self_arg) {}
const char *func_name() const { return "xpath_descendantbyname"; }
- String *val_raw(String *nodeset);
+ bool val_native(THD *thd, Native *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_descendantbyname>(thd, this); }
};
@@ -354,7 +307,7 @@ public:
Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml),
need_self(need_self_arg) {}
const char *func_name() const { return "xpath_ancestorbyname"; }
- String *val_raw(String *nodeset);
+ bool val_native(THD *thd, Native *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_ancestorbyname>(thd, this); }
};
@@ -368,7 +321,7 @@ public:
String *pxml):
Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml) {}
const char *func_name() const { return "xpath_parentbyname"; }
- String *val_raw(String *nodeset);
+ bool val_native(THD *thd, Native *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_parentbyname>(thd, this); }
};
@@ -382,7 +335,7 @@ public:
uint l_arg, String *pxml):
Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml) {}
const char *func_name() const { return "xpath_attributebyname"; }
- String *val_raw(String *nodeset);
+ bool val_native(THD *thd, Native *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_attributebyname>(thd, this); }
};
@@ -399,7 +352,7 @@ public:
Item_nodeset_func_predicate(THD *thd, Item *a, Item *b, String *pxml):
Item_nodeset_func(thd, a, b, pxml) {}
const char *func_name() const { return "xpath_predicate"; }
- String *val_raw(String *nodeset);
+ bool val_native(THD *thd, Native *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_predicate>(thd, this); }
};
@@ -412,7 +365,7 @@ public:
Item_nodeset_func_elementbyindex(THD *thd, Item *a, Item *b, String *pxml):
Item_nodeset_func(thd, a, b, pxml) { }
const char *func_name() const { return "xpath_elementbyindex"; }
- String *val_raw(String *nodeset);
+ bool val_native(THD *thd, Native *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_elementbyindex>(thd, this); }
};
@@ -427,7 +380,7 @@ public:
class Item_xpath_cast_bool :public Item_bool_func
{
String *pxml;
- String tmp_value;
+ NativeNodesetBuffer tmp_native_value;
public:
Item_xpath_cast_bool(THD *thd, Item *a, String *pxml_arg):
Item_bool_func(thd, a), pxml(pxml_arg) {}
@@ -436,8 +389,8 @@ public:
{
if (args[0]->fixed_type_handler() == &type_handler_xpath_nodeset)
{
- String *flt= args[0]->val_raw(&tmp_value);
- return flt->length() == sizeof(MY_XPATH_FLT) ? 1 : 0;
+ args[0]->val_native(current_thd, &tmp_native_value);
+ return tmp_native_value.elements() == 1 ? 1 : 0;
}
return args[0]->val_real() ? 1 : 0;
}
@@ -466,11 +419,13 @@ public:
class Item_nodeset_context_cache :public Item_nodeset_func
{
public:
- String *string_cache;
- Item_nodeset_context_cache(THD *thd, String *str_arg, String *pxml):
- Item_nodeset_func(thd, pxml), string_cache(str_arg) { }
- String *val_raw(String *res)
- { return string_cache; }
+ Native *native_cache;
+ Item_nodeset_context_cache(THD *thd, Native *native_arg, String *pxml):
+ Item_nodeset_func(thd, pxml), native_cache(native_arg) { }
+ bool val_native(THD *thd, Native *nodeset)
+ {
+ return nodeset->copy(*native_cache);
+ }
bool fix_length_and_dec() { max_length= MAX_BLOB_WIDTH;; return FALSE; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_context_cache>(thd, this); }
@@ -480,7 +435,7 @@ public:
class Item_func_xpath_position :public Item_long_func
{
String *pxml;
- String tmp_value;
+ NativeNodesetBuffer tmp_native_value;
public:
Item_func_xpath_position(THD *thd, Item *a, String *p):
Item_long_func(thd, a), pxml(p) {}
@@ -488,9 +443,9 @@ public:
bool fix_length_and_dec() { max_length=10; return FALSE; }
longlong val_int()
{
- String *flt= args[0]->val_raw(&tmp_value);
- if (flt->length() == sizeof(MY_XPATH_FLT))
- return ((MY_XPATH_FLT*)flt->ptr())->pos + 1;
+ args[0]->val_native(current_thd, &tmp_native_value);
+ if (tmp_native_value.elements() == 1)
+ return tmp_native_value.element(0).pos + 1;
return 0;
}
Item *get_copy(THD *thd)
@@ -501,7 +456,7 @@ public:
class Item_func_xpath_count :public Item_long_func
{
String *pxml;
- String tmp_value;
+ NativeNodesetBuffer tmp_native_value;
public:
Item_func_xpath_count(THD *thd, Item *a, String *p):
Item_long_func(thd, a), pxml(p) {}
@@ -510,11 +465,11 @@ public:
longlong val_int()
{
uint predicate_supplied_context_size;
- String *res= args[0]->val_raw(&tmp_value);
- if (res->length() == sizeof(MY_XPATH_FLT) &&
- (predicate_supplied_context_size= ((MY_XPATH_FLT*)res->ptr())->size))
+ args[0]->val_native(current_thd, &tmp_native_value);
+ if (tmp_native_value.elements() == 1 &&
+ (predicate_supplied_context_size= tmp_native_value.element(0).size))
return predicate_supplied_context_size;
- return res->length() / sizeof(MY_XPATH_FLT);
+ return tmp_native_value.elements();
}
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_xpath_count>(thd, this); }
@@ -524,7 +479,7 @@ public:
class Item_func_xpath_sum :public Item_real_func
{
String *pxml;
- String tmp_value;
+ NativeNodesetBuffer tmp_native_value;
public:
Item_func_xpath_sum(THD *thd, Item *a, String *p):
Item_real_func(thd, a), pxml(p) {}
@@ -533,9 +488,9 @@ public:
double val_real()
{
double sum= 0;
- String *res= args[0]->val_raw(&tmp_value);
- MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) res->ptr();
- MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
+ args[0]->val_native(current_thd, &tmp_native_value);
+ MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) tmp_native_value.ptr();
+ MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) tmp_native_value.end();
uint numnodes= pxml->length() / sizeof(MY_XML_NODE);
MY_XML_NODE *nodebeg= (MY_XML_NODE*) pxml->ptr();
@@ -552,8 +507,8 @@ public:
{
char *end;
int err;
- double add= my_strntod(collation.collation, (char*) node->beg,
- node->end - node->beg, &end, &err);
+ double add= collation.collation->strntod((char*) node->beg,
+ node->end - node->beg, &end, &err);
if (!err)
sum+= add;
}
@@ -596,7 +551,7 @@ public:
class Item_nodeset_to_const_comparator :public Item_bool_func
{
String *pxml;
- String tmp_nodeset;
+ NativeNodesetBuffer tmp_nodeset;
public:
Item_nodeset_to_const_comparator(THD *thd, Item *nodeset, Item *cmpfunc,
String *p):
@@ -606,7 +561,7 @@ public:
{
return mark_unsupported_function(func_name(), arg, VCOL_IMPOSSIBLE);
}
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(0);
@@ -617,9 +572,9 @@ public:
Item_func *comp= (Item_func*)args[1];
Item_string_xml_non_const *fake=
(Item_string_xml_non_const*)(comp->arguments()[0]);
- String *res= args[0]->val_raw(&tmp_nodeset);
- MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) res->ptr();
- MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
+ args[0]->val_native(current_thd, &tmp_nodeset);
+ MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) tmp_nodeset.ptr();
+ MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) tmp_nodeset.end();
MY_XML_NODE *nodebeg= (MY_XML_NODE*) pxml->ptr();
uint numnodes= pxml->length() / sizeof(MY_XML_NODE);
@@ -648,32 +603,32 @@ public:
};
-String *Item_nodeset_func_rootelement::val_raw(String *nodeset)
+bool Item_nodeset_func_rootelement::val_native(THD *thd, Native *nodeset)
{
nodeset->length(0);
- ((XPathFilter*)nodeset)->append_element(0, 0);
- return nodeset;
+ return MY_XPATH_FLT(0, 0).append_to(nodeset);
}
-String * Item_nodeset_func_union::val_raw(String *nodeset)
+bool Item_nodeset_func_union::val_native(THD *thd, Native *nodeset)
{
uint num_nodes= pxml->length() / sizeof(MY_XML_NODE);
- String set0, *s0= args[0]->val_raw(&set0);
- String set1, *s1= args[1]->val_raw(&set1);
+ NativeNodesetBuffer set0, set1;
+ args[0]->val_native(thd, &set0);
+ args[1]->val_native(thd, &set1);
String both_str;
both_str.alloc(num_nodes);
char *both= (char*) both_str.ptr();
bzero((void*)both, num_nodes);
MY_XPATH_FLT *flt;
- fltbeg= (MY_XPATH_FLT*) s0->ptr();
- fltend= (MY_XPATH_FLT*) (s0->ptr() + s0->length());
+ fltbeg= (MY_XPATH_FLT*) set0.ptr();
+ fltend= (MY_XPATH_FLT*) set0.end();
for (flt= fltbeg; flt < fltend; flt++)
both[flt->num]= 1;
- fltbeg= (MY_XPATH_FLT*) s1->ptr();
- fltend= (MY_XPATH_FLT*) (s1->ptr() + s1->length());
+ fltbeg= (MY_XPATH_FLT*) set1.ptr();
+ fltend= (MY_XPATH_FLT*) set1.end();
for (flt= fltbeg; flt < fltend; flt++)
both[flt->num]= 1;
@@ -681,29 +636,29 @@ String * Item_nodeset_func_union::val_raw(String *nodeset)
for (uint i= 0, pos= 0; i < num_nodes; i++)
{
if (both[i])
- ((XPathFilter*)nodeset)->append_element(i, pos++);
+ MY_XPATH_FLT(i, pos++).append_to(nodeset);
}
- return nodeset;
+ return false;
}
-String *Item_nodeset_func_selfbyname::val_raw(String *nodeset)
+bool Item_nodeset_func_selfbyname::val_native(THD *thd, Native *nodeset)
{
- prepare(nodeset);
+ prepare(thd, nodeset);
for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
{
uint pos= 0;
MY_XML_NODE *self= &nodebeg[flt->num];
if (validname(self))
- ((XPathFilter*)nodeset)->append_element(flt->num,pos++);
+ MY_XPATH_FLT(flt->num, pos++).append_to(nodeset);
}
- return nodeset;
+ return false;
}
-String *Item_nodeset_func_childbyname::val_raw(String *nodeset)
+bool Item_nodeset_func_childbyname::val_native(THD *thd, Native *nodeset)
{
- prepare(nodeset);
+ prepare(thd, nodeset);
for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
{
MY_XML_NODE *self= &nodebeg[flt->num];
@@ -715,40 +670,40 @@ String *Item_nodeset_func_childbyname::val_raw(String *nodeset)
if ((node->parent == flt->num) &&
(node->type == MY_XML_NODE_TAG) &&
validname(node))
- ((XPathFilter*)nodeset)->append_element(j, pos++);
+ MY_XPATH_FLT(j, pos++).append_to(nodeset);
}
}
- return nodeset;
+ return false;
}
-String *Item_nodeset_func_descendantbyname::val_raw(String *nodeset)
+bool Item_nodeset_func_descendantbyname::val_native(THD *thd, Native *nodeset)
{
- prepare(nodeset);
+ prepare(thd, nodeset);
for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
{
uint pos= 0;
MY_XML_NODE *self= &nodebeg[flt->num];
if (need_self && validname(self))
- ((XPathFilter*)nodeset)->append_element(flt->num,pos++);
+ MY_XPATH_FLT(flt->num, pos++).append_to(nodeset);
for (uint j= flt->num + 1 ; j < numnodes ; j++)
{
MY_XML_NODE *node= &nodebeg[j];
if (node->level <= self->level)
break;
if ((node->type == MY_XML_NODE_TAG) && validname(node))
- ((XPathFilter*)nodeset)->append_element(j,pos++);
+ MY_XPATH_FLT(j, pos++).append_to(nodeset);
}
}
- return nodeset;
+ return false;
}
-String *Item_nodeset_func_ancestorbyname::val_raw(String *nodeset)
+bool Item_nodeset_func_ancestorbyname::val_native(THD *thd, Native *nodeset)
{
char *active;
String active_str;
- prepare(nodeset);
+ prepare(thd, nodeset);
active_str.alloc(numnodes);
active= (char*) active_str.ptr();
bzero((void*)active, numnodes);
@@ -780,17 +735,17 @@ String *Item_nodeset_func_ancestorbyname::val_raw(String *nodeset)
for (uint j= 0; j < numnodes ; j++)
{
if (active[j])
- ((XPathFilter*)nodeset)->append_element(j, --pos);
+ MY_XPATH_FLT(j, --pos).append_to(nodeset);
}
- return nodeset;
+ return false;
}
-String *Item_nodeset_func_parentbyname::val_raw(String *nodeset)
+bool Item_nodeset_func_parentbyname::val_native(THD *thd, Native *nodeset)
{
char *active;
String active_str;
- prepare(nodeset);
+ prepare(thd, nodeset);
active_str.alloc(numnodes);
active= (char*) active_str.ptr();
bzero((void*)active, numnodes);
@@ -803,15 +758,15 @@ String *Item_nodeset_func_parentbyname::val_raw(String *nodeset)
for (uint j= 0, pos= 0; j < numnodes ; j++)
{
if (active[j])
- ((XPathFilter*)nodeset)->append_element(j, pos++);
+ MY_XPATH_FLT(j, pos++).append_to(nodeset);
}
- return nodeset;
+ return false;
}
-String *Item_nodeset_func_attributebyname::val_raw(String *nodeset)
+bool Item_nodeset_func_attributebyname::val_native(THD *thd, Native *nodeset)
{
- prepare(nodeset);
+ prepare(thd, nodeset);
for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
{
MY_XML_NODE *self= &nodebeg[flt->num];
@@ -823,52 +778,50 @@ String *Item_nodeset_func_attributebyname::val_raw(String *nodeset)
if ((node->parent == flt->num) &&
(node->type == MY_XML_NODE_ATTR) &&
validname(node))
- ((XPathFilter*)nodeset)->append_element(j, pos++);
+ MY_XPATH_FLT(j, pos++).append_to(nodeset);
}
}
- return nodeset;
+ return false;
}
-String *Item_nodeset_func_predicate::val_raw(String *str)
+bool Item_nodeset_func_predicate::val_native(THD *thd, Native *str)
{
Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0];
Item_func *comp_func= (Item_func*)args[1];
uint pos= 0, size;
- prepare(str);
+ prepare(thd, str);
size= (uint)(fltend - fltbeg);
for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
{
nodeset_func->context_cache.length(0);
- ((XPathFilter*)(&nodeset_func->context_cache))->append_element(flt->num,
- flt->pos,
- size);
+ MY_XPATH_FLT(flt->num, flt->pos, size).
+ append_to(&nodeset_func->context_cache);
if (comp_func->val_int())
- ((XPathFilter*)str)->append_element(flt->num, pos++);
+ MY_XPATH_FLT(flt->num, pos++).append_to(str);
}
- return str;
+ return false;
}
-String *Item_nodeset_func_elementbyindex::val_raw(String *nodeset)
+bool Item_nodeset_func_elementbyindex::val_native(THD *thd, Native *nodeset)
{
Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0];
- prepare(nodeset);
+ prepare(thd, nodeset);
MY_XPATH_FLT *flt;
uint pos, size= (uint)(fltend - fltbeg);
for (pos= 0, flt= fltbeg; flt < fltend; flt++)
{
nodeset_func->context_cache.length(0);
- ((XPathFilter*)(&nodeset_func->context_cache))->append_element(flt->num,
- flt->pos,
- size);
+ MY_XPATH_FLT(flt->num, flt->pos, size).
+ append_to(&nodeset_func->context_cache);
int index= (int) (args[1]->val_int()) - 1;
if (index >= 0 &&
(flt->pos == (uint) index ||
(args[1]->type_handler()->is_bool_type())))
- ((XPathFilter*)nodeset)->append_element(flt->num, pos++);
+ MY_XPATH_FLT(flt->num, pos++).append_to(nodeset);
}
- return nodeset;
+ return false;
}
@@ -1489,16 +1442,16 @@ my_xpath_lex_scan(MY_XPATH *xpath,
}
// Check ident, or a function call, or a keyword
- if ((length= xpath->cs->cset->ctype(xpath->cs, &ctype,
- (const uchar*) beg,
- (const uchar*) end)) > 0 &&
+ if ((length= xpath->cs->ctype(&ctype,
+ (const uchar*) beg,
+ (const uchar*) end)) > 0 &&
((ctype & (_MY_L | _MY_U)) || *beg == '_'))
{
// scan untill the end of the idenfitier
for (beg+= length;
- (length= xpath->cs->cset->ctype(xpath->cs, &ctype,
- (const uchar*) beg,
- (const uchar*) end)) > 0 &&
+ (length= xpath->cs->ctype(&ctype,
+ (const uchar*) beg,
+ (const uchar*) end)) > 0 &&
((ctype & (_MY_L | _MY_U | _MY_NMR)) ||
*beg == '_' || *beg == '-' || *beg == '.') ;
beg+= length) /* no op */;
@@ -1793,7 +1746,7 @@ my_xpath_parse_AxisSpecifier_NodeTest_opt_Predicate_list(MY_XPATH *xpath)
while (my_xpath_parse_term(xpath, MY_XPATH_LEX_LB))
{
Item *prev_context= xpath->context;
- String *context_cache;
+ Native *context_cache;
context_cache= &((Item_nodeset_func*)xpath->context)->context_cache;
xpath->context= new (xpath->thd->mem_root)
Item_nodeset_context_cache(xpath->thd, context_cache, xpath->pxml);
@@ -3070,19 +3023,20 @@ bool Item_func_xml_update::collect_result(String *str,
String *Item_func_xml_update::val_str(String *str)
{
- String *nodeset, *rep;
+ String *rep;
null_value= 0;
if (!nodeset_func || get_xml(&xml) ||
!(rep= args[2]->val_str(&tmp_value3)) ||
- !(nodeset= nodeset_func->val_raw(&tmp_value2)))
+ nodeset_func->type_handler() != &type_handler_xpath_nodeset ||
+ nodeset_func->val_native(current_thd, &tmp_native_value2))
{
null_value= 1;
return 0;
}
- MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) nodeset->ptr();
- MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (nodeset->ptr() + nodeset->length());
+ MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) tmp_native_value2.ptr();
+ MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) tmp_native_value2.end();
/* Allow replacing of one tag only */
if (fltend - fltbeg != 1)
diff --git a/sql/item_xmlfunc.h b/sql/item_xmlfunc.h
index ce34697d9bd..806739d1139 100644
--- a/sql/item_xmlfunc.h
+++ b/sql/item_xmlfunc.h
@@ -2,6 +2,7 @@
#define ITEM_XMLFUNC_INCLUDED
/* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2009, 2019, 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
@@ -23,6 +24,42 @@
typedef struct my_xml_node_st MY_XML_NODE;
+/* Structure to store nodeset elements */
+class MY_XPATH_FLT
+{
+public:
+ uint num; // Absolute position in MY_XML_NODE array
+ uint pos; // Relative position in context
+ uint size; // Context size
+public:
+ MY_XPATH_FLT(uint32 num_arg, uint32 pos_arg)
+ :num(num_arg), pos(pos_arg), size(0)
+ { }
+ MY_XPATH_FLT(uint32 num_arg, uint32 pos_arg, uint32 size_arg)
+ :num(num_arg), pos(pos_arg), size(size_arg)
+ { }
+ bool append_to(Native *to) const
+ {
+ return to->append((const char*) this, (uint32) sizeof(*this));
+ }
+};
+
+
+class NativeNodesetBuffer: public NativeBuffer<16*sizeof(MY_XPATH_FLT)>
+{
+public:
+ const MY_XPATH_FLT &element(uint i) const
+ {
+ const MY_XPATH_FLT *p= (MY_XPATH_FLT*) (ptr() + i * sizeof(MY_XPATH_FLT));
+ return *p;
+ }
+ uint32 elements() const
+ {
+ return length() / sizeof(MY_XPATH_FLT);
+ }
+};
+
+
class Item_xml_str_func: public Item_str_func
{
protected:
@@ -103,7 +140,8 @@ public:
class Item_func_xml_update: public Item_xml_str_func
{
- String tmp_value2, tmp_value3;
+ NativeNodesetBuffer tmp_native_value2;
+ String tmp_value3;
bool collect_result(String *str,
const MY_XML_NODE *cut,
const String *replace);
diff --git a/sql/key.cc b/sql/key.cc
index bf50094a9e4..9dbb7a15726 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
- Copyright (c) 2018, MariaDB
+ Copyright (c) 2018, 2020, 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
@@ -159,7 +159,7 @@ void key_copy(uchar *to_key, const uchar *from_record, KEY *key_info,
CHARSET_INFO *cs= field->charset();
uint bytes= field->get_key_image(to_key, length, Field::itRAW);
if (bytes < length)
- cs->cset->fill(cs, (char*) to_key + bytes, length - bytes, ' ');
+ cs->fill((char*) to_key + bytes, length - bytes, ' ');
}
}
}
@@ -324,12 +324,10 @@ bool key_cmp_if_same(TABLE *table,const uchar *key,uint idx,uint key_length)
const uchar *pos= table->record[0] + key_part->offset;
if (length > char_length)
{
- char_length= my_charpos(cs, pos, pos + length, char_length);
+ char_length= cs->charpos(pos, pos + length, char_length);
set_if_smaller(char_length, length);
}
- if (cs->coll->strnncollsp(cs,
- (const uchar*) key, length,
- (const uchar*) pos, char_length))
+ if (cs->strnncollsp(key, length, pos, char_length))
return 1;
continue;
}
@@ -387,9 +385,9 @@ void field_unpack(String *to, Field *field, const uchar *rec, uint max_length,
Align, returning not more than "char_length" characters.
*/
size_t charpos, char_length= max_length / cs->mbmaxlen;
- if ((charpos= my_charpos(cs, tmp.ptr(),
- tmp.ptr() + tmp.length(),
- char_length)) < tmp.length())
+ if ((charpos= cs->charpos(tmp.ptr(),
+ tmp.ptr() + tmp.length(),
+ char_length)) < tmp.length())
tmp.length(charpos);
}
if (max_length < field->pack_length())
@@ -757,12 +755,12 @@ ulong key_hashnr(KEY *key_info, uint used_key_parts, const uchar *key)
{
if (cs->mbmaxlen > 1)
{
- size_t char_length= my_charpos(cs, pos + pack_length,
- pos + pack_length + length,
- length / cs->mbmaxlen);
+ size_t char_length= cs->charpos(pos + pack_length,
+ pos + pack_length + length,
+ length / cs->mbmaxlen);
set_if_smaller(length, char_length);
}
- cs->coll->hash_sort(cs, pos+pack_length, length, &nr, &nr2);
+ cs->hash_sort(pos+pack_length, length, &nr, &nr2);
key+= pack_length;
}
else
@@ -871,19 +869,18 @@ bool key_buf_cmp(KEY *key_info, uint used_key_parts,
size_t byte_len1= length1, byte_len2= length2;
if (cs->mbmaxlen > 1)
{
- size_t char_length1= my_charpos(cs, pos1 + pack_length,
- pos1 + pack_length + length1,
- length1 / cs->mbmaxlen);
- size_t char_length2= my_charpos(cs, pos2 + pack_length,
- pos2 + pack_length + length2,
- length2 / cs->mbmaxlen);
+ size_t char_length1= cs->charpos(pos1 + pack_length,
+ pos1 + pack_length + length1,
+ length1 / cs->mbmaxlen);
+ size_t char_length2= cs->charpos(pos2 + pack_length,
+ pos2 + pack_length + length2,
+ length2 / cs->mbmaxlen);
set_if_smaller(length1, char_length1);
set_if_smaller(length2, char_length2);
}
if (length1 != length2 ||
- cs->coll->strnncollsp(cs,
- pos1 + pack_length, byte_len1,
- pos2 + pack_length, byte_len2))
+ cs->strnncollsp(pos1 + pack_length, byte_len1,
+ pos2 + pack_length, byte_len2))
return TRUE;
key1+= pack_length; key2+= pack_length;
}
diff --git a/sql/keycaches.cc b/sql/keycaches.cc
index 60049cdd67d..10bec7c1de8 100644
--- a/sql/keycaches.cc
+++ b/sql/keycaches.cc
@@ -23,6 +23,9 @@
NAMED_ILIST key_caches;
NAMED_ILIST rpl_filters;
+extern "C" PSI_memory_key key_memory_KEY_CACHE;
+extern PSI_memory_key key_memory_NAMED_ILINK_name;
+
/**
ilink (intrusive list element) with a name
*/
@@ -37,7 +40,8 @@ public:
size_t name_length_arg, uchar* data_arg)
:name_length(name_length_arg), data(data_arg)
{
- name= my_strndup(name_arg, name_length, MYF(MY_WME));
+ name= my_strndup(key_memory_NAMED_ILINK_name, name_arg, name_length,
+ MYF(MY_WME));
links->push_back(this);
}
inline bool cmp(const char *name_cmp, size_t length)
@@ -118,8 +122,8 @@ KEY_CACHE *create_key_cache(const char *name, size_t length)
DBUG_ENTER("create_key_cache");
DBUG_PRINT("enter",("name: %.*s", (int)length, name));
- if ((key_cache= (KEY_CACHE*) my_malloc(sizeof(KEY_CACHE),
- MYF(MY_ZEROFILL | MY_WME))))
+ if ((key_cache= (KEY_CACHE*) my_malloc(key_memory_KEY_CACHE,
+ sizeof(KEY_CACHE), MYF(MY_ZEROFILL | MY_WME))))
{
if (!new NAMED_ILINK(&key_caches, name, length, (uchar*) key_cache))
{
diff --git a/sql/lex.h b/sql/lex.h
index 92ce01a1094..cc9e126c702 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -239,6 +239,7 @@ static SYMBOL symbols[] = {
{ "FALSE", SYM(FALSE_SYM)},
{ "FAST", SYM(FAST_SYM)},
{ "FAULTS", SYM(FAULTS_SYM)},
+ { "FEDERATED", SYM(FEDERATED_SYM)},
{ "FETCH", SYM(FETCH_SYM)},
{ "FIELDS", SYM(COLUMNS)},
{ "FILE", SYM(FILE_SYM)},
@@ -261,8 +262,6 @@ static SYMBOL symbols[] = {
{ "FUNCTION", SYM(FUNCTION_SYM)},
{ "GENERAL", SYM(GENERAL)},
{ "GENERATED", SYM(GENERATED_SYM)},
- { "GEOMETRY", SYM(GEOMETRY_SYM)},
- { "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION)},
{ "GET_FORMAT", SYM(GET_FORMAT)},
{ "GET", SYM(GET_SYM)},
{ "GLOBAL", SYM(GLOBAL_SYM)},
@@ -343,7 +342,6 @@ static SYMBOL symbols[] = {
{ "LIMIT", SYM(LIMIT)},
{ "LINEAR", SYM(LINEAR_SYM)},
{ "LINES", SYM(LINES)},
- { "LINESTRING", SYM(LINESTRING)},
{ "LIST", SYM(LIST_SYM)},
{ "LOAD", SYM(LOAD)},
{ "LOCAL", SYM(LOCAL_SYM)},
@@ -408,10 +406,8 @@ static SYMBOL symbols[] = {
{ "MODE", SYM(MODE_SYM)},
{ "MODIFIES", SYM(MODIFIES_SYM)},
{ "MODIFY", SYM(MODIFY_SYM)},
+ { "MONITOR", SYM(MONITOR_SYM)},
{ "MONTH", SYM(MONTH_SYM)},
- { "MULTILINESTRING", SYM(MULTILINESTRING)},
- { "MULTIPOINT", SYM(MULTIPOINT)},
- { "MULTIPOLYGON", SYM(MULTIPOLYGON)},
{ "MUTEX", SYM(MUTEX_SYM)},
{ "MYSQL", SYM(MYSQL_SYM)},
{ "MYSQL_ERRNO", SYM(MYSQL_ERRNO_SYM)},
@@ -476,8 +472,6 @@ static SYMBOL symbols[] = {
{ "PHASE", SYM(PHASE_SYM)},
{ "PLUGIN", SYM(PLUGIN_SYM)},
{ "PLUGINS", SYM(PLUGINS_SYM)},
- { "POINT", SYM(POINT_SYM)},
- { "POLYGON", SYM(POLYGON)},
{ "PORT", SYM(PORT_SYM)},
{ "PORTION", SYM(PORTION_SYM)},
{ "PRECEDES", SYM(PRECEDES_SYM)},
@@ -528,6 +522,10 @@ static SYMBOL symbols[] = {
{ "REPAIR", SYM(REPAIR)},
{ "REPEATABLE", SYM(REPEATABLE_SYM)},
{ "REPLACE", SYM(REPLACE)},
+ { "REPLAY", SYM(REPLAY_SYM)},
+ { "REPLICA", SYM(SLAVE)},
+ { "REPLICAS", SYM(SLAVES)},
+ { "REPLICA_POS", SYM(SLAVE_POS_SYM)},
{ "REPLICATION", SYM(REPLICATION)},
{ "REPEAT", SYM(REPEAT_SYM)},
{ "REQUIRE", SYM(REQUIRE_SYM)},
@@ -749,6 +747,8 @@ static SYMBOL sql_functions[] = {
{ "EXTRACT", SYM(EXTRACT_SYM)},
{ "FIRST_VALUE", SYM(FIRST_VALUE_SYM)},
{ "GROUP_CONCAT", SYM(GROUP_CONCAT_SYM)},
+ { "JSON_ARRAYAGG", SYM(JSON_ARRAYAGG_SYM)},
+ { "JSON_OBJECTAGG", SYM(JSON_OBJECTAGG_SYM)},
{ "LAG", SYM(LAG_SYM)},
{ "LEAD", SYM(LEAD_SYM)},
{ "MAX", SYM(MAX_SYM)},
diff --git a/sql/lex_string.h b/sql/lex_string.h
index 88a7154b064..008e5f75812 100644
--- a/sql/lex_string.h
+++ b/sql/lex_string.h
@@ -18,8 +18,50 @@
#ifndef LEX_STRING_INCLUDED
#define LEX_STRING_INCLUDED
+
typedef struct st_mysql_const_lex_string LEX_CSTRING;
+
+class Lex_cstring : public LEX_CSTRING
+{
+ public:
+ Lex_cstring()
+ {
+ str= NULL;
+ length= 0;
+ }
+ Lex_cstring(const LEX_CSTRING &str)
+ {
+ LEX_CSTRING::operator=(str);
+ }
+ Lex_cstring(const char *_str, size_t _len)
+ {
+ str= _str;
+ length= _len;
+ }
+ Lex_cstring(const char *start, const char *end)
+ {
+ DBUG_ASSERT(start <= end);
+ str= start;
+ length= end - start;
+ }
+ void set(const char *_str, size_t _len)
+ {
+ str= _str;
+ length= _len;
+ }
+};
+
+
+class Lex_cstring_strlen: public Lex_cstring
+{
+public:
+ Lex_cstring_strlen(const char *from)
+ :Lex_cstring(from, from ? strlen(from) : 0)
+ { }
+};
+
+
/* Functions to compare if two lex strings are equal */
static inline bool lex_string_cmp(CHARSET_INFO *charset, const LEX_CSTRING *a,
diff --git a/sql/lock.cc b/sql/lock.cc
index 94e0d2733c7..7f69946c35e 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -76,7 +76,6 @@
#include "lock.h"
#include "sql_base.h" // close_tables_for_reopen
#include "sql_parse.h" // is_log_table_write_query
-#include "sql_acl.h" // SUPER_ACL
#include "sql_handler.h"
#include <hash.h>
#include "wsrep_mysqld.h"
@@ -109,12 +108,13 @@ static int
lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
{
uint system_count, i;
- bool is_superuser, log_table_write_query;
+ bool ignore_read_only, log_table_write_query;
DBUG_ENTER("lock_tables_check");
system_count= 0;
- is_superuser= thd->security_ctx->master_access & SUPER_ACL;
+ ignore_read_only=
+ (thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY) != NO_ACL;
log_table_write_query= (is_log_table_write_query(thd->lex->sql_command)
|| ((flags & MYSQL_LOCK_LOG_TABLE) != 0));
@@ -179,7 +179,7 @@ lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
if (!(flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY) && !t->s->tmp_table)
{
if (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE &&
- !is_superuser && opt_readonly && !thd->slave_thread)
+ !ignore_read_only && opt_readonly && !thd->slave_thread)
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
DBUG_RETURN(1);
@@ -645,7 +645,7 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
a->lock_count, b->lock_count));
if (!(sql_lock= (MYSQL_LOCK*)
- my_malloc(sizeof(*sql_lock)+
+ my_malloc(key_memory_MYSQL_LOCK, sizeof(*sql_lock) +
sizeof(THR_LOCK_DATA*)*((a->lock_count+b->lock_count)*2) +
sizeof(TABLE*)*(a->table_count+b->table_count),MYF(MY_WME))))
DBUG_RETURN(0); // Fatal error
@@ -764,7 +764,8 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
sizeof(table_ptr) * table_count;
if (!(sql_lock= (MYSQL_LOCK*) (flags & GET_LOCK_ON_THD ?
thd->alloc(amount) :
- my_malloc(amount, MYF(0)))))
+ my_malloc(key_memory_MYSQL_LOCK, amount,
+ MYF(0)))))
DBUG_RETURN(0);
locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1);
to= table_buf= sql_lock->table= (TABLE**) (locks + lock_count * 2);
@@ -858,8 +859,10 @@ bool lock_schema_name(THD *thd, const char *db)
if (thd->has_read_only_protection())
return TRUE;
- global_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_DDL, MDL_STATEMENT);
- mdl_request.init(MDL_key::SCHEMA, db, "", MDL_EXCLUSIVE, MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&global_request, MDL_key::BACKUP, "", "", MDL_BACKUP_DDL,
+ MDL_STATEMENT);
+ MDL_REQUEST_INIT(&mdl_request, MDL_key::SCHEMA, db, "", MDL_EXCLUSIVE,
+ MDL_TRANSACTION);
mdl_requests.push_front(&mdl_request);
mdl_requests.push_front(&global_request);
@@ -916,10 +919,12 @@ bool lock_object_name(THD *thd, MDL_key::enum_mdl_namespace mdl_type,
if (thd->has_read_only_protection())
return TRUE;
- global_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_DDL, MDL_STATEMENT);
- schema_request.init(MDL_key::SCHEMA, db, "", MDL_INTENTION_EXCLUSIVE,
- MDL_TRANSACTION);
- mdl_request.init(mdl_type, db, name, MDL_EXCLUSIVE, MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&global_request, MDL_key::BACKUP, "", "", MDL_BACKUP_DDL,
+ MDL_STATEMENT);
+ MDL_REQUEST_INIT(&schema_request, MDL_key::SCHEMA, db, "",
+ MDL_INTENTION_EXCLUSIVE, MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&mdl_request, mdl_type, db, name, MDL_EXCLUSIVE,
+ MDL_TRANSACTION);
mdl_requests.push_front(&mdl_request);
mdl_requests.push_front(&schema_request);
@@ -1040,7 +1045,7 @@ bool Global_read_lock::lock_global_read_lock(THD *thd)
MDL_BACKUP_FTWRL1));
DBUG_ASSERT(! thd->mdl_context.is_lock_owner(MDL_key::BACKUP, "", "",
MDL_BACKUP_FTWRL2));
- mdl_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_FTWRL1,
+ MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_FTWRL1,
MDL_EXPLICIT);
do
diff --git a/sql/log.cc b/sql/log.cc
index 1da73ab25df..647e5fbd60d 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -34,7 +34,6 @@
#include "sql_parse.h" // command_name
#include "sql_time.h" // calc_time_from_sec, my_time_compare
#include "tztime.h" // my_tz_OFFSET0, struct Time_zone
-#include "sql_acl.h" // SUPER_ACL
#include "log_event.h" // Query_log_event
#include "rpl_filter.h"
#include "rpl_rli.h"
@@ -91,7 +90,13 @@ static bool binlog_savepoint_rollback_can_release_mdl(handlerton *hton,
static int binlog_commit(handlerton *hton, THD *thd, bool all);
static int binlog_rollback(handlerton *hton, THD *thd, bool all);
static int binlog_prepare(handlerton *hton, THD *thd, bool all);
+static int binlog_xa_recover_dummy(handlerton *hton, XID *xid_list, uint len);
+static int binlog_commit_by_xid(handlerton *hton, XID *xid);
+static int binlog_rollback_by_xid(handlerton *hton, XID *xid);
static int binlog_start_consistent_snapshot(handlerton *hton, THD *thd);
+static int binlog_flush_cache(THD *thd, binlog_cache_mngr *cache_mngr,
+ Log_event *end_ev, bool all, bool using_stmt,
+ bool using_trx);
static const LEX_CSTRING write_error_msg=
{ STRING_WITH_LEN("error writing to the binary log") };
@@ -253,7 +258,7 @@ void make_default_log_name(char **out, const char* log_ext, bool once)
else
{
my_free(*out);
- *out= my_strdup(buff, MYF(MY_WME));
+ *out= my_strdup(PSI_INSTRUMENT_ME, buff, MYF(MY_WME));
}
}
@@ -769,7 +774,7 @@ bool Log_to_csv_event_handler::
DBUG_ASSERT(table->field[0]->type() == MYSQL_TYPE_TIMESTAMP);
- ((Field_timestamp*) table->field[0])->store_TIME(
+ table->field[0]->store_timestamp(
hrtime_to_my_time(event_time), hrtime_sec_part(event_time));
/* do a write */
@@ -910,7 +915,7 @@ bool Log_to_csv_event_handler::
/* store the time and user values */
DBUG_ASSERT(table->field[0]->type() == MYSQL_TYPE_TIMESTAMP);
- ((Field_timestamp*) table->field[0])->store_TIME(
+ table->field[0]->store_timestamp(
hrtime_to_my_time(current_time), hrtime_sec_part(current_time));
if (table->field[1]->store(user_host, user_host_len, client_cs))
goto err;
@@ -1681,9 +1686,6 @@ binlog_trans_log_truncate(THD *thd, my_off_t pos)
int binlog_init(void *p)
{
binlog_hton= (handlerton *)p;
- binlog_hton->state= (WSREP_ON || opt_bin_log) ? SHOW_OPTION_YES
- : SHOW_OPTION_NO;
- binlog_hton->db_type=DB_TYPE_BINLOG;
binlog_hton->savepoint_offset= sizeof(my_off_t);
binlog_hton->close_connection= binlog_close_connection;
binlog_hton->savepoint_set= binlog_savepoint_set;
@@ -1692,8 +1694,15 @@ int binlog_init(void *p)
binlog_savepoint_rollback_can_release_mdl;
binlog_hton->commit= binlog_commit;
binlog_hton->rollback= binlog_rollback;
- binlog_hton->prepare= binlog_prepare;
- binlog_hton->start_consistent_snapshot= binlog_start_consistent_snapshot;
+ if (WSREP_ON || opt_bin_log)
+ {
+ binlog_hton->prepare= binlog_prepare;
+ binlog_hton->start_consistent_snapshot= binlog_start_consistent_snapshot;
+ binlog_hton->commit_by_xid= binlog_commit_by_xid;
+ binlog_hton->rollback_by_xid= binlog_rollback_by_xid;
+ // recover needs to be set to make xa{commit,rollback}_handlerton effective
+ binlog_hton->recover= binlog_xa_recover_dummy;
+ }
binlog_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
return 0;
}
@@ -1723,8 +1732,8 @@ static int binlog_close_connection(handlerton *hton, THD *thd)
if (len > 0) wsrep_dump_rbr_buf(thd, buf, len);
}
#endif /* WITH_WSREP */
- DBUG_ASSERT(cache_mngr->trx_cache.empty() && cache_mngr->stmt_cache.empty());
- thd_set_ha_data(thd, binlog_hton, NULL);
+ DBUG_ASSERT(cache_mngr->trx_cache.empty());
+ DBUG_ASSERT(cache_mngr->stmt_cache.empty());
cache_mngr->~binlog_cache_mngr();
my_free(cache_mngr);
DBUG_RETURN(0);
@@ -1766,7 +1775,8 @@ binlog_flush_cache(THD *thd, binlog_cache_mngr *cache_mngr,
DBUG_PRINT("enter", ("end_ev: %p", end_ev));
if ((using_stmt && !cache_mngr->stmt_cache.empty()) ||
- (using_trx && !cache_mngr->trx_cache.empty()))
+ (using_trx && !cache_mngr->trx_cache.empty()) ||
+ thd->transaction.xid_state.is_explicit_XA())
{
if (using_stmt && thd->binlog_flush_pending_rows_event(TRUE, FALSE))
DBUG_RETURN(1);
@@ -1838,6 +1848,17 @@ binlog_commit_flush_stmt_cache(THD *thd, bool all,
DBUG_RETURN(binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, FALSE));
}
+
+inline size_t serialize_with_xid(XID *xid, char *buf,
+ const char *query, size_t q_len)
+{
+ memcpy(buf, query, q_len);
+
+ return
+ q_len + strlen(static_cast<event_xid_t*>(xid)->serialize(buf + q_len));
+}
+
+
/**
This function flushes the trx-cache upon commit.
@@ -1851,11 +1872,28 @@ static inline int
binlog_commit_flush_trx_cache(THD *thd, bool all, binlog_cache_mngr *cache_mngr)
{
DBUG_ENTER("binlog_commit_flush_trx_cache");
- Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"),
- TRUE, TRUE, TRUE, 0);
+
+ const char query[]= "XA COMMIT ";
+ const size_t q_len= sizeof(query) - 1; // do not count trailing 0
+ char buf[q_len + ser_buf_size]= "COMMIT";
+ size_t buflen= sizeof("COMMIT") - 1;
+
+ if (thd->lex->sql_command == SQLCOM_XA_COMMIT &&
+ thd->lex->xa_opt != XA_ONE_PHASE)
+ {
+ DBUG_ASSERT(thd->transaction.xid_state.is_explicit_XA());
+ DBUG_ASSERT(thd->transaction.xid_state.get_state_code() ==
+ XA_PREPARED);
+
+ buflen= serialize_with_xid(thd->transaction.xid_state.get_xid(),
+ buf, query, q_len);
+ }
+ Query_log_event end_evt(thd, buf, buflen, TRUE, TRUE, TRUE, 0);
+
DBUG_RETURN(binlog_flush_cache(thd, cache_mngr, &end_evt, all, FALSE, TRUE));
}
+
/**
This function flushes the trx-cache upon rollback.
@@ -1869,8 +1907,20 @@ static inline int
binlog_rollback_flush_trx_cache(THD *thd, bool all,
binlog_cache_mngr *cache_mngr)
{
- Query_log_event end_evt(thd, STRING_WITH_LEN("ROLLBACK"),
- TRUE, TRUE, TRUE, 0);
+ const char query[]= "XA ROLLBACK ";
+ const size_t q_len= sizeof(query) - 1; // do not count trailing 0
+ char buf[q_len + ser_buf_size]= "ROLLBACK";
+ size_t buflen= sizeof("ROLLBACK") - 1;
+
+ if (thd->transaction.xid_state.is_explicit_XA())
+ {
+ /* for not prepared use plain ROLLBACK */
+ if (thd->transaction.xid_state.get_state_code() == XA_PREPARED)
+ buflen= serialize_with_xid(thd->transaction.xid_state.get_xid(),
+ buf, query, q_len);
+ }
+ Query_log_event end_evt(thd, buf, buflen, TRUE, TRUE, TRUE, 0);
+
return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, FALSE, TRUE));
}
@@ -1888,23 +1938,10 @@ static inline int
binlog_commit_flush_xid_caches(THD *thd, binlog_cache_mngr *cache_mngr,
bool all, my_xid xid)
{
- if (xid)
- {
- Xid_log_event end_evt(thd, xid, TRUE);
- return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, TRUE));
- }
- else
- {
- /*
- Empty xid occurs in XA COMMIT ... ONE PHASE.
- In this case, we do not have a MySQL xid for the transaction, and the
- external XA transaction coordinator will have to handle recovery if
- needed. So we end the transaction with a plain COMMIT query event.
- */
- Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"),
- TRUE, TRUE, TRUE, 0);
- return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, TRUE));
- }
+ DBUG_ASSERT(xid); // replaced former treatment of ONE-PHASE XA
+
+ Xid_log_event end_evt(thd, xid, TRUE);
+ return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, TRUE));
}
/**
@@ -1960,17 +1997,62 @@ binlog_truncate_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr, bool all)
DBUG_RETURN(error);
}
+
+inline bool is_preparing_xa(THD *thd)
+{
+ return
+ thd->transaction.xid_state.is_explicit_XA() &&
+ thd->lex->sql_command == SQLCOM_XA_PREPARE;
+}
+
+
static int binlog_prepare(handlerton *hton, THD *thd, bool all)
{
- /*
- do nothing.
- just pretend we can do 2pc, so that MySQL won't
- switch to 1pc.
- real work will be done in MYSQL_BIN_LOG::log_and_order()
- */
+ /* Do nothing unless the transaction is a user XA. */
+ return is_preparing_xa(thd) ? binlog_commit(NULL, thd, all) : 0;
+}
+
+
+static int binlog_xa_recover_dummy(handlerton *hton __attribute__((unused)),
+ XID *xid_list __attribute__((unused)),
+ uint len __attribute__((unused)))
+{
+ /* Does nothing. */
return 0;
}
+
+static int binlog_commit_by_xid(handlerton *hton, XID *xid)
+{
+ THD *thd= current_thd;
+
+ (void) thd->binlog_setup_trx_data();
+
+ DBUG_ASSERT(thd->lex->sql_command == SQLCOM_XA_COMMIT);
+
+ return binlog_commit(hton, thd, TRUE);
+}
+
+
+static int binlog_rollback_by_xid(handlerton *hton, XID *xid)
+{
+ THD *thd= current_thd;
+
+ (void) thd->binlog_setup_trx_data();
+
+ DBUG_ASSERT(thd->lex->sql_command == SQLCOM_XA_ROLLBACK ||
+ (thd->transaction.xid_state.get_state_code() == XA_ROLLBACK_ONLY));
+ return binlog_rollback(hton, thd, TRUE);
+}
+
+
+inline bool is_prepared_xa(THD *thd)
+{
+ return thd->transaction.xid_state.is_explicit_XA() &&
+ thd->transaction.xid_state.get_state_code() == XA_PREPARED;
+}
+
+
/*
We flush the cache wrapped in a beging/rollback if:
. aborting a single or multi-statement transaction and;
@@ -1993,7 +2075,50 @@ static bool trans_cannot_safely_rollback(THD *thd, bool all)
thd->wsrep_binlog_format() == BINLOG_FORMAT_MIXED) ||
(trans_has_updated_non_trans_table(thd) &&
ending_single_stmt_trans(thd,all) &&
- thd->wsrep_binlog_format() == BINLOG_FORMAT_MIXED));
+ thd->wsrep_binlog_format() == BINLOG_FORMAT_MIXED) ||
+ is_prepared_xa(thd));
+}
+
+
+/**
+ Specific log flusher invoked through log_xa_prepare().
+*/
+static int binlog_commit_flush_xa_prepare(THD *thd, bool all,
+ binlog_cache_mngr *cache_mngr)
+{
+ XID *xid= thd->transaction.xid_state.get_xid();
+ {
+ // todo assert wsrep_simulate || is_open()
+
+ /*
+ Log the XA END event first.
+ We don't do that in trans_xa_end() as XA COMMIT ONE PHASE
+ is logged as simple BEGIN/COMMIT so the XA END should
+ not get to the log.
+ */
+ const char query[]= "XA END ";
+ const size_t q_len= sizeof(query) - 1; // do not count trailing 0
+ char buf[q_len + ser_buf_size];
+ size_t buflen;
+ binlog_cache_data *cache_data;
+ IO_CACHE *file;
+
+ memcpy(buf, query, q_len);
+ buflen= q_len +
+ strlen(static_cast<event_xid_t*>(xid)->serialize(buf + q_len));
+ cache_data= cache_mngr->get_binlog_cache_data(true);
+ file= &cache_data->cache_log;
+ thd->lex->sql_command= SQLCOM_XA_END;
+ Query_log_event xa_end(thd, buf, buflen, true, false, true, 0);
+ if (mysql_bin_log.write_event(&xa_end, cache_data, file))
+ return 1;
+ thd->lex->sql_command= SQLCOM_XA_PREPARE;
+ }
+
+ cache_mngr->using_xa= FALSE;
+ XA_prepare_log_event end_evt(thd, xid, FALSE);
+
+ return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, TRUE));
}
@@ -2020,7 +2145,11 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
if (!cache_mngr)
{
- DBUG_ASSERT(WSREP(thd));
+ DBUG_ASSERT(WSREP(thd) ||
+ (thd->lex->sql_command != SQLCOM_XA_PREPARE &&
+ !(thd->lex->sql_command == SQLCOM_XA_COMMIT &&
+ thd->lex->xa_opt == XA_ONE_PHASE)));
+
DBUG_RETURN(0);
}
@@ -2039,7 +2168,8 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
error= binlog_commit_flush_stmt_cache(thd, all, cache_mngr);
}
- if (cache_mngr->trx_cache.empty())
+ if (cache_mngr->trx_cache.empty() &&
+ thd->transaction.xid_state.get_state_code() != XA_PREPARED)
{
/*
we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid()
@@ -2056,8 +2186,11 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
Otherwise, we accumulate the changes.
*/
if (likely(!error) && ending_trans(thd, all))
- error= binlog_commit_flush_trx_cache(thd, all, cache_mngr);
-
+ {
+ error= is_preparing_xa(thd) ?
+ binlog_commit_flush_xa_prepare(thd, all, cache_mngr) :
+ binlog_commit_flush_trx_cache (thd, all, cache_mngr);
+ }
/*
This is part of the stmt rollback.
*/
@@ -2081,6 +2214,7 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
static int binlog_rollback(handlerton *hton, THD *thd, bool all)
{
DBUG_ENTER("binlog_rollback");
+
int error= 0;
binlog_cache_mngr *const cache_mngr=
(binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
@@ -2088,6 +2222,8 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
if (!cache_mngr)
{
DBUG_ASSERT(WSREP(thd));
+ DBUG_ASSERT(thd->lex->sql_command != SQLCOM_XA_ROLLBACK);
+
DBUG_RETURN(0);
}
@@ -2102,15 +2238,16 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
*/
if (cache_mngr->stmt_cache.has_incident())
{
- error= mysql_bin_log.write_incident(thd);
+ error |= static_cast<int>(mysql_bin_log.write_incident(thd));
cache_mngr->reset(true, false);
}
else if (!cache_mngr->stmt_cache.empty())
{
- error= binlog_commit_flush_stmt_cache(thd, all, cache_mngr);
+ error |= binlog_commit_flush_stmt_cache(thd, all, cache_mngr);
}
- if (cache_mngr->trx_cache.empty())
+ if (cache_mngr->trx_cache.empty() &&
+ thd->transaction.xid_state.get_state_code() != XA_PREPARED)
{
/*
we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid()
@@ -2212,8 +2349,8 @@ void MYSQL_BIN_LOG::set_write_error(THD *thd, bool is_transactional)
if (WSREP_EMULATE_BINLOG(thd))
{
if (is_transactional)
- trans_register_ha(thd, TRUE, binlog_hton);
- trans_register_ha(thd, FALSE, binlog_hton);
+ trans_register_ha(thd, TRUE, binlog_hton, 0);
+ trans_register_ha(thd, FALSE, binlog_hton, 0);
}
#endif /* WITH_WSREP */
DBUG_VOID_RETURN;
@@ -2413,8 +2550,8 @@ File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg)
*errmsg = "Could not open log file";
goto err;
}
- if (init_io_cache(log, file, (size_t)binlog_file_cache_size, READ_CACHE, 0, 0,
- MYF(MY_WME|MY_DONT_CHECK_FILESIZE)))
+ if (init_io_cache_ext(log, file, (size_t)binlog_file_cache_size, READ_CACHE,
+ 0, 0, MYF(MY_WME|MY_DONT_CHECK_FILESIZE), key_file_binlog_cache))
{
sql_print_error("Failed to create a cache on log (file '%s')",
log_file_name);
@@ -2592,24 +2729,14 @@ end:
}
-void MYSQL_LOG::init(enum_log_type log_type_arg,
- enum cache_type io_cache_type_arg)
-{
- DBUG_ENTER("MYSQL_LOG::init");
- log_type= log_type_arg;
- io_cache_type= io_cache_type_arg;
- DBUG_PRINT("info",("log_type: %d", log_type));
- DBUG_VOID_RETURN;
-}
-
-
bool MYSQL_LOG::init_and_set_log_file_name(const char *log_name,
const char *new_name,
ulong next_log_number,
enum_log_type log_type_arg,
enum cache_type io_cache_type_arg)
{
- init(log_type_arg, io_cache_type_arg);
+ log_type= log_type_arg;
+ io_cache_type= io_cache_type_arg;
if (new_name)
{
@@ -2663,7 +2790,7 @@ bool MYSQL_LOG::open(
write_error= 0;
- if (!(name= my_strdup(log_name, MYF(MY_WME))))
+ if (!(name= my_strdup(key_memory_MYSQL_LOG_name, log_name, MYF(MY_WME))))
{
name= (char *)log_name; // for the error message
goto err;
@@ -3403,10 +3530,11 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
O_RDWR | O_CREAT | O_BINARY | O_CLOEXEC,
MYF(MY_WME))) < 0 ||
mysql_file_sync(index_file_nr, MYF(MY_WME)) ||
- init_io_cache(&index_file, index_file_nr,
+ init_io_cache_ext(&index_file, index_file_nr,
IO_SIZE, WRITE_CACHE,
mysql_file_seek(index_file_nr, 0L, MY_SEEK_END, MYF(0)),
- 0, MYF(MY_WME | MY_WAIT_IF_FULL)) ||
+ 0, MYF(MY_WME | MY_WAIT_IF_FULL),
+ m_key_file_log_index_cache) ||
DBUG_EVALUATE_IF("fault_injection_openning_index", 1, 0))
{
/*
@@ -3460,7 +3588,6 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
*/
bool MYSQL_BIN_LOG::open(const char *log_name,
- enum_log_type log_type_arg,
const char *new_name,
ulong next_log_number,
enum cache_type io_cache_type_arg,
@@ -3471,7 +3598,6 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
File file= -1;
xid_count_per_binlog *new_xid_list_entry= NULL, *b;
DBUG_ENTER("MYSQL_BIN_LOG::open");
- DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
mysql_mutex_assert_owner(&LOCK_log);
@@ -3491,7 +3617,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
/* We need to calculate new log file name for purge to delete old */
if (init_and_set_log_file_name(log_name, new_name, next_log_number,
- log_type_arg, io_cache_type_arg))
+ LOG_BIN, io_cache_type_arg))
{
sql_print_error("MYSQL_BIN_LOG::open failed to generate new file name.");
DBUG_RETURN(1);
@@ -4319,7 +4445,7 @@ bool MYSQL_BIN_LOG::reset_logs(THD *thd, bool create_new_log,
}
}
if (create_new_log && !open_index_file(index_file_name, 0, FALSE))
- if (unlikely((error= open(save_name, log_type, 0, next_log_number,
+ if (unlikely((error= open(save_name, 0, next_log_number,
io_cache_type, max_size, 0, FALSE))))
goto err;
my_free((void *) save_name);
@@ -4455,14 +4581,16 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
{
rli->last_inuse_relaylog= NULL;
included= 1;
- to_purge_if_included= my_strdup(ir->name, MYF(0));
+ to_purge_if_included= my_strdup(key_memory_Relay_log_info_group_relay_log_name,
+ ir->name, MYF(0));
}
rli->free_inuse_relaylog(ir);
ir= next;
}
rli->inuse_relaylog_list= ir;
if (ir)
- to_purge_if_included= my_strdup(ir->name, MYF(0));
+ to_purge_if_included= my_strdup(key_memory_Relay_log_info_group_relay_log_name,
+ ir->name, MYF(0));
/*
Read the next log file name from the index file and pass it back to
@@ -5055,55 +5183,6 @@ MYSQL_BIN_LOG::is_xidlist_idle_nolock()
return true;
}
-#ifdef WITH_WSREP
-inline bool
-is_gtid_cached_internal(IO_CACHE *file)
-{
- uchar data[EVENT_TYPE_OFFSET+1];
- bool result= false;
- my_off_t write_pos= my_b_tell(file);
- if (reinit_io_cache(file, READ_CACHE, 0, 0, 0))
- return false;
- /*
- In the cache we have gtid event if , below condition is true,
- */
- my_b_read(file, data, sizeof(data));
- uint event_type= (uchar)data[EVENT_TYPE_OFFSET];
- if (event_type == GTID_LOG_EVENT)
- result= true;
- /*
- Cleanup , Why because we have not read the full buffer
- and this will cause next to next reinit_io_cache(called in write_cache)
- to make cache empty.
- */
- file->read_pos= file->read_end;
- if (reinit_io_cache(file, WRITE_CACHE, write_pos, 0, 0))
- return false;
- return result;
-}
-#endif
-
-#ifdef WITH_WSREP
-inline bool
-MYSQL_BIN_LOG::is_gtid_cached(THD *thd)
-{
- binlog_cache_mngr *mngr= (binlog_cache_mngr *) thd_get_ha_data(
- thd, binlog_hton);
- if (!mngr)
- return false;
- binlog_cache_data *cache_trans= mngr->get_binlog_cache_data(
- use_trans_cache(thd, true));
- binlog_cache_data *cache_stmt= mngr->get_binlog_cache_data(
- use_trans_cache(thd, false));
- if (cache_trans && !cache_trans->empty() &&
- is_gtid_cached_internal(&cache_trans->cache_log))
- return true;
- if (cache_stmt && !cache_stmt->empty() &&
- is_gtid_cached_internal(&cache_stmt->cache_log))
- return true;
- return false;
-}
-#endif
/**
Create a new log file name.
@@ -5226,34 +5305,33 @@ int MYSQL_BIN_LOG::new_file_impl()
}
new_name_ptr=new_name;
- if (log_type == LOG_BIN)
{
+ /*
+ We log the whole file name for log file as the user may decide
+ to change base names at some point.
+ */
+ Rotate_log_event r(new_name + dirname_length(new_name), 0, LOG_EVENT_OFFSET,
+ is_relay_log ? Rotate_log_event::RELAY_LOG : 0);
+ /*
+ The current relay-log's closing Rotate event must have checksum
+ value computed with an algorithm of the last relay-logged FD event.
+ */
+ if (is_relay_log)
+ r.checksum_alg= relay_log_checksum_alg;
+ DBUG_ASSERT(!is_relay_log ||
+ relay_log_checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF);
+ if (DBUG_EVALUATE_IF("fault_injection_new_file_rotate_event",
+ (error= close_on_error= TRUE), FALSE) ||
+ (error= write_event(&r)))
{
- /*
- We log the whole file name for log file as the user may decide
- to change base names at some point.
- */
- Rotate_log_event r(new_name+dirname_length(new_name), 0, LOG_EVENT_OFFSET,
- is_relay_log ? Rotate_log_event::RELAY_LOG : 0);
- /*
- The current relay-log's closing Rotate event must have checksum
- value computed with an algorithm of the last relay-logged FD event.
- */
- if (is_relay_log)
- r.checksum_alg= relay_log_checksum_alg;
- DBUG_ASSERT(!is_relay_log || relay_log_checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF);
- if(DBUG_EVALUATE_IF("fault_injection_new_file_rotate_event", (error=close_on_error=TRUE), FALSE) ||
- (error= write_event(&r)))
- {
- DBUG_EXECUTE_IF("fault_injection_new_file_rotate_event", errno=2;);
- close_on_error= TRUE;
- my_printf_error(ER_ERROR_ON_WRITE,
- ER_THD_OR_DEFAULT(current_thd, ER_CANT_OPEN_FILE),
- MYF(ME_FATAL), name, errno);
- goto end;
- }
- bytes_written += r.data_written;
+ DBUG_EXECUTE_IF("fault_injection_new_file_rotate_event", errno= 2;);
+ close_on_error= TRUE;
+ my_printf_error(ER_ERROR_ON_WRITE,
+ ER_THD_OR_DEFAULT(current_thd, ER_CANT_OPEN_FILE),
+ MYF(ME_FATAL), name, errno);
+ goto end;
}
+ bytes_written+= r.data_written;
}
/*
@@ -5284,7 +5362,7 @@ int MYSQL_BIN_LOG::new_file_impl()
delay_close= true;
}
close(close_flag);
- if (log_type == LOG_BIN && checksum_alg_reset != BINLOG_CHECKSUM_ALG_UNDEF)
+ if (checksum_alg_reset != BINLOG_CHECKSUM_ALG_UNDEF)
{
DBUG_ASSERT(!is_relay_log);
DBUG_ASSERT(binlog_checksum_options != checksum_alg_reset);
@@ -5311,8 +5389,7 @@ int MYSQL_BIN_LOG::new_file_impl()
{
/* reopen the binary log file. */
file_to_open= new_name_ptr;
- error= open(old_name, log_type, new_name_ptr, 0, io_cache_type,
- max_size, 1, FALSE);
+ error= open(old_name, new_name_ptr, 0, io_cache_type, max_size, 1, FALSE);
}
/* handle reopening errors */
@@ -5652,7 +5729,8 @@ binlog_cache_mngr *THD::binlog_setup_trx_data()
if (cache_mngr)
DBUG_RETURN(cache_mngr); // Already set up
- cache_mngr= (binlog_cache_mngr*) my_malloc(sizeof(binlog_cache_mngr), MYF(MY_ZEROFILL));
+ cache_mngr= (binlog_cache_mngr*) my_malloc(key_memory_binlog_cache_mngr,
+ sizeof(binlog_cache_mngr), MYF(MY_ZEROFILL));
if (!cache_mngr ||
open_cached_file(&cache_mngr->stmt_cache.cache_log, mysql_tmpdir,
LOG_PREFIX, (size_t)binlog_stmt_cache_size, MYF(MY_WME)) ||
@@ -5728,36 +5806,52 @@ THD::binlog_start_trans_and_stmt()
{
DBUG_VOID_RETURN;
}
- /* Write Gtid
- Get domain id only when gtid mode is set
- If this event is replicate through a master then ,
- we will forward the same gtid another nodes
- We have to do this only one time in mysql transaction.
- Since this function is called multiple times , We will check for
- ha_info->is_started()
- */
+ /* If this event replicates through a master-slave then we need to
+ inject manually GTID so it is preserved in the cluster. We are writing
+ directly to WSREP buffer and not in IO cache because in case of IO cache
+ GTID event will be duplicated in binlog.
+ We have to do this only one time in mysql transaction.
+ Since this function is called multiple times , We will check for
+ ha_info->is_started().
+ */
Ha_trx_info *ha_info;
ha_info= this->ha_data[binlog_hton->slot].ha_info + (mstmt_mode ? 1 : 0);
- if (!ha_info->is_started() && wsrep_gtid_mode
- && this->variables.gtid_seq_no)
+ if (!ha_info->is_started() &&
+ (this->variables.gtid_seq_no || this->variables.wsrep_gtid_seq_no) &&
+ wsrep_on(this) &&
+ (this->wsrep_cs().mode() == wsrep::client_state::m_local))
{
- binlog_cache_mngr *const cache_mngr=
- (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
- binlog_cache_data *cache_data= cache_mngr->get_binlog_cache_data(1);
- IO_CACHE *file= &cache_data->cache_log;
- Log_event_writer writer(file, cache_data);
- Gtid_log_event gtid_event(this, this->variables.gtid_seq_no,
- this->variables.gtid_domain_id,
- true, LOG_EVENT_SUPPRESS_USE_F,
- true, 0);
- gtid_event.server_id= this->variables.server_id;
- writer.write(&gtid_event);
+ uchar *buf= 0;
+ size_t len= 0;
+ IO_CACHE tmp_io_cache;
+ Log_event_writer writer(&tmp_io_cache, 0);
+ if(!open_cached_file(&tmp_io_cache, mysql_tmpdir, TEMP_PREFIX,
+ 128, MYF(MY_WME)))
+ {
+ uint64 seqno= this->variables.gtid_seq_no;
+ uint32 domain_id= this->variables.gtid_domain_id;
+ uint32 server_id= this->variables.server_id;
+ if (!this->variables.gtid_seq_no && this->variables.wsrep_gtid_seq_no)
+ {
+ seqno= this->variables.wsrep_gtid_seq_no;
+ domain_id= wsrep_gtid_server.domain_id;
+ server_id= wsrep_gtid_server.server_id;
+ }
+ Gtid_log_event gtid_event(this, seqno, domain_id, true,
+ LOG_EVENT_SUPPRESS_USE_F, true, 0);
+ gtid_event.server_id= server_id;
+ writer.write(&gtid_event);
+ wsrep_write_cache_buf(&tmp_io_cache, &buf, &len);
+ if (len > 0) this->wsrep_cs().append_data(wsrep::const_buffer(buf, len));
+ if (buf) my_free(buf);
+ close_cached_file(&tmp_io_cache);
+ }
}
#endif
if (mstmt_mode)
- trans_register_ha(this, TRUE, binlog_hton);
- trans_register_ha(this, FALSE, binlog_hton);
+ trans_register_ha(this, TRUE, binlog_hton, 0);
+ trans_register_ha(this, FALSE, binlog_hton, 0);
/*
Mark statement transaction as read/write. We never start
a binary log transaction and keep it read-only,
@@ -5801,7 +5895,7 @@ binlog_start_consistent_snapshot(handlerton *hton, THD *thd)
strmake_buf(cache_mngr->last_commit_pos_file, mysql_bin_log.last_commit_pos_file);
cache_mngr->last_commit_pos_offset= mysql_bin_log.last_commit_pos_offset;
- trans_register_ha(thd, TRUE, hton);
+ trans_register_ha(thd, TRUE, binlog_hton, 0);
DBUG_RETURN(err);
}
@@ -6033,20 +6127,9 @@ MYSQL_BIN_LOG::write_gtid_event(THD *thd, bool standalone,
DBUG_ENTER("write_gtid_event");
DBUG_PRINT("enter", ("standalone: %d", standalone));
-#ifdef WITH_WSREP
- if (WSREP(thd) &&
- (wsrep_thd_trx_seqno(thd) > 0) &&
- wsrep_gtid_mode && !thd->variables.gtid_seq_no)
- {
- domain_id= wsrep_gtid_domain_id;
- } else {
-#endif /* WITH_WSREP */
+ seq_no= thd->variables.gtid_seq_no;
domain_id= thd->variables.gtid_domain_id;
-#ifdef WITH_WSREP
- }
-#endif /* WITH_WSREP */
local_server_id= thd->variables.server_id;
- seq_no= thd->variables.gtid_seq_no;
DBUG_ASSERT(local_server_id != 0);
@@ -6093,8 +6176,11 @@ MYSQL_BIN_LOG::write_gtid_event(THD *thd, bool standalone,
DBUG_ASSERT(this == &mysql_bin_log);
#ifdef WITH_WSREP
- if (wsrep_gtid_mode && is_gtid_cached(thd))
- DBUG_RETURN(false);
+ if (wsrep_gtid_mode)
+ {
+ thd->variables.gtid_domain_id= global_system_variables.gtid_domain_id;
+ thd->variables.server_id= global_system_variables.server_id;
+ }
#endif
if (write_event(&gtid_event))
@@ -7396,10 +7482,10 @@ MYSQL_BIN_LOG::write_transaction_to_binlog(THD *thd,
entry.all= all;
entry.using_stmt_cache= using_stmt_cache;
entry.using_trx_cache= using_trx_cache;
- entry.need_unlog= false;
+ entry.need_unlog= is_preparing_xa(thd);
ha_info= all ? thd->transaction.all.ha_list : thd->transaction.stmt.ha_list;
- for (; ha_info; ha_info= ha_info->next())
+ for (; !entry.need_unlog && ha_info; ha_info= ha_info->next())
{
if (ha_info->is_started() && ha_info->ht() != binlog_hton &&
!ha_info->ht()->commit_checkpoint_request)
@@ -7751,7 +7837,7 @@ MYSQL_BIN_LOG::write_transaction_to_binlog_events(group_commit_entry *entry)
Release commit order and if leader, wait for prior commit to
complete. This establishes total order for group leaders.
*/
- if (wsrep_ordered_commit(entry->thd, entry->all, wsrep_apply_error()))
+ if (wsrep_ordered_commit(entry->thd, entry->all))
{
entry->thd->wakeup_subsequent_commits(1);
return 1;
@@ -7972,7 +8058,9 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
We already checked before that at least one cache is non-empty; if both
are empty we would have skipped calling into here.
*/
- DBUG_ASSERT(!cache_mngr->stmt_cache.empty() || !cache_mngr->trx_cache.empty());
+ DBUG_ASSERT(!cache_mngr->stmt_cache.empty() ||
+ !cache_mngr->trx_cache.empty() ||
+ current->thd->transaction.xid_state.is_explicit_XA());
if (unlikely((current->error= write_transaction_or_stmt(current,
commit_id))))
@@ -7981,7 +8069,7 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
strmake_buf(cache_mngr->last_commit_pos_file, log_file_name);
commit_offset= my_b_write_tell(&log_file);
cache_mngr->last_commit_pos_offset= commit_offset;
- if (cache_mngr->using_xa && cache_mngr->xa_xid)
+ if ((cache_mngr->using_xa && cache_mngr->xa_xid) || current->need_unlog)
{
/*
If all storage engines support commit_checkpoint_request(), then we
@@ -8216,7 +8304,8 @@ MYSQL_BIN_LOG::write_transaction_or_stmt(group_commit_entry *entry,
binlog_cache_mngr *mngr= entry->cache_mngr;
DBUG_ENTER("MYSQL_BIN_LOG::write_transaction_or_stmt");
- if (write_gtid_event(entry->thd, false, entry->using_trx_cache, commit_id))
+ if (write_gtid_event(entry->thd, is_prepared_xa(entry->thd),
+ entry->using_trx_cache, commit_id))
DBUG_RETURN(ER_ERROR_ON_WRITE);
if (entry->using_stmt_cache && !mngr->stmt_cache.empty() &&
@@ -8502,9 +8591,9 @@ void MYSQL_BIN_LOG::close(uint exiting)
if (log_state == LOG_OPENED)
{
+ DBUG_ASSERT(log_type == LOG_BIN);
#ifdef HAVE_REPLICATION
- if (log_type == LOG_BIN &&
- (exiting & LOG_CLOSE_STOP_EVENT))
+ if (exiting & LOG_CLOSE_STOP_EVENT)
{
Stop_log_event s;
// the checksumming rule for relay-log case is similar to Rotate
@@ -8541,8 +8630,7 @@ void MYSQL_BIN_LOG::close(uint exiting)
#endif /* HAVE_REPLICATION */
/* don't pwrite in a file opened with O_APPEND - it doesn't work */
- if (log_file.type == WRITE_CACHE && log_type == LOG_BIN
- && !(exiting & LOG_CLOSE_DELAYED_CLOSE))
+ if (log_file.type == WRITE_CACHE && !(exiting & LOG_CLOSE_DELAYED_CLOSE))
{
my_off_t org_position= mysql_file_tell(log_file.file, MYF(0));
if (!failed_to_save_state)
@@ -9165,7 +9253,8 @@ int TC_LOG_MMAP::open(const char *opt_name)
npages=(uint)file_length/tc_log_page_size;
if (npages < 3) // to guarantee non-empty pool
goto err;
- if (!(pages=(PAGE *)my_malloc(npages*sizeof(PAGE), MYF(MY_WME|MY_ZEROFILL))))
+ if (!(pages=(PAGE *)my_malloc(key_memory_TC_LOG_MMAP_pages,
+ npages*sizeof(PAGE), MYF(MY_WME|MY_ZEROFILL))))
goto err;
inited=3;
for (pg=pages, i=0; i < npages; i++, pg++)
@@ -9475,7 +9564,8 @@ int TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
{
uint32 size= sizeof(*pending_checkpoint) + sizeof(ulong) * (ncookies - 1);
if (!(pending_checkpoint=
- (pending_cookies *)my_malloc(size, MYF(MY_ZEROFILL))))
+ (pending_cookies *)my_malloc(PSI_INSTRUMENT_ME, size,
+ MYF(MY_ZEROFILL))))
{
my_error(ER_OUTOFMEMORY, MYF(0), size);
mysql_mutex_unlock(&LOCK_pending_checkpoint);
@@ -9614,8 +9704,8 @@ int TC_LOG_MMAP::recover()
goto err1;
}
- if (my_hash_init(&xids, &my_charset_bin, tc_log_page_size/3, 0,
- sizeof(my_xid), 0, 0, MYF(0)))
+ if (my_hash_init(PSI_INSTRUMENT_ME, &xids, &my_charset_bin,
+ tc_log_page_size/3, 0, sizeof(my_xid), 0, 0, MYF(0)))
goto err1;
for ( ; p < end_p ; p++)
@@ -9693,7 +9783,7 @@ int TC_LOG_BINLOG::open(const char *opt_name)
{
mysql_mutex_lock(&LOCK_log);
/* generate a new binlog to mask a corrupted one */
- open(opt_name, LOG_BIN, 0, 0, WRITE_CACHE, max_binlog_size, 0, TRUE);
+ open(opt_name, 0, 0, WRITE_CACHE, max_binlog_size, 0, TRUE);
mysql_mutex_unlock(&LOCK_log);
cleanup();
return 1;
@@ -9919,6 +10009,46 @@ int TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
DBUG_RETURN(BINLOG_COOKIE_GET_ERROR_FLAG(cookie));
}
+static bool write_empty_xa_prepare(THD *thd, binlog_cache_mngr *cache_mngr)
+{
+ return binlog_commit_flush_xa_prepare(thd, true, cache_mngr);
+}
+
+int TC_LOG_BINLOG::unlog_xa_prepare(THD *thd, bool all)
+{
+ DBUG_ASSERT(is_preparing_xa(thd));
+
+ binlog_cache_mngr *cache_mngr= thd->binlog_setup_trx_data();
+ int cookie= 0;
+
+ if (!cache_mngr->need_unlog)
+ {
+ Ha_trx_info *ha_info;
+ uint rw_count= ha_count_rw_all(thd, &ha_info);
+ bool rc= false;
+
+ if (rw_count > 0)
+ {
+ /* an empty XA-prepare event group is logged */
+#ifndef DBUG_OFF
+ for (ha_info= thd->transaction.all.ha_list; rw_count > 1 && ha_info;
+ ha_info= ha_info->next())
+ DBUG_ASSERT(ha_info->ht() != binlog_hton);
+#endif
+ rc= write_empty_xa_prepare(thd, cache_mngr); // normally gains need_unlog
+ trans_register_ha(thd, true, binlog_hton, 0); // do it for future commmit
+ }
+ if (rw_count == 0 || !cache_mngr->need_unlog)
+ return rc;
+ }
+
+ cookie= BINLOG_COOKIE_MAKE(cache_mngr->binlog_id, cache_mngr->delayed_error);
+ cache_mngr->need_unlog= false;
+
+ return unlog(cookie, 1);
+}
+
+
void
TC_LOG_BINLOG::commit_checkpoint_notify(void *cookie)
{
@@ -10128,13 +10258,13 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
#endif
if (! fdle->is_valid() ||
- (do_xa && my_hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
+ (do_xa && my_hash_init(key_memory_binlog_recover_exec, &xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
sizeof(my_xid), 0, 0, MYF(0))))
goto err1;
if (do_xa)
- init_alloc_root(&mem_root, "TC_LOG_BINLOG", TC_LOG_PAGE_SIZE,
- TC_LOG_PAGE_SIZE, MYF(0));
+ init_alloc_root(key_memory_binlog_recover_exec, &mem_root,
+ TC_LOG_PAGE_SIZE, TC_LOG_PAGE_SIZE, MYF(0));
fdle->flags&= ~LOG_EVENT_BINLOG_IN_USE_F; // abort on the first error
@@ -10235,6 +10365,7 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
((last_gtid_standalone && !ev->is_part_of_group(typ)) ||
(!last_gtid_standalone &&
(typ == XID_EVENT ||
+ typ == XA_PREPARE_LOG_EVENT ||
(LOG_EVENT_IS_QUERY(typ) &&
(((Query_log_event *)ev)->is_commit() ||
((Query_log_event *)ev)->is_rollback()))))))
@@ -10440,24 +10571,6 @@ MYSQL_BIN_LOG::do_binlog_recovery(const char *opt_name, bool do_xa_recovery)
#ifdef INNODB_COMPATIBILITY_HOOKS
-/**
- Get the file name of the MySQL binlog.
- @return the name of the binlog file
-*/
-extern "C"
-const char* mysql_bin_log_file_name(void)
-{
- return mysql_bin_log.get_log_fname();
-}
-/**
- Get the current position of the MySQL binlog.
- @return byte offset from the beginning of the binlog
-*/
-extern "C"
-ulonglong mysql_bin_log_file_pos(void)
-{
- return (ulonglong) mysql_bin_log.get_log_file()->pos_in_file;
-}
/*
Get the current position of the MySQL binlog for transaction currently being
committed.
@@ -10564,7 +10677,7 @@ static struct st_mysql_sys_var *binlog_sys_vars[]=
/*
Copy out the non-directory part of binlog position filename for the
`binlog_snapshot_file' status variable, same way as it is done for
- SHOW MASTER STATUS.
+ SHOW BINLOG STATUS.
*/
static void
set_binlog_snapshot_file(const char *src)
@@ -10815,8 +10928,8 @@ void wsrep_register_binlog_handler(THD *thd, bool trx)
Set callbacks in order to be able to call commmit or rollback.
*/
if (trx)
- trans_register_ha(thd, TRUE, binlog_hton);
- trans_register_ha(thd, FALSE, binlog_hton);
+ trans_register_ha(thd, TRUE, binlog_hton, 0);
+ trans_register_ha(thd, FALSE, binlog_hton, 0);
/*
Set the binary log as read/write otherwise callbacks are not called.
diff --git a/sql/log.h b/sql/log.h
index 4b80bdfd81f..1071538fbfd 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -61,6 +61,7 @@ class TC_LOG
bool need_prepare_ordered,
bool need_commit_ordered) = 0;
virtual int unlog(ulong cookie, my_xid xid)=0;
+ virtual int unlog_xa_prepare(THD *thd, bool all)= 0;
virtual void commit_checkpoint_notify(void *cookie)= 0;
protected:
@@ -115,6 +116,10 @@ public:
return 1;
}
int unlog(ulong cookie, my_xid xid) { return 0; }
+ int unlog_xa_prepare(THD *thd, bool all)
+ {
+ return 0;
+ }
void commit_checkpoint_notify(void *cookie) { DBUG_ASSERT(0); };
};
@@ -198,6 +203,10 @@ class TC_LOG_MMAP: public TC_LOG
int log_and_order(THD *thd, my_xid xid, bool all,
bool need_prepare_ordered, bool need_commit_ordered);
int unlog(ulong cookie, my_xid xid);
+ int unlog_xa_prepare(THD *thd, bool all)
+ {
+ return 0;
+ }
void commit_checkpoint_notify(void *cookie);
int recover();
@@ -305,13 +314,6 @@ public:
enum_log_type log_type,
const char *new_name, ulong next_file_number,
enum cache_type io_cache_type_arg);
- bool init_and_set_log_file_name(const char *log_name,
- const char *new_name,
- ulong next_log_number,
- enum_log_type log_type_arg,
- enum cache_type io_cache_type_arg);
- void init(enum_log_type log_type_arg,
- enum cache_type io_cache_type_arg);
void close(uint exiting);
inline bool is_open() { return log_state != LOG_CLOSED; }
const char *generate_name(const char *log_name,
@@ -335,7 +337,12 @@ public:
/** Instrumentation key to use for file io in @c log_file */
PSI_file_key m_log_file_key;
#endif
- /* for documentation of mutexes held in various places in code */
+
+ bool init_and_set_log_file_name(const char *log_name,
+ const char *new_name,
+ ulong next_log_number,
+ enum_log_type log_type_arg,
+ enum cache_type io_cache_type_arg);
};
/* Tell the io thread if we can delay the master info sync. */
@@ -414,8 +421,6 @@ struct wait_for_commit;
class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
{
- private:
-#ifdef HAVE_PSI_INTERFACE
/** The instrumentation key to use for @ LOCK_index. */
PSI_mutex_key m_key_LOCK_index;
/** The instrumentation key to use for @ COND_relay_log_updated */
@@ -423,14 +428,13 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
/** The instrumentation key to use for @ COND_bin_log_updated */
PSI_cond_key m_key_bin_log_update;
/** The instrumentation key to use for opening the log file. */
- PSI_file_key m_key_file_log;
+ PSI_file_key m_key_file_log, m_key_file_log_cache;
/** The instrumentation key to use for opening the log index file. */
- PSI_file_key m_key_file_log_index;
+ PSI_file_key m_key_file_log_index, m_key_file_log_index_cache;
- PSI_file_key m_key_COND_queue_busy;
+ PSI_cond_key m_key_COND_queue_busy;
/** The instrumentation key to use for LOCK_binlog_end_pos. */
PSI_mutex_key m_key_LOCK_binlog_end_pos;
-#endif
struct group_commit_entry
{
@@ -564,13 +568,6 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
bool write_transaction_to_binlog_events(group_commit_entry *entry);
void trx_group_commit_leader(group_commit_entry *leader);
bool is_xidlist_idle_nolock();
-#ifdef WITH_WSREP
- /*
- When this mariadb node is slave and galera enabled. So in this case
- we write the gtid in wsrep_run_commit itself.
- */
- inline bool is_gtid_cached(THD *thd);
-#endif
public:
/*
A list of struct xid_count_per_binlog is used to keep track of how many
@@ -597,7 +594,7 @@ public:
:binlog_id(0), xid_count(0), notify_count(0)
{
binlog_name_len= log_file_name_len;
- binlog_name= (char *) my_malloc(binlog_name_len, MYF(MY_ZEROFILL));
+ binlog_name= (char *) my_malloc(PSI_INSTRUMENT_ME, binlog_name_len, MYF(MY_ZEROFILL));
if (binlog_name)
memcpy(binlog_name, log_file_name, binlog_name_len);
}
@@ -684,15 +681,19 @@ public:
PSI_cond_key key_relay_log_update,
PSI_cond_key key_bin_log_update,
PSI_file_key key_file_log,
+ PSI_file_key key_file_log_cache,
PSI_file_key key_file_log_index,
- PSI_file_key key_COND_queue_busy,
+ PSI_file_key key_file_log_index_cache,
+ PSI_cond_key key_COND_queue_busy,
PSI_mutex_key key_LOCK_binlog_end_pos)
{
m_key_LOCK_index= key_LOCK_index;
m_key_relay_log_update= key_relay_log_update;
m_key_bin_log_update= key_bin_log_update;
m_key_file_log= key_file_log;
+ m_key_file_log_cache= key_file_log_cache;
m_key_file_log_index= key_file_log_index;
+ m_key_file_log_index_cache= key_file_log_index_cache;
m_key_COND_queue_busy= key_COND_queue_busy;
m_key_LOCK_binlog_end_pos= key_LOCK_binlog_end_pos;
}
@@ -705,6 +706,7 @@ public:
int log_and_order(THD *thd, my_xid xid, bool all,
bool need_prepare_ordered, bool need_commit_ordered);
int unlog(ulong cookie, my_xid xid);
+ int unlog_xa_prepare(THD *thd, bool all);
void commit_checkpoint_notify(void *cookie);
int recover(LOG_INFO *linfo, const char *last_log_name, IO_CACHE *first_log,
Format_description_log_event *fdle, bool do_xa);
@@ -787,7 +789,6 @@ public:
void init_pthread_objects();
void cleanup();
bool open(const char *log_name,
- enum_log_type log_type,
const char *new_name,
ulong next_log_number,
enum cache_type io_cache_type_arg,
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 6ac9ee28dad..d9537839f6c 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2000, 2019, Oracle and/or its affiliates.
+ Copyright (c) 2000, 2018, Oracle and/or its affiliates.
Copyright (c) 2009, 2020, MariaDB
This program is free software; you can redistribute it and/or modify
@@ -18,7 +18,7 @@
#include "mariadb.h"
#include "sql_priv.h"
-
+#include "handler.h"
#ifndef MYSQL_CLIENT
#include "unireg.h"
#include "log_event.h"
@@ -39,7 +39,6 @@
#include "transaction.h"
#include <my_dir.h>
#include "sql_show.h" // append_identifier
-#include "debug_sync.h" // debug_sync
#include <mysql/psi/mysql_statement.h>
#include <strfunc.h>
#include "compat56.h"
@@ -57,6 +56,10 @@
#define my_b_write_string(A, B) my_b_write((A), (uchar*)(B), (uint) (sizeof(B) - 1))
+PSI_memory_key key_memory_log_event;
+PSI_memory_key key_memory_Incident_log_event_message;
+PSI_memory_key key_memory_Rows_query_log_event_rows_query;
+
/**
BINLOG_CHECKSUM variable.
*/
@@ -80,9 +83,6 @@ TYPELIB binlog_checksum_typelib=
};
-
-#define log_cs &my_charset_latin1
-
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
/*
@@ -107,179 +107,6 @@ const Version checksum_version_split_mariadb(5, 3, 0);
// First MySQL version with fraction seconds
const Version fsp_version_split_mysql(5, 6, 0);
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-static int rows_event_stmt_cleanup(rpl_group_info *rgi, THD* thd);
-
-static const char *HA_ERR(int i)
-{
- /*
- This function should only be called in case of an error
- was detected
- */
- DBUG_ASSERT(i != 0);
- switch (i) {
- case HA_ERR_KEY_NOT_FOUND: return "HA_ERR_KEY_NOT_FOUND";
- case HA_ERR_FOUND_DUPP_KEY: return "HA_ERR_FOUND_DUPP_KEY";
- case HA_ERR_RECORD_CHANGED: return "HA_ERR_RECORD_CHANGED";
- case HA_ERR_WRONG_INDEX: return "HA_ERR_WRONG_INDEX";
- case HA_ERR_CRASHED: return "HA_ERR_CRASHED";
- case HA_ERR_WRONG_IN_RECORD: return "HA_ERR_WRONG_IN_RECORD";
- case HA_ERR_OUT_OF_MEM: return "HA_ERR_OUT_OF_MEM";
- case HA_ERR_NOT_A_TABLE: return "HA_ERR_NOT_A_TABLE";
- case HA_ERR_WRONG_COMMAND: return "HA_ERR_WRONG_COMMAND";
- case HA_ERR_OLD_FILE: return "HA_ERR_OLD_FILE";
- case HA_ERR_NO_ACTIVE_RECORD: return "HA_ERR_NO_ACTIVE_RECORD";
- case HA_ERR_RECORD_DELETED: return "HA_ERR_RECORD_DELETED";
- case HA_ERR_RECORD_FILE_FULL: return "HA_ERR_RECORD_FILE_FULL";
- case HA_ERR_INDEX_FILE_FULL: return "HA_ERR_INDEX_FILE_FULL";
- case HA_ERR_END_OF_FILE: return "HA_ERR_END_OF_FILE";
- case HA_ERR_UNSUPPORTED: return "HA_ERR_UNSUPPORTED";
- case HA_ERR_TO_BIG_ROW: return "HA_ERR_TO_BIG_ROW";
- case HA_WRONG_CREATE_OPTION: return "HA_WRONG_CREATE_OPTION";
- case HA_ERR_FOUND_DUPP_UNIQUE: return "HA_ERR_FOUND_DUPP_UNIQUE";
- case HA_ERR_UNKNOWN_CHARSET: return "HA_ERR_UNKNOWN_CHARSET";
- case HA_ERR_WRONG_MRG_TABLE_DEF: return "HA_ERR_WRONG_MRG_TABLE_DEF";
- case HA_ERR_CRASHED_ON_REPAIR: return "HA_ERR_CRASHED_ON_REPAIR";
- case HA_ERR_CRASHED_ON_USAGE: return "HA_ERR_CRASHED_ON_USAGE";
- case HA_ERR_LOCK_WAIT_TIMEOUT: return "HA_ERR_LOCK_WAIT_TIMEOUT";
- case HA_ERR_LOCK_TABLE_FULL: return "HA_ERR_LOCK_TABLE_FULL";
- case HA_ERR_READ_ONLY_TRANSACTION: return "HA_ERR_READ_ONLY_TRANSACTION";
- case HA_ERR_LOCK_DEADLOCK: return "HA_ERR_LOCK_DEADLOCK";
- case HA_ERR_CANNOT_ADD_FOREIGN: return "HA_ERR_CANNOT_ADD_FOREIGN";
- case HA_ERR_NO_REFERENCED_ROW: return "HA_ERR_NO_REFERENCED_ROW";
- case HA_ERR_ROW_IS_REFERENCED: return "HA_ERR_ROW_IS_REFERENCED";
- case HA_ERR_NO_SAVEPOINT: return "HA_ERR_NO_SAVEPOINT";
- case HA_ERR_NON_UNIQUE_BLOCK_SIZE: return "HA_ERR_NON_UNIQUE_BLOCK_SIZE";
- case HA_ERR_NO_SUCH_TABLE: return "HA_ERR_NO_SUCH_TABLE";
- case HA_ERR_TABLE_EXIST: return "HA_ERR_TABLE_EXIST";
- case HA_ERR_NO_CONNECTION: return "HA_ERR_NO_CONNECTION";
- case HA_ERR_NULL_IN_SPATIAL: return "HA_ERR_NULL_IN_SPATIAL";
- case HA_ERR_TABLE_DEF_CHANGED: return "HA_ERR_TABLE_DEF_CHANGED";
- case HA_ERR_NO_PARTITION_FOUND: return "HA_ERR_NO_PARTITION_FOUND";
- case HA_ERR_RBR_LOGGING_FAILED: return "HA_ERR_RBR_LOGGING_FAILED";
- case HA_ERR_DROP_INDEX_FK: return "HA_ERR_DROP_INDEX_FK";
- case HA_ERR_FOREIGN_DUPLICATE_KEY: return "HA_ERR_FOREIGN_DUPLICATE_KEY";
- case HA_ERR_TABLE_NEEDS_UPGRADE: return "HA_ERR_TABLE_NEEDS_UPGRADE";
- case HA_ERR_TABLE_READONLY: return "HA_ERR_TABLE_READONLY";
- case HA_ERR_AUTOINC_READ_FAILED: return "HA_ERR_AUTOINC_READ_FAILED";
- case HA_ERR_AUTOINC_ERANGE: return "HA_ERR_AUTOINC_ERANGE";
- case HA_ERR_GENERIC: return "HA_ERR_GENERIC";
- case HA_ERR_RECORD_IS_THE_SAME: return "HA_ERR_RECORD_IS_THE_SAME";
- case HA_ERR_LOGGING_IMPOSSIBLE: return "HA_ERR_LOGGING_IMPOSSIBLE";
- case HA_ERR_CORRUPT_EVENT: return "HA_ERR_CORRUPT_EVENT";
- case HA_ERR_ROWS_EVENT_APPLY : return "HA_ERR_ROWS_EVENT_APPLY";
- }
- return "No Error!";
-}
-
-
-/*
- Return true if an error caught during event execution is a temporary error
- that will cause automatic retry of the event group during parallel
- replication, false otherwise.
-
- In parallel replication, conflicting transactions can occasionally cause
- deadlocks; such errors are handled automatically by rolling back re-trying
- the transactions, so should not pollute the error log.
-*/
-static bool
-is_parallel_retry_error(rpl_group_info *rgi, int err)
-{
- if (!rgi->is_parallel_exec)
- return false;
- if (rgi->speculation == rpl_group_info::SPECULATE_OPTIMISTIC)
- return true;
- if (rgi->killed_for_retry &&
- (err == ER_QUERY_INTERRUPTED || err == ER_CONNECTION_KILLED))
- return true;
- return has_temporary_error(rgi->thd);
-}
-
-
-/**
- Error reporting facility for Rows_log_event::do_apply_event
-
- @param level error, warning or info
- @param ha_error HA_ERR_ code
- @param rli pointer to the active Relay_log_info instance
- @param thd pointer to the slave thread's thd
- @param table pointer to the event's table object
- @param type the type of the event
- @param log_name the master binlog file name
- @param pos the master binlog file pos (the next after the event)
-
-*/
-static void inline slave_rows_error_report(enum loglevel level, int ha_error,
- rpl_group_info *rgi, THD *thd,
- TABLE *table, const char * type,
- const char *log_name, my_off_t pos)
-{
- const char *handler_error= (ha_error ? HA_ERR(ha_error) : NULL);
- char buff[MAX_SLAVE_ERRMSG], *slider;
- const char *buff_end= buff + sizeof(buff);
- size_t len;
- Diagnostics_area::Sql_condition_iterator it=
- thd->get_stmt_da()->sql_conditions();
- Relay_log_info const *rli= rgi->rli;
- const Sql_condition *err;
- buff[0]= 0;
- int errcode= thd->is_error() ? thd->get_stmt_da()->sql_errno() : 0;
-
- /*
- In parallel replication, deadlocks or other temporary errors can happen
- occasionally in normal operation, they will be handled correctly and
- automatically by re-trying the transactions. So do not pollute the error
- log with messages about them.
- */
- if (is_parallel_retry_error(rgi, errcode))
- return;
-
- for (err= it++, slider= buff; err && slider < buff_end - 1;
- slider += len, err= it++)
- {
- len= my_snprintf(slider, buff_end - slider,
- " %s, Error_code: %d;", err->get_message_text(),
- err->get_sql_errno());
- }
-
- if (ha_error != 0)
- rli->report(level, errcode, rgi->gtid_info(),
- "Could not execute %s event on table %s.%s;"
- "%s handler error %s; "
- "the event's master log %s, end_log_pos %llu",
- type, table->s->db.str, table->s->table_name.str,
- buff, handler_error == NULL ? "<unknown>" : handler_error,
- log_name, pos);
- else
- rli->report(level, errcode, rgi->gtid_info(),
- "Could not execute %s event on table %s.%s;"
- "%s the event's master log %s, end_log_pos %llu",
- type, table->s->db.str, table->s->table_name.str,
- buff, log_name, pos);
-}
-#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.
@@ -292,7 +119,7 @@ class Write_on_release_cache
public:
enum flag
{
- FLUSH_F= 1
+ FLUSH_F
};
typedef unsigned short flag_set;
@@ -383,187 +210,6 @@ private:
Log_event *m_ev; // Used for Flashback
};
-/*
- pretty_print_str()
-*/
-
-#ifdef MYSQL_CLIENT
-static bool pretty_print_str(IO_CACHE* cache, const char* str, int len)
-{
- const char* end = str + len;
- if (my_b_write_byte(cache, '\''))
- goto err;
-
- while (str < end)
- {
- char c;
- int error;
-
- switch ((c=*str++)) {
- case '\n': error= my_b_write(cache, (uchar*)"\\n", 2); break;
- case '\r': error= my_b_write(cache, (uchar*)"\\r", 2); break;
- case '\\': error= my_b_write(cache, (uchar*)"\\\\", 2); break;
- case '\b': error= my_b_write(cache, (uchar*)"\\b", 2); break;
- case '\t': error= my_b_write(cache, (uchar*)"\\t", 2); break;
- case '\'': error= my_b_write(cache, (uchar*)"\\'", 2); break;
- case 0 : error= my_b_write(cache, (uchar*)"\\0", 2); break;
- default:
- error= my_b_write_byte(cache, c);
- break;
- }
- if (unlikely(error))
- goto err;
- }
- return my_b_write_byte(cache, '\'');
-
-err:
- return 1;
-}
-#endif /* MYSQL_CLIENT */
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-
-inline int idempotent_error_code(int err_code)
-{
- int ret= 0;
-
- switch (err_code)
- {
- case 0:
- ret= 1;
- break;
- /*
- The following list of "idempotent" errors
- means that an error from the list might happen
- because of idempotent (more than once)
- applying of a binlog file.
- Notice, that binlog has a ddl operation its
- second applying may cause
-
- case HA_ERR_TABLE_DEF_CHANGED:
- case HA_ERR_CANNOT_ADD_FOREIGN:
-
- which are not included into to the list.
-
- Note that HA_ERR_RECORD_DELETED is not in the list since
- do_exec_row() should not return that error code.
- */
- case HA_ERR_RECORD_CHANGED:
- case HA_ERR_KEY_NOT_FOUND:
- case HA_ERR_END_OF_FILE:
- case HA_ERR_FOUND_DUPP_KEY:
- case HA_ERR_FOUND_DUPP_UNIQUE:
- case HA_ERR_FOREIGN_DUPLICATE_KEY:
- case HA_ERR_NO_REFERENCED_ROW:
- case HA_ERR_ROW_IS_REFERENCED:
- ret= 1;
- break;
- default:
- ret= 0;
- break;
- }
- return (ret);
-}
-
-/**
- Ignore error code specified on command line.
-*/
-
-inline int ignored_error_code(int err_code)
-{
- if (use_slave_mask && bitmap_is_set(&slave_error_mask, err_code))
- {
- statistic_increment(slave_skipped_errors, LOCK_status);
- return 1;
- }
- return err_code == ER_SLAVE_IGNORED_TABLE;
-}
-
-/*
- This function converts an engine's error to a server error.
-
- If the thread does not have an error already reported, it tries to
- define it by calling the engine's method print_error. However, if a
- mapping is not found, it uses the ER_UNKNOWN_ERROR and prints out a
- warning message.
-*/
-int convert_handler_error(int error, THD* thd, TABLE *table)
-{
- uint actual_error= (thd->is_error() ? thd->get_stmt_da()->sql_errno() :
- 0);
-
- if (actual_error == 0)
- {
- table->file->print_error(error, MYF(0));
- actual_error= (thd->is_error() ? thd->get_stmt_da()->sql_errno() :
- ER_UNKNOWN_ERROR);
- if (actual_error == ER_UNKNOWN_ERROR)
- if (global_system_variables.log_warnings)
- sql_print_warning("Unknown error detected %d in handler", error);
- }
-
- return (actual_error);
-}
-
-inline bool concurrency_error_code(int error)
-{
- switch (error)
- {
- case ER_LOCK_WAIT_TIMEOUT:
- case ER_LOCK_DEADLOCK:
- case ER_XA_RBDEADLOCK:
- return TRUE;
- default:
- return (FALSE);
- }
-}
-
-inline bool unexpected_error_code(int unexpected_error)
-{
- switch (unexpected_error)
- {
- case ER_NET_READ_ERROR:
- case ER_NET_ERROR_ON_WRITE:
- case ER_QUERY_INTERRUPTED:
- case ER_STATEMENT_TIMEOUT:
- case ER_CONNECTION_KILLED:
- case ER_SERVER_SHUTDOWN:
- case ER_NEW_ABORTING_CONNECTION:
- return(TRUE);
- default:
- return(FALSE);
- }
-}
-
-/*
- pretty_print_str()
-*/
-
-static void
-pretty_print_str(String *packet, const char *str, int len)
-{
- const char *end= str + len;
- packet->append(STRING_WITH_LEN("'"));
- while (str < end)
- {
- char c;
- switch ((c=*str++)) {
- case '\n': packet->append(STRING_WITH_LEN("\\n")); break;
- case '\r': packet->append(STRING_WITH_LEN("\\r")); break;
- case '\\': packet->append(STRING_WITH_LEN("\\\\")); break;
- case '\b': packet->append(STRING_WITH_LEN("\\b")); break;
- case '\t': packet->append(STRING_WITH_LEN("\\t")); break;
- case '\'': packet->append(STRING_WITH_LEN("\\'")); break;
- case 0 : packet->append(STRING_WITH_LEN("\\0")); break;
- default:
- packet->append(&c, 1);
- break;
- }
- }
- packet->append(STRING_WITH_LEN("'"));
-}
-#endif /* !MYSQL_CLIENT */
-
#ifndef DBUG_OFF
#define DBUG_DUMP_EVENT_BUF(B,L) \
do { \
@@ -587,131 +233,6 @@ pretty_print_str(String *packet, const char *str, int len)
#define DBUG_DUMP_EVENT_BUF(B,L) do { } while(0)
#endif
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-
-/**
- Create a prefix for the temporary files that is to be used for
- load data file name for this master
-
- @param name Store prefix of name here
- @param connection_name Connection name
-
- @return pointer to end of name
-
- @description
- We assume that FN_REFLEN is big enough to hold
- MAX_CONNECTION_NAME * MAX_FILENAME_MBWIDTH characters + 2 numbers +
- a short extension.
-
- The resulting file name has the following parts, each separated with a '-'
- - PREFIX_SQL_LOAD (SQL_LOAD-)
- - If a connection name is given (multi-master setup):
- - Add an extra '-' to mark that this is a multi-master file
- - connection name in lower case, converted to safe file characters.
- (see create_logfile_name_with_suffix()).
- - server_id
- - A last '-' (after server_id).
-*/
-
-static char *load_data_tmp_prefix(char *name,
- LEX_CSTRING *connection_name)
-{
- name= strmov(name, PREFIX_SQL_LOAD);
- if (connection_name->length)
- {
- uint buf_length;
- uint errors;
- /* Add marker that this is a multi-master-file */
- *name++='-';
- /* Convert connection_name to a safe filename */
- buf_length= strconvert(system_charset_info, connection_name->str, FN_REFLEN,
- &my_charset_filename, name, FN_REFLEN, &errors);
- name+= buf_length;
- *name++= '-';
- }
- name= int10_to_str(global_system_variables.server_id, name, 10);
- *name++ = '-';
- *name= '\0'; // For testing prefixes
- return name;
-}
-
-
-/**
- Creates a temporary name for LOAD DATA INFILE
-
- @param buf Store new filename here
- @param file_id File_id (part of file name)
- @param event_server_id Event_id (part of file name)
- @param ext Extension for file name
-
- @return
- Pointer to start of extension
-*/
-
-static char *slave_load_file_stem(char *buf, uint file_id,
- int event_server_id, const char *ext,
- LEX_CSTRING *connection_name)
-{
- char *res;
- res= buf+ unpack_dirname(buf, slave_load_tmpdir);
- to_unix_path(buf);
- buf= load_data_tmp_prefix(res, connection_name);
- buf= int10_to_str(event_server_id, buf, 10);
- *buf++ = '-';
- res= int10_to_str(file_id, buf, 10);
- strmov(res, ext); // Add extension last
- return res; // Pointer to extension
-}
-#endif
-
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-
-/**
- Delete all temporary files used for SQL_LOAD.
-*/
-
-static void cleanup_load_tmpdir(LEX_CSTRING *connection_name)
-{
- MY_DIR *dirp;
- FILEINFO *file;
- uint i;
- char dir[FN_REFLEN], fname[FN_REFLEN];
- char prefbuf[31 + MAX_CONNECTION_NAME* MAX_FILENAME_MBWIDTH + 1];
- DBUG_ENTER("cleanup_load_tmpdir");
-
- unpack_dirname(dir, slave_load_tmpdir);
- if (!(dirp=my_dir(dir, MYF(MY_WME))))
- return;
-
- /*
- When we are deleting temporary files, we should only remove
- the files associated with the server id of our server.
- We don't use event_server_id here because since we've disabled
- direct binlogging of Create_file/Append_file/Exec_load events
- we cannot meet Start_log event in the middle of events from one
- LOAD DATA.
- */
-
- load_data_tmp_prefix(prefbuf, connection_name);
- DBUG_PRINT("enter", ("dir: '%s' prefix: '%s'", dir, prefbuf));
-
- for (i=0 ; i < (uint)dirp->number_of_files; i++)
- {
- file=dirp->dir_entry+i;
- if (is_prefix(file->name, prefbuf))
- {
- fn_format(fname,file->name,slave_load_tmpdir,"",MY_UNPACK_FILENAME);
- mysql_file_delete(key_file_misc, fname, MYF(0));
- }
- }
-
- my_dirend(dirp);
- DBUG_VOID_RETURN;
-}
-#endif
-
-
/*
read_str()
*/
@@ -893,7 +414,7 @@ query_event_uncompress(const Format_description_log_event *description_event,
}
else
{
- new_dst = (char *)my_malloc(alloc_size, MYF(MY_WME));
+ new_dst = (char *)my_malloc(PSI_INSTRUMENT_ME, alloc_size, MYF(MY_WME));
if (!new_dst)
return 1;
@@ -1015,7 +536,7 @@ row_log_event_uncompress(const Format_description_log_event *description_event,
}
else
{
- new_dst = (char *)my_malloc(alloc_size, MYF(MY_WME));
+ new_dst = (char *)my_malloc(PSI_INSTRUMENT_ME, alloc_size, MYF(MY_WME));
if (!new_dst)
return 1;
@@ -1126,80 +647,6 @@ int binlog_buf_uncompress(const char *src, char *dst, uint32 len,
return 0;
}
-#ifndef MYSQL_CLIENT
-
-/**
- Append a version of the 'str' string suitable for use in a query to
- the 'to' string. To generate a correct escaping, the character set
- information in 'csinfo' is used.
-*/
-
-int append_query_string(CHARSET_INFO *csinfo, String *to,
- const char *str, size_t len, bool no_backslash)
-{
- char *beg, *ptr;
- uint32 const orig_len= to->length();
- if (to->reserve(orig_len + len * 2 + 4))
- return 1;
-
- beg= (char*) to->ptr() + to->length();
- ptr= beg;
- if (csinfo->escape_with_backslash_is_dangerous)
- ptr= str_to_hex(ptr, str, len);
- else
- {
- *ptr++= '\'';
- if (!no_backslash)
- {
- ptr+= escape_string_for_mysql(csinfo, ptr, 0, str, len);
- }
- else
- {
- const char *frm_str= str;
-
- for (; frm_str < (str + len); frm_str++)
- {
- /* Using '' way to represent "'" */
- if (*frm_str == '\'')
- *ptr++= *frm_str;
-
- *ptr++= *frm_str;
- }
- }
-
- *ptr++= '\'';
- }
- to->length((uint32)(orig_len + ptr - beg));
- return 0;
-}
-#endif
-
-
-/**
- Prints a "session_var=value" string. Used by mysqlbinlog to print some SET
- commands just before it prints a query.
-*/
-
-#ifdef MYSQL_CLIENT
-
-static bool print_set_option(IO_CACHE* file, uint32 bits_changed,
- uint32 option, uint32 flags, const char* name,
- bool* need_comma)
-{
- if (bits_changed & option)
- {
- if (*need_comma)
- if (my_b_write(file, (uchar*)", ", 2))
- goto err;
- if (my_b_printf(file, "%s=%d", name, MY_TEST(flags & option)))
- goto err;
- *need_comma= 1;
- }
- return 0;
-err:
- return 1;
-}
-#endif
/**************************************************************************
Log_event methods (= the parent class of all events)
@@ -1280,51 +727,6 @@ const char* Log_event::get_type_str()
Log_event::Log_event()
*/
-#ifndef MYSQL_CLIENT
-Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
- :log_pos(0), temp_buf(0), exec_time(0), thd(thd_arg),
- checksum_alg(BINLOG_CHECKSUM_ALG_UNDEF)
-{
- server_id= thd->variables.server_id;
- when= thd->start_time;
- when_sec_part=thd->start_time_sec_part;
-
- if (using_trans)
- cache_type= Log_event::EVENT_TRANSACTIONAL_CACHE;
- else
- cache_type= Log_event::EVENT_STMT_CACHE;
- flags= flags_arg |
- (thd->variables.option_bits & OPTION_SKIP_REPLICATION ?
- LOG_EVENT_SKIP_REPLICATION_F : 0);
-}
-
-/**
- This minimal constructor is for when you are not even sure that there
- is a valid THD. For example in the server when we are shutting down or
- flushing logs after receiving a SIGHUP (then we must write a Rotate to
- the binlog but we have no THD, so we need this minimal constructor).
-*/
-
-Log_event::Log_event()
- :temp_buf(0), exec_time(0), flags(0), cache_type(EVENT_INVALID_CACHE),
- thd(0), checksum_alg(BINLOG_CHECKSUM_ALG_UNDEF)
-{
- server_id= global_system_variables.server_id;
- /*
- We can't call my_time() here as this would cause a call before
- my_init() is called
- */
- when= 0;
- when_sec_part=0;
- log_pos= 0;
-}
-#endif /* !MYSQL_CLIENT */
-
-
-/*
- Log_event::Log_event()
-*/
-
Log_event::Log_event(const char* buf,
const Format_description_log_event* description_event)
:temp_buf(0), exec_time(0), cache_type(Log_event::EVENT_INVALID_CACHE),
@@ -1395,395 +797,6 @@ Log_event::Log_event(const char* buf,
/* otherwise, go on with reading the header from buf (nothing now) */
}
-#ifndef MYSQL_CLIENT
-#ifdef HAVE_REPLICATION
-
-int Log_event::do_update_pos(rpl_group_info *rgi)
-{
- Relay_log_info *rli= rgi->rli;
- DBUG_ENTER("Log_event::do_update_pos");
-
- DBUG_ASSERT(!rli->belongs_to_client());
- /*
- rli is null when (as far as I (Guilhem) know) the caller is
- Load_log_event::do_apply_event *and* that one is called from
- Execute_load_log_event::do_apply_event. In this case, we don't
- do anything here ; Execute_load_log_event::do_apply_event will
- call Log_event::do_apply_event again later with the proper rli.
- Strictly speaking, if we were sure that rli is null only in the
- case discussed above, 'if (rli)' is useless here. But as we are
- not 100% sure, keep it for now.
-
- Matz: I don't think we will need this check with this refactoring.
- */
- if (rli)
- {
- /*
- In parallel execution, delay position update for the events that are
- not part of event groups (format description, rotate, and such) until
- the actual event execution reaches that point.
- */
- if (!rgi->is_parallel_exec || is_group_event(get_type_code()))
- rli->stmt_done(log_pos, thd, rgi);
- }
- DBUG_RETURN(0); // Cannot fail currently
-}
-
-
-Log_event::enum_skip_reason
-Log_event::do_shall_skip(rpl_group_info *rgi)
-{
- Relay_log_info *rli= rgi->rli;
- DBUG_PRINT("info", ("ev->server_id: %lu, ::server_id: %lu,"
- " rli->replicate_same_server_id: %d,"
- " rli->slave_skip_counter: %llu",
- (ulong) server_id,
- (ulong) global_system_variables.server_id,
- rli->replicate_same_server_id,
- rli->slave_skip_counter));
- if ((server_id == global_system_variables.server_id &&
- !rli->replicate_same_server_id) ||
- (rli->slave_skip_counter == 1 && rli->is_in_group()) ||
- (flags & LOG_EVENT_SKIP_REPLICATION_F &&
- opt_replicate_events_marked_for_skip != RPL_SKIP_REPLICATE))
- return EVENT_SKIP_IGNORE;
- if (rli->slave_skip_counter > 0)
- return EVENT_SKIP_COUNT;
- return EVENT_SKIP_NOT;
-}
-
-
-/*
- Log_event::pack_info()
-*/
-
-void Log_event::pack_info(Protocol *protocol)
-{
- protocol->store("", &my_charset_bin);
-}
-
-
-/**
- Only called by SHOW BINLOG EVENTS
-*/
-int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos)
-{
- const char *p= strrchr(log_name, FN_LIBCHAR);
- const char *event_type;
- if (p)
- log_name = p + 1;
-
- protocol->prepare_for_resend();
- protocol->store(log_name, &my_charset_bin);
- protocol->store((ulonglong) pos);
- event_type = get_type_str();
- protocol->store(event_type, strlen(event_type), &my_charset_bin);
- protocol->store((uint32) server_id);
- protocol->store((ulonglong) log_pos);
- pack_info(protocol);
- return protocol->write();
-}
-#endif /* HAVE_REPLICATION */
-
-
-/**
- init_show_field_list() prepares the column names and types for the
- output of SHOW BINLOG EVENTS; it is used only by SHOW BINLOG
- EVENTS.
-*/
-
-void Log_event::init_show_field_list(THD *thd, List<Item>* field_list)
-{
- MEM_ROOT *mem_root= thd->mem_root;
- field_list->push_back(new (mem_root)
- Item_empty_string(thd, "Log_name", 20),
- mem_root);
- field_list->push_back(new (mem_root)
- Item_return_int(thd, "Pos",
- MY_INT64_NUM_DECIMAL_DIGITS,
- MYSQL_TYPE_LONGLONG),
- mem_root);
- field_list->push_back(new (mem_root)
- Item_empty_string(thd, "Event_type", 20),
- mem_root);
- field_list->push_back(new (mem_root)
- Item_return_int(thd, "Server_id", 10,
- MYSQL_TYPE_LONG),
- mem_root);
- field_list->push_back(new (mem_root)
- Item_return_int(thd, "End_log_pos",
- MY_INT64_NUM_DECIMAL_DIGITS,
- MYSQL_TYPE_LONGLONG),
- mem_root);
- field_list->push_back(new (mem_root) Item_empty_string(thd, "Info", 20),
- mem_root);
-}
-
-/**
- A decider of whether to trigger checksum computation or not.
- To be invoked in Log_event::write() stack.
- The decision is positive
-
- S,M) if it's been marked for checksumming with @c checksum_alg
-
- M) otherwise, if @@global.binlog_checksum is not NONE and the event is
- directly written to the binlog file.
- The to-be-cached event decides at @c write_cache() time.
-
- Otherwise the decision is negative.
-
- @note A side effect of the method is altering Log_event::checksum_alg
- it the latter was undefined at calling.
-
- @return true (positive) or false (negative)
-*/
-my_bool Log_event::need_checksum()
-{
- DBUG_ENTER("Log_event::need_checksum");
- my_bool ret;
- /*
- few callers of Log_event::write
- (incl FD::write, FD constructing code on the slave side, Rotate relay log
- and Stop event)
- provides their checksum alg preference through Log_event::checksum_alg.
- */
- if (checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF)
- ret= checksum_alg != BINLOG_CHECKSUM_ALG_OFF;
- else
- {
- ret= binlog_checksum_options && cache_type == Log_event::EVENT_NO_CACHE;
- checksum_alg= ret ? (enum_binlog_checksum_alg)binlog_checksum_options
- : BINLOG_CHECKSUM_ALG_OFF;
- }
- /*
- FD calls the methods before data_written has been calculated.
- The following invariant claims if the current is not the first
- call (and therefore data_written is not zero) then `ret' must be
- TRUE. It may not be null because FD is always checksummed.
- */
-
- DBUG_ASSERT(get_type_code() != FORMAT_DESCRIPTION_EVENT || ret ||
- data_written == 0);
-
- DBUG_ASSERT(!ret ||
- ((checksum_alg == binlog_checksum_options ||
- /*
- Stop event closes the relay-log and its checksum alg
- preference is set by the caller can be different
- from the server's binlog_checksum_options.
- */
- get_type_code() == STOP_EVENT ||
- /*
- Rotate:s can be checksummed regardless of the server's
- binlog_checksum_options. That applies to both
- the local RL's Rotate and the master's Rotate
- which IO thread instantiates via queue_binlog_ver_3_event.
- */
- get_type_code() == ROTATE_EVENT ||
- get_type_code() == START_ENCRYPTION_EVENT ||
- /* FD is always checksummed */
- get_type_code() == FORMAT_DESCRIPTION_EVENT) &&
- checksum_alg != BINLOG_CHECKSUM_ALG_OFF));
-
- DBUG_ASSERT(checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF);
-
- DBUG_ASSERT(((get_type_code() != ROTATE_EVENT &&
- get_type_code() != STOP_EVENT) ||
- get_type_code() != FORMAT_DESCRIPTION_EVENT) ||
- cache_type == Log_event::EVENT_NO_CACHE);
-
- DBUG_RETURN(ret);
-}
-
-int Log_event_writer::write_internal(const uchar *pos, size_t len)
-{
- if (my_b_safe_write(file, pos, len))
- return 1;
- bytes_written+= len;
- return 0;
-}
-
-/*
- as soon as encryption produces the first output block, write event_len
- where it should be in a valid event header
-*/
-int Log_event_writer::maybe_write_event_len(uchar *pos, size_t len)
-{
- if (len && event_len)
- {
- DBUG_ASSERT(len >= EVENT_LEN_OFFSET);
- if (write_internal(pos + EVENT_LEN_OFFSET - 4, 4))
- return 1;
- int4store(pos + EVENT_LEN_OFFSET - 4, event_len);
- event_len= 0;
- }
- return 0;
-}
-
-int Log_event_writer::encrypt_and_write(const uchar *pos, size_t len)
-{
- uchar *dst= 0;
- size_t dstsize= 0;
-
- if (ctx)
- {
- dstsize= encryption_encrypted_length((uint)len, ENCRYPTION_KEY_SYSTEM_DATA,
- crypto->key_version);
- if (!(dst= (uchar*)my_safe_alloca(dstsize)))
- return 1;
-
- uint dstlen;
- if (len == 0)
- dstlen= 0;
- else if (encryption_ctx_update(ctx, pos, (uint)len, dst, &dstlen))
- goto err;
-
- if (maybe_write_event_len(dst, dstlen))
- return 1;
- pos= dst;
- len= dstlen;
- }
- if (write_internal(pos, len))
- goto err;
-
- my_safe_afree(dst, dstsize);
- return 0;
-err:
- my_safe_afree(dst, dstsize);
- return 1;
-}
-
-int Log_event_writer::write_header(uchar *pos, size_t len)
-{
- DBUG_ENTER("Log_event_writer::write_header");
- /*
- recording checksum of FD event computed with dropped
- possibly active LOG_EVENT_BINLOG_IN_USE_F flag.
- Similar step at verication: the active flag is dropped before
- checksum computing.
- */
- if (checksum_len)
- {
- uchar save=pos[FLAGS_OFFSET];
- pos[FLAGS_OFFSET]&= ~LOG_EVENT_BINLOG_IN_USE_F;
- crc= my_checksum(0, pos, len);
- pos[FLAGS_OFFSET]= save;
- }
-
- if (ctx)
- {
- uchar iv[BINLOG_IV_LENGTH];
- crypto->set_iv(iv, (uint32)my_b_safe_tell(file));
- if (encryption_ctx_init(ctx, crypto->key, crypto->key_length,
- iv, sizeof(iv), ENCRYPTION_FLAG_ENCRYPT | ENCRYPTION_FLAG_NOPAD,
- ENCRYPTION_KEY_SYSTEM_DATA, crypto->key_version))
- DBUG_RETURN(1);
-
- DBUG_ASSERT(len >= LOG_EVENT_HEADER_LEN);
- event_len= uint4korr(pos + EVENT_LEN_OFFSET);
- DBUG_ASSERT(event_len >= len);
- memcpy(pos + EVENT_LEN_OFFSET, pos, 4);
- pos+= 4;
- len-= 4;
- }
- DBUG_RETURN(encrypt_and_write(pos, len));
-}
-
-int Log_event_writer::write_data(const uchar *pos, size_t len)
-{
- DBUG_ENTER("Log_event_writer::write_data");
- if (checksum_len)
- crc= my_checksum(crc, pos, len);
-
- DBUG_RETURN(encrypt_and_write(pos, len));
-}
-
-int Log_event_writer::write_footer()
-{
- DBUG_ENTER("Log_event_writer::write_footer");
- if (checksum_len)
- {
- uchar checksum_buf[BINLOG_CHECKSUM_LEN];
- int4store(checksum_buf, crc);
- if (encrypt_and_write(checksum_buf, BINLOG_CHECKSUM_LEN))
- DBUG_RETURN(ER_ERROR_ON_WRITE);
- }
- if (ctx)
- {
- uint dstlen;
- uchar dst[MY_AES_BLOCK_SIZE*2];
- if (encryption_ctx_finish(ctx, dst, &dstlen))
- DBUG_RETURN(1);
- if (maybe_write_event_len(dst, dstlen) || write_internal(dst, dstlen))
- DBUG_RETURN(ER_ERROR_ON_WRITE);
- }
- DBUG_RETURN(0);
-}
-
-/*
- Log_event::write_header()
-*/
-
-bool Log_event::write_header(size_t event_data_length)
-{
- uchar header[LOG_EVENT_HEADER_LEN];
- ulong now;
- DBUG_ENTER("Log_event::write_header");
- DBUG_PRINT("enter", ("filepos: %lld length: %zu type: %d",
- (longlong) writer->pos(), event_data_length,
- (int) get_type_code()));
-
- writer->checksum_len= need_checksum() ? BINLOG_CHECKSUM_LEN : 0;
-
- /* Store number of bytes that will be written by this event */
- data_written= event_data_length + sizeof(header) + writer->checksum_len;
-
- /*
- log_pos != 0 if this is relay-log event. In this case we should not
- change the position
- */
-
- if (is_artificial_event())
- {
- /*
- Artificial events are automatically generated and do not exist
- in master's binary log, so log_pos should be set to 0.
- */
- log_pos= 0;
- }
- else if (!log_pos)
- {
- /*
- Calculate the position of where the next event will start
- (end of this event, that is).
- */
-
- log_pos= writer->pos() + data_written;
-
- DBUG_EXECUTE_IF("dbug_master_binlog_over_2GB", log_pos += (1ULL <<31););
- }
-
- now= get_time(); // Query start time
-
- /*
- Header will be of size LOG_EVENT_HEADER_LEN for all events, except for
- FORMAT_DESCRIPTION_EVENT and ROTATE_EVENT, where it will be
- LOG_EVENT_MINIMAL_HEADER_LEN (remember these 2 have a frozen header,
- because we read them before knowing the format).
- */
-
- int4store(header, now); // timestamp
- header[EVENT_TYPE_OFFSET]= get_type_code();
- int4store(header+ SERVER_ID_OFFSET, server_id);
- int4store(header+ EVENT_LEN_OFFSET, data_written);
- int4store(header+ LOG_POS_OFFSET, log_pos);
- int2store(header + FLAGS_OFFSET, flags);
-
- bool ret= writer->write_header(header, sizeof(header));
- DBUG_RETURN(ret);
-}
-
-#endif /* !MYSQL_CLIENT */
/**
This needn't be format-tolerant, because we only parse the first
@@ -1864,7 +877,7 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
*/
sz += MY_AES_BLOCK_SIZE;
#endif
- char *newpkt= (char*)my_malloc(sz, MYF(MY_WME));
+ char *newpkt= (char*)my_malloc(PSI_INSTRUMENT_ME, sz, MYF(MY_WME));
if (!newpkt)
DBUG_RETURN(LOG_READ_MEM);
memcpy(newpkt, packet->ptr(), ev_offset);
@@ -2169,6 +1182,9 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
case XID_EVENT:
ev = new Xid_log_event(buf, fdle);
break;
+ case XA_PREPARE_LOG_EVENT:
+ ev = new XA_prepare_log_event(buf, fdle);
+ break;
case RAND_EVENT:
ev = new Rand_log_event(buf, fdle);
break;
@@ -2220,7 +1236,6 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
case PREVIOUS_GTIDS_LOG_EVENT:
case TRANSACTION_CONTEXT_EVENT:
case VIEW_CHANGE_EVENT:
- case XA_PREPARE_LOG_EVENT:
ev= new Ignorable_log_event(buf, fdle,
get_type_str((Log_event_type) event_type));
break;
@@ -2298,2201 +1313,6 @@ exit:
DBUG_RETURN(ev);
}
-#ifdef MYSQL_CLIENT
-
-static bool hexdump_minimal_header_to_io_cache(IO_CACHE *file,
- my_off_t offset,
- uchar *ptr)
-{
- DBUG_ASSERT(LOG_EVENT_MINIMAL_HEADER_LEN == 19);
-
- /*
- Pretty-print the first LOG_EVENT_MINIMAL_HEADER_LEN (19) bytes of the
- common header, which contains the basic information about the log event.
- Every event will have at least this much header, but events could contain
- more headers (which must be printed by other methods, if desired).
- */
- char emit_buf[120]; // Enough for storing one line
- size_t emit_buf_written;
-
- if (my_b_printf(file,
- "# "
- "|Timestamp "
- "|Type "
- "|Master ID "
- "|Size "
- "|Master Pos "
- "|Flags\n"))
- goto err;
- emit_buf_written=
- my_snprintf(emit_buf, sizeof(emit_buf),
- "# %8llx " /* Position */
- "|%02x %02x %02x %02x " /* Timestamp */
- "|%02x " /* Type */
- "|%02x %02x %02x %02x " /* Master ID */
- "|%02x %02x %02x %02x " /* Size */
- "|%02x %02x %02x %02x " /* Master Pos */
- "|%02x %02x\n", /* Flags */
- (ulonglong) offset, /* Position */
- ptr[0], ptr[1], ptr[2], ptr[3], /* Timestamp */
- ptr[4], /* Type */
- ptr[5], ptr[6], ptr[7], ptr[8], /* Master ID */
- ptr[9], ptr[10], ptr[11], ptr[12], /* Size */
- ptr[13], ptr[14], ptr[15], ptr[16], /* Master Pos */
- ptr[17], ptr[18]); /* Flags */
-
- DBUG_ASSERT(static_cast<size_t>(emit_buf_written) < sizeof(emit_buf));
- if (my_b_write(file, reinterpret_cast<uchar*>(emit_buf), emit_buf_written) ||
- my_b_write(file, (uchar*)"#\n", 2))
- goto err;
-
- return 0;
-err:
- return 1;
-}
-
-
-/*
- The number of bytes to print per line. Should be an even number,
- and "hexdump -C" uses 16, so we'll duplicate that here.
-*/
-#define HEXDUMP_BYTES_PER_LINE 16
-
-static void format_hex_line(char *emit_buff)
-{
- memset(emit_buff + 1, ' ',
- 1 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
- HEXDUMP_BYTES_PER_LINE);
- emit_buff[0]= '#';
- emit_buff[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 1]= '|';
- emit_buff[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
- HEXDUMP_BYTES_PER_LINE]= '|';
- emit_buff[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
- HEXDUMP_BYTES_PER_LINE + 1]= '\n';
- emit_buff[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
- HEXDUMP_BYTES_PER_LINE + 2]= '\0';
-}
-
-static bool hexdump_data_to_io_cache(IO_CACHE *file,
- my_off_t offset,
- uchar *ptr,
- my_off_t size)
-{
- /*
- 2 = '# '
- 8 = address
- 2 = ' '
- (HEXDUMP_BYTES_PER_LINE * 3 + 1) = Each byte prints as two hex digits,
- plus a space
- 2 = ' |'
- HEXDUMP_BYTES_PER_LINE = text representation
- 2 = '|\n'
- 1 = '\0'
- */
- char emit_buffer[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
- HEXDUMP_BYTES_PER_LINE + 2 + 1 ];
- char *h,*c;
- my_off_t i;
-
- if (size == 0)
- return 0; // ok, nothing to do
-
- format_hex_line(emit_buffer);
- /*
- Print the rest of the event (without common header)
- */
- my_off_t starting_offset = offset;
- for (i= 0,
- c= emit_buffer + 2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2,
- h= emit_buffer + 2 + 8 + 2;
- i < size;
- i++, ptr++)
- {
- my_snprintf(h, 4, "%02x ", *ptr);
- h+= 3;
-
- *c++= my_isprint(&my_charset_bin, *ptr) ? *ptr : '.';
-
- /* Print in groups of HEXDUMP_BYTES_PER_LINE characters. */
- if ((i % HEXDUMP_BYTES_PER_LINE) == (HEXDUMP_BYTES_PER_LINE - 1))
- {
- /* remove \0 left after printing hex byte representation */
- *h= ' ';
- /* prepare space to print address */
- memset(emit_buffer + 2, ' ', 8);
- /* print address */
- size_t const emit_buf_written= my_snprintf(emit_buffer + 2, 9, "%8llx",
- (ulonglong) starting_offset);
- /* remove \0 left after printing address */
- emit_buffer[2 + emit_buf_written]= ' ';
- if (my_b_write(file, reinterpret_cast<uchar*>(emit_buffer),
- sizeof(emit_buffer) - 1))
- goto err;
- c= emit_buffer + 2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2;
- h= emit_buffer + 2 + 8 + 2;
- format_hex_line(emit_buffer);
- starting_offset+= HEXDUMP_BYTES_PER_LINE;
- }
- else if ((i % (HEXDUMP_BYTES_PER_LINE / 2))
- == ((HEXDUMP_BYTES_PER_LINE / 2) - 1))
- {
- /*
- In the middle of the group of HEXDUMP_BYTES_PER_LINE, emit an extra
- space in the hex string, to make two groups.
- */
- *h++= ' ';
- }
-
- }
-
- /*
- There is still data left in our buffer, which means that the previous
- line was not perfectly HEXDUMP_BYTES_PER_LINE characters, so write an
- incomplete line, with spaces to pad out to the same length as a full
- line would be, to make things more readable.
- */
- if (h != emit_buffer + 2 + 8 + 2)
- {
- *h= ' ';
- *c++= '|'; *c++= '\n';
- memset(emit_buffer + 2, ' ', 8);
- size_t const emit_buf_written= my_snprintf(emit_buffer + 2, 9, "%8llx",
- (ulonglong) starting_offset);
- emit_buffer[2 + emit_buf_written]= ' ';
- /* pad unprinted area */
- memset(h, ' ',
- (HEXDUMP_BYTES_PER_LINE * 3 + 1) - (h - (emit_buffer + 2 + 8 + 2)));
- if (my_b_write(file, reinterpret_cast<uchar*>(emit_buffer),
- c - emit_buffer))
- goto err;
- }
- if (my_b_write(file, (uchar*)"#\n", 2))
- goto err;
-
- return 0;
-err:
- return 1;
-}
-
-/*
- Log_event::print_header()
-*/
-
-bool Log_event::print_header(IO_CACHE* file,
- PRINT_EVENT_INFO* print_event_info,
- bool is_more __attribute__((unused)))
-{
- char llbuff[22];
- my_off_t hexdump_from= print_event_info->hexdump_from;
- DBUG_ENTER("Log_event::print_header");
-
- if (my_b_write_byte(file, '#') ||
- print_timestamp(file) ||
- my_b_printf(file, " server id %lu end_log_pos %s ", (ulong) server_id,
- llstr(log_pos,llbuff)))
- goto err;
-
- /* print the checksum */
-
- if (checksum_alg != BINLOG_CHECKSUM_ALG_OFF &&
- checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF)
- {
- char checksum_buf[BINLOG_CHECKSUM_LEN * 2 + 4]; // to fit to "%p "
- size_t const bytes_written=
- my_snprintf(checksum_buf, sizeof(checksum_buf), "0x%08x ", crc);
- if (my_b_printf(file, "%s ", get_type(&binlog_checksum_typelib,
- checksum_alg)) ||
- my_b_printf(file, checksum_buf, bytes_written))
- goto err;
- }
-
- /* mysqlbinlog --hexdump */
- if (print_event_info->hexdump_from)
- {
- my_b_write_byte(file, '\n');
- uchar *ptr= (uchar*)temp_buf;
- my_off_t size= uint4korr(ptr + EVENT_LEN_OFFSET);
- my_off_t hdr_len= get_header_len(print_event_info->common_header_len);
-
- size-= hdr_len;
-
- if (my_b_printf(file, "# Position\n"))
- goto err;
-
- /* Write the header, nicely formatted by field. */
- if (hexdump_minimal_header_to_io_cache(file, hexdump_from, ptr))
- goto err;
-
- ptr+= hdr_len;
- hexdump_from+= hdr_len;
-
- /* Print the rest of the data, mimicking "hexdump -C" output. */
- if (hexdump_data_to_io_cache(file, hexdump_from, ptr, size))
- goto err;
-
- /*
- Prefix the next line so that the output from print_helper()
- will appear as a comment.
- */
- if (my_b_write(file, (uchar*)"# Event: ", 9))
- goto err;
- }
-
- DBUG_RETURN(0);
-
-err:
- DBUG_RETURN(1);
-}
-
-
-/**
- Prints a quoted string to io cache.
- Control characters are displayed as hex sequence, e.g. \x00
- Single-quote and backslash characters are escaped with a \
-
- @param[in] file IO cache
- @param[in] prt Pointer to string
- @param[in] length String length
-*/
-
-static void
-my_b_write_quoted(IO_CACHE *file, const uchar *ptr, uint length)
-{
- const uchar *s;
- my_b_write_byte(file, '\'');
- for (s= ptr; length > 0 ; s++, length--)
- {
- if (*s > 0x1F)
- my_b_write_byte(file, *s);
- else if (*s == '\'')
- my_b_write(file, (uchar*)"\\'", 2);
- else if (*s == '\\')
- my_b_write(file, (uchar*)"\\\\", 2);
- else
- {
- uchar hex[10];
- size_t len= my_snprintf((char*) hex, sizeof(hex), "%s%02x", "\\x", *s);
- my_b_write(file, hex, len);
- }
- }
- my_b_write_byte(file, '\'');
-}
-
-
-/**
- Prints a bit string to io cache in format b'1010'.
-
- @param[in] file IO cache
- @param[in] ptr Pointer to string
- @param[in] nbits Number of bits
-*/
-static void
-my_b_write_bit(IO_CACHE *file, const uchar *ptr, uint nbits)
-{
- uint bitnum, nbits8= ((nbits + 7) / 8) * 8, skip_bits= nbits8 - nbits;
- my_b_write(file, (uchar*)"b'", 2);
- for (bitnum= skip_bits ; bitnum < nbits8; bitnum++)
- {
- int is_set= (ptr[(bitnum) / 8] >> (7 - bitnum % 8)) & 0x01;
- my_b_write_byte(file, (is_set ? '1' : '0'));
- }
- my_b_write_byte(file, '\'');
-}
-
-
-/**
- Prints a packed string to io cache.
- The string consists of length packed to 1 or 2 bytes,
- followed by string data itself.
-
- @param[in] file IO cache
- @param[in] ptr Pointer to string
- @param[in] length String size
-
- @retval - number of bytes scanned.
-*/
-static size_t
-my_b_write_quoted_with_length(IO_CACHE *file, const uchar *ptr, uint length)
-{
- if (length < 256)
- {
- length= *ptr;
- my_b_write_quoted(file, ptr + 1, length);
- return length + 1;
- }
- else
- {
- length= uint2korr(ptr);
- my_b_write_quoted(file, ptr + 2, length);
- return length + 2;
- }
-}
-
-
-/**
- Prints a 32-bit number in both signed and unsigned representation
-
- @param[in] file IO cache
- @param[in] sl Signed number
- @param[in] ul Unsigned number
-*/
-static bool
-my_b_write_sint32_and_uint32(IO_CACHE *file, int32 si, uint32 ui)
-{
- bool res= my_b_printf(file, "%d", si);
- if (si < 0)
- if (my_b_printf(file, " (%u)", ui))
- res= 1;
- return res;
-}
-
-
-/**
- Print a packed value of the given SQL type into IO cache
-
- @param[in] file IO cache
- @param[in] ptr Pointer to string
- @param[in] type Column type
- @param[in] meta Column meta information
- @param[out] typestr SQL type string buffer (for verbose output)
- @param[out] typestr_length Size of typestr
-
- @retval - number of bytes scanned from ptr.
- Except in case of NULL, in which case we return 1 to indicate ok
-*/
-
-static size_t
-log_event_print_value(IO_CACHE *file, PRINT_EVENT_INFO *print_event_info,
- const uchar *ptr, uint type, uint meta,
- char *typestr, size_t typestr_length)
-{
- uint32 length= 0;
-
- if (type == MYSQL_TYPE_STRING)
- {
- if (meta >= 256)
- {
- uint byte0= meta >> 8;
- uint byte1= meta & 0xFF;
-
- if ((byte0 & 0x30) != 0x30)
- {
- /* a long CHAR() field: see #37426 */
- length= byte1 | (((byte0 & 0x30) ^ 0x30) << 4);
- type= byte0 | 0x30;
- }
- else
- length = meta & 0xFF;
- }
- else
- length= meta;
- }
-
- switch (type) {
- case MYSQL_TYPE_LONG:
- {
- strmake(typestr, "INT", typestr_length);
- if (!ptr)
- goto return_null;
-
- int32 si= sint4korr(ptr);
- uint32 ui= uint4korr(ptr);
- my_b_write_sint32_and_uint32(file, si, ui);
- return 4;
- }
-
- case MYSQL_TYPE_TINY:
- {
- strmake(typestr, "TINYINT", typestr_length);
- if (!ptr)
- goto return_null;
-
- my_b_write_sint32_and_uint32(file, (int) (signed char) *ptr,
- (uint) (unsigned char) *ptr);
- return 1;
- }
-
- case MYSQL_TYPE_SHORT:
- {
- strmake(typestr, "SHORTINT", typestr_length);
- if (!ptr)
- goto return_null;
-
- int32 si= (int32) sint2korr(ptr);
- uint32 ui= (uint32) uint2korr(ptr);
- my_b_write_sint32_and_uint32(file, si, ui);
- return 2;
- }
-
- case MYSQL_TYPE_INT24:
- {
- strmake(typestr, "MEDIUMINT", typestr_length);
- if (!ptr)
- goto return_null;
-
- int32 si= sint3korr(ptr);
- uint32 ui= uint3korr(ptr);
- my_b_write_sint32_and_uint32(file, si, ui);
- return 3;
- }
-
- case MYSQL_TYPE_LONGLONG:
- {
- strmake(typestr, "LONGINT", typestr_length);
- if (!ptr)
- goto return_null;
-
- char tmp[64];
- size_t length;
- longlong si= sint8korr(ptr);
- length= (longlong10_to_str(si, tmp, -10) - tmp);
- my_b_write(file, (uchar*)tmp, length);
- if (si < 0)
- {
- ulonglong ui= uint8korr(ptr);
- longlong10_to_str((longlong) ui, tmp, 10);
- my_b_printf(file, " (%s)", tmp);
- }
- return 8;
- }
-
- case MYSQL_TYPE_NEWDECIMAL:
- {
- uint precision= meta >> 8;
- uint decimals= meta & 0xFF;
- my_snprintf(typestr, typestr_length, "DECIMAL(%d,%d)",
- precision, decimals);
- if (!ptr)
- goto return_null;
-
- uint bin_size= my_decimal_get_binary_size(precision, decimals);
- my_decimal dec((const uchar *) ptr, precision, decimals);
- int length= DECIMAL_MAX_STR_LENGTH;
- char buff[DECIMAL_MAX_STR_LENGTH + 1];
- decimal2string(&dec, buff, &length, 0, 0, 0);
- my_b_write(file, (uchar*)buff, length);
- return bin_size;
- }
-
- case MYSQL_TYPE_FLOAT:
- {
- strmake(typestr, "FLOAT", typestr_length);
- if (!ptr)
- goto return_null;
-
- float fl;
- float4get(fl, ptr);
- char tmp[320];
- sprintf(tmp, "%-20g", (double) fl);
- my_b_printf(file, "%s", tmp); /* my_snprintf doesn't support %-20g */
- return 4;
- }
-
- case MYSQL_TYPE_DOUBLE:
- {
- double dbl;
- strmake(typestr, "DOUBLE", typestr_length);
- if (!ptr)
- goto return_null;
-
- float8get(dbl, ptr);
- char tmp[320];
- sprintf(tmp, "%-.20g", dbl); /* strmake doesn't support %-20g */
- my_b_printf(file, tmp, "%s");
- return 8;
- }
-
- case MYSQL_TYPE_BIT:
- {
- /* Meta-data: bit_len, bytes_in_rec, 2 bytes */
- uint nbits= ((meta >> 8) * 8) + (meta & 0xFF);
- my_snprintf(typestr, typestr_length, "BIT(%d)", nbits);
- if (!ptr)
- goto return_null;
-
- length= (nbits + 7) / 8;
- my_b_write_bit(file, ptr, nbits);
- return length;
- }
-
- case MYSQL_TYPE_TIMESTAMP:
- {
- strmake(typestr, "TIMESTAMP", typestr_length);
- if (!ptr)
- goto return_null;
-
- uint32 i32= uint4korr(ptr);
- my_b_printf(file, "%d", i32);
- return 4;
- }
-
- case MYSQL_TYPE_TIMESTAMP2:
- {
- my_snprintf(typestr, typestr_length, "TIMESTAMP(%d)", meta);
- if (!ptr)
- goto return_null;
-
- char buf[MAX_DATE_STRING_REP_LENGTH];
- struct timeval tm;
- my_timestamp_from_binary(&tm, ptr, meta);
- int buflen= my_timeval_to_str(&tm, buf, meta);
- my_b_write(file, (uchar*)buf, buflen);
- return my_timestamp_binary_length(meta);
- }
-
- case MYSQL_TYPE_DATETIME:
- {
- strmake(typestr, "DATETIME", typestr_length);
- if (!ptr)
- goto return_null;
-
- ulong d, t;
- uint64 i64= uint8korr(ptr); /* YYYYMMDDhhmmss */
- d= (ulong) (i64 / 1000000);
- t= (ulong) (i64 % 1000000);
-
- my_b_printf(file, "'%04d-%02d-%02d %02d:%02d:%02d'",
- (int) (d / 10000), (int) (d % 10000) / 100, (int) (d % 100),
- (int) (t / 10000), (int) (t % 10000) / 100, (int) t % 100);
- return 8;
- }
-
- case MYSQL_TYPE_DATETIME2:
- {
- my_snprintf(typestr, typestr_length, "DATETIME(%d)", meta);
- if (!ptr)
- goto return_null;
-
- char buf[MAX_DATE_STRING_REP_LENGTH];
- MYSQL_TIME ltime;
- longlong packed= my_datetime_packed_from_binary(ptr, meta);
- TIME_from_longlong_datetime_packed(&ltime, packed);
- int buflen= my_datetime_to_str(&ltime, buf, meta);
- my_b_write_quoted(file, (uchar *) buf, buflen);
- return my_datetime_binary_length(meta);
- }
-
- case MYSQL_TYPE_TIME:
- {
- strmake(typestr, "TIME", typestr_length);
- if (!ptr)
- goto return_null;
-
- int32 tmp= sint3korr(ptr);
- int32 i32= tmp >= 0 ? tmp : - tmp;
- const char *sign= tmp < 0 ? "-" : "";
- my_b_printf(file, "'%s%02d:%02d:%02d'",
- sign, i32 / 10000, (i32 % 10000) / 100, i32 % 100, i32);
- return 3;
- }
-
- case MYSQL_TYPE_TIME2:
- {
- my_snprintf(typestr, typestr_length, "TIME(%d)", meta);
- if (!ptr)
- goto return_null;
-
- char buf[MAX_DATE_STRING_REP_LENGTH];
- MYSQL_TIME ltime;
- longlong packed= my_time_packed_from_binary(ptr, meta);
- TIME_from_longlong_time_packed(&ltime, packed);
- int buflen= my_time_to_str(&ltime, buf, meta);
- my_b_write_quoted(file, (uchar *) buf, buflen);
- return my_time_binary_length(meta);
- }
-
- case MYSQL_TYPE_NEWDATE:
- {
- strmake(typestr, "DATE", typestr_length);
- if (!ptr)
- goto return_null;
-
- uint32 tmp= uint3korr(ptr);
- int part;
- char buf[11];
- char *pos= &buf[10]; // start from '\0' to the beginning
-
- /* Copied from field.cc */
- *pos--=0; // End NULL
- part=(int) (tmp & 31);
- *pos--= (char) ('0'+part%10);
- *pos--= (char) ('0'+part/10);
- *pos--= ':';
- part=(int) (tmp >> 5 & 15);
- *pos--= (char) ('0'+part%10);
- *pos--= (char) ('0'+part/10);
- *pos--= ':';
- part=(int) (tmp >> 9);
- *pos--= (char) ('0'+part%10); part/=10;
- *pos--= (char) ('0'+part%10); part/=10;
- *pos--= (char) ('0'+part%10); part/=10;
- *pos= (char) ('0'+part);
- my_b_printf(file , "'%s'", buf);
- return 3;
- }
-
- case MYSQL_TYPE_DATE:
- {
- strmake(typestr, "DATE", typestr_length);
- if (!ptr)
- goto return_null;
-
- uint i32= uint3korr(ptr);
- my_b_printf(file , "'%04d:%02d:%02d'",
- (int)(i32 / (16L * 32L)), (int)(i32 / 32L % 16L),
- (int)(i32 % 32L));
- return 3;
- }
-
- case MYSQL_TYPE_YEAR:
- {
- strmake(typestr, "YEAR", typestr_length);
- if (!ptr)
- goto return_null;
-
- uint32 i32= *ptr;
- my_b_printf(file, "%04d", i32+ 1900);
- return 1;
- }
-
- case MYSQL_TYPE_ENUM:
- switch (meta & 0xFF) {
- case 1:
- strmake(typestr, "ENUM(1 byte)", typestr_length);
- if (!ptr)
- goto return_null;
-
- my_b_printf(file, "%d", (int) *ptr);
- return 1;
- case 2:
- {
- strmake(typestr, "ENUM(2 bytes)", typestr_length);
- if (!ptr)
- goto return_null;
-
- int32 i32= uint2korr(ptr);
- my_b_printf(file, "%d", i32);
- return 2;
- }
- default:
- my_b_printf(file, "!! Unknown ENUM packlen=%d", meta & 0xFF);
- return 0;
- }
- break;
-
- case MYSQL_TYPE_SET:
- my_snprintf(typestr, typestr_length, "SET(%d bytes)", meta & 0xFF);
- if (!ptr)
- goto return_null;
-
- my_b_write_bit(file, ptr , (meta & 0xFF) * 8);
- return meta & 0xFF;
-
- case MYSQL_TYPE_BLOB:
- switch (meta) {
- case 1:
- strmake(typestr, "TINYBLOB/TINYTEXT", typestr_length);
- if (!ptr)
- goto return_null;
-
- length= *ptr;
- my_b_write_quoted(file, ptr + 1, length);
- return length + 1;
- case 2:
- strmake(typestr, "BLOB/TEXT", typestr_length);
- if (!ptr)
- goto return_null;
-
- length= uint2korr(ptr);
- my_b_write_quoted(file, ptr + 2, length);
- return length + 2;
- case 3:
- strmake(typestr, "MEDIUMBLOB/MEDIUMTEXT", typestr_length);
- if (!ptr)
- goto return_null;
-
- length= uint3korr(ptr);
- my_b_write_quoted(file, ptr + 3, length);
- return length + 3;
- case 4:
- strmake(typestr, "LONGBLOB/LONGTEXT", typestr_length);
- if (!ptr)
- goto return_null;
-
- length= uint4korr(ptr);
- my_b_write_quoted(file, ptr + 4, length);
- return length + 4;
- default:
- my_b_printf(file, "!! Unknown BLOB packlen=%d", length);
- return 0;
- }
-
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VAR_STRING:
- length= meta;
- my_snprintf(typestr, typestr_length, "VARSTRING(%d)", length);
- if (!ptr)
- goto return_null;
-
- return my_b_write_quoted_with_length(file, ptr, length);
-
- case MYSQL_TYPE_STRING:
- my_snprintf(typestr, typestr_length, "STRING(%d)", length);
- if (!ptr)
- goto return_null;
-
- return my_b_write_quoted_with_length(file, ptr, length);
-
- case MYSQL_TYPE_DECIMAL:
- print_event_info->flush_for_error();
- fprintf(stderr, "\nError: Found Old DECIMAL (mysql-4.1 or earlier). "
- "Not enough metadata to display the value.\n");
- break;
- default:
- print_event_info->flush_for_error();
- fprintf(stderr,
- "\nError: Don't know how to handle column type: %d meta: %d (%04x)\n",
- type, meta, meta);
- break;
- }
- *typestr= 0;
- return 0;
-
-return_null:
- return my_b_write(file, (uchar*) "NULL", 4) ? 0 : 1;
-}
-
-
-/**
- Print a packed row into IO cache
-
- @param[in] file IO cache
- @param[in] td Table definition
- @param[in] print_event_into Print parameters
- @param[in] cols_bitmap Column bitmaps.
- @param[in] value Pointer to packed row
- @param[in] prefix Row's SQL clause ("SET", "WHERE", etc)
-
- @retval 0 error
- # number of bytes scanned.
-*/
-
-
-size_t
-Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td,
- PRINT_EVENT_INFO *print_event_info,
- MY_BITMAP *cols_bitmap,
- const uchar *value, const uchar *prefix,
- const my_bool no_fill_output)
-{
- const uchar *value0= value;
- const uchar *null_bits= value;
- uint null_bit_index= 0;
- char typestr[64]= "";
-
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- /* Storing the review SQL */
- IO_CACHE *review_sql= &print_event_info->review_sql_cache;
- LEX_STRING review_str;
-#endif
-
- /*
- Skip metadata bytes which gives the information about nullabity of master
- columns. Master writes one bit for each affected column.
- */
-
- value+= (bitmap_bits_set(cols_bitmap) + 7) / 8;
-
- if (!no_fill_output)
- if (my_b_printf(file, "%s", prefix))
- goto err;
-
- for (uint i= 0; i < (uint)td->size(); i ++)
- {
- size_t size;
- int is_null= (null_bits[null_bit_index / 8]
- >> (null_bit_index % 8)) & 0x01;
-
- if (bitmap_is_set(cols_bitmap, i) == 0)
- continue;
-
- if (!no_fill_output)
- if (my_b_printf(file, "### @%d=", static_cast<int>(i + 1)))
- goto err;
-
- if (!is_null)
- {
- size_t fsize= td->calc_field_size((uint)i, (uchar*) value);
- if (value + fsize > m_rows_end)
- {
- if (!no_fill_output)
- if (my_b_printf(file, "***Corrupted replication event was detected."
- " Not printing the value***\n"))
- goto err;
- value+= fsize;
- return 0;
- }
- }
-
- if (!no_fill_output)
- {
- size= log_event_print_value(file, print_event_info, is_null? NULL: value,
- td->type(i), td->field_metadata(i),
- typestr, sizeof(typestr));
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- if (need_flashback_review)
- {
- String tmp_str, hex_str;
- IO_CACHE tmp_cache;
-
- // Using a tmp IO_CACHE to get the value output
- open_cached_file(&tmp_cache, NULL, NULL, 0, MYF(MY_WME | MY_NABP));
- size= log_event_print_value(&tmp_cache, print_event_info,
- is_null ? NULL: value,
- td->type(i), td->field_metadata(i),
- typestr, sizeof(typestr));
- error= copy_event_cache_to_string_and_reinit(&tmp_cache, &review_str);
- close_cached_file(&tmp_cache);
- if (unlikely(error))
- return 0;
-
- switch (td->type(i)) // Converting a string to HEX format
- {
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_STRING:
- case MYSQL_TYPE_BLOB:
- // Avoid write_pos changed to a new area
- // tmp_str.free();
- tmp_str.append(review_str.str + 1, review_str.length - 2); // Removing quotation marks
- if (hex_str.alloc(tmp_str.length()*2+1)) // If out of memory
- {
- fprintf(stderr, "\nError: Out of memory. "
- "Could not print correct binlog event.\n");
- exit(1);
- }
- octet2hex((char*) hex_str.ptr(), tmp_str.ptr(), tmp_str.length());
- if (my_b_printf(review_sql, ", UNHEX('%s')", hex_str.ptr()))
- goto err;
- break;
- default:
- tmp_str.free();
- if (tmp_str.append(review_str.str, review_str.length) ||
- my_b_printf(review_sql, ", %s", tmp_str.ptr()))
- goto err;
- break;
- }
- my_free(revieww_str.str);
- }
-#endif
- }
- else
- {
- IO_CACHE tmp_cache;
- open_cached_file(&tmp_cache, NULL, NULL, 0, MYF(MY_WME | MY_NABP));
- size= log_event_print_value(&tmp_cache, print_event_info,
- is_null ? NULL: value,
- td->type(i), td->field_metadata(i),
- typestr, sizeof(typestr));
- close_cached_file(&tmp_cache);
- }
-
- if (!size)
- goto err;
-
- if (!is_null)
- value+= size;
-
- if (print_event_info->verbose > 1 && !no_fill_output)
- {
- if (my_b_write(file, (uchar*)" /* ", 4) ||
- my_b_printf(file, "%s ", typestr) ||
- my_b_printf(file, "meta=%d nullable=%d is_null=%d ",
- td->field_metadata(i),
- td->maybe_null(i), is_null) ||
- my_b_write(file, (uchar*)"*/", 2))
- goto err;
- }
-
- if (!no_fill_output)
- if (my_b_write_byte(file, '\n'))
- goto err;
-
- null_bit_index++;
- }
- return value - value0;
-
-err:
- return 0;
-}
-
-
-/**
- Exchange the SET part and WHERE part for the Update events.
- Revert the operations order for the Write and Delete events.
- And then revert the events order from the last one to the first one.
-
- @param[in] print_event_info PRINT_EVENT_INFO
- @param[in] rows_buff Packed event buff
-*/
-
-void Rows_log_event::change_to_flashback_event(PRINT_EVENT_INFO *print_event_info,
- uchar *rows_buff, Log_event_type ev_type)
-{
- Table_map_log_event *map;
- table_def *td;
- DYNAMIC_ARRAY rows_arr;
- uchar *swap_buff1;
- uchar *rows_pos= rows_buff + m_rows_before_size;
-
- if (!(map= print_event_info->m_table_map.get_table(m_table_id)) ||
- !(td= map->create_table_def()))
- return;
-
- /* If the write rows event contained no values for the AI */
- if (((get_general_type_code() == WRITE_ROWS_EVENT) && (m_rows_buf==m_rows_end)))
- goto end;
-
- (void) my_init_dynamic_array(&rows_arr, sizeof(LEX_STRING), 8, 8, MYF(0));
-
- for (uchar *value= m_rows_buf; value < m_rows_end; )
- {
- uchar *start_pos= value;
- size_t length1= 0;
- if (!(length1= print_verbose_one_row(NULL, td, print_event_info,
- &m_cols, value,
- (const uchar*) "", TRUE)))
- {
- fprintf(stderr, "\nError row length: %zu\n", length1);
- exit(1);
- }
- value+= length1;
-
- swap_buff1= (uchar *) my_malloc(length1, MYF(0));
- if (!swap_buff1)
- {
- fprintf(stderr, "\nError: Out of memory. "
- "Could not exchange to flashback event.\n");
- exit(1);
- }
- memcpy(swap_buff1, start_pos, length1);
-
- // For Update_event, we have the second part
- size_t length2= 0;
- if (ev_type == UPDATE_ROWS_EVENT ||
- ev_type == UPDATE_ROWS_EVENT_V1)
- {
- if (!(length2= print_verbose_one_row(NULL, td, print_event_info,
- &m_cols, value,
- (const uchar*) "", TRUE)))
- {
- fprintf(stderr, "\nError row length: %zu\n", length2);
- exit(1);
- }
- value+= length2;
-
- void *swap_buff2= my_malloc(length2, MYF(0));
- if (!swap_buff2)
- {
- fprintf(stderr, "\nError: Out of memory. "
- "Could not exchange to flashback event.\n");
- exit(1);
- }
- memcpy(swap_buff2, start_pos + length1, length2); // WHERE part
-
- /* Swap SET and WHERE part */
- memcpy(start_pos, swap_buff2, length2);
- memcpy(start_pos + length2, swap_buff1, length1);
- my_free(swap_buff2);
- }
-
- my_free(swap_buff1);
-
- /* Copying one row into a buff, and pushing into the array */
- LEX_STRING one_row;
-
- one_row.length= length1 + length2;
- one_row.str= (char *) my_malloc(one_row.length, MYF(0));
- memcpy(one_row.str, start_pos, one_row.length);
- if (one_row.str == NULL || push_dynamic(&rows_arr, (uchar *) &one_row))
- {
- fprintf(stderr, "\nError: Out of memory. "
- "Could not push flashback event into array.\n");
- exit(1);
- }
- }
-
- /* Copying rows from the end to the begining into event */
- for (uint i= rows_arr.elements; i > 0; --i)
- {
- LEX_STRING *one_row= dynamic_element(&rows_arr, i - 1, LEX_STRING*);
-
- memcpy(rows_pos, (uchar *)one_row->str, one_row->length);
- rows_pos+= one_row->length;
- my_free(one_row->str);
- }
- delete_dynamic(&rows_arr);
-
-end:
- delete td;
-}
-
-/**
- Calc length of a packed value of the given SQL type
-
- @param[in] ptr Pointer to string
- @param[in] type Column type
- @param[in] meta Column meta information
-
- @retval - number of bytes scanned from ptr.
- Except in case of NULL, in which case we return 1 to indicate ok
-*/
-
-static size_t calc_field_event_length(const uchar *ptr, uint type, uint meta)
-{
- uint32 length= 0;
-
- if (type == MYSQL_TYPE_STRING)
- {
- if (meta >= 256)
- {
- uint byte0= meta >> 8;
- uint byte1= meta & 0xFF;
-
- if ((byte0 & 0x30) != 0x30)
- {
- /* a long CHAR() field: see #37426 */
- length= byte1 | (((byte0 & 0x30) ^ 0x30) << 4);
- type= byte0 | 0x30;
- }
- else
- length = meta & 0xFF;
- }
- else
- length= meta;
- }
-
- switch (type) {
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_TIMESTAMP:
- return 4;
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_YEAR:
- return 1;
- case MYSQL_TYPE_SHORT:
- return 2;
- case MYSQL_TYPE_INT24:
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_NEWDATE:
- case MYSQL_TYPE_DATE:
- return 3;
- case MYSQL_TYPE_LONGLONG:
- case MYSQL_TYPE_DATETIME:
- return 8;
- case MYSQL_TYPE_NEWDECIMAL:
- {
- uint precision= meta >> 8;
- uint decimals= meta & 0xFF;
- uint bin_size= my_decimal_get_binary_size(precision, decimals);
- return bin_size;
- }
- case MYSQL_TYPE_FLOAT:
- return 4;
- case MYSQL_TYPE_DOUBLE:
- return 8;
- case MYSQL_TYPE_BIT:
- {
- /* Meta-data: bit_len, bytes_in_rec, 2 bytes */
- uint nbits= ((meta >> 8) * 8) + (meta & 0xFF);
- length= (nbits + 7) / 8;
- return length;
- }
- case MYSQL_TYPE_TIMESTAMP2:
- return my_timestamp_binary_length(meta);
- case MYSQL_TYPE_DATETIME2:
- return my_datetime_binary_length(meta);
- case MYSQL_TYPE_TIME2:
- return my_time_binary_length(meta);
- case MYSQL_TYPE_ENUM:
- switch (meta & 0xFF) {
- case 1:
- case 2:
- return (meta & 0xFF);
- default:
- /* Unknown ENUM packlen=%d", meta & 0xFF */
- return 0;
- }
- break;
- case MYSQL_TYPE_SET:
- return meta & 0xFF;
- case MYSQL_TYPE_BLOB:
- switch (meta) {
- default:
- return 0;
- case 1:
- return *ptr + 1;
- case 2:
- return uint2korr(ptr) + 2;
- case 3:
- return uint3korr(ptr) + 3;
- case 4:
- return uint4korr(ptr) + 4;
- }
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VAR_STRING:
- length= meta;
- /* fall through */
- case MYSQL_TYPE_STRING:
- if (length < 256)
- return (uint) *ptr + 1;
- return uint2korr(ptr) + 2;
- case MYSQL_TYPE_DECIMAL:
- break;
- default:
- break;
- }
- return 0;
-}
-
-
-size_t
-Rows_log_event::calc_row_event_length(table_def *td,
- PRINT_EVENT_INFO *print_event_info,
- MY_BITMAP *cols_bitmap,
- const uchar *value)
-{
- const uchar *value0= value;
- const uchar *null_bits= value;
- uint null_bit_index= 0;
-
- /*
- Skip metadata bytes which gives the information about nullabity of master
- columns. Master writes one bit for each affected column.
- */
-
- value+= (bitmap_bits_set(cols_bitmap) + 7) / 8;
-
- for (uint i= 0; i < (uint)td->size(); i ++)
- {
- int is_null;
- is_null= (null_bits[null_bit_index / 8] >> (null_bit_index % 8)) & 0x01;
-
- if (bitmap_is_set(cols_bitmap, i) == 0)
- continue;
-
- if (!is_null)
- {
- size_t size;
- size_t fsize= td->calc_field_size((uint)i, (uchar*) value);
- if (value + fsize > m_rows_end)
- {
- /* Corrupted replication event was detected, skipping entry */
- return 0;
- }
- if (!(size= calc_field_event_length(value, td->type(i),
- td->field_metadata(i))))
- return 0;
- value+= size;
- }
- null_bit_index++;
- }
- return value - value0;
-}
-
-
-/**
- Calculate how many rows there are in the event
-
- @param[in] file IO cache
- @param[in] print_event_into Print parameters
-*/
-
-void Rows_log_event::count_row_events(PRINT_EVENT_INFO *print_event_info)
-{
- Table_map_log_event *map;
- table_def *td;
- uint row_events;
- Log_event_type general_type_code= get_general_type_code();
-
- switch (general_type_code) {
- case WRITE_ROWS_EVENT:
- case DELETE_ROWS_EVENT:
- row_events= 1;
- break;
- case UPDATE_ROWS_EVENT:
- row_events= 2;
- break;
- default:
- DBUG_ASSERT(0); /* Not possible */
- return;
- }
-
- if (!(map= print_event_info->m_table_map.get_table(m_table_id)) ||
- !(td= map->create_table_def()))
- {
- /* Row event for unknown table */
- return;
- }
-
- for (const uchar *value= m_rows_buf; value < m_rows_end; )
- {
- size_t length;
- print_event_info->row_events++;
-
- /* Print the first image */
- if (!(length= calc_row_event_length(td, print_event_info,
- &m_cols, value)))
- break;
- value+= length;
- DBUG_ASSERT(value <= m_rows_end);
-
- /* Print the second image (for UPDATE only) */
- if (row_events == 2)
- {
- if (!(length= calc_row_event_length(td, print_event_info,
- &m_cols_ai, value)))
- break;
- value+= length;
- DBUG_ASSERT(value <= m_rows_end);
- }
- }
- delete td;
-}
-
-
-/**
- Print a row event into IO cache in human readable form (in SQL format)
-
- @param[in] file IO cache
- @param[in] print_event_into Print parameters
-*/
-
-bool Rows_log_event::print_verbose(IO_CACHE *file,
- PRINT_EVENT_INFO *print_event_info)
-{
- Table_map_log_event *map;
- table_def *td= 0;
- const char *sql_command, *sql_clause1, *sql_clause2;
- const char *sql_command_short __attribute__((unused));
- Log_event_type general_type_code= get_general_type_code();
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- IO_CACHE *review_sql= &print_event_info->review_sql_cache;
-#endif
-
- if (m_extra_row_data)
- {
- uint8 extra_data_len= m_extra_row_data[EXTRA_ROW_INFO_LEN_OFFSET];
- uint8 extra_payload_len= extra_data_len - EXTRA_ROW_INFO_HDR_BYTES;
- assert(extra_data_len >= EXTRA_ROW_INFO_HDR_BYTES);
-
- if (my_b_printf(file, "### Extra row data format: %u, len: %u :",
- m_extra_row_data[EXTRA_ROW_INFO_FORMAT_OFFSET],
- extra_payload_len))
- goto err;
- if (extra_payload_len)
- {
- /*
- Buffer for hex view of string, including '0x' prefix,
- 2 hex chars / byte and trailing 0
- */
- const int buff_len= 2 + (256 * 2) + 1;
- char buff[buff_len];
- str_to_hex(buff, (const char*) &m_extra_row_data[EXTRA_ROW_INFO_HDR_BYTES],
- extra_payload_len);
- if (my_b_printf(file, "%s", buff))
- goto err;
- }
- if (my_b_printf(file, "\n"))
- goto err;
- }
-
- switch (general_type_code) {
- case WRITE_ROWS_EVENT:
- sql_command= "INSERT INTO";
- sql_clause1= "### SET\n";
- sql_clause2= NULL;
- sql_command_short= "I";
- break;
- case DELETE_ROWS_EVENT:
- sql_command= "DELETE FROM";
- sql_clause1= "### WHERE\n";
- sql_clause2= NULL;
- sql_command_short= "D";
- break;
- case UPDATE_ROWS_EVENT:
- sql_command= "UPDATE";
- sql_clause1= "### WHERE\n";
- sql_clause2= "### SET\n";
- sql_command_short= "U";
- break;
- default:
- sql_command= sql_clause1= sql_clause2= NULL;
- sql_command_short= "";
- DBUG_ASSERT(0); /* Not possible */
- }
-
- if (!(map= print_event_info->m_table_map.get_table(m_table_id)) ||
- !(td= map->create_table_def()))
- {
- return (my_b_printf(file, "### Row event for unknown table #%lu",
- (ulong) m_table_id));
- }
-
- /* If the write rows event contained no values for the AI */
- if (((general_type_code == WRITE_ROWS_EVENT) && (m_rows_buf==m_rows_end)))
- {
- if (my_b_printf(file, "### INSERT INTO %`s.%`s VALUES ()\n",
- map->get_db_name(), map->get_table_name()))
- goto err;
- goto end;
- }
-
- for (const uchar *value= m_rows_buf; value < m_rows_end; )
- {
- size_t length;
- print_event_info->row_events++;
-
- if (my_b_printf(file, "### %s %`s.%`s\n",
- sql_command,
- map->get_db_name(), map->get_table_name()))
- goto err;
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- if (need_flashback_review)
- if (my_b_printf(review_sql, "\nINSERT INTO `%s`.`%s` VALUES ('%s'",
- map->get_review_dbname(), map->get_review_tablename(),
- sql_command_short))
- goto err;
-#endif
-
- /* Print the first image */
- if (!(length= print_verbose_one_row(file, td, print_event_info,
- &m_cols, value,
- (const uchar*) sql_clause1)))
- goto err;
- value+= length;
-
- /* Print the second image (for UPDATE only) */
- if (sql_clause2)
- {
- if (!(length= print_verbose_one_row(file, td, print_event_info,
- &m_cols_ai, value,
- (const uchar*) sql_clause2)))
- goto err;
- value+= length;
- }
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- else
- {
- if (need_flashback_review)
- for (size_t i= 0; i < td->size(); i ++)
- if (my_b_printf(review_sql, ", NULL"))
- goto err;
- }
-
- if (need_flashback_review)
- if (my_b_printf(review_sql, ")%s\n", print_event_info->delimiter))
- goto err;
-#endif
- }
-
-end:
- delete td;
- return 0;
-err:
- delete td;
- return 1;
-}
-
-void free_table_map_log_event(Table_map_log_event *event)
-{
- delete event;
-}
-
-/**
- Encode the event, optionally per 'do_print_encoded' arg store the
- result into the argument cache; optionally per event_info's
- 'verbose' print into the cache a verbose representation of the event.
- Note, no extra wrapping is done to the being io-cached data, like
- to producing a BINLOG query. It's left for a routine that extracts from
- the cache.
-
- @param file pointer to IO_CACHE
- @param print_event_info pointer to print_event_info specializing
- what out of and how to print the event
- @param do_print_encoded whether to store base64-encoded event
- into @file.
-*/
-bool Log_event::print_base64(IO_CACHE* file,
- PRINT_EVENT_INFO* print_event_info,
- bool do_print_encoded)
-{
- uchar *ptr= (uchar *)temp_buf;
- uint32 size= uint4korr(ptr + EVENT_LEN_OFFSET);
- DBUG_ENTER("Log_event::print_base64");
-
- if (is_flashback)
- {
- uint tmp_size= size;
- Rows_log_event *ev= NULL;
- Log_event_type ev_type = (enum Log_event_type) ptr[EVENT_TYPE_OFFSET];
- if (checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF &&
- checksum_alg != BINLOG_CHECKSUM_ALG_OFF)
- tmp_size-= BINLOG_CHECKSUM_LEN; // checksum is displayed through the header
- switch (ev_type) {
- case WRITE_ROWS_EVENT:
- ptr[EVENT_TYPE_OFFSET]= DELETE_ROWS_EVENT;
- ev= new Delete_rows_log_event((const char*) ptr, tmp_size,
- glob_description_event);
- ev->change_to_flashback_event(print_event_info, ptr, ev_type);
- break;
- case WRITE_ROWS_EVENT_V1:
- ptr[EVENT_TYPE_OFFSET]= DELETE_ROWS_EVENT_V1;
- ev= new Delete_rows_log_event((const char*) ptr, tmp_size,
- glob_description_event);
- ev->change_to_flashback_event(print_event_info, ptr, ev_type);
- break;
- case DELETE_ROWS_EVENT:
- ptr[EVENT_TYPE_OFFSET]= WRITE_ROWS_EVENT;
- ev= new Write_rows_log_event((const char*) ptr, tmp_size,
- glob_description_event);
- ev->change_to_flashback_event(print_event_info, ptr, ev_type);
- break;
- case DELETE_ROWS_EVENT_V1:
- ptr[EVENT_TYPE_OFFSET]= WRITE_ROWS_EVENT_V1;
- ev= new Write_rows_log_event((const char*) ptr, tmp_size,
- glob_description_event);
- ev->change_to_flashback_event(print_event_info, ptr, ev_type);
- break;
- case UPDATE_ROWS_EVENT:
- case UPDATE_ROWS_EVENT_V1:
- ev= new Update_rows_log_event((const char*) ptr, tmp_size,
- glob_description_event);
- ev->change_to_flashback_event(print_event_info, ptr, ev_type);
- break;
- default:
- break;
- }
- delete ev;
- }
-
- if (do_print_encoded)
- {
- size_t const tmp_str_sz= my_base64_needed_encoded_length((int) size);
- char *tmp_str;
- if (!(tmp_str= (char *) my_malloc(tmp_str_sz, MYF(MY_WME))))
- goto err;
-
- if (my_base64_encode(ptr, (size_t) size, tmp_str))
- {
- DBUG_ASSERT(0);
- }
-
- my_b_printf(file, "%s\n", tmp_str);
- my_free(tmp_str);
- }
-
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- if (print_event_info->verbose || print_event_info->print_row_count ||
- need_flashback_review)
-#else
- // Flashback need the table_map to parse the event
- if (print_event_info->verbose || print_event_info->print_row_count ||
- is_flashback)
-#endif
- {
- Rows_log_event *ev= NULL;
- Log_event_type et= (Log_event_type) ptr[EVENT_TYPE_OFFSET];
-
- if (checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF &&
- checksum_alg != BINLOG_CHECKSUM_ALG_OFF)
- size-= BINLOG_CHECKSUM_LEN; // checksum is displayed through the header
-
- switch (et)
- {
- case TABLE_MAP_EVENT:
- {
- Table_map_log_event *map;
- map= new Table_map_log_event((const char*) ptr, size,
- glob_description_event);
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- if (need_flashback_review)
- {
- map->set_review_dbname(m_review_dbname.ptr());
- map->set_review_tablename(m_review_tablename.ptr());
- }
-#endif
- print_event_info->m_table_map.set_table(map->get_table_id(), map);
- break;
- }
- case WRITE_ROWS_EVENT:
- case WRITE_ROWS_EVENT_V1:
- {
- ev= new Write_rows_log_event((const char*) ptr, size,
- glob_description_event);
- break;
- }
- case DELETE_ROWS_EVENT:
- case DELETE_ROWS_EVENT_V1:
- {
- ev= new Delete_rows_log_event((const char*) ptr, size,
- glob_description_event);
- break;
- }
- case UPDATE_ROWS_EVENT:
- case UPDATE_ROWS_EVENT_V1:
- {
- ev= new Update_rows_log_event((const char*) ptr, size,
- glob_description_event);
- break;
- }
- case WRITE_ROWS_COMPRESSED_EVENT:
- case WRITE_ROWS_COMPRESSED_EVENT_V1:
- {
- ev= new Write_rows_compressed_log_event((const char*) ptr, size,
- glob_description_event);
- break;
- }
- case UPDATE_ROWS_COMPRESSED_EVENT:
- case UPDATE_ROWS_COMPRESSED_EVENT_V1:
- {
- ev= new Update_rows_compressed_log_event((const char*) ptr, size,
- glob_description_event);
- break;
- }
- case DELETE_ROWS_COMPRESSED_EVENT:
- case DELETE_ROWS_COMPRESSED_EVENT_V1:
- {
- ev= new Delete_rows_compressed_log_event((const char*) ptr, size,
- glob_description_event);
- break;
- }
- default:
- break;
- }
-
- if (ev)
- {
- bool error= 0;
-
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- ev->need_flashback_review= need_flashback_review;
- if (print_event_info->verbose)
- {
- if (ev->print_verbose(file, print_event_info))
- goto err;
- }
- else
- {
- IO_CACHE tmp_cache;
-
- if (open_cached_file(&tmp_cache, NULL, NULL, 0,
- MYF(MY_WME | MY_NABP)))
- {
- delete ev;
- goto err;
- }
-
- error= ev->print_verbose(&tmp_cache, print_event_info);
- close_cached_file(&tmp_cache);
- if (unlikely(error))
- {
- delete ev;
- goto err;
- }
- }
-#else
- if (print_event_info->verbose)
- {
- /*
- Verbose event printout can't start before encoded data
- got enquoted. This is done at this point though multi-row
- statement remain vulnerable.
- TODO: fix MDEV-10362 to remove this workaround.
- */
- if (print_event_info->base64_output_mode !=
- BASE64_OUTPUT_DECODE_ROWS)
- my_b_printf(file, "'%s\n", print_event_info->delimiter);
- error= ev->print_verbose(file, print_event_info);
- }
- else
- {
- ev->count_row_events(print_event_info);
- }
-#endif
- delete ev;
- if (unlikely(error))
- goto err;
- }
- }
- DBUG_RETURN(0);
-
-err:
- DBUG_RETURN(1);
-}
-
-
-/*
- Log_event::print_timestamp()
-*/
-
-bool Log_event::print_timestamp(IO_CACHE* file, time_t* ts)
-{
- struct tm *res;
- time_t my_when= when;
- DBUG_ENTER("Log_event::print_timestamp");
- if (!ts)
- ts = &my_when;
- res=localtime(ts);
-
- DBUG_RETURN(my_b_printf(file,"%02d%02d%02d %2d:%02d:%02d",
- res->tm_year % 100,
- res->tm_mon+1,
- res->tm_mday,
- res->tm_hour,
- res->tm_min,
- res->tm_sec));
-}
-
-#endif /* MYSQL_CLIENT */
-
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-inline Log_event::enum_skip_reason
-Log_event::continue_group(rpl_group_info *rgi)
-{
- if (rgi->rli->slave_skip_counter == 1)
- return Log_event::EVENT_SKIP_IGNORE;
- return Log_event::do_shall_skip(rgi);
-}
-#endif
-
-/**************************************************************************
- Query_log_event methods
-**************************************************************************/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-
-/**
- This (which is used only for SHOW BINLOG EVENTS) could be updated to
- print SET @@session_var=. But this is not urgent, as SHOW BINLOG EVENTS is
- only an information, it does not produce suitable queries to replay (for
- example it does not print LOAD DATA INFILE).
- @todo
- show the catalog ??
-*/
-
-void Query_log_event::pack_info(Protocol *protocol)
-{
- // TODO: show the catalog ??
- char buf_mem[1024];
- String buf(buf_mem, sizeof(buf_mem), system_charset_info);
- buf.real_alloc(9 + db_len + q_len);
- if (!(flags & LOG_EVENT_SUPPRESS_USE_F)
- && db && db_len)
- {
- buf.append(STRING_WITH_LEN("use "));
- append_identifier(protocol->thd, &buf, db, db_len);
- buf.append(STRING_WITH_LEN("; "));
- }
- if (query && q_len)
- buf.append(query, q_len);
- protocol->store(&buf);
-}
-#endif
-
-#ifndef MYSQL_CLIENT
-
-/**
- Utility function for the next method (Query_log_event::write()) .
-*/
-static void store_str_with_code_and_len(uchar **dst, const char *src,
- uint len, uint code)
-{
- /*
- only 1 byte to store the length of catalog, so it should not
- surpass 255
- */
- DBUG_ASSERT(len <= 255);
- DBUG_ASSERT(src);
- *((*dst)++)= (uchar) code;
- *((*dst)++)= (uchar) len;
- bmove(*dst, src, len);
- (*dst)+= len;
-}
-
-
-/**
- Query_log_event::write().
-
- @note
- In this event we have to modify the header to have the correct
- EVENT_LEN_OFFSET as we don't yet know how many status variables we
- will print!
-*/
-
-bool Query_log_event::write()
-{
- uchar buf[QUERY_HEADER_LEN + MAX_SIZE_LOG_EVENT_STATUS];
- uchar *start, *start_of_status;
- ulong event_length;
-
- if (!query)
- return 1; // Something wrong with event
-
- /*
- We want to store the thread id:
- (- as an information for the user when he reads the binlog)
- - if the query uses temporary table: for the slave SQL thread to know to
- which master connection the temp table belongs.
- Now imagine we (write()) are called by the slave SQL thread (we are
- logging a query executed by this thread; the slave runs with
- --log-slave-updates). Then this query will be logged with
- thread_id=the_thread_id_of_the_SQL_thread. Imagine that 2 temp tables of
- the same name were created simultaneously on the master (in the master
- binlog you have
- CREATE TEMPORARY TABLE t; (thread 1)
- CREATE TEMPORARY TABLE t; (thread 2)
- ...)
- then in the slave's binlog there will be
- CREATE TEMPORARY TABLE t; (thread_id_of_the_slave_SQL_thread)
- CREATE TEMPORARY TABLE t; (thread_id_of_the_slave_SQL_thread)
- which is bad (same thread id!).
-
- To avoid this, we log the thread's thread id EXCEPT for the SQL
- slave thread for which we log the original (master's) thread id.
- Now this moves the bug: what happens if the thread id on the
- master was 10 and when the slave replicates the query, a
- connection number 10 is opened by a normal client on the slave,
- and updates a temp table of the same name? We get a problem
- again. To avoid this, in the handling of temp tables (sql_base.cc)
- we use thread_id AND server_id. TODO when this is merged into
- 4.1: in 4.1, slave_proxy_id has been renamed to pseudo_thread_id
- and is a session variable: that's to make mysqlbinlog work with
- temp tables. We probably need to introduce
-
- SET PSEUDO_SERVER_ID
- for mysqlbinlog in 4.1. mysqlbinlog would print:
- SET PSEUDO_SERVER_ID=
- SET PSEUDO_THREAD_ID=
- for each query using temp tables.
- */
- int4store(buf + Q_THREAD_ID_OFFSET, slave_proxy_id);
- int4store(buf + Q_EXEC_TIME_OFFSET, exec_time);
- buf[Q_DB_LEN_OFFSET] = (char) db_len;
- int2store(buf + Q_ERR_CODE_OFFSET, error_code);
-
- /*
- You MUST always write status vars in increasing order of code. This
- guarantees that a slightly older slave will be able to parse those he
- knows.
- */
- start_of_status= start= buf+QUERY_HEADER_LEN;
- if (flags2_inited)
- {
- *start++= Q_FLAGS2_CODE;
- int4store(start, flags2);
- start+= 4;
- }
- if (sql_mode_inited)
- {
- *start++= Q_SQL_MODE_CODE;
- int8store(start, (ulonglong)sql_mode);
- start+= 8;
- }
- if (catalog_len) // i.e. this var is inited (false for 4.0 events)
- {
- store_str_with_code_and_len(&start,
- catalog, catalog_len, Q_CATALOG_NZ_CODE);
- /*
- In 5.0.x where x<4 masters we used to store the end zero here. This was
- a waste of one byte so we don't do it in x>=4 masters. We change code to
- Q_CATALOG_NZ_CODE, because re-using the old code would make x<4 slaves
- of this x>=4 master segfault (expecting a zero when there is
- none). Remaining compatibility problems are: the older slave will not
- find the catalog; but it is will not crash, and it's not an issue
- that it does not find the catalog as catalogs were not used in these
- older MySQL versions (we store it in binlog and read it from relay log
- but do nothing useful with it). What is an issue is that the older slave
- will stop processing the Q_* blocks (and jumps to the db/query) as soon
- as it sees unknown Q_CATALOG_NZ_CODE; so it will not be able to read
- Q_AUTO_INCREMENT*, Q_CHARSET and so replication will fail silently in
- various ways. Documented that you should not mix alpha/beta versions if
- they are not exactly the same version, with example of 5.0.3->5.0.2 and
- 5.0.4->5.0.3. If replication is from older to new, the new will
- recognize Q_CATALOG_CODE and have no problem.
- */
- }
- if (auto_increment_increment != 1 || auto_increment_offset != 1)
- {
- *start++= Q_AUTO_INCREMENT;
- int2store(start, auto_increment_increment);
- int2store(start+2, auto_increment_offset);
- start+= 4;
- }
- if (charset_inited)
- {
- *start++= Q_CHARSET_CODE;
- memcpy(start, charset, 6);
- start+= 6;
- }
- if (time_zone_len)
- {
- /* In the TZ sys table, column Name is of length 64 so this should be ok */
- DBUG_ASSERT(time_zone_len <= MAX_TIME_ZONE_NAME_LENGTH);
- store_str_with_code_and_len(&start,
- time_zone_str, time_zone_len, Q_TIME_ZONE_CODE);
- }
- if (lc_time_names_number)
- {
- DBUG_ASSERT(lc_time_names_number <= 0xFFFF);
- *start++= Q_LC_TIME_NAMES_CODE;
- int2store(start, lc_time_names_number);
- start+= 2;
- }
- if (charset_database_number)
- {
- DBUG_ASSERT(charset_database_number <= 0xFFFF);
- *start++= Q_CHARSET_DATABASE_CODE;
- int2store(start, charset_database_number);
- start+= 2;
- }
- if (table_map_for_update)
- {
- *start++= Q_TABLE_MAP_FOR_UPDATE_CODE;
- int8store(start, table_map_for_update);
- start+= 8;
- }
- if (master_data_written != 0)
- {
- /*
- Q_MASTER_DATA_WRITTEN_CODE only exists in relay logs where the master
- has binlog_version<4 and the slave has binlog_version=4. See comment
- for master_data_written in log_event.h for details.
- */
- *start++= Q_MASTER_DATA_WRITTEN_CODE;
- int4store(start, master_data_written);
- start+= 4;
- }
-
- if (thd && thd->need_binlog_invoker())
- {
- LEX_CSTRING user;
- LEX_CSTRING host;
- memset(&user, 0, sizeof(user));
- memset(&host, 0, sizeof(host));
-
- if (thd->slave_thread && thd->has_invoker())
- {
- /* user will be null, if master is older than this patch */
- user= thd->get_invoker_user();
- host= thd->get_invoker_host();
- }
- else
- {
- Security_context *ctx= thd->security_ctx;
-
- if (thd->need_binlog_invoker() == THD::INVOKER_USER)
- {
- user.str= ctx->priv_user;
- host.str= ctx->priv_host;
- host.length= strlen(host.str);
- }
- else
- {
- user.str= ctx->priv_role;
- host= empty_clex_str;
- }
- user.length= strlen(user.str);
- }
-
- if (user.length > 0)
- {
- *start++= Q_INVOKER;
-
- /*
- Store user length and user. The max length of use is 16, so 1 byte is
- enough to store the user's length.
- */
- *start++= (uchar)user.length;
- memcpy(start, user.str, user.length);
- start+= user.length;
-
- /*
- Store host length and host. The max length of host is 60, so 1 byte is
- enough to store the host's length.
- */
- *start++= (uchar)host.length;
- memcpy(start, host.str, host.length);
- start+= host.length;
- }
- }
-
- if (thd && thd->query_start_sec_part_used)
- {
- *start++= Q_HRNOW;
- get_time();
- int3store(start, when_sec_part);
- start+= 3;
- }
- /*
- NOTE: When adding new status vars, please don't forget to update
- the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update the function
- code_name() in this file.
-
- Here there could be code like
- if (command-line-option-which-says-"log_this_variable" && inited)
- {
- *start++= Q_THIS_VARIABLE_CODE;
- int4store(start, this_variable);
- start+= 4;
- }
- */
-
- /* Store length of status variables */
- status_vars_len= (uint) (start-start_of_status);
- DBUG_ASSERT(status_vars_len <= MAX_SIZE_LOG_EVENT_STATUS);
- int2store(buf + Q_STATUS_VARS_LEN_OFFSET, status_vars_len);
-
- /*
- Calculate length of whole event
- The "1" below is the \0 in the db's length
- */
- event_length= (uint) (start-buf) + get_post_header_size_for_derived() + db_len + 1 + q_len;
-
- return write_header(event_length) ||
- write_data(buf, QUERY_HEADER_LEN) ||
- write_post_header_for_derived() ||
- write_data(start_of_status, (uint) (start-start_of_status)) ||
- write_data(safe_str(db), db_len + 1) ||
- write_data(query, q_len) ||
- write_footer();
-}
-
-bool Query_compressed_log_event::write()
-{
- const char *query_tmp = query;
- uint32 q_len_tmp = q_len;
- uint32 alloc_size;
- bool ret = true;
- q_len = alloc_size = binlog_get_compress_len(q_len);
- query = (char *)my_safe_alloca(alloc_size);
- if(query && !binlog_buf_compress(query_tmp, (char *)query, q_len_tmp, &q_len))
- {
- ret = Query_log_event::write();
- }
- my_safe_afree((void *)query, alloc_size);
- query = query_tmp;
- q_len = q_len_tmp;
- return ret;
-}
-
-/**
- The simplest constructor that could possibly work. This is used for
- creating static objects that have a special meaning and are invisible
- to the log.
-*/
-Query_log_event::Query_log_event()
- :Log_event(), data_buf(0)
-{
- memset(&user, 0, sizeof(user));
- memset(&host, 0, sizeof(host));
-}
-
-
-/*
- SYNOPSIS
- Query_log_event::Query_log_event()
- thd_arg - thread handle
- query_arg - array of char representing the query
- query_length - size of the `query_arg' array
- using_trans - there is a modified transactional table
- direct - Don't cache statement
- suppress_use - suppress the generation of 'USE' statements
- errcode - the error code of the query
-
- DESCRIPTION
- Creates an event for binlogging
- The value for `errcode' should be supplied by caller.
-*/
-Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, size_t query_length, bool using_trans,
- bool direct, bool suppress_use, int errcode)
-
- :Log_event(thd_arg,
- (thd_arg->thread_specific_used ? LOG_EVENT_THREAD_SPECIFIC_F :
- 0) |
- (suppress_use ? LOG_EVENT_SUPPRESS_USE_F : 0),
- using_trans),
- data_buf(0), query(query_arg), catalog(thd_arg->catalog),
- db(thd_arg->db.str), q_len((uint32) query_length),
- thread_id(thd_arg->thread_id),
- /* save the original thread id; we already know the server id */
- slave_proxy_id((ulong)thd_arg->variables.pseudo_thread_id),
- flags2_inited(1), sql_mode_inited(1), charset_inited(1),
- sql_mode(thd_arg->variables.sql_mode),
- auto_increment_increment(thd_arg->variables.auto_increment_increment),
- auto_increment_offset(thd_arg->variables.auto_increment_offset),
- lc_time_names_number(thd_arg->variables.lc_time_names->number),
- charset_database_number(0),
- table_map_for_update((ulonglong)thd_arg->table_map_for_update),
- master_data_written(0)
-{
- time_t end_time;
-
-#ifdef WITH_WSREP
- /*
- If Query_log_event will contain non trans keyword (not BEGIN, COMMIT,
- SAVEPOINT or ROLLBACK) we disable PA for this transaction.
- */
- if (WSREP_ON && !is_trans_keyword())
- thd->wsrep_PA_safe= false;
-#endif /* WITH_WSREP */
-
- memset(&user, 0, sizeof(user));
- memset(&host, 0, sizeof(host));
-
- error_code= errcode;
-
- end_time= my_time(0);
- exec_time = (ulong) (end_time - thd_arg->start_time);
- /**
- @todo this means that if we have no catalog, then it is replicated
- as an existing catalog of length zero. is that safe? /sven
- */
- catalog_len = (catalog) ? (uint32) strlen(catalog) : 0;
- /* status_vars_len is set just before writing the event */
- db_len = (db) ? (uint32) strlen(db) : 0;
- if (thd_arg->variables.collation_database != thd_arg->db_charset)
- charset_database_number= thd_arg->variables.collation_database->number;
-
- /*
- We only replicate over the bits of flags2 that we need: the rest
- are masked out by "& OPTIONS_WRITTEN_TO_BINLOG".
-
- We also force AUTOCOMMIT=1. Rationale (cf. BUG#29288): After
- fixing BUG#26395, we always write BEGIN and COMMIT around all
- transactions (even single statements in autocommit mode). This is
- so that replication from non-transactional to transactional table
- and error recovery from XA to non-XA table should work as
- expected. The BEGIN/COMMIT are added in log.cc. However, there is
- one exception: MyISAM bypasses log.cc and writes directly to the
- binlog. So if autocommit is off, master has MyISAM, and slave has
- a transactional engine, then the slave will just see one long
- never-ending transaction. The only way to bypass explicit
- BEGIN/COMMIT in the binlog is by using a non-transactional table.
- So setting AUTOCOMMIT=1 will make this work as expected.
-
- Note: explicitly replicate AUTOCOMMIT=1 from master. We do not
- assume AUTOCOMMIT=1 on slave; the slave still reads the state of
- the autocommit flag as written by the master to the binlog. This
- behavior may change after WL#4162 has been implemented.
- */
- flags2= (uint32) (thd_arg->variables.option_bits &
- (OPTIONS_WRITTEN_TO_BIN_LOG & ~OPTION_NOT_AUTOCOMMIT));
- DBUG_ASSERT(thd_arg->variables.character_set_client->number < 256*256);
- DBUG_ASSERT(thd_arg->variables.collation_connection->number < 256*256);
- DBUG_ASSERT(thd_arg->variables.collation_server->number < 256*256);
- DBUG_ASSERT(thd_arg->variables.character_set_client->mbminlen == 1);
- int2store(charset, thd_arg->variables.character_set_client->number);
- int2store(charset+2, thd_arg->variables.collation_connection->number);
- int2store(charset+4, thd_arg->variables.collation_server->number);
- if (thd_arg->time_zone_used)
- {
- /*
- Note that our event becomes dependent on the Time_zone object
- representing the time zone. Fortunately such objects are never deleted
- or changed during mysqld's lifetime.
- */
- time_zone_len= thd_arg->variables.time_zone->get_name()->length();
- time_zone_str= thd_arg->variables.time_zone->get_name()->ptr();
- }
- else
- time_zone_len= 0;
-
- LEX *lex= thd->lex;
- /*
- Defines that the statement will be written directly to the binary log
- without being wrapped by a BEGIN...COMMIT. Otherwise, the statement
- will be written to either the trx-cache or stmt-cache.
-
- Note that a cache will not be used if the parameter direct is TRUE.
- */
- bool use_cache= FALSE;
- /*
- TRUE defines that the trx-cache must be used and by consequence the
- use_cache is TRUE.
-
- Note that a cache will not be used if the parameter direct is TRUE.
- */
- bool trx_cache= FALSE;
- cache_type= Log_event::EVENT_INVALID_CACHE;
-
- if (!direct)
- {
- switch (lex->sql_command)
- {
- case SQLCOM_DROP_TABLE:
- case SQLCOM_DROP_SEQUENCE:
- use_cache= (lex->tmp_table() && thd->in_multi_stmt_transaction_mode());
- break;
-
- case SQLCOM_CREATE_TABLE:
- case SQLCOM_CREATE_SEQUENCE:
- /*
- If we are using CREATE ... SELECT or if we are a slave
- executing BEGIN...COMMIT (generated by CREATE...SELECT) we
- have to use the transactional cache to ensure we don't
- calculate any checksum for the CREATE part.
- */
- trx_cache= (lex->first_select_lex()->item_list.elements &&
- thd->is_current_stmt_binlog_format_row()) ||
- (thd->variables.option_bits & OPTION_GTID_BEGIN);
- use_cache= (lex->tmp_table() &&
- thd->in_multi_stmt_transaction_mode()) || trx_cache;
- break;
- case SQLCOM_SET_OPTION:
- if (lex->autocommit)
- use_cache= trx_cache= FALSE;
- else
- use_cache= TRUE;
- break;
- case SQLCOM_RELEASE_SAVEPOINT:
- case SQLCOM_ROLLBACK_TO_SAVEPOINT:
- case SQLCOM_SAVEPOINT:
- use_cache= trx_cache= TRUE;
- break;
- default:
- use_cache= sqlcom_can_generate_row_events(thd);
- break;
- }
- }
-
- if (!use_cache || direct)
- {
- cache_type= Log_event::EVENT_NO_CACHE;
- }
- else if (using_trans || trx_cache || stmt_has_updated_trans_table(thd) ||
- thd->lex->is_mixed_stmt_unsafe(thd->in_multi_stmt_transaction_mode(),
- thd->variables.binlog_direct_non_trans_update,
- trans_has_updated_trans_table(thd),
- thd->tx_isolation))
- cache_type= Log_event::EVENT_TRANSACTIONAL_CACHE;
- else
- cache_type= Log_event::EVENT_STMT_CACHE;
- DBUG_ASSERT(cache_type != Log_event::EVENT_INVALID_CACHE);
- DBUG_PRINT("info",("Query_log_event has flags2: %lu sql_mode: %llu cache_tye: %d",
- (ulong) flags2, sql_mode, cache_type));
-}
-
-Query_compressed_log_event::Query_compressed_log_event(THD* thd_arg, const char* query_arg,
- ulong query_length, bool using_trans,
- bool direct, bool suppress_use, int errcode)
- :Query_log_event(thd_arg, query_arg, query_length, using_trans, direct,
- suppress_use, errcode),
- query_buf(0)
-{
-
-}
-#endif /* MYSQL_CLIENT */
/* 2 utility functions for the next method */
@@ -4851,7 +1671,8 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
*/
#if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE)
- if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1
+ if (!(start= data_buf = (Log_event::Byte*) my_malloc(PSI_INSTRUMENT_ME,
+ catalog_len + 1
+ time_zone_len + 1
+ user.length + 1
+ host.length + 1
@@ -4862,7 +1683,8 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
+ QUERY_CACHE_FLAGS_SIZE,
MYF(MY_WME))))
#else
- if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1
+ if (!(start= data_buf = (Log_event::Byte*) my_malloc(PSI_INSTRUMENT_ME,
+ catalog_len + 1
+ time_zone_len + 1
+ user.length + 1
+ host.length + 1
@@ -4969,8 +1791,8 @@ Query_compressed_log_event::Query_compressed_log_event(const char *buf,
}
/* Reserve one byte for '\0' */
- query_buf = (Log_event::Byte*)my_malloc(ALIGN_SIZE(un_len + 1),
- MYF(MY_WME));
+ query_buf = (Log_event::Byte*)my_malloc(PSI_INSTRUMENT_ME,
+ ALIGN_SIZE(un_len + 1), MYF(MY_WME));
if(query_buf &&
!binlog_buf_uncompress(query, (char *)query_buf, q_len, &un_len))
{
@@ -5159,962 +1981,10 @@ Query_log_event::begin_event(String *packet, ulong ev_offset,
}
-#ifdef MYSQL_CLIENT
-/**
- Query_log_event::print().
-
- @todo
- print the catalog ??
-*/
-bool Query_log_event::print_query_header(IO_CACHE* file,
- PRINT_EVENT_INFO* print_event_info)
-{
- // TODO: print the catalog ??
- char buff[64], *end; // Enough for SET TIMESTAMP
- bool different_db= 1;
- uint32 tmp;
-
- if (!print_event_info->short_form)
- {
- if (print_header(file, print_event_info, FALSE) ||
- my_b_printf(file,
- "\t%s\tthread_id=%lu\texec_time=%lu\terror_code=%d\n",
- get_type_str(), (ulong) thread_id, (ulong) exec_time,
- error_code))
- goto err;
- }
-
- if ((flags & LOG_EVENT_SUPPRESS_USE_F))
- {
- if (!is_trans_keyword())
- print_event_info->db[0]= '\0';
- }
- else if (db)
- {
- different_db= memcmp(print_event_info->db, db, db_len + 1);
- if (different_db)
- memcpy(print_event_info->db, db, db_len + 1);
- if (db[0] && different_db)
- if (my_b_printf(file, "use %`s%s\n", db, print_event_info->delimiter))
- goto err;
- }
-
- end=int10_to_str((long) when, strmov(buff,"SET TIMESTAMP="),10);
- if (when_sec_part && when_sec_part <= TIME_MAX_SECOND_PART)
- {
- *end++= '.';
- end=int10_to_str(when_sec_part, end, 10);
- }
- end= strmov(end, print_event_info->delimiter);
- *end++='\n';
- if (my_b_write(file, (uchar*) buff, (uint) (end-buff)))
- goto err;
- if ((!print_event_info->thread_id_printed ||
- ((flags & LOG_EVENT_THREAD_SPECIFIC_F) &&
- thread_id != print_event_info->thread_id)))
- {
- // If --short-form, print deterministic value instead of pseudo_thread_id.
- if (my_b_printf(file,"SET @@session.pseudo_thread_id=%lu%s\n",
- short_form ? 999999999 : (ulong)thread_id,
- print_event_info->delimiter))
- goto err;
- print_event_info->thread_id= thread_id;
- print_event_info->thread_id_printed= 1;
- }
-
- /*
- If flags2_inited==0, this is an event from 3.23 or 4.0; nothing to
- print (remember we don't produce mixed relay logs so there cannot be
- 5.0 events before that one so there is nothing to reset).
- */
- if (likely(flags2_inited)) /* likely as this will mainly read 5.0 logs */
- {
- /* tmp is a bitmask of bits which have changed. */
- if (likely(print_event_info->flags2_inited))
- /* All bits which have changed */
- tmp= (print_event_info->flags2) ^ flags2;
- else /* that's the first Query event we read */
- {
- print_event_info->flags2_inited= 1;
- tmp= ~((uint32)0); /* all bits have changed */
- }
-
- if (unlikely(tmp)) /* some bits have changed */
- {
- bool need_comma= 0;
- if (my_b_write_string(file, "SET ") ||
- print_set_option(file, tmp, OPTION_NO_FOREIGN_KEY_CHECKS, ~flags2,
- "@@session.foreign_key_checks", &need_comma)||
- print_set_option(file, tmp, OPTION_AUTO_IS_NULL, flags2,
- "@@session.sql_auto_is_null", &need_comma) ||
- print_set_option(file, tmp, OPTION_RELAXED_UNIQUE_CHECKS, ~flags2,
- "@@session.unique_checks", &need_comma) ||
- print_set_option(file, tmp, OPTION_NOT_AUTOCOMMIT, ~flags2,
- "@@session.autocommit", &need_comma) ||
- print_set_option(file, tmp, OPTION_NO_CHECK_CONSTRAINT_CHECKS,
- ~flags2,
- "@@session.check_constraint_checks", &need_comma) ||
- my_b_printf(file,"%s\n", print_event_info->delimiter))
- goto err;
- print_event_info->flags2= flags2;
- }
- }
-
- /*
- Now the session variables;
- it's more efficient to pass SQL_MODE as a number instead of a
- comma-separated list.
- FOREIGN_KEY_CHECKS, SQL_AUTO_IS_NULL, UNIQUE_CHECKS are session-only
- variables (they have no global version; they're not listed in
- sql_class.h), The tests below work for pure binlogs or pure relay
- logs. Won't work for mixed relay logs but we don't create mixed
- relay logs (that is, there is no relay log with a format change
- except within the 3 first events, which mysqlbinlog handles
- gracefully). So this code should always be good.
- */
-
- if (likely(sql_mode_inited) &&
- (unlikely(print_event_info->sql_mode != sql_mode ||
- !print_event_info->sql_mode_inited)))
- {
- char llbuff[22];
- if (my_b_printf(file,"SET @@session.sql_mode=%s%s\n",
- ullstr(sql_mode, llbuff), print_event_info->delimiter))
- goto err;
- print_event_info->sql_mode= sql_mode;
- print_event_info->sql_mode_inited= 1;
- }
- if (print_event_info->auto_increment_increment != auto_increment_increment ||
- print_event_info->auto_increment_offset != auto_increment_offset)
- {
- if (my_b_printf(file,"SET @@session.auto_increment_increment=%lu, @@session.auto_increment_offset=%lu%s\n",
- auto_increment_increment,auto_increment_offset,
- print_event_info->delimiter))
- goto err;
- print_event_info->auto_increment_increment= auto_increment_increment;
- print_event_info->auto_increment_offset= auto_increment_offset;
- }
-
- /* TODO: print the catalog when we feature SET CATALOG */
-
- if (likely(charset_inited) &&
- (unlikely(!print_event_info->charset_inited ||
- memcmp(print_event_info->charset, charset, 6))))
- {
- CHARSET_INFO *cs_info= get_charset(uint2korr(charset), MYF(MY_WME));
- if (cs_info)
- {
- /* for mysql client */
- if (my_b_printf(file, "/*!\\C %s */%s\n",
- cs_info->csname, print_event_info->delimiter))
- goto err;
- }
- if (my_b_printf(file,"SET "
- "@@session.character_set_client=%d,"
- "@@session.collation_connection=%d,"
- "@@session.collation_server=%d"
- "%s\n",
- uint2korr(charset),
- uint2korr(charset+2),
- uint2korr(charset+4),
- print_event_info->delimiter))
- goto err;
- memcpy(print_event_info->charset, charset, 6);
- print_event_info->charset_inited= 1;
- }
- if (time_zone_len)
- {
- if (memcmp(print_event_info->time_zone_str,
- time_zone_str, time_zone_len+1))
- {
- if (my_b_printf(file,"SET @@session.time_zone='%s'%s\n",
- time_zone_str, print_event_info->delimiter))
- goto err;
- memcpy(print_event_info->time_zone_str, time_zone_str, time_zone_len+1);
- }
- }
- if (lc_time_names_number != print_event_info->lc_time_names_number)
- {
- if (my_b_printf(file, "SET @@session.lc_time_names=%d%s\n",
- lc_time_names_number, print_event_info->delimiter))
- goto err;
- print_event_info->lc_time_names_number= lc_time_names_number;
- }
- if (charset_database_number != print_event_info->charset_database_number)
- {
- if (charset_database_number)
- {
- if (my_b_printf(file, "SET @@session.collation_database=%d%s\n",
- charset_database_number, print_event_info->delimiter))
- goto err;
- }
- else if (my_b_printf(file, "SET @@session.collation_database=DEFAULT%s\n",
- print_event_info->delimiter))
- goto err;
- print_event_info->charset_database_number= charset_database_number;
- }
- return 0;
-
-err:
- return 1;
-}
-
-
-bool Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- Write_on_release_cache cache(&print_event_info->head_cache, file, 0, this);
-
- /**
- reduce the size of io cache so that the write function is called
- for every call to my_b_write().
- */
- DBUG_EXECUTE_IF ("simulate_file_write_error",
- {(&cache)->write_pos= (&cache)->write_end- 500;});
- if (print_query_header(&cache, print_event_info))
- goto err;
- if (!is_flashback)
- {
- if (my_b_write(&cache, (uchar*) query, q_len) ||
- my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
- goto err;
- }
- else // is_flashback == 1
- {
- if (strcmp("BEGIN", query) == 0)
- {
- if (my_b_write(&cache, (uchar*) "COMMIT", 6) ||
- my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
- goto err;
- }
- else if (strcmp("COMMIT", query) == 0)
- {
- if (my_b_write(&cache, (uchar*) "BEGIN", 5) ||
- my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
- goto err;
- }
- }
- return cache.flush_data();
-err:
- return 1;
-}
-#endif /* MYSQL_CLIENT */
-
-
-/*
- Query_log_event::do_apply_event()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-
-int Query_log_event::do_apply_event(rpl_group_info *rgi)
-{
- return do_apply_event(rgi, query, q_len);
-}
-
-/**
- Compare if two errors should be regarded as equal.
- This is to handle the case when you can get slightly different errors
- on master and slave for the same thing.
- @param
- expected_error Error we got on master
- actual_error Error we got on slave
-
- @return
- 1 Errors are equal
- 0 Errors are different
-*/
-
-bool test_if_equal_repl_errors(int expected_error, int actual_error)
-{
- if (expected_error == actual_error)
- return 1;
- switch (expected_error) {
- case ER_DUP_ENTRY:
- case ER_DUP_ENTRY_WITH_KEY_NAME:
- case ER_DUP_KEY:
- case ER_AUTOINC_READ_FAILED:
- return (actual_error == ER_DUP_ENTRY ||
- actual_error == ER_DUP_ENTRY_WITH_KEY_NAME ||
- actual_error == ER_DUP_KEY ||
- actual_error == ER_AUTOINC_READ_FAILED ||
- actual_error == HA_ERR_AUTOINC_ERANGE);
- case ER_UNKNOWN_TABLE:
- return actual_error == ER_IT_IS_A_VIEW;
- default:
- break;
- }
- return 0;
-}
-
-
-/**
- @todo
- Compare the values of "affected rows" around here. Something
- like:
- @code
- if ((uint32) affected_in_event != (uint32) affected_on_slave)
- {
- sql_print_error("Slave: did not get the expected number of affected \
- rows running query from master - expected %d, got %d (this numbers \
- should have matched modulo 4294967296).", 0, ...);
- thd->query_error = 1;
- }
- @endcode
- We may also want an option to tell the slave to ignore "affected"
- mismatch. This mismatch could be implemented with a new ER_ code, and
- to ignore it you would use --slave-skip-errors...
-*/
-int Query_log_event::do_apply_event(rpl_group_info *rgi,
- const char *query_arg, uint32 q_len_arg)
-{
- int expected_error,actual_error= 0;
- Schema_specification_st db_options;
- uint64 sub_id= 0;
- void *hton= NULL;
- rpl_gtid gtid;
- Relay_log_info const *rli= rgi->rli;
- Rpl_filter *rpl_filter= rli->mi->rpl_filter;
- bool current_stmt_is_commit;
- DBUG_ENTER("Query_log_event::do_apply_event");
-
- /*
- Colleagues: please never free(thd->catalog) in MySQL. This would
- lead to bugs as here thd->catalog is a part of an alloced block,
- not an entire alloced block (see
- Query_log_event::do_apply_event()). Same for thd->db. Thank
- you.
- */
- thd->catalog= catalog_len ? (char *) catalog : (char *)"";
-
- size_t valid_len= Well_formed_prefix(system_charset_info,
- db, db_len, NAME_LEN).length();
-
- if (valid_len != db_len)
- {
- rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
- ER_THD(thd, ER_SLAVE_FATAL_ERROR),
- "Invalid database name in Query event.");
- thd->is_slave_error= true;
- goto end;
- }
-
- set_thd_db(thd, rpl_filter, db, db_len);
-
- /*
- Setting the character set and collation of the current database thd->db.
- */
- load_db_opt_by_name(thd, thd->db.str, &db_options);
- if (db_options.default_table_charset)
- thd->db_charset= db_options.default_table_charset;
- thd->variables.auto_increment_increment= auto_increment_increment;
- thd->variables.auto_increment_offset= auto_increment_offset;
-
- DBUG_PRINT("info", ("log_pos: %lu", (ulong) log_pos));
-
- thd->clear_error(1);
- current_stmt_is_commit= is_commit();
-
- DBUG_ASSERT(!current_stmt_is_commit || !rgi->tables_to_lock);
- rgi->slave_close_thread_tables(thd);
-
- /*
- Note: We do not need to execute reset_one_shot_variables() if this
- db_ok() test fails.
- Reason: The db stored in binlog events is the same for SET and for
- its companion query. If the SET is ignored because of
- db_ok(), the companion query will also be ignored, and if
- the companion query is ignored in the db_ok() test of
- ::do_apply_event(), then the companion SET also have so
- we don't need to reset_one_shot_variables().
- */
- if (is_trans_keyword() || rpl_filter->db_ok(thd->db.str))
- {
- thd->set_time(when, when_sec_part);
- thd->set_query_and_id((char*)query_arg, q_len_arg,
- thd->charset(), next_query_id());
- thd->variables.pseudo_thread_id= thread_id; // for temp tables
- DBUG_PRINT("query",("%s", thd->query()));
-
- if (unlikely(!(expected_error= error_code)) ||
- ignored_error_code(expected_error) ||
- !unexpected_error_code(expected_error))
- {
- thd->slave_expected_error= expected_error;
- if (flags2_inited)
- /*
- all bits of thd->variables.option_bits which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG
- must take their value from flags2.
- */
- thd->variables.option_bits= flags2|(thd->variables.option_bits & ~OPTIONS_WRITTEN_TO_BIN_LOG);
- /*
- else, we are in a 3.23/4.0 binlog; we previously received a
- Rotate_log_event which reset thd->variables.option_bits and sql_mode etc, so
- nothing to do.
- */
- /*
- We do not replicate MODE_NO_DIR_IN_CREATE. That is, if the master is a
- slave which runs with SQL_MODE=MODE_NO_DIR_IN_CREATE, this should not
- force us to ignore the dir too. Imagine you are a ring of machines, and
- one has a disk problem so that you temporarily need
- MODE_NO_DIR_IN_CREATE on this machine; you don't want it to propagate
- elsewhere (you don't want all slaves to start ignoring the dirs).
- */
- if (sql_mode_inited)
- thd->variables.sql_mode=
- (sql_mode_t) ((thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) |
- (sql_mode & ~(sql_mode_t) MODE_NO_DIR_IN_CREATE));
- if (charset_inited)
- {
- rpl_sql_thread_info *sql_info= thd->system_thread_info.rpl_sql_info;
- if (sql_info->cached_charset_compare(charset))
- {
- /* Verify that we support the charsets found in the event. */
- if (!(thd->variables.character_set_client=
- get_charset(uint2korr(charset), MYF(MY_WME))) ||
- !(thd->variables.collation_connection=
- get_charset(uint2korr(charset+2), MYF(MY_WME))) ||
- !(thd->variables.collation_server=
- get_charset(uint2korr(charset+4), MYF(MY_WME))))
- {
- /*
- We updated the thd->variables with nonsensical values (0). Let's
- set them to something safe (i.e. which avoids crash), and we'll
- stop with EE_UNKNOWN_CHARSET in compare_errors (unless set to
- ignore this error).
- */
- set_slave_thread_default_charset(thd, rgi);
- goto compare_errors;
- }
- thd->update_charset(); // for the charset change to take effect
- /*
- Reset thd->query_string.cs to the newly set value.
- Note, there is a small flaw here. For a very short time frame
- if the new charset is different from the old charset and
- if another thread executes "SHOW PROCESSLIST" after
- the above thd->set_query_and_id() and before this thd->set_query(),
- and if the current query has some non-ASCII characters,
- the another thread may see some '?' marks in the PROCESSLIST
- result. This should be acceptable now. This is a reminder
- to fix this if any refactoring happens here sometime.
- */
- thd->set_query((char*) query_arg, q_len_arg, thd->charset());
- }
- }
- if (time_zone_len)
- {
- String tmp(time_zone_str, time_zone_len, &my_charset_bin);
- if (!(thd->variables.time_zone= my_tz_find(thd, &tmp)))
- {
- my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), tmp.c_ptr());
- thd->variables.time_zone= global_system_variables.time_zone;
- goto compare_errors;
- }
- }
- if (lc_time_names_number)
- {
- if (!(thd->variables.lc_time_names=
- my_locale_by_number(lc_time_names_number)))
- {
- my_printf_error(ER_UNKNOWN_ERROR,
- "Unknown locale: '%d'", MYF(0), lc_time_names_number);
- thd->variables.lc_time_names= &my_locale_en_US;
- goto compare_errors;
- }
- }
- else
- thd->variables.lc_time_names= &my_locale_en_US;
- if (charset_database_number)
- {
- CHARSET_INFO *cs;
- if (!(cs= get_charset(charset_database_number, MYF(0))))
- {
- char buf[20];
- int10_to_str((int) charset_database_number, buf, -10);
- my_error(ER_UNKNOWN_COLLATION, MYF(0), buf);
- goto compare_errors;
- }
- thd->variables.collation_database= cs;
- }
- else
- thd->variables.collation_database= thd->db_charset;
-
- {
- const CHARSET_INFO *cs= thd->charset();
- /*
- We cannot ask for parsing a statement using a character set
- without state_maps (parser internal data).
- */
- if (!cs->state_map)
- {
- rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
- ER_THD(thd, ER_SLAVE_FATAL_ERROR),
- "character_set cannot be parsed");
- thd->is_slave_error= true;
- goto end;
- }
- }
-
- /*
- Record any GTID in the same transaction, so slave state is
- transactionally consistent.
- */
- if (current_stmt_is_commit)
- {
- thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
- if (rgi->gtid_pending)
- {
- sub_id= rgi->gtid_sub_id;
- rgi->gtid_pending= false;
-
- gtid= rgi->current_gtid;
- if (unlikely(rpl_global_gtid_slave_state->record_gtid(thd, &gtid,
- sub_id,
- true, false,
- &hton)))
- {
- int errcode= thd->get_stmt_da()->sql_errno();
- if (!is_parallel_retry_error(rgi, errcode))
- rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE,
- rgi->gtid_info(),
- "Error during COMMIT: failed to update GTID state in "
- "%s.%s: %d: %s",
- "mysql", rpl_gtid_slave_state_table_name.str,
- errcode,
- thd->get_stmt_da()->message());
- sub_id= 0;
- thd->is_slave_error= 1;
- goto end;
- }
- }
- }
-
- thd->table_map_for_update= (table_map)table_map_for_update;
- thd->set_invoker(&user, &host);
- /*
- Flag if we need to rollback the statement transaction on
- slave if it by chance succeeds.
- If we expected a non-zero error code and get nothing and,
- it is a concurrency issue or ignorable issue, effects
- of the statement should be rolled back.
- */
- if (unlikely(expected_error) &&
- (ignored_error_code(expected_error) ||
- concurrency_error_code(expected_error)))
- {
- thd->variables.option_bits|= OPTION_MASTER_SQL_ERROR;
- thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
- }
- /* Execute the query (note that we bypass dispatch_command()) */
- Parser_state parser_state;
- if (!parser_state.init(thd, thd->query(), thd->query_length()))
- {
- DBUG_ASSERT(thd->m_digest == NULL);
- thd->m_digest= & thd->m_digest_state;
- DBUG_ASSERT(thd->m_statement_psi == NULL);
- thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state,
- stmt_info_rpl.m_key,
- thd->db.str, thd->db.length,
- thd->charset());
- THD_STAGE_INFO(thd, stage_init);
- MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(), thd->query_length());
- if (thd->m_digest != NULL)
- thd->m_digest->reset(thd->m_token_array, max_digest_length);
-
- if (thd->slave_thread)
- {
- /*
- To be compatible with previous releases, the slave thread uses the global
- log_slow_disabled_statements value, wich can be changed dynamically, so we
- have to set the sql_log_slow respectively.
- */
- thd->variables.sql_log_slow= !MY_TEST(global_system_variables.log_slow_disabled_statements & LOG_SLOW_DISABLE_SLAVE);
- }
-
- mysql_parse(thd, thd->query(), thd->query_length(), &parser_state,
- FALSE, FALSE);
- /* Finalize server status flags after executing a statement. */
- thd->update_server_status();
- log_slow_statement(thd);
- thd->lex->restore_set_statement_var();
- }
-
- thd->variables.option_bits&= ~OPTION_MASTER_SQL_ERROR;
- }
- else
- {
- /*
- The query got a really bad error on the master (thread killed etc),
- which could be inconsistent. Parse it to test the table names: if the
- replicate-*-do|ignore-table rules say "this query must be ignored" then
- we exit gracefully; otherwise we warn about the bad error and tell DBA
- to check/fix it.
- */
- if (mysql_test_parse_for_slave(thd, thd->query(), thd->query_length()))
- thd->clear_error(1);
- else
- {
- rli->report(ERROR_LEVEL, expected_error, rgi->gtid_info(),
- "\
-Query partially completed on the master (error on master: %d) \
-and was aborted. There is a chance that your master is inconsistent at this \
-point. If you are sure that your master is ok, run this query manually on the \
-slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; \
-START SLAVE; . Query: '%s'", expected_error, thd->query());
- thd->is_slave_error= 1;
- }
- goto end;
- }
-
- /* If the query was not ignored, it is printed to the general log */
- if (likely(!thd->is_error()) ||
- thd->get_stmt_da()->sql_errno() != ER_SLAVE_IGNORED_TABLE)
- general_log_write(thd, COM_QUERY, thd->query(), thd->query_length());
- else
- {
- /*
- Bug#54201: If we skip an INSERT query that uses auto_increment, then we
- should reset any @@INSERT_ID set by an Intvar_log_event associated with
- the query; otherwise the @@INSERT_ID will linger until the next INSERT
- that uses auto_increment and may affect extra triggers on the slave etc.
-
- We reset INSERT_ID unconditionally; it is probably cheaper than
- checking if it is necessary.
- */
- thd->auto_inc_intervals_forced.empty();
- }
-
-compare_errors:
- /*
- In the slave thread, we may sometimes execute some DROP / * 40005
- TEMPORARY * / TABLE that come from parts of binlogs (likely if we
- use RESET SLAVE or CHANGE MASTER TO), while the temporary table
- has already been dropped. To ignore such irrelevant "table does
- not exist errors", we silently clear the error if TEMPORARY was used.
- */
- if ((thd->lex->sql_command == SQLCOM_DROP_TABLE ||
- thd->lex->sql_command == SQLCOM_DROP_SEQUENCE) &&
- thd->lex->tmp_table() &&
- thd->is_error() && thd->get_stmt_da()->sql_errno() == ER_BAD_TABLE_ERROR &&
- !expected_error)
- thd->get_stmt_da()->reset_diagnostics_area();
- /*
- If we expected a non-zero error code, and we don't get the same error
- code, and it should be ignored or is related to a concurrency issue.
- */
- actual_error= thd->is_error() ? thd->get_stmt_da()->sql_errno() : 0;
- DBUG_PRINT("info",("expected_error: %d sql_errno: %d",
- expected_error, actual_error));
-
- if ((unlikely(expected_error) &&
- !test_if_equal_repl_errors(expected_error, actual_error) &&
- !concurrency_error_code(expected_error)) &&
- !ignored_error_code(actual_error) &&
- !ignored_error_code(expected_error))
- {
- rli->report(ERROR_LEVEL, 0, rgi->gtid_info(),
- "Query caused different errors on master and slave. "
- "Error on master: message (format)='%s' error code=%d ; "
- "Error on slave: actual message='%s', error code=%d. "
- "Default database: '%s'. Query: '%s'",
- ER_THD(thd, expected_error),
- expected_error,
- actual_error ? thd->get_stmt_da()->message() : "no error",
- actual_error,
- print_slave_db_safe(db), query_arg);
- thd->is_slave_error= 1;
- }
- /*
- If we get the same error code as expected and it is not a concurrency
- issue, or should be ignored.
- */
- else if ((test_if_equal_repl_errors(expected_error, actual_error) &&
- !concurrency_error_code(expected_error)) ||
- ignored_error_code(actual_error))
- {
- DBUG_PRINT("info",("error ignored"));
- thd->clear_error(1);
- if (actual_error == ER_QUERY_INTERRUPTED ||
- actual_error == ER_CONNECTION_KILLED)
- thd->reset_killed();
- }
- /*
- Other cases: mostly we expected no error and get one.
- */
- else if (unlikely(thd->is_slave_error || thd->is_fatal_error))
- {
- if (!is_parallel_retry_error(rgi, actual_error))
- rli->report(ERROR_LEVEL, actual_error, rgi->gtid_info(),
- "Error '%s' on query. Default database: '%s'. Query: '%s'",
- (actual_error ? thd->get_stmt_da()->message() :
- "unexpected success or fatal error"),
- thd->get_db(), query_arg);
- thd->is_slave_error= 1;
-#ifdef WITH_WSREP
- if (wsrep_thd_is_toi(thd) && wsrep_must_ignore_error(thd))
- {
- thd->clear_error(1);
- thd->killed= NOT_KILLED;
- thd->wsrep_has_ignored_error= true;
- }
-#endif /* WITH_WSREP */
- }
-
- /*
- TODO: compare the values of "affected rows" around here. Something
- like:
- if ((uint32) affected_in_event != (uint32) affected_on_slave)
- {
- sql_print_error("Slave: did not get the expected number of affected \
- rows running query from master - expected %d, got %d (this numbers \
- should have matched modulo 4294967296).", 0, ...);
- thd->is_slave_error = 1;
- }
- We may also want an option to tell the slave to ignore "affected"
- mismatch. This mismatch could be implemented with a new ER_ code, and
- to ignore it you would use --slave-skip-errors...
-
- To do the comparison we need to know the value of "affected" which the
- above mysql_parse() computed. And we need to know the value of
- "affected" in the master's binlog. Both will be implemented later. The
- important thing is that we now have the format ready to log the values
- of "affected" in the binlog. So we can release 5.0.0 before effectively
- logging "affected" and effectively comparing it.
- */
- } /* End of if (db_ok(... */
-
- {
- /**
- The following failure injecion works in cooperation with tests
- setting @@global.debug= 'd,stop_slave_middle_group'.
- The sql thread receives the killed status and will proceed
- to shutdown trying to finish incomplete events group.
- */
- DBUG_EXECUTE_IF("stop_slave_middle_group",
- if (!current_stmt_is_commit && is_begin() == 0)
- {
- if (thd->transaction.all.modified_non_trans_table)
- const_cast<Relay_log_info*>(rli)->abort_slave= 1;
- };);
- }
-
-end:
- if (unlikely(sub_id && !thd->is_slave_error))
- rpl_global_gtid_slave_state->update_state_hash(sub_id, &gtid, hton, rgi);
-
- /*
- Probably we have set thd->query, thd->db, thd->catalog to point to places
- in the data_buf of this event. Now the event is going to be deleted
- probably, so data_buf will be freed, so the thd->... listed above will be
- pointers to freed memory.
- So we must set them to 0, so that those bad pointers values are not later
- used. Note that "cleanup" queries like automatic DROP TEMPORARY TABLE
- don't suffer from these assignments to 0 as DROP TEMPORARY
- TABLE uses the db.table syntax.
- */
- thd->catalog= 0;
- thd->set_db(&null_clex_str); /* will free the current database */
- thd->reset_query();
- DBUG_PRINT("info", ("end: query= 0"));
-
- /* Mark the statement completed. */
- MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
- thd->m_statement_psi= NULL;
- thd->m_digest= NULL;
-
- /*
- As a disk space optimization, future masters will not log an event for
- LAST_INSERT_ID() if that function returned 0 (and thus they will be able
- to replace the THD::stmt_depends_on_first_successful_insert_id_in_prev_stmt
- variable by (THD->first_successful_insert_id_in_prev_stmt > 0) ; with the
- resetting below we are ready to support that.
- */
- thd->first_successful_insert_id_in_prev_stmt_for_binlog= 0;
- thd->first_successful_insert_id_in_prev_stmt= 0;
- thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
- free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
- DBUG_RETURN(thd->is_slave_error);
-}
-
-Log_event::enum_skip_reason
-Query_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- Relay_log_info *rli= rgi->rli;
- DBUG_ENTER("Query_log_event::do_shall_skip");
- DBUG_PRINT("debug", ("query: '%s' q_len: %d", query, q_len));
- DBUG_ASSERT(query && q_len > 0);
- DBUG_ASSERT(thd == rgi->thd);
-
- /*
- An event skipped due to @@skip_replication must not be counted towards the
- number of events to be skipped due to @@sql_slave_skip_counter.
- */
- if (flags & LOG_EVENT_SKIP_REPLICATION_F &&
- opt_replicate_events_marked_for_skip != RPL_SKIP_REPLICATE)
- DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE);
-
- if (rli->slave_skip_counter > 0)
- {
- if (is_begin())
- {
- thd->variables.option_bits|= OPTION_BEGIN | OPTION_GTID_BEGIN;
- DBUG_RETURN(Log_event::continue_group(rgi));
- }
-
- if (is_commit() || is_rollback())
- {
- thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN);
- DBUG_RETURN(Log_event::EVENT_SKIP_COUNT);
- }
- }
-#ifdef WITH_WSREP
- else if (WSREP_ON && wsrep_mysql_replication_bundle && opt_slave_domain_parallel_threads == 0 &&
- thd->wsrep_mysql_replicated > 0 &&
- (is_begin() || is_commit()))
- {
- if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle)
- {
- WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated);
- DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE);
- }
- else
- {
- thd->wsrep_mysql_replicated = 0;
- }
- }
-#endif
- DBUG_RETURN(Log_event::do_shall_skip(rgi));
-}
-
-
-bool
-Query_log_event::peek_is_commit_rollback(const char *event_start,
- size_t event_len,
- enum enum_binlog_checksum_alg checksum_alg)
-{
- if (checksum_alg == BINLOG_CHECKSUM_ALG_CRC32)
- {
- if (event_len > BINLOG_CHECKSUM_LEN)
- event_len-= BINLOG_CHECKSUM_LEN;
- else
- event_len= 0;
- }
- else
- DBUG_ASSERT(checksum_alg == BINLOG_CHECKSUM_ALG_UNDEF ||
- checksum_alg == BINLOG_CHECKSUM_ALG_OFF);
-
- if (event_len < LOG_EVENT_HEADER_LEN + QUERY_HEADER_LEN || event_len < 9)
- return false;
- return !memcmp(event_start + (event_len-7), "\0COMMIT", 7) ||
- !memcmp(event_start + (event_len-9), "\0ROLLBACK", 9);
-}
-
-#endif
-
-
/**************************************************************************
Start_log_event_v3 methods
**************************************************************************/
-#ifndef MYSQL_CLIENT
-Start_log_event_v3::Start_log_event_v3()
- :Log_event(), created(0), binlog_version(BINLOG_VERSION),
- dont_set_created(0)
-{
- memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
-}
-#endif
-
-/*
- Start_log_event_v3::pack_info()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Start_log_event_v3::pack_info(Protocol *protocol)
-{
- char buf[12 + ST_SERVER_VER_LEN + 14 + 22], *pos;
- pos= strmov(buf, "Server ver: ");
- pos= strmov(pos, server_version);
- pos= strmov(pos, ", Binlog ver: ");
- pos= int10_to_str(binlog_version, pos, 10);
- protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
-}
-#endif
-
-
-/*
- Start_log_event_v3::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- DBUG_ENTER("Start_log_event_v3::print");
-
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F);
-
- if (!print_event_info->short_form)
- {
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\tStart: binlog v %d, server v %s created ",
- binlog_version, server_version) ||
- print_timestamp(&cache))
- goto err;
- if (created)
- if (my_b_printf(&cache," at startup"))
- goto err;
- if (my_b_printf(&cache, "\n"))
- goto err;
- if (flags & LOG_EVENT_BINLOG_IN_USE_F)
- if (my_b_printf(&cache,
- "# Warning: this binlog is either in use or was not "
- "closed properly.\n"))
- goto err;
- }
- if (!is_artificial_event() && created)
- {
-#ifdef WHEN_WE_HAVE_THE_RESET_CONNECTION_SQL_COMMAND
- /*
- This is for mysqlbinlog: like in replication, we want to delete the stale
- tmp files left by an unclean shutdown of mysqld (temporary tables)
- and rollback unfinished transaction.
- Probably this can be done with RESET CONNECTION (syntax to be defined).
- */
- if (my_b_printf(&cache,"RESET CONNECTION%s\n",
- print_event_info->delimiter))
- goto err;
-#else
- if (my_b_printf(&cache,"ROLLBACK%s\n", print_event_info->delimiter))
- goto err;
-#endif
- }
- if (temp_buf &&
- print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER &&
- !print_event_info->short_form)
- {
- /* BINLOG is matched with the delimiter below on the same level */
- bool do_print_encoded=
- print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS;
- if (do_print_encoded)
- my_b_printf(&cache, "BINLOG '\n");
-
- if (print_base64(&cache, print_event_info, do_print_encoded))
- goto err;
-
- if (do_print_encoded)
- my_b_printf(&cache, "'%s\n", print_event_info->delimiter);
-
- print_event_info->printed_fd_event= TRUE;
- }
- DBUG_RETURN(cache.flush_data());
-err:
- DBUG_RETURN(1);
-}
-#endif /* MYSQL_CLIENT */
-
-/*
- Start_log_event_v3::Start_log_event_v3()
-*/
Start_log_event_v3::Start_log_event_v3(const char* buf, uint event_len,
const Format_description_log_event
@@ -6137,108 +2007,6 @@ Start_log_event_v3::Start_log_event_v3(const char* buf, uint event_len,
}
-/*
- Start_log_event_v3::write()
-*/
-
-#ifndef MYSQL_CLIENT
-bool Start_log_event_v3::write()
-{
- char buff[START_V3_HEADER_LEN];
- int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
- memcpy(buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
- if (!dont_set_created)
- created= get_time(); // this sets when and when_sec_part as a side effect
- int4store(buff + ST_CREATED_OFFSET,created);
- return write_header(sizeof(buff)) ||
- write_data(buff, sizeof(buff)) ||
- write_footer();
-}
-#endif
-
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-
-/**
- Start_log_event_v3::do_apply_event() .
- The master started
-
- IMPLEMENTATION
- - To handle the case where the master died without having time to write
- DROP TEMPORARY TABLE, DO RELEASE_LOCK (prepared statements' deletion is
- TODO), we clean up all temporary tables that we got, if we are sure we
- can (see below).
-
- @todo
- - Remove all active user locks.
- Guilhem 2003-06: this is true but not urgent: the worst it can cause is
- the use of a bit of memory for a user lock which will not be used
- anymore. If the user lock is later used, the old one will be released. In
- other words, no deadlock problem.
-*/
-
-int Start_log_event_v3::do_apply_event(rpl_group_info *rgi)
-{
- DBUG_ENTER("Start_log_event_v3::do_apply_event");
- int error= 0;
- Relay_log_info *rli= rgi->rli;
-
- switch (binlog_version)
- {
- case 3:
- case 4:
- /*
- This can either be 4.x (then a Start_log_event_v3 is only at master
- startup so we are sure the master has restarted and cleared his temp
- tables; the event always has 'created'>0) or 5.0 (then we have to test
- 'created').
- */
- if (created)
- {
- rli->close_temporary_tables();
-
- /*
- The following is only false if we get here with a BINLOG statement
- */
- if (rli->mi)
- cleanup_load_tmpdir(&rli->mi->cmp_connection_name);
- }
- break;
-
- /*
- Now the older formats; in that case load_tmpdir is cleaned up by the I/O
- thread.
- */
- case 1:
- if (strncmp(rli->relay_log.description_event_for_exec->server_version,
- "3.23.57",7) >= 0 && created)
- {
- /*
- Can distinguish, based on the value of 'created': this event was
- generated at master startup.
- */
- rli->close_temporary_tables();
- }
- /*
- Otherwise, can't distinguish a Start_log_event generated at
- master startup and one generated by master FLUSH LOGS, so cannot
- be sure temp tables have to be dropped. So do nothing.
- */
- break;
- default:
- /*
- This case is not expected. It can be either an event corruption or an
- unsupported binary log version.
- */
- rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
- ER_THD(thd, ER_SLAVE_FATAL_ERROR),
- "Binlog version not supported");
- DBUG_RETURN(1);
- }
- DBUG_RETURN(error);
-}
-#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
-
/***************************************************************************
Format_description_log_event methods
****************************************************************************/
@@ -6273,7 +2041,8 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
common_header_len= LOG_EVENT_HEADER_LEN;
number_of_event_types= LOG_EVENT_TYPES;
/* we'll catch my_malloc() error in is_valid() */
- post_header_len=(uint8*) my_malloc(number_of_event_types*sizeof(uint8)
+ post_header_len=(uint8*) my_malloc(PSI_INSTRUMENT_ME,
+ number_of_event_types*sizeof(uint8)
+ BINLOG_CHECKSUM_ALG_DESC_LEN,
MYF(0));
/*
@@ -6306,6 +2075,7 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
post_header_len[USER_VAR_EVENT-1]= USER_VAR_HEADER_LEN;
post_header_len[FORMAT_DESCRIPTION_EVENT-1]= FORMAT_DESCRIPTION_HEADER_LEN;
post_header_len[XID_EVENT-1]= XID_HEADER_LEN;
+ post_header_len[XA_PREPARE_LOG_EVENT-1]= XA_PREPARE_HEADER_LEN;
post_header_len[BEGIN_LOAD_QUERY_EVENT-1]= BEGIN_LOAD_QUERY_HEADER_LEN;
post_header_len[EXECUTE_LOAD_QUERY_EVENT-1]= EXECUTE_LOAD_QUERY_HEADER_LEN;
/*
@@ -6399,8 +2169,8 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
make the slave detect less corruptions).
*/
number_of_event_types= FORMAT_DESCRIPTION_EVENT - 1;
- post_header_len=(uint8*) my_malloc(number_of_event_types*sizeof(uint8),
- MYF(0));
+ post_header_len=(uint8*) my_malloc(PSI_INSTRUMENT_ME,
+ number_of_event_types*sizeof(uint8), MYF(0));
if (post_header_len)
{
post_header_len[START_EVENT_V3-1]= START_V3_HEADER_LEN;
@@ -6468,7 +2238,8 @@ Format_description_log_event(const char* buf,
common_header_len, number_of_event_types));
/* If alloc fails, we'll detect it in is_valid() */
- post_header_len= (uint8*) my_memdup((uchar*)buf+ST_COMMON_HEADER_LEN_OFFSET+1,
+ post_header_len= (uint8*) my_memdup(PSI_INSTRUMENT_ME,
+ buf+ST_COMMON_HEADER_LEN_OFFSET+1,
number_of_event_types*
sizeof(*post_header_len),
MYF(0));
@@ -6488,159 +2259,6 @@ Format_description_log_event(const char* buf,
DBUG_VOID_RETURN;
}
-#ifndef MYSQL_CLIENT
-bool Format_description_log_event::write()
-{
- bool ret;
- bool no_checksum;
- /*
- We don't call Start_log_event_v3::write() because this would make 2
- my_b_safe_write().
- */
- uchar buff[START_V3_HEADER_LEN+1];
- size_t rec_size= sizeof(buff) + BINLOG_CHECKSUM_ALG_DESC_LEN +
- number_of_event_types;
- int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
- memcpy((char*) buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
- if (!dont_set_created)
- created= get_time();
- int4store(buff + ST_CREATED_OFFSET,created);
- buff[ST_COMMON_HEADER_LEN_OFFSET]= common_header_len;
- /*
- if checksum is requested
- record the checksum-algorithm descriptor next to
- post_header_len vector which will be followed by the checksum value.
- Master is supposed to trigger checksum computing by binlog_checksum_options,
- slave does it via marking the event according to
- FD_queue checksum_alg value.
- */
- compile_time_assert(BINLOG_CHECKSUM_ALG_DESC_LEN == 1);
-#ifdef DBUG_ASSERT_EXISTS
- data_written= 0; // to prepare for need_checksum assert
-#endif
- uint8 checksum_byte= (uint8)
- (need_checksum() ? checksum_alg : BINLOG_CHECKSUM_ALG_OFF);
- /*
- FD of checksum-aware server is always checksum-equipped, (V) is in,
- regardless of @@global.binlog_checksum policy.
- Thereby a combination of (A) == 0, (V) != 0 means
- it's the checksum-aware server's FD event that heads checksum-free binlog
- file.
- Here 0 stands for checksumming OFF to evaluate (V) as 0 is that case.
- A combination of (A) != 0, (V) != 0 denotes FD of the checksum-aware server
- heading the checksummed binlog.
- (A), (V) presence in FD of the checksum-aware server makes the event
- 1 + 4 bytes bigger comparing to the former FD.
- */
-
- if ((no_checksum= (checksum_alg == BINLOG_CHECKSUM_ALG_OFF)))
- {
- checksum_alg= BINLOG_CHECKSUM_ALG_CRC32; // Forcing (V) room to fill anyway
- }
- ret= write_header(rec_size) ||
- write_data(buff, sizeof(buff)) ||
- write_data(post_header_len, number_of_event_types) ||
- write_data(&checksum_byte, sizeof(checksum_byte)) ||
- write_footer();
- if (no_checksum)
- checksum_alg= BINLOG_CHECKSUM_ALG_OFF;
- return ret;
-}
-#endif
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Format_description_log_event::do_apply_event(rpl_group_info *rgi)
-{
- int ret= 0;
- Relay_log_info *rli= rgi->rli;
- DBUG_ENTER("Format_description_log_event::do_apply_event");
-
- /*
- As a transaction NEVER spans on 2 or more binlogs:
- if we have an active transaction at this point, the master died
- while writing the transaction to the binary log, i.e. while
- flushing the binlog cache to the binlog. XA guarantees that master has
- rolled back. So we roll back.
- Note: this event could be sent by the master to inform us of the
- format of its binlog; in other words maybe it is not at its
- original place when it comes to us; we'll know this by checking
- log_pos ("artificial" events have log_pos == 0).
- */
- if (!is_artificial_event() && created && thd->transaction.all.ha_list)
- {
- /* This is not an error (XA is safe), just an information */
- rli->report(INFORMATION_LEVEL, 0, NULL,
- "Rolling back unfinished transaction (no COMMIT "
- "or ROLLBACK in relay log). A probable cause is that "
- "the master died while writing the transaction to "
- "its binary log, thus rolled back too.");
- rgi->cleanup_context(thd, 1);
- }
-
- /*
- If this event comes from ourselves, there is no cleaning task to
- perform, we don't call Start_log_event_v3::do_apply_event()
- (this was just to update the log's description event).
- */
- if (server_id != (uint32) global_system_variables.server_id)
- {
- /*
- If the event was not requested by the slave i.e. the master sent
- it while the slave asked for a position >4, the event will make
- rli->group_master_log_pos advance. Say that the slave asked for
- position 1000, and the Format_desc event's end is 96. Then in
- the beginning of replication rli->group_master_log_pos will be
- 0, then 96, then jump to first really asked event (which is
- >96). So this is ok.
- */
- ret= Start_log_event_v3::do_apply_event(rgi);
- }
-
- if (!ret)
- {
- /* Save the information describing this binlog */
- copy_crypto_data(rli->relay_log.description_event_for_exec);
- delete rli->relay_log.description_event_for_exec;
- rli->relay_log.description_event_for_exec= this;
- }
-
- DBUG_RETURN(ret);
-}
-
-int Format_description_log_event::do_update_pos(rpl_group_info *rgi)
-{
- if (server_id == (uint32) global_system_variables.server_id)
- {
- /*
- We only increase the relay log position if we are skipping
- events and do not touch any group_* variables, nor flush the
- relay log info. If there is a crash, we will have to re-skip
- the events again, but that is a minor issue.
-
- If we do not skip stepping the group log position (and the
- server id was changed when restarting the server), it might well
- be that we start executing at a position that is invalid, e.g.,
- at a Rows_log_event or a Query_log_event preceeded by a
- Intvar_log_event instead of starting at a Table_map_log_event or
- the Intvar_log_event respectively.
- */
- rgi->inc_event_relay_log_pos();
- return 0;
- }
- else
- {
- return Log_event::do_update_pos(rgi);
- }
-}
-
-Log_event::enum_skip_reason
-Format_description_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- return Log_event::EVENT_SKIP_NOT;
-}
-
-#endif
-
bool Format_description_log_event::start_decryption(Start_encryption_log_event* sele)
{
DBUG_ASSERT(crypto_data.scheme == 0);
@@ -6776,42 +2394,7 @@ Start_encryption_log_event::Start_encryption_log_event(
crypto_scheme= ~0; // invalid
}
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Start_encryption_log_event::do_apply_event(rpl_group_info* rgi)
-{
- return rgi->rli->relay_log.description_event_for_exec->start_decryption(this);
-}
-
-int Start_encryption_log_event::do_update_pos(rpl_group_info *rgi)
-{
- /*
- master never sends Start_encryption_log_event, any SELE that a slave
- might see was created locally in MYSQL_BIN_LOG::open() on the slave
- */
- rgi->inc_event_relay_log_pos();
- return 0;
-}
-
-#endif
-#ifndef MYSQL_SERVER
-bool Start_encryption_log_event::print(FILE* file,
- PRINT_EVENT_INFO* print_event_info)
-{
- Write_on_release_cache cache(&print_event_info->head_cache, file);
- StringBuffer<1024> buf;
- buf.append(STRING_WITH_LEN("# Encryption scheme: "));
- buf.append_ulonglong(crypto_scheme);
- buf.append(STRING_WITH_LEN(", key_version: "));
- buf.append_ulonglong(key_version);
- buf.append(STRING_WITH_LEN(", nonce: "));
- buf.append_hex(nonce, BINLOG_NONCE_LENGTH);
- buf.append(STRING_WITH_LEN("\n# The rest of the binlog is encrypted!\n"));
- if (my_b_write(&cache, (uchar*)buf.ptr(), buf.length()))
- return 1;
- return (cache.flush_data());
-}
-#endif
/**************************************************************************
Load_log_event methods
General note about Load_log_event: the binlogging of LOAD DATA INFILE is
@@ -6829,252 +2412,6 @@ bool Start_encryption_log_event::print(FILE* file,
positions displayed in SHOW SLAVE STATUS then are fine too).
**************************************************************************/
-/*
- Load_log_event::print_query()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-bool Load_log_event::print_query(THD *thd, bool need_db, const char *cs,
- String *buf, my_off_t *fn_start,
- my_off_t *fn_end, const char *qualify_db)
-{
- if (need_db && db && db_len)
- {
- buf->append(STRING_WITH_LEN("use "));
- append_identifier(thd, buf, db, db_len);
- buf->append(STRING_WITH_LEN("; "));
- }
-
- buf->append(STRING_WITH_LEN("LOAD DATA "));
-
- if (is_concurrent)
- buf->append(STRING_WITH_LEN("CONCURRENT "));
-
- if (fn_start)
- *fn_start= buf->length();
-
- if (check_fname_outside_temp_buf())
- buf->append(STRING_WITH_LEN("LOCAL "));
- buf->append(STRING_WITH_LEN("INFILE '"));
- buf->append_for_single_quote(fname, fname_len);
- buf->append(STRING_WITH_LEN("' "));
-
- if (sql_ex.opt_flags & REPLACE_FLAG)
- buf->append(STRING_WITH_LEN("REPLACE "));
- else if (sql_ex.opt_flags & IGNORE_FLAG)
- buf->append(STRING_WITH_LEN("IGNORE "));
-
- buf->append(STRING_WITH_LEN("INTO"));
-
- if (fn_end)
- *fn_end= buf->length();
-
- buf->append(STRING_WITH_LEN(" TABLE "));
- if (qualify_db)
- {
- append_identifier(thd, buf, qualify_db, strlen(qualify_db));
- buf->append(STRING_WITH_LEN("."));
- }
- append_identifier(thd, buf, table_name, table_name_len);
-
- if (cs != NULL)
- {
- buf->append(STRING_WITH_LEN(" CHARACTER SET "));
- buf->append(cs, strlen(cs));
- }
-
- /* We have to create all optional fields as the default is not empty */
- buf->append(STRING_WITH_LEN(" FIELDS TERMINATED BY "));
- pretty_print_str(buf, sql_ex.field_term, sql_ex.field_term_len);
- if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG)
- buf->append(STRING_WITH_LEN(" OPTIONALLY "));
- buf->append(STRING_WITH_LEN(" ENCLOSED BY "));
- pretty_print_str(buf, sql_ex.enclosed, sql_ex.enclosed_len);
-
- buf->append(STRING_WITH_LEN(" ESCAPED BY "));
- pretty_print_str(buf, sql_ex.escaped, sql_ex.escaped_len);
-
- buf->append(STRING_WITH_LEN(" LINES TERMINATED BY "));
- pretty_print_str(buf, sql_ex.line_term, sql_ex.line_term_len);
- if (sql_ex.line_start_len)
- {
- buf->append(STRING_WITH_LEN(" STARTING BY "));
- pretty_print_str(buf, sql_ex.line_start, sql_ex.line_start_len);
- }
-
- if ((long) skip_lines > 0)
- {
- buf->append(STRING_WITH_LEN(" IGNORE "));
- buf->append_ulonglong(skip_lines);
- buf->append(STRING_WITH_LEN(" LINES "));
- }
-
- if (num_fields)
- {
- uint i;
- const char *field= fields;
- buf->append(STRING_WITH_LEN(" ("));
- for (i = 0; i < num_fields; i++)
- {
- if (i)
- {
- /*
- Yes, the space and comma is reversed here. But this is mostly dead
- code, at most used when reading really old binlogs from old servers,
- so better just leave it as is...
- */
- buf->append(STRING_WITH_LEN(" ,"));
- }
- append_identifier(thd, buf, field, field_lens[i]);
- field+= field_lens[i] + 1;
- }
- buf->append(STRING_WITH_LEN(")"));
- }
- return 0;
-}
-
-
-void Load_log_event::pack_info(Protocol *protocol)
-{
- char query_buffer[1024];
- String query_str(query_buffer, sizeof(query_buffer), system_charset_info);
-
- query_str.length(0);
- print_query(protocol->thd, TRUE, NULL, &query_str, 0, 0, NULL);
- protocol->store(query_str.ptr(), query_str.length(), &my_charset_bin);
-}
-#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
-
-
-#ifndef MYSQL_CLIENT
-
-/*
- Load_log_event::write_data_header()
-*/
-
-bool Load_log_event::write_data_header()
-{
- char buf[LOAD_HEADER_LEN];
- int4store(buf + L_THREAD_ID_OFFSET, slave_proxy_id);
- int4store(buf + L_EXEC_TIME_OFFSET, exec_time);
- int4store(buf + L_SKIP_LINES_OFFSET, skip_lines);
- buf[L_TBL_LEN_OFFSET] = (char)table_name_len;
- buf[L_DB_LEN_OFFSET] = (char)db_len;
- int4store(buf + L_NUM_FIELDS_OFFSET, num_fields);
- return write_data(buf, LOAD_HEADER_LEN) != 0;
-}
-
-
-/*
- Load_log_event::write_data_body()
-*/
-
-bool Load_log_event::write_data_body()
-{
- if (sql_ex.write_data(writer))
- return 1;
- if (num_fields && fields && field_lens)
- {
- if (write_data(field_lens, num_fields) ||
- write_data(fields, field_block_len))
- return 1;
- }
- return (write_data(table_name, table_name_len + 1) ||
- write_data(db, db_len + 1) ||
- write_data(fname, fname_len));
-}
-
-
-/*
- Load_log_event::Load_log_event()
-*/
-
-Load_log_event::Load_log_event(THD *thd_arg, const sql_exchange *ex,
- const char *db_arg, const char *table_name_arg,
- List<Item> &fields_arg,
- bool is_concurrent_arg,
- enum enum_duplicates handle_dup,
- bool ignore, bool using_trans)
- :Log_event(thd_arg,
- thd_arg->thread_specific_used ? LOG_EVENT_THREAD_SPECIFIC_F : 0,
- using_trans),
- thread_id(thd_arg->thread_id),
- slave_proxy_id((ulong)thd_arg->variables.pseudo_thread_id),
- num_fields(0),fields(0),
- field_lens(0),field_block_len(0),
- table_name(table_name_arg ? table_name_arg : ""),
- db(db_arg), fname(ex->file_name), local_fname(FALSE),
- is_concurrent(is_concurrent_arg)
-{
- time_t end_time;
- time(&end_time);
- exec_time = (ulong) (end_time - thd_arg->start_time);
- /* db can never be a zero pointer in 4.0 */
- db_len = (uint32) strlen(db);
- table_name_len = (uint32) strlen(table_name);
- fname_len = (fname) ? (uint) strlen(fname) : 0;
- sql_ex.field_term = ex->field_term->ptr();
- sql_ex.field_term_len = (uint8) ex->field_term->length();
- sql_ex.enclosed = ex->enclosed->ptr();
- sql_ex.enclosed_len = (uint8) ex->enclosed->length();
- sql_ex.line_term = ex->line_term->ptr();
- sql_ex.line_term_len = (uint8) ex->line_term->length();
- sql_ex.line_start = ex->line_start->ptr();
- sql_ex.line_start_len = (uint8) ex->line_start->length();
- sql_ex.escaped = ex->escaped->ptr();
- sql_ex.escaped_len = (uint8) ex->escaped->length();
- sql_ex.opt_flags = 0;
- sql_ex.cached_new_format = -1;
-
- if (ex->dumpfile)
- sql_ex.opt_flags|= DUMPFILE_FLAG;
- if (ex->opt_enclosed)
- sql_ex.opt_flags|= OPT_ENCLOSED_FLAG;
-
- sql_ex.empty_flags= 0;
-
- switch (handle_dup) {
- case DUP_REPLACE:
- sql_ex.opt_flags|= REPLACE_FLAG;
- break;
- case DUP_UPDATE: // Impossible here
- case DUP_ERROR:
- break;
- }
- if (ignore)
- sql_ex.opt_flags|= IGNORE_FLAG;
-
- if (!ex->field_term->length())
- sql_ex.empty_flags |= FIELD_TERM_EMPTY;
- if (!ex->enclosed->length())
- sql_ex.empty_flags |= ENCLOSED_EMPTY;
- if (!ex->line_term->length())
- sql_ex.empty_flags |= LINE_TERM_EMPTY;
- if (!ex->line_start->length())
- sql_ex.empty_flags |= LINE_START_EMPTY;
- if (!ex->escaped->length())
- sql_ex.empty_flags |= ESCAPED_EMPTY;
-
- skip_lines = ex->skip_lines;
-
- List_iterator<Item> li(fields_arg);
- field_lens_buf.length(0);
- fields_buf.length(0);
- Item* item;
- while ((item = li++))
- {
- num_fields++;
- uchar len= (uchar) item->name.length;
- field_block_len += len + 1;
- fields_buf.append(item->name.str, len + 1);
- field_lens_buf.append((char*)&len, 1);
- }
-
- field_lens = (const uchar*)field_lens_buf.ptr();
- fields = fields_buf.ptr();
-}
-#endif /* !MYSQL_CLIENT */
-
/**
@note
@@ -7172,531 +2509,10 @@ err:
}
-/*
- Load_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Load_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- return print(file, print_event_info, 0);
-}
-
-
-bool Load_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info,
- bool commented)
-{
- Write_on_release_cache cache(&print_event_info->head_cache, file_arg);
- bool different_db= 1;
- DBUG_ENTER("Load_log_event::print");
-
- if (!print_event_info->short_form)
- {
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\tQuery\tthread_id=%ld\texec_time=%ld\n",
- thread_id, exec_time))
- goto err;
- }
-
- if (db)
- {
- /*
- If the database is different from the one of the previous statement, we
- need to print the "use" command, and we update the last_db.
- But if commented, the "use" is going to be commented so we should not
- update the last_db.
- */
- if ((different_db= memcmp(print_event_info->db, db, db_len + 1)) &&
- !commented)
- memcpy(print_event_info->db, db, db_len + 1);
- }
-
- if (db && db[0] && different_db)
- if (my_b_printf(&cache, "%suse %`s%s\n",
- commented ? "# " : "",
- db, print_event_info->delimiter))
- goto err;
-
- if (flags & LOG_EVENT_THREAD_SPECIFIC_F)
- if (my_b_printf(&cache,"%sSET @@session.pseudo_thread_id=%lu%s\n",
- commented ? "# " : "", (ulong)thread_id,
- print_event_info->delimiter))
- goto err;
- if (my_b_printf(&cache, "%sLOAD DATA ",
- commented ? "# " : ""))
- goto err;
- if (check_fname_outside_temp_buf())
- if (my_b_write_string(&cache, "LOCAL "))
- goto err;
- if (my_b_printf(&cache, "INFILE '%-*s' ", fname_len, fname))
- goto err;
-
- if (sql_ex.opt_flags & REPLACE_FLAG)
- {
- if (my_b_write_string(&cache, "REPLACE "))
- goto err;
- }
- else if (sql_ex.opt_flags & IGNORE_FLAG)
- if (my_b_write_string(&cache, "IGNORE "))
- goto err;
-
- if (my_b_printf(&cache, "INTO TABLE `%s`", table_name) ||
- my_b_write_string(&cache, " FIELDS TERMINATED BY ") ||
- pretty_print_str(&cache, sql_ex.field_term, sql_ex.field_term_len))
- goto err;
-
- if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG)
- if (my_b_write_string(&cache, " OPTIONALLY "))
- goto err;
- if (my_b_write_string(&cache, " ENCLOSED BY ") ||
- pretty_print_str(&cache, sql_ex.enclosed, sql_ex.enclosed_len) ||
- my_b_write_string(&cache, " ESCAPED BY ") ||
- pretty_print_str(&cache, sql_ex.escaped, sql_ex.escaped_len) ||
- my_b_write_string(&cache, " LINES TERMINATED BY ") ||
- pretty_print_str(&cache, sql_ex.line_term, sql_ex.line_term_len))
- goto err;
-
- if (sql_ex.line_start)
- {
- if (my_b_write_string(&cache," STARTING BY ") ||
- pretty_print_str(&cache, sql_ex.line_start, sql_ex.line_start_len))
- goto err;
- }
- if ((long) skip_lines > 0)
- if (my_b_printf(&cache, " IGNORE %ld LINES", (long) skip_lines))
- goto err;
-
- if (num_fields)
- {
- uint i;
- const char* field = fields;
- if (my_b_write_string(&cache, " ("))
- goto err;
- for (i = 0; i < num_fields; i++)
- {
- if (i)
- if (my_b_write_byte(&cache, ','))
- goto err;
- if (my_b_printf(&cache, "%`s", field))
- goto err;
- field += field_lens[i] + 1;
- }
- if (my_b_write_byte(&cache, ')'))
- goto err;
- }
-
- if (my_b_printf(&cache, "%s\n", print_event_info->delimiter))
- goto err;
- DBUG_RETURN(cache.flush_data());
-err:
- DBUG_RETURN(1);
-}
-#endif /* MYSQL_CLIENT */
-
-#ifndef MYSQL_CLIENT
-
-/**
- Load_log_event::set_fields()
-
- @note
- This function can not use the member variable
- for the database, since LOAD DATA INFILE on the slave
- can be for a different database than the current one.
- This is the reason for the affected_db argument to this method.
-*/
-
-void Load_log_event::set_fields(const char* affected_db,
- List<Item> &field_list,
- Name_resolution_context *context)
-{
- uint i;
- const char* field = fields;
- for (i= 0; i < num_fields; i++)
- {
- LEX_CSTRING field_name= {field, field_lens[i] };
- field_list.push_back(new (thd->mem_root)
- Item_field(thd, context, affected_db, table_name,
- &field_name),
- thd->mem_root);
- field+= field_lens[i] + 1;
- }
-}
-#endif /* !MYSQL_CLIENT */
-
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-/**
- Does the data loading job when executing a LOAD DATA on the slave.
-
- @param net
- @param rli
- @param use_rli_only_for_errors If set to 1, rli is provided to
- Load_log_event::exec_event only for this
- function to have RPL_LOG_NAME and
- rli->last_slave_error, both being used by
- error reports. rli's position advancing
- is skipped (done by the caller which is
- Execute_load_log_event::exec_event).
- If set to 0, rli is provided for full use,
- i.e. for error reports and position
- advancing.
-
- @todo
- fix this; this can be done by testing rules in
- Create_file_log_event::exec_event() and then discarding Append_block and
- al.
- @todo
- this is a bug - this needs to be moved to the I/O thread
-
- @retval
- 0 Success
- @retval
- 1 Failure
-*/
-
-int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi,
- bool use_rli_only_for_errors)
-{
- Relay_log_info const *rli= rgi->rli;
- Rpl_filter *rpl_filter= rli->mi->rpl_filter;
- DBUG_ENTER("Load_log_event::do_apply_event");
-
- 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 */
- DBUG_ASSERT(!rgi->m_table_map.count());
- /*
- Usually lex_start() is called by mysql_parse(), but we need it here
- as the present method does not call mysql_parse().
- */
- lex_start(thd);
- thd->lex->local_file= local_fname;
- thd->reset_for_next_command(0); // Errors are cleared above
-
- /*
- We test replicate_*_db rules. Note that we have already prepared
- the file to load, even if we are going to ignore and delete it
- now. So it is possible that we did a lot of disk writes for
- nothing. In other words, a big LOAD DATA INFILE on the master will
- still consume a lot of space on the slave (space in the relay log
- + space of temp files: twice the space of the file to load...)
- even if it will finally be ignored. TODO: fix this; this can be
- done by testing rules in Create_file_log_event::do_apply_event()
- and then discarding Append_block and al. Another way is do the
- filtering in the I/O thread (more efficient: no disk writes at
- all).
-
-
- Note: We do not need to execute reset_one_shot_variables() if this
- db_ok() test fails.
- Reason: The db stored in binlog events is the same for SET and for
- its companion query. If the SET is ignored because of
- db_ok(), the companion query will also be ignored, and if
- the companion query is ignored in the db_ok() test of
- ::do_apply_event(), then the companion SET also have so
- we don't need to reset_one_shot_variables().
- */
- if (rpl_filter->db_ok(thd->db.str))
- {
- thd->set_time(when, when_sec_part);
- thd->set_query_id(next_query_id());
- thd->get_stmt_da()->opt_clear_warning_info(thd->query_id);
-
- 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;
-
- // the table will be opened in mysql_load
- if (rpl_filter->is_on() && !rpl_filter->tables_ok(thd->db.str, &tables))
- {
- // TODO: this is a bug - this needs to be moved to the I/O thread
- if (net)
- skip_load_data_infile(net);
- }
- else
- {
- enum enum_duplicates handle_dup;
- bool ignore= 0;
- char query_buffer[1024];
- String query_str(query_buffer, sizeof(query_buffer), system_charset_info);
- char *load_data_query;
-
- query_str.length(0);
- /*
- Forge LOAD DATA INFILE query which will be used in SHOW PROCESS LIST
- and written to slave's binlog if binlogging is on.
- */
- print_query(thd, FALSE, NULL, &query_str, NULL, NULL, NULL);
- if (!(load_data_query= (char *)thd->strmake(query_str.ptr(),
- query_str.length())))
- {
- /*
- This will set thd->fatal_error in case of OOM. So we surely will notice
- that something is wrong.
- */
- goto error;
- }
-
- thd->set_query(load_data_query, (uint) (query_str.length()));
-
- if (sql_ex.opt_flags & REPLACE_FLAG)
- handle_dup= DUP_REPLACE;
- else if (sql_ex.opt_flags & IGNORE_FLAG)
- {
- ignore= 1;
- handle_dup= DUP_ERROR;
- }
- else
- {
- /*
- When replication is running fine, if it was DUP_ERROR on the
- master then we could choose IGNORE here, because if DUP_ERROR
- suceeded on master, and data is identical on the master and slave,
- then there should be no uniqueness errors on slave, so IGNORE is
- the same as DUP_ERROR. But in the unlikely case of uniqueness errors
- (because the data on the master and slave happen to be different
- (user error or bug), we want LOAD DATA to print an error message on
- the slave to discover the problem.
-
- If reading from net (a 3.23 master), mysql_load() will change this
- to IGNORE.
- */
- handle_dup= DUP_ERROR;
- }
- /*
- We need to set thd->lex->sql_command and thd->lex->duplicates
- since InnoDB tests these variables to decide if this is a LOAD
- DATA ... REPLACE INTO ... statement even though mysql_parse()
- is not called. This is not needed in 5.0 since there the LOAD
- DATA ... statement is replicated using mysql_parse(), which
- sets the thd->lex fields correctly.
- */
- thd->lex->sql_command= SQLCOM_LOAD;
- thd->lex->duplicates= handle_dup;
-
- sql_exchange ex((char*)fname, sql_ex.opt_flags & DUMPFILE_FLAG);
- String field_term(sql_ex.field_term,sql_ex.field_term_len,log_cs);
- String enclosed(sql_ex.enclosed,sql_ex.enclosed_len,log_cs);
- String line_term(sql_ex.line_term,sql_ex.line_term_len,log_cs);
- String line_start(sql_ex.line_start,sql_ex.line_start_len,log_cs);
- String escaped(sql_ex.escaped,sql_ex.escaped_len, log_cs);
- ex.field_term= &field_term;
- ex.enclosed= &enclosed;
- ex.line_term= &line_term;
- ex.line_start= &line_start;
- ex.escaped= &escaped;
-
- ex.opt_enclosed = (sql_ex.opt_flags & OPT_ENCLOSED_FLAG);
- if (sql_ex.empty_flags & FIELD_TERM_EMPTY)
- ex.field_term->length(0);
-
- ex.skip_lines = skip_lines;
- List<Item> field_list;
- thd->lex->first_select_lex()->context.resolve_in_table_list_only(&tables);
- set_fields(tables.db.str,
- field_list, &thd->lex->first_select_lex()->context);
- thd->variables.pseudo_thread_id= thread_id;
- if (net)
- {
- // mysql_load will use thd->net to read the file
- thd->net.vio = net->vio;
- // Make sure the client does not get confused about the packet sequence
- thd->net.pkt_nr = net->pkt_nr;
- }
- /*
- It is safe to use tmp_list twice because we are not going to
- update it inside mysql_load().
- */
- List<Item> tmp_list;
- if (thd->open_temporary_tables(&tables) ||
- mysql_load(thd, &ex, &tables, field_list, tmp_list, tmp_list,
- handle_dup, ignore, net != 0))
- thd->is_slave_error= 1;
- if (thd->cuted_fields)
- {
- /* log_pos is the position of the LOAD event in the master log */
- sql_print_warning("Slave: load data infile on table '%s' at "
- "log position %llu in log '%s' produced %ld "
- "warning(s). Default database: '%s'",
- (char*) table_name, log_pos, RPL_LOG_NAME,
- (ulong) thd->cuted_fields,
- thd->get_db());
- }
- if (net)
- net->pkt_nr= thd->net.pkt_nr;
- }
- }
- else
- {
- /*
- We will just ask the master to send us /dev/null if we do not
- want to load the data.
- TODO: this a bug - needs to be done in I/O thread
- */
- if (net)
- skip_load_data_infile(net);
- }
-
-error:
- thd->net.vio = 0;
- const char *remember_db= thd->get_db();
- thd->catalog= 0;
- thd->set_db(&null_clex_str); /* will free the current database */
- thd->reset_query();
- thd->get_stmt_da()->set_overwrite_status(true);
- thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
- thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN);
- thd->get_stmt_da()->set_overwrite_status(false);
- close_thread_tables(thd);
- /*
- - If transaction rollback was requested due to deadlock
- perform it and release metadata locks.
- - If inside a multi-statement transaction,
- defer the release of metadata locks until the current
- transaction is either committed or rolled back. This prevents
- other statements from modifying the table for the entire
- duration of this transaction. This provides commit ordering
- and guarantees serializability across multiple transactions.
- - If in autocommit mode, or outside a transactional context,
- automatically release metadata locks of the current statement.
- */
- if (thd->transaction_rollback_request)
- {
- trans_rollback_implicit(thd);
- thd->mdl_context.release_transactional_locks();
- }
- else if (! thd->in_multi_stmt_transaction_mode())
- thd->mdl_context.release_transactional_locks();
- else
- thd->mdl_context.release_statement_locks();
-
- DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error",
- thd->is_slave_error= 0; thd->is_fatal_error= 1;);
-
- if (unlikely(thd->is_slave_error))
- {
- /* this err/sql_errno code is copy-paste from net_send_error() */
- const char *err;
- int sql_errno;
- if (thd->is_error())
- {
- err= thd->get_stmt_da()->message();
- sql_errno= thd->get_stmt_da()->sql_errno();
- }
- else
- {
- sql_errno=ER_UNKNOWN_ERROR;
- err= ER_THD(thd, sql_errno);
- }
- rli->report(ERROR_LEVEL, sql_errno, rgi->gtid_info(), "\
-Error '%s' running LOAD DATA INFILE on table '%s'. Default database: '%s'",
- err, (char*)table_name, remember_db);
- free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
- DBUG_RETURN(1);
- }
- free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
-
- if (unlikely(thd->is_fatal_error))
- {
- char buf[256];
- my_snprintf(buf, sizeof(buf),
- "Running LOAD DATA INFILE on table '%-.64s'."
- " Default database: '%-.64s'",
- (char*)table_name,
- remember_db);
-
- rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, rgi->gtid_info(),
- ER_THD(thd, ER_SLAVE_FATAL_ERROR), buf);
- DBUG_RETURN(1);
- }
-
- DBUG_RETURN( use_rli_only_for_errors ? 0 : Log_event::do_apply_event(rgi) );
-}
-#endif
-
-
/**************************************************************************
Rotate_log_event methods
**************************************************************************/
-/*
- Rotate_log_event::pack_info()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Rotate_log_event::pack_info(Protocol *protocol)
-{
- StringBuffer<256> tmp(log_cs);
- tmp.length(0);
- tmp.append(new_log_ident, ident_len);
- tmp.append(STRING_WITH_LEN(";pos="));
- tmp.append_ulonglong(pos);
- protocol->store(tmp.ptr(), tmp.length(), &my_charset_bin);
-}
-#endif
-
-
-/*
- Rotate_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Rotate_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- char buf[22];
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F);
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_write_string(&cache, "\tRotate to "))
- goto err;
- if (new_log_ident)
- if (my_b_write(&cache, (uchar*) new_log_ident, (uint)ident_len))
- goto err;
- if (my_b_printf(&cache, " pos: %s\n", llstr(pos, buf)))
- goto err;
- return cache.flush_data();
-err:
- return 1;
-}
-#endif /* MYSQL_CLIENT */
-
-
-
-/*
- Rotate_log_event::Rotate_log_event() (2 constructors)
-*/
-
-
-#ifndef MYSQL_CLIENT
-Rotate_log_event::Rotate_log_event(const char* new_log_ident_arg,
- uint ident_len_arg, ulonglong pos_arg,
- uint flags_arg)
- :Log_event(), new_log_ident(new_log_ident_arg),
- pos(pos_arg),ident_len(ident_len_arg ? ident_len_arg :
- (uint) strlen(new_log_ident_arg)), flags(flags_arg)
-{
- DBUG_ENTER("Rotate_log_event::Rotate_log_event(...,flags)");
- DBUG_PRINT("enter",("new_log_ident: %s pos: %llu flags: %lu", new_log_ident_arg,
- pos_arg, (ulong) flags));
- cache_type= EVENT_NO_CACHE;
- if (flags & DUP_NAME)
- new_log_ident= my_strndup(new_log_ident_arg, ident_len, MYF(MY_WME));
- if (flags & RELAY_LOG)
- set_relay_log_event();
- DBUG_VOID_RETURN;
-}
-#endif
-
-
Rotate_log_event::Rotate_log_event(const char* buf, uint event_len,
const Format_description_log_event* description_event)
:Log_event(buf, description_event) ,new_log_ident(0), flags(DUP_NAME)
@@ -7712,197 +2528,16 @@ Rotate_log_event::Rotate_log_event(const char* buf, uint event_len,
ident_len= (uint)(event_len - (LOG_EVENT_MINIMAL_HEADER_LEN + post_header_len));
ident_offset= post_header_len;
set_if_smaller(ident_len,FN_REFLEN-1);
- new_log_ident= my_strndup(buf + ident_offset, (uint) ident_len, MYF(MY_WME));
+ new_log_ident= my_strndup(PSI_INSTRUMENT_ME, buf + ident_offset, (uint) ident_len, MYF(MY_WME));
DBUG_PRINT("debug", ("new_log_ident: '%s'", new_log_ident));
DBUG_VOID_RETURN;
}
-/*
- Rotate_log_event::write()
-*/
-
-#ifndef MYSQL_CLIENT
-bool Rotate_log_event::write()
-{
- char buf[ROTATE_HEADER_LEN];
- int8store(buf + R_POS_OFFSET, pos);
- return (write_header(ROTATE_HEADER_LEN + ident_len) ||
- write_data(buf, ROTATE_HEADER_LEN) ||
- write_data(new_log_ident, (uint) ident_len) ||
- write_footer());
-}
-#endif
-
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-
-/*
- Got a rotate log event from the master.
-
- This is mainly used so that we can later figure out the logname and
- position for the master.
-
- We can't rotate the slave's BINlog as this will cause infinitive rotations
- in a A -> B -> A setup.
- The NOTES below is a wrong comment which will disappear when 4.1 is merged.
-
- This must only be called from the Slave SQL thread, since it calls
- Relay_log_info::flush().
-
- @retval
- 0 ok
- 1 error
-*/
-int Rotate_log_event::do_update_pos(rpl_group_info *rgi)
-{
- int error= 0;
- Relay_log_info *rli= rgi->rli;
- DBUG_ENTER("Rotate_log_event::do_update_pos");
-
- DBUG_PRINT("info", ("server_id=%lu; ::server_id=%lu",
- (ulong) this->server_id, (ulong) global_system_variables.server_id));
- DBUG_PRINT("info", ("new_log_ident: %s", this->new_log_ident));
- DBUG_PRINT("info", ("pos: %llu", this->pos));
-
- /*
- If we are in a transaction or in a group: the only normal case is
- when the I/O thread was copying a big transaction, then it was
- stopped and restarted: we have this in the relay log:
-
- BEGIN
- ...
- ROTATE (a fake one)
- ...
- COMMIT or ROLLBACK
-
- In that case, we don't want to touch the coordinates which
- correspond to the beginning of the transaction. Starting from
- 5.0.0, there also are some rotates from the slave itself, in the
- relay log, which shall not change the group positions.
-
- In parallel replication, rotate event is executed out-of-band with normal
- events, so we cannot update group_master_log_name or _pos here, it will
- be updated with the next normal event instead.
- */
- if ((server_id != global_system_variables.server_id ||
- rli->replicate_same_server_id) &&
- !is_relay_log_event() &&
- !rli->is_in_group() &&
- !rgi->is_parallel_exec)
- {
- mysql_mutex_lock(&rli->data_lock);
- DBUG_PRINT("info", ("old group_master_log_name: '%s' "
- "old group_master_log_pos: %lu",
- rli->group_master_log_name,
- (ulong) rli->group_master_log_pos));
- memcpy(rli->group_master_log_name, new_log_ident, ident_len+1);
- rli->notify_group_master_log_name_update();
- rli->inc_group_relay_log_pos(pos, rgi, TRUE /* skip_lock */);
- DBUG_PRINT("info", ("new group_master_log_name: '%s' "
- "new group_master_log_pos: %lu",
- rli->group_master_log_name,
- (ulong) rli->group_master_log_pos));
- mysql_mutex_unlock(&rli->data_lock);
- rpl_global_gtid_slave_state->record_and_update_gtid(thd, rgi);
- error= rli->flush();
-
- /*
- Reset thd->variables.option_bits and sql_mode etc, because this could
- be the signal of a master's downgrade from 5.0 to 4.0.
- However, no need to reset description_event_for_exec: indeed, if the next
- master is 5.0 (even 5.0.1) we will soon get a Format_desc; if the next
- master is 4.0 then the events are in the slave's format (conversion).
- */
- set_slave_thread_options(thd);
- set_slave_thread_default_charset(thd, rgi);
- thd->variables.sql_mode= global_system_variables.sql_mode;
- thd->variables.auto_increment_increment=
- thd->variables.auto_increment_offset= 1;
- }
- else
- rgi->inc_event_relay_log_pos();
-
- DBUG_RETURN(error);
-}
-
-
-Log_event::enum_skip_reason
-Rotate_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- enum_skip_reason reason= Log_event::do_shall_skip(rgi);
-
- switch (reason) {
- case Log_event::EVENT_SKIP_NOT:
- case Log_event::EVENT_SKIP_COUNT:
- return Log_event::EVENT_SKIP_NOT;
-
- case Log_event::EVENT_SKIP_IGNORE:
- return Log_event::EVENT_SKIP_IGNORE;
- }
- DBUG_ASSERT(0);
- return Log_event::EVENT_SKIP_NOT; // To keep compiler happy
-}
-
-#endif
-
-
/**************************************************************************
Binlog_checkpoint_log_event methods
**************************************************************************/
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Binlog_checkpoint_log_event::pack_info(Protocol *protocol)
-{
- protocol->store(binlog_file_name, binlog_file_len, &my_charset_bin);
-}
-
-
-Log_event::enum_skip_reason
-Binlog_checkpoint_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- enum_skip_reason reason= Log_event::do_shall_skip(rgi);
- if (reason == EVENT_SKIP_COUNT)
- reason= EVENT_SKIP_NOT;
- return reason;
-}
-#endif
-
-
-#ifdef MYSQL_CLIENT
-bool Binlog_checkpoint_log_event::print(FILE *file,
- PRINT_EVENT_INFO *print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F);
-
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_write_string(&cache, "\tBinlog checkpoint ") ||
- my_b_write(&cache, (uchar*)binlog_file_name, binlog_file_len) ||
- my_b_write_byte(&cache, '\n'))
- return 1;
- return cache.flush_data();
-}
-#endif /* MYSQL_CLIENT */
-
-
-#ifdef MYSQL_SERVER
-Binlog_checkpoint_log_event::Binlog_checkpoint_log_event(
- const char *binlog_file_name_arg,
- uint binlog_file_len_arg)
- :Log_event(),
- binlog_file_name(my_strndup(binlog_file_name_arg, binlog_file_len_arg,
- MYF(MY_WME))),
- binlog_file_len(binlog_file_len_arg)
-{
- cache_type= EVENT_NO_CACHE;
-}
-#endif /* MYSQL_SERVER */
-
-
Binlog_checkpoint_log_event::Binlog_checkpoint_log_event(
const char *buf, uint event_len,
const Format_description_log_event *description_event)
@@ -7920,25 +2555,12 @@ Binlog_checkpoint_log_event::Binlog_checkpoint_log_event(
binlog_file_len= uint4korr(buf);
if (event_len - (header_size + post_header_len) < binlog_file_len)
return;
- binlog_file_name= my_strndup(buf + post_header_len, binlog_file_len,
+ binlog_file_name= my_strndup(PSI_INSTRUMENT_ME, buf + post_header_len, binlog_file_len,
MYF(MY_WME));
return;
}
-#ifndef MYSQL_CLIENT
-bool Binlog_checkpoint_log_event::write()
-{
- uchar buf[BINLOG_CHECKPOINT_HEADER_LEN];
- int4store(buf, binlog_file_len);
- return write_header(BINLOG_CHECKPOINT_HEADER_LEN + binlog_file_len) ||
- write_data(buf, BINLOG_CHECKPOINT_HEADER_LEN) ||
- write_data(binlog_file_name, binlog_file_len) ||
- write_footer();
-}
-#endif /* MYSQL_CLIENT */
-
-
/**************************************************************************
Global transaction ID stuff
**************************************************************************/
@@ -7958,7 +2580,7 @@ Gtid_log_event::Gtid_log_event(const char *buf, uint event_len,
buf+= 8;
domain_id= uint4korr(buf);
buf+= 4;
- flags2= *buf;
+ flags2= *(buf++);
if (flags2 & FL_GROUP_COMMIT_ID)
{
if (event_len < (uint)header_size + GTID_HEADER_LEN + 2)
@@ -7966,338 +2588,24 @@ Gtid_log_event::Gtid_log_event(const char *buf, uint event_len,
seq_no= 0; // So is_valid() returns false
return;
}
- ++buf;
commit_id= uint8korr(buf);
+ buf+= 8;
}
-}
-
-
-#ifdef MYSQL_SERVER
-
-Gtid_log_event::Gtid_log_event(THD *thd_arg, uint64 seq_no_arg,
- uint32 domain_id_arg, bool standalone,
- uint16 flags_arg, bool is_transactional,
- uint64 commit_id_arg)
- : Log_event(thd_arg, flags_arg, is_transactional),
- seq_no(seq_no_arg), commit_id(commit_id_arg), domain_id(domain_id_arg),
- flags2((standalone ? FL_STANDALONE : 0) | (commit_id_arg ? FL_GROUP_COMMIT_ID : 0))
-{
- cache_type= Log_event::EVENT_NO_CACHE;
- bool is_tmp_table= thd_arg->lex->stmt_accessed_temp_table();
- if (thd_arg->transaction.stmt.trans_did_wait() ||
- thd_arg->transaction.all.trans_did_wait())
- flags2|= FL_WAITED;
- if (thd_arg->transaction.stmt.trans_did_ddl() ||
- thd_arg->transaction.stmt.has_created_dropped_temp_table() ||
- thd_arg->transaction.all.trans_did_ddl() ||
- thd_arg->transaction.all.has_created_dropped_temp_table())
- flags2|= FL_DDL;
- else if (is_transactional && !is_tmp_table)
- flags2|= FL_TRANSACTIONAL;
- if (!(thd_arg->variables.option_bits & OPTION_RPL_SKIP_PARALLEL))
- flags2|= FL_ALLOW_PARALLEL;
- /* Preserve any DDL or WAITED flag in the slave's binlog. */
- if (thd_arg->rgi_slave)
- flags2|= (thd_arg->rgi_slave->gtid_ev_flags2 & (FL_DDL|FL_WAITED));
-}
-
-
-/*
- Used to record GTID while sending binlog to slave, without having to
- fully contruct every Gtid_log_event() needlessly.
-*/
-bool
-Gtid_log_event::peek(const char *event_start, size_t event_len,
- enum enum_binlog_checksum_alg checksum_alg,
- uint32 *domain_id, uint32 *server_id, uint64 *seq_no,
- uchar *flags2, const Format_description_log_event *fdev)
-{
- const char *p;
-
- if (checksum_alg == BINLOG_CHECKSUM_ALG_CRC32)
- {
- if (event_len > BINLOG_CHECKSUM_LEN)
- event_len-= BINLOG_CHECKSUM_LEN;
- else
- event_len= 0;
- }
- else
- DBUG_ASSERT(checksum_alg == BINLOG_CHECKSUM_ALG_UNDEF ||
- checksum_alg == BINLOG_CHECKSUM_ALG_OFF);
-
- if (event_len < (uint32)fdev->common_header_len + GTID_HEADER_LEN)
- return true;
- *server_id= uint4korr(event_start + SERVER_ID_OFFSET);
- p= event_start + fdev->common_header_len;
- *seq_no= uint8korr(p);
- p+= 8;
- *domain_id= uint4korr(p);
- p+= 4;
- *flags2= (uchar)*p;
- return false;
-}
-
-
-bool
-Gtid_log_event::write()
-{
- uchar buf[GTID_HEADER_LEN+2];
- size_t write_len;
-
- int8store(buf, seq_no);
- int4store(buf+8, domain_id);
- buf[12]= flags2;
- if (flags2 & FL_GROUP_COMMIT_ID)
- {
- int8store(buf+13, commit_id);
- write_len= GTID_HEADER_LEN + 2;
- }
- else
- {
- bzero(buf+13, GTID_HEADER_LEN-13);
- write_len= GTID_HEADER_LEN;
- }
- return write_header(write_len) ||
- write_data(buf, write_len) ||
- write_footer();
-}
-
-
-/*
- Replace a GTID event with either a BEGIN event, dummy event, or nothing, as
- appropriate to work with old slave that does not know global transaction id.
-
- The need_dummy_event argument is an IN/OUT argument. It is passed as TRUE
- if slave has capability lower than MARIA_SLAVE_CAPABILITY_TOLERATE_HOLES.
- It is returned TRUE if we return a BEGIN (or dummy) event to be sent to the
- slave, FALSE if event should be skipped completely.
-*/
-int
-Gtid_log_event::make_compatible_event(String *packet, bool *need_dummy_event,
- ulong ev_offset,
- enum enum_binlog_checksum_alg checksum_alg)
-{
- uchar flags2;
- if (packet->length() - ev_offset < LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN)
- return 1;
- flags2= (*packet)[ev_offset + LOG_EVENT_HEADER_LEN + 12];
- if (flags2 & FL_STANDALONE)
- {
- if (*need_dummy_event)
- return Query_log_event::dummy_event(packet, ev_offset, checksum_alg);
- return 0;
- }
-
- *need_dummy_event= true;
- return Query_log_event::begin_event(packet, ev_offset, checksum_alg);
-}
-
-
-#ifdef HAVE_REPLICATION
-void
-Gtid_log_event::pack_info(Protocol *protocol)
-{
- char buf[6+5+10+1+10+1+20+1+4+20+1];
- char *p;
- p = strmov(buf, (flags2 & FL_STANDALONE ? "GTID " : "BEGIN GTID "));
- p= longlong10_to_str(domain_id, p, 10);
- *p++= '-';
- p= longlong10_to_str(server_id, p, 10);
- *p++= '-';
- p= longlong10_to_str(seq_no, p, 10);
- if (flags2 & FL_GROUP_COMMIT_ID)
- {
- p= strmov(p, " cid=");
- p= longlong10_to_str(commit_id, p, 10);
- }
-
- protocol->store(buf, p-buf, &my_charset_bin);
-}
-
-static char gtid_begin_string[] = "BEGIN";
-
-int
-Gtid_log_event::do_apply_event(rpl_group_info *rgi)
-{
- ulonglong bits= thd->variables.option_bits;
- thd->variables.server_id= this->server_id;
- thd->variables.gtid_domain_id= this->domain_id;
- thd->variables.gtid_seq_no= this->seq_no;
- rgi->gtid_ev_flags2= flags2;
- thd->reset_for_next_command();
-
- if (opt_gtid_strict_mode && opt_bin_log && opt_log_slave_updates)
- {
- if (mysql_bin_log.check_strict_gtid_sequence(this->domain_id,
- this->server_id, this->seq_no))
- return 1;
- }
-
- DBUG_ASSERT((bits & OPTION_GTID_BEGIN) == 0);
-
- Master_info *mi=rgi->rli->mi;
- switch (flags2 & (FL_DDL | FL_TRANSACTIONAL))
- {
- case FL_TRANSACTIONAL:
- mi->total_trans_groups++;
- break;
- case FL_DDL:
- mi->total_ddl_groups++;
- break;
- default:
- mi->total_non_trans_groups++;
- }
-
- if (flags2 & FL_STANDALONE)
- return 0;
-
- /* Execute this like a BEGIN query event. */
- bits|= OPTION_GTID_BEGIN;
- if (flags2 & FL_ALLOW_PARALLEL)
- bits&= ~(ulonglong)OPTION_RPL_SKIP_PARALLEL;
- else
- bits|= (ulonglong)OPTION_RPL_SKIP_PARALLEL;
- thd->variables.option_bits= bits;
- DBUG_PRINT("info", ("Set OPTION_GTID_BEGIN"));
- thd->set_query_and_id(gtid_begin_string, sizeof(gtid_begin_string)-1,
- &my_charset_bin, next_query_id());
- thd->lex->sql_command= SQLCOM_BEGIN;
- thd->is_slave_error= 0;
- status_var_increment(thd->status_var.com_stat[thd->lex->sql_command]);
- if (trans_begin(thd, 0))
- {
- DBUG_PRINT("error", ("trans_begin() failed"));
- thd->is_slave_error= 1;
- }
- thd->update_stats();
-
- if (likely(!thd->is_slave_error))
- general_log_write(thd, COM_QUERY, thd->query(), thd->query_length());
-
- thd->reset_query();
- free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
- return thd->is_slave_error;
-}
-
-
-int
-Gtid_log_event::do_update_pos(rpl_group_info *rgi)
-{
- rgi->inc_event_relay_log_pos();
- return 0;
-}
-
-
-Log_event::enum_skip_reason
-Gtid_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- Relay_log_info *rli= rgi->rli;
- /*
- An event skipped due to @@skip_replication must not be counted towards the
- number of events to be skipped due to @@sql_slave_skip_counter.
- */
- if (flags & LOG_EVENT_SKIP_REPLICATION_F &&
- opt_replicate_events_marked_for_skip != RPL_SKIP_REPLICATE)
- return Log_event::EVENT_SKIP_IGNORE;
-
- if (rli->slave_skip_counter > 0)
- {
- if (!(flags2 & FL_STANDALONE))
- {
- thd->variables.option_bits|= OPTION_BEGIN;
- DBUG_ASSERT(rgi->rli->get_flag(Relay_log_info::IN_TRANSACTION));
- }
- return Log_event::continue_group(rgi);
- }
- return Log_event::do_shall_skip(rgi);
-}
-
-
-#endif /* HAVE_REPLICATION */
-
-#else /* !MYSQL_SERVER */
-
-bool
-Gtid_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
-{
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F, this);
- char buf[21];
- char buf2[21];
-
- if (!print_event_info->short_form && !is_flashback)
+ if (flags2 & (FL_PREPARED_XA | FL_COMPLETED_XA))
{
- print_header(&cache, print_event_info, FALSE);
- longlong10_to_str(seq_no, buf, 10);
- if (my_b_printf(&cache, "\tGTID %u-%u-%s", domain_id, server_id, buf))
- goto err;
- if (flags2 & FL_GROUP_COMMIT_ID)
- {
- longlong10_to_str(commit_id, buf2, 10);
- if (my_b_printf(&cache, " cid=%s", buf2))
- goto err;
- }
- if (flags2 & FL_DDL)
- if (my_b_write_string(&cache, " ddl"))
- goto err;
- if (flags2 & FL_TRANSACTIONAL)
- if (my_b_write_string(&cache, " trans"))
- goto err;
- if (flags2 & FL_WAITED)
- if (my_b_write_string(&cache, " waited"))
- goto err;
- if (my_b_printf(&cache, "\n"))
- goto err;
-
- if (!print_event_info->allow_parallel_printed ||
- print_event_info->allow_parallel != !!(flags2 & FL_ALLOW_PARALLEL))
- {
- if (my_b_printf(&cache,
- "/*!100101 SET @@session.skip_parallel_replication=%u*/%s\n",
- !(flags2 & FL_ALLOW_PARALLEL),
- print_event_info->delimiter))
- goto err;
- print_event_info->allow_parallel= !!(flags2 & FL_ALLOW_PARALLEL);
- print_event_info->allow_parallel_printed= true;
- }
-
- if (!print_event_info->domain_id_printed ||
- print_event_info->domain_id != domain_id)
- {
- if (my_b_printf(&cache,
- "/*!100001 SET @@session.gtid_domain_id=%u*/%s\n",
- domain_id, print_event_info->delimiter))
- goto err;
- print_event_info->domain_id= domain_id;
- print_event_info->domain_id_printed= true;
- }
+ xid.formatID= uint4korr(buf);
+ buf+= 4;
- if (!print_event_info->server_id_printed ||
- print_event_info->server_id != server_id)
- {
- if (my_b_printf(&cache, "/*!100001 SET @@session.server_id=%u*/%s\n",
- server_id, print_event_info->delimiter))
- goto err;
- print_event_info->server_id= server_id;
- print_event_info->server_id_printed= true;
- }
+ xid.gtrid_length= (long) buf[0];
+ xid.bqual_length= (long) buf[1];
+ buf+= 2;
- if (!is_flashback)
- if (my_b_printf(&cache, "/*!100001 SET @@session.gtid_seq_no=%s*/%s\n",
- buf, print_event_info->delimiter))
- goto err;
+ long data_length= xid.bqual_length + xid.gtrid_length;
+ memcpy(xid.data, buf, data_length);
+ buf+= data_length;
}
- if (!(flags2 & FL_STANDALONE))
- if (my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : "BEGIN\n%s\n", print_event_info->delimiter))
- goto err;
-
- return cache.flush_data();
-err:
- return 1;
}
-#endif /* MYSQL_SERVER */
-
/* GTID list. */
@@ -8319,8 +2627,8 @@ Gtid_list_log_event::Gtid_list_log_event(const char *buf, uint event_len,
gl_flags= val & ((uint32)0xf << 28);
buf+= 4;
if (event_len - (header_size + post_header_len) < count*element_size ||
- (!(list= (rpl_gtid *)my_malloc(count*sizeof(*list) + (count == 0),
- MYF(MY_WME)))))
+ (!(list= (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME,
+ count*sizeof(*list) + (count == 0), MYF(MY_WME)))))
return;
for (i= 0; i < count; ++i)
@@ -8337,7 +2645,8 @@ Gtid_list_log_event::Gtid_list_log_event(const char *buf, uint event_len,
if ((gl_flags & FLAG_IGN_GTIDS))
{
uint32 i;
- if (!(sub_id_list= (uint64 *)my_malloc(count*sizeof(uint64), MYF(MY_WME))))
+ if (!(sub_id_list= (uint64 *)my_malloc(PSI_INSTRUMENT_ME,
+ count*sizeof(uint64), MYF(MY_WME))))
{
my_free(list);
list= NULL;
@@ -8360,213 +2669,6 @@ Gtid_list_log_event::Gtid_list_log_event(const char *buf, uint event_len,
}
-#ifdef MYSQL_SERVER
-
-Gtid_list_log_event::Gtid_list_log_event(rpl_binlog_state *gtid_set,
- uint32 gl_flags_)
- : count(gtid_set->count()), gl_flags(gl_flags_), list(0), sub_id_list(0)
-{
- cache_type= EVENT_NO_CACHE;
- /* Failure to allocate memory will be caught by is_valid() returning false. */
- if (count < (1<<28) &&
- (list = (rpl_gtid *)my_malloc(count * sizeof(*list) + (count == 0),
- MYF(MY_WME))))
- gtid_set->get_gtid_list(list, count);
-}
-
-
-Gtid_list_log_event::Gtid_list_log_event(slave_connection_state *gtid_set,
- uint32 gl_flags_)
- : count(gtid_set->count()), gl_flags(gl_flags_), list(0), sub_id_list(0)
-{
- cache_type= EVENT_NO_CACHE;
- /* Failure to allocate memory will be caught by is_valid() returning false. */
- if (count < (1<<28) &&
- (list = (rpl_gtid *)my_malloc(count * sizeof(*list) + (count == 0),
- MYF(MY_WME))))
- {
- gtid_set->get_gtid_list(list, count);
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
- if (gl_flags & FLAG_IGN_GTIDS)
- {
- uint32 i;
-
- if (!(sub_id_list= (uint64 *)my_malloc(count * sizeof(uint64),
- MYF(MY_WME))))
- {
- my_free(list);
- list= NULL;
- return;
- }
- for (i= 0; i < count; ++i)
- {
- if (!(sub_id_list[i]=
- rpl_global_gtid_slave_state->next_sub_id(list[i].domain_id)))
- {
- my_free(list);
- my_free(sub_id_list);
- list= NULL;
- sub_id_list= NULL;
- return;
- }
- }
- }
-#endif
- }
-}
-
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-bool
-Gtid_list_log_event::to_packet(String *packet)
-{
- uint32 i;
- uchar *p;
- uint32 needed_length;
-
- DBUG_ASSERT(count < 1<<28);
-
- needed_length= packet->length() + get_data_size();
- if (packet->reserve(needed_length))
- return true;
- p= (uchar *)packet->ptr() + packet->length();;
- packet->length(needed_length);
- int4store(p, (count & ((1<<28)-1)) | gl_flags);
- p += 4;
- /* Initialise the padding for empty Gtid_list. */
- if (count == 0)
- int2store(p, 0);
- for (i= 0; i < count; ++i)
- {
- int4store(p, list[i].domain_id);
- int4store(p+4, list[i].server_id);
- int8store(p+8, list[i].seq_no);
- p += 16;
- }
-
- return false;
-}
-
-
-bool
-Gtid_list_log_event::write()
-{
- char buf[128];
- String packet(buf, sizeof(buf), system_charset_info);
-
- packet.length(0);
- if (to_packet(&packet))
- return true;
- return write_header(get_data_size()) ||
- write_data(packet.ptr(), packet.length()) ||
- write_footer();
-}
-
-
-int
-Gtid_list_log_event::do_apply_event(rpl_group_info *rgi)
-{
- Relay_log_info *rli= const_cast<Relay_log_info*>(rgi->rli);
- int ret;
- if (gl_flags & FLAG_IGN_GTIDS)
- {
- void *hton= NULL;
- uint32 i;
-
- for (i= 0; i < count; ++i)
- {
- if ((ret= rpl_global_gtid_slave_state->record_gtid(thd, &list[i],
- sub_id_list[i],
- false, false, &hton)))
- return ret;
- rpl_global_gtid_slave_state->update_state_hash(sub_id_list[i], &list[i],
- hton, NULL);
- }
- }
- ret= Log_event::do_apply_event(rgi);
- if (rli->until_condition == Relay_log_info::UNTIL_GTID &&
- (gl_flags & FLAG_UNTIL_REACHED))
- {
- char str_buf[128];
- String str(str_buf, sizeof(str_buf), system_charset_info);
- rli->until_gtid_pos.to_string(&str);
- sql_print_information("Slave SQL thread stops because it reached its"
- " UNTIL master_gtid_pos %s", str.c_ptr_safe());
- rli->abort_slave= true;
- rli->stop_for_until= true;
- }
- free_root(thd->mem_root, MYF(MY_KEEP_PREALLOC));
- return ret;
-}
-
-
-Log_event::enum_skip_reason
-Gtid_list_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- enum_skip_reason reason= Log_event::do_shall_skip(rgi);
- if (reason == EVENT_SKIP_COUNT)
- reason= EVENT_SKIP_NOT;
- return reason;
-}
-
-
-void
-Gtid_list_log_event::pack_info(Protocol *protocol)
-{
- char buf_mem[1024];
- String buf(buf_mem, sizeof(buf_mem), system_charset_info);
- uint32 i;
- bool first;
-
- buf.length(0);
- buf.append(STRING_WITH_LEN("["));
- first= true;
- for (i= 0; i < count; ++i)
- rpl_slave_state_tostring_helper(&buf, &list[i], &first);
- buf.append(STRING_WITH_LEN("]"));
-
- protocol->store(&buf);
-}
-#endif /* HAVE_REPLICATION */
-
-#else /* !MYSQL_SERVER */
-
-bool
-Gtid_list_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F);
- char buf[21];
- uint32 i;
-
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\tGtid list ["))
- goto err;
-
- for (i= 0; i < count; ++i)
- {
- longlong10_to_str(list[i].seq_no, buf, 10);
- if (my_b_printf(&cache, "%u-%u-%s", list[i].domain_id,
- list[i].server_id, buf))
- goto err;
- if (i < count-1)
- if (my_b_printf(&cache, ",\n# "))
- goto err;
- }
- if (my_b_printf(&cache, "]\n"))
- goto err;
-
- return cache.flush_data();
-err:
- return 1;
-}
-
-#endif /* MYSQL_SERVER */
-
-
/*
Used to record gtid_list event while sending binlog to slave, without having to
fully contruct the event object.
@@ -8601,8 +2703,8 @@ Gtid_list_log_event::peek(const char *event_start, size_t event_len,
if (event_len < (uint32)fdev->common_header_len + GTID_LIST_HEADER_LEN +
16 * count)
return true;
- if (!(gtid_list= (rpl_gtid *)my_malloc(sizeof(rpl_gtid)*count + (count == 0),
- MYF(MY_WME))))
+ if (!(gtid_list= (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME,
+ sizeof(rpl_gtid)*count + (count == 0), MYF(MY_WME))))
return true;
*out_gtid_list= gtid_list;
*out_list_len= count;
@@ -8626,22 +2728,6 @@ Gtid_list_log_event::peek(const char *event_start, size_t event_len,
**************************************************************************/
/*
- Intvar_log_event::pack_info()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Intvar_log_event::pack_info(Protocol *protocol)
-{
- char buf[256], *pos;
- pos= strmake(buf, get_var_type_name(), sizeof(buf)-23);
- *pos++= '=';
- pos= longlong10_to_str(val, pos, -10);
- protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
-}
-#endif
-
-
-/*
Intvar_log_event::Intvar_log_event()
*/
@@ -8671,135 +2757,10 @@ const char* Intvar_log_event::get_var_type_name()
}
-/*
- Intvar_log_event::write()
-*/
-
-#ifndef MYSQL_CLIENT
-bool Intvar_log_event::write()
-{
- uchar buf[9];
- buf[I_TYPE_OFFSET]= (uchar) type;
- int8store(buf + I_VAL_OFFSET, val);
- return write_header(sizeof(buf)) ||
- write_data(buf, sizeof(buf)) ||
- write_footer();
-}
-#endif
-
-
-/*
- Intvar_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- char llbuff[22];
- const char *UNINIT_VAR(msg);
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F);
-
- if (!print_event_info->short_form)
- {
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_write_string(&cache, "\tIntvar\n"))
- goto err;
- }
-
- if (my_b_printf(&cache, "SET "))
- goto err;
- switch (type) {
- case LAST_INSERT_ID_EVENT:
- msg="LAST_INSERT_ID";
- break;
- case INSERT_ID_EVENT:
- msg="INSERT_ID";
- break;
- case INVALID_INT_EVENT:
- default: // cannot happen
- msg="INVALID_INT";
- break;
- }
- if (my_b_printf(&cache, "%s=%s%s\n",
- msg, llstr(val,llbuff), print_event_info->delimiter))
- goto err;
-
- return cache.flush_data();
-err:
- return 1;
-}
-#endif
-
-
-#if defined(HAVE_REPLICATION)&& !defined(MYSQL_CLIENT)
-
-/*
- Intvar_log_event::do_apply_event()
-*/
-
-int Intvar_log_event::do_apply_event(rpl_group_info *rgi)
-{
- DBUG_ENTER("Intvar_log_event::do_apply_event");
- if (rgi->deferred_events_collecting)
- {
- DBUG_PRINT("info",("deferring event"));
- DBUG_RETURN(rgi->deferred_events->add(this));
- }
-
- switch (type) {
- case LAST_INSERT_ID_EVENT:
- thd->first_successful_insert_id_in_prev_stmt= val;
- DBUG_PRINT("info",("last_insert_id_event: %ld", (long) val));
- break;
- case INSERT_ID_EVENT:
- thd->force_one_auto_inc_interval(val);
- break;
- }
- DBUG_RETURN(0);
-}
-
-int Intvar_log_event::do_update_pos(rpl_group_info *rgi)
-{
- rgi->inc_event_relay_log_pos();
- return 0;
-}
-
-
-Log_event::enum_skip_reason
-Intvar_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- /*
- It is a common error to set the slave skip counter to 1 instead of
- 2 when recovering from an insert which used a auto increment,
- rand, or user var. Therefore, if the slave skip counter is 1, we
- just say that this event should be skipped by ignoring it, meaning
- that we do not change the value of the slave skip counter since it
- will be decreased by the following insert event.
- */
- return continue_group(rgi);
-}
-
-#endif
-
-
/**************************************************************************
Rand_log_event methods
**************************************************************************/
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Rand_log_event::pack_info(Protocol *protocol)
-{
- char buf1[256], *pos;
- pos= strmov(buf1,"rand_seed1=");
- pos= int10_to_str((long) seed1, pos, 10);
- pos= strmov(pos, ",rand_seed2=");
- pos= int10_to_str((long) seed2, pos, 10);
- protocol->store(buf1, (uint) (pos-buf1), &my_charset_bin);
-}
-#endif
-
-
Rand_log_event::Rand_log_event(const char* buf,
const Format_description_log_event* description_event)
:Log_event(buf, description_event)
@@ -8812,118 +2773,10 @@ Rand_log_event::Rand_log_event(const char* buf,
}
-#ifndef MYSQL_CLIENT
-bool Rand_log_event::write()
-{
- uchar buf[16];
- int8store(buf + RAND_SEED1_OFFSET, seed1);
- int8store(buf + RAND_SEED2_OFFSET, seed2);
- return write_header(sizeof(buf)) ||
- write_data(buf, sizeof(buf)) ||
- write_footer();
-}
-#endif
-
-
-#ifdef MYSQL_CLIENT
-bool Rand_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F);
-
- char llbuff[22],llbuff2[22];
- if (!print_event_info->short_form)
- {
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_write_string(&cache, "\tRand\n"))
- goto err;
- }
- if (my_b_printf(&cache, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s%s\n",
- llstr(seed1, llbuff),llstr(seed2, llbuff2),
- print_event_info->delimiter))
- goto err;
-
- return cache.flush_data();
-err:
- return 1;
-}
-#endif /* MYSQL_CLIENT */
-
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Rand_log_event::do_apply_event(rpl_group_info *rgi)
-{
- if (rgi->deferred_events_collecting)
- return rgi->deferred_events->add(this);
-
- thd->rand.seed1= (ulong) seed1;
- thd->rand.seed2= (ulong) seed2;
- return 0;
-}
-
-int Rand_log_event::do_update_pos(rpl_group_info *rgi)
-{
- rgi->inc_event_relay_log_pos();
- return 0;
-}
-
-
-Log_event::enum_skip_reason
-Rand_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- /*
- It is a common error to set the slave skip counter to 1 instead of
- 2 when recovering from an insert which used a auto increment,
- rand, or user var. Therefore, if the slave skip counter is 1, we
- just say that this event should be skipped by ignoring it, meaning
- that we do not change the value of the slave skip counter since it
- will be decreased by the following insert event.
- */
- return continue_group(rgi);
-}
-
-/**
- Exec deferred Int-, Rand- and User- var events prefixing
- a Query-log-event event.
-
- @param thd THD handle
-
- @return false on success, true if a failure in an event applying occurred.
-*/
-bool slave_execute_deferred_events(THD *thd)
-{
- bool res= false;
- rpl_group_info *rgi= thd->rgi_slave;
-
- DBUG_ASSERT(rgi && (!rgi->deferred_events_collecting || rgi->deferred_events));
-
- if (!rgi->deferred_events_collecting || rgi->deferred_events->is_empty())
- return res;
-
- res= rgi->deferred_events->execute(rgi);
- rgi->deferred_events->rewind();
-
- return res;
-}
-
-#endif /* !MYSQL_CLIENT */
-
-
/**************************************************************************
Xid_log_event methods
**************************************************************************/
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Xid_log_event::pack_info(Protocol *protocol)
-{
- char buf[128], *pos;
- pos= strmov(buf, "COMMIT /* xid=");
- pos= longlong10_to_str(xid, pos, 10);
- pos= strmov(pos, " */");
- protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
-}
-#endif
-
/**
@note
It's ok not to use int8store here,
@@ -8936,7 +2789,7 @@ void Xid_log_event::pack_info(Protocol *protocol)
Xid_log_event::
Xid_log_event(const char* buf,
const Format_description_log_event *description_event)
- :Log_event(buf, description_event)
+ :Xid_apply_log_event(buf, description_event)
{
/* The Post-Header is empty. The Variable Data part begins immediately. */
buf+= description_event->common_header_len +
@@ -8944,273 +2797,48 @@ Xid_log_event(const char* buf,
memcpy((char*) &xid, buf, sizeof(xid));
}
-
-#ifndef MYSQL_CLIENT
-bool Xid_log_event::write()
-{
- DBUG_EXECUTE_IF("do_not_write_xid", return 0;);
- return write_header(sizeof(xid)) ||
- write_data((uchar*)&xid, sizeof(xid)) ||
- write_footer();
-}
-#endif
-
-
-#ifdef MYSQL_CLIENT
-bool Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+/**************************************************************************
+ XA_prepare_log_event methods
+**************************************************************************/
+XA_prepare_log_event::
+XA_prepare_log_event(const char* buf,
+ const Format_description_log_event *description_event)
+ :Xid_apply_log_event(buf, description_event)
{
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F, this);
+ buf+= description_event->common_header_len +
+ description_event->post_header_len[XA_PREPARE_LOG_EVENT-1];
+ one_phase= * (bool *) buf;
+ buf+= 1;
- if (!print_event_info->short_form)
+ m_xid.formatID= uint4korr(buf);
+ buf+= 4;
+ m_xid.gtrid_length= uint4korr(buf);
+ buf+= 4;
+ // Todo: validity here and elsewhere checks to be replaced by MDEV-21839 fixes
+ if (m_xid.gtrid_length <= 0 || m_xid.gtrid_length > MAXGTRIDSIZE)
{
- char buf[64];
- longlong10_to_str(xid, buf, 10);
-
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\tXid = %s\n", buf))
- goto err;
+ m_xid.formatID= -1;
+ return;
}
- if (my_b_printf(&cache, is_flashback ? "BEGIN%s\n" : "COMMIT%s\n",
- print_event_info->delimiter))
- goto err;
-
- return cache.flush_data();
-err:
- return 1;
-}
-#endif /* MYSQL_CLIENT */
-
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Xid_log_event::do_apply_event(rpl_group_info *rgi)
-{
- bool res;
- int err;
- rpl_gtid gtid;
- uint64 sub_id= 0;
- Relay_log_info const *rli= rgi->rli;
- void *hton= NULL;
-
- /*
- XID_EVENT works like a COMMIT statement. And it also updates the
- mysql.gtid_slave_pos table with the GTID of the current transaction.
-
- Therefore, it acts much like a normal SQL statement, so we need to do
- THD::reset_for_next_command() as if starting a new statement.
- */
- thd->reset_for_next_command();
- /*
- Record any GTID in the same transaction, so slave state is transactionally
- consistent.
- */
-#ifdef WITH_WSREP
- thd->wsrep_affected_rows= 0;
-#endif
-
- if (rgi->gtid_pending)
+ m_xid.bqual_length= uint4korr(buf);
+ buf+= 4;
+ if (m_xid.bqual_length < 0 || m_xid.bqual_length > MAXBQUALSIZE)
{
- sub_id= rgi->gtid_sub_id;
- rgi->gtid_pending= false;
-
- gtid= rgi->current_gtid;
- err= rpl_global_gtid_slave_state->record_gtid(thd, &gtid, sub_id, true,
- false, &hton);
- if (unlikely(err))
- {
- int ec= thd->get_stmt_da()->sql_errno();
- /*
- Do not report an error if this is really a kill due to a deadlock.
- In this case, the transaction will be re-tried instead.
- */
- if (!is_parallel_retry_error(rgi, ec))
- rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE, rgi->gtid_info(),
- "Error during XID COMMIT: failed to update GTID state in "
- "%s.%s: %d: %s",
- "mysql", rpl_gtid_slave_state_table_name.str, ec,
- thd->get_stmt_da()->message());
- thd->is_slave_error= 1;
- return err;
- }
-
- DBUG_EXECUTE_IF("gtid_fail_after_record_gtid",
- { my_error(ER_ERROR_DURING_COMMIT, MYF(0), HA_ERR_WRONG_COMMAND);
- thd->is_slave_error= 1;
- return 1;
- });
+ m_xid.formatID= -1;
+ return;
}
+ DBUG_ASSERT(m_xid.gtrid_length + m_xid.bqual_length <= XIDDATASIZE);
- /* For a slave Xid_log_event is COMMIT */
- general_log_print(thd, COM_QUERY,
- "COMMIT /* implicit, from Xid_log_event */");
- thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
- res= trans_commit(thd); /* Automatically rolls back on error. */
- thd->mdl_context.release_transactional_locks();
-#ifdef WITH_WSREP
- if (WSREP(thd)) mysql_mutex_lock(&thd->LOCK_thd_data);
- if ((!res || (WSREP(thd) && thd->wsrep_trx().state() == wsrep::transaction::s_must_replay )) && sub_id)
-#else
- if (likely(!res) && sub_id)
-#endif /* WITH_WSREP */
- rpl_global_gtid_slave_state->update_state_hash(sub_id, &gtid, hton, rgi);
-#ifdef WITH_WSREP
- if (WSREP(thd)) mysql_mutex_unlock(&thd->LOCK_thd_data);
-#endif /* WITH_WSREP */
- /*
- Increment the global status commit count variable
- */
- status_var_increment(thd->status_var.com_stat[SQLCOM_COMMIT]);
+ memcpy(m_xid.data, buf, m_xid.gtrid_length + m_xid.bqual_length);
- return res;
+ xid= NULL;
}
-Log_event::enum_skip_reason
-Xid_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- DBUG_ENTER("Xid_log_event::do_shall_skip");
- if (rgi->rli->slave_skip_counter > 0)
- {
- DBUG_ASSERT(!rgi->rli->get_flag(Relay_log_info::IN_TRANSACTION));
- thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN);
- DBUG_RETURN(Log_event::EVENT_SKIP_COUNT);
- }
-#ifdef WITH_WSREP
- else if (wsrep_mysql_replication_bundle && WSREP_ON &&
- opt_slave_domain_parallel_threads == 0)
- {
- if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle)
- {
- WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated);
- DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE);
- }
- else
- {
- thd->wsrep_mysql_replicated = 0;
- }
- }
-#endif
- DBUG_RETURN(Log_event::do_shall_skip(rgi));
-}
-#endif /* !MYSQL_CLIENT */
-
/**************************************************************************
User_var_log_event methods
**************************************************************************/
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-static bool
-user_var_append_name_part(THD *thd, String *buf,
- const char *name, size_t name_len)
-{
- return buf->append("@") ||
- append_identifier(thd, buf, name, name_len) ||
- buf->append("=");
-}
-
-void User_var_log_event::pack_info(Protocol* protocol)
-{
- if (is_null)
- {
- char buf_mem[FN_REFLEN+7];
- String buf(buf_mem, sizeof(buf_mem), system_charset_info);
- buf.length(0);
- if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
- buf.append("NULL"))
- return;
- protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
- }
- else
- {
- switch (type) {
- case REAL_RESULT:
- {
- double real_val;
- char buf2[MY_GCVT_MAX_FIELD_WIDTH+1];
- char buf_mem[FN_REFLEN + MY_GCVT_MAX_FIELD_WIDTH + 1];
- String buf(buf_mem, sizeof(buf_mem), system_charset_info);
- float8get(real_val, val);
- buf.length(0);
- if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
- buf.append(buf2, my_gcvt(real_val, MY_GCVT_ARG_DOUBLE,
- MY_GCVT_MAX_FIELD_WIDTH, buf2, NULL)))
- return;
- protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
- break;
- }
- case INT_RESULT:
- {
- char buf2[22];
- char buf_mem[FN_REFLEN + 22];
- String buf(buf_mem, sizeof(buf_mem), system_charset_info);
- buf.length(0);
- if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
- buf.append(buf2,
- longlong10_to_str(uint8korr(val), buf2,
- ((flags & User_var_log_event::UNSIGNED_F) ? 10 : -10))-buf2))
- return;
- protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
- break;
- }
- case DECIMAL_RESULT:
- {
- char buf_mem[FN_REFLEN + DECIMAL_MAX_STR_LENGTH];
- String buf(buf_mem, sizeof(buf_mem), system_charset_info);
- char buf2[DECIMAL_MAX_STR_LENGTH+1];
- String str(buf2, sizeof(buf2), &my_charset_bin);
- buf.length(0);
- my_decimal((const uchar *) (val + 2), val[0], val[1]).to_string(&str);
- if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
- buf.append(buf2))
- return;
- protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
- break;
- }
- case STRING_RESULT:
- {
- /* 15 is for 'COLLATE' and other chars */
- char buf_mem[FN_REFLEN + 512 + 1 + 2*MY_CS_NAME_SIZE+15];
- String buf(buf_mem, sizeof(buf_mem), system_charset_info);
- CHARSET_INFO *cs;
- buf.length(0);
- if (!(cs= get_charset(charset_number, MYF(0))))
- {
- if (buf.append("???"))
- return;
- }
- else
- {
- size_t old_len;
- char *beg, *end;
- if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
- buf.append("_") ||
- buf.append(cs->csname) ||
- buf.append(" "))
- return;
- old_len= buf.length();
- if (buf.reserve(old_len + val_len * 2 + 3 + sizeof(" COLLATE ") +
- MY_CS_NAME_SIZE))
- return;
- beg= const_cast<char *>(buf.ptr()) + old_len;
- end= str_to_hex(beg, val, val_len);
- buf.length(old_len + (end - beg));
- if (buf.append(" COLLATE ") ||
- buf.append(cs->name))
- return;
- }
- protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
- break;
- }
- case ROW_RESULT:
- default:
- DBUG_ASSERT(0);
- return;
- }
- }
-}
-#endif /* !MYSQL_CLIENT */
-
-
User_var_log_event::
User_var_log_event(const char* buf, uint event_len,
const Format_description_log_event* description_event)
@@ -9303,434 +2931,6 @@ err:
}
-#ifndef MYSQL_CLIENT
-bool User_var_log_event::write()
-{
- char buf[UV_NAME_LEN_SIZE];
- char buf1[UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
- UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE];
- uchar buf2[MY_MAX(8, DECIMAL_MAX_FIELD_SIZE + 2)], *pos= buf2;
- uint unsigned_len= 0;
- uint buf1_length;
- size_t event_length;
-
- int4store(buf, name_len);
-
- if ((buf1[0]= is_null))
- {
- buf1_length= 1;
- val_len= 0; // Length of 'pos'
- }
- else
- {
- buf1[1]= type;
- int4store(buf1 + 2, charset_number);
-
- switch (type) {
- case REAL_RESULT:
- float8store(buf2, *(double*) val);
- break;
- case INT_RESULT:
- int8store(buf2, *(longlong*) val);
- unsigned_len= 1;
- break;
- case DECIMAL_RESULT:
- {
- my_decimal *dec= (my_decimal *)val;
- dec->fix_buffer_pointer();
- buf2[0]= (char)(dec->intg + dec->frac);
- buf2[1]= (char)dec->frac;
- decimal2bin((decimal_t*)val, buf2+2, buf2[0], buf2[1]);
- val_len= decimal_bin_size(buf2[0], buf2[1]) + 2;
- break;
- }
- case STRING_RESULT:
- pos= (uchar*) val;
- break;
- case ROW_RESULT:
- default:
- DBUG_ASSERT(0);
- return 0;
- }
- int4store(buf1 + 2 + UV_CHARSET_NUMBER_SIZE, val_len);
- buf1_length= 10;
- }
-
- /* Length of the whole event */
- event_length= sizeof(buf)+ name_len + buf1_length + val_len + unsigned_len;
-
- return write_header(event_length) ||
- write_data(buf, sizeof(buf)) ||
- write_data(name, name_len) ||
- write_data(buf1, buf1_length) ||
- write_data(pos, val_len) ||
- write_data(&flags, unsigned_len) ||
- write_footer();
-}
-#endif
-
-
-/*
- User_var_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F);
-
- if (!print_event_info->short_form)
- {
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_write_string(&cache, "\tUser_var\n"))
- goto err;
- }
-
- if (my_b_write_string(&cache, "SET @") ||
- my_b_write_backtick_quote(&cache, name, name_len))
- goto err;
-
- if (is_null)
- {
- if (my_b_printf(&cache, ":=NULL%s\n", print_event_info->delimiter))
- goto err;
- }
- else
- {
- switch (type) {
- case REAL_RESULT:
- double real_val;
- char real_buf[FMT_G_BUFSIZE(14)];
- float8get(real_val, val);
- sprintf(real_buf, "%.14g", real_val);
- if (my_b_printf(&cache, ":=%s%s\n", real_buf,
- print_event_info->delimiter))
- goto err;
- break;
- case INT_RESULT:
- char int_buf[22];
- longlong10_to_str(uint8korr(val), int_buf,
- ((flags & User_var_log_event::UNSIGNED_F) ? 10 : -10));
- if (my_b_printf(&cache, ":=%s%s\n", int_buf,
- print_event_info->delimiter))
- goto err;
- break;
- case DECIMAL_RESULT:
- {
- char str_buf[200];
- int str_len= sizeof(str_buf) - 1;
- int precision= (int)val[0];
- int scale= (int)val[1];
- decimal_digit_t dec_buf[10];
- decimal_t dec;
- dec.len= 10;
- dec.buf= dec_buf;
-
- bin2decimal((uchar*) val+2, &dec, precision, scale);
- decimal2string(&dec, str_buf, &str_len, 0, 0, 0);
- str_buf[str_len]= 0;
- if (my_b_printf(&cache, ":=%s%s\n", str_buf,
- print_event_info->delimiter))
- goto err;
- break;
- }
- case STRING_RESULT:
- {
- /*
- Let's express the string in hex. That's the most robust way. If we
- print it in character form instead, we need to escape it with
- character_set_client which we don't know (we will know it in 5.0, but
- in 4.1 we don't know it easily when we are printing
- User_var_log_event). Explanation why we would need to bother with
- character_set_client (quoting Bar):
- > Note, the parser doesn't switch to another unescaping mode after
- > it has met a character set introducer.
- > For example, if an SJIS client says something like:
- > SET @a= _ucs2 \0a\0b'
- > the string constant is still unescaped according to SJIS, not
- > according to UCS2.
- */
- char *hex_str;
- CHARSET_INFO *cs;
- bool error;
-
- // 2 hex digits / byte
- hex_str= (char *) my_malloc(2 * val_len + 1 + 3, MYF(MY_WME));
- if (!hex_str)
- goto err;
- str_to_hex(hex_str, val, val_len);
- /*
- For proper behaviour when mysqlbinlog|mysql, we need to explicitly
- specify the variable's collation. It will however cause problems when
- people want to mysqlbinlog|mysql into another server not supporting the
- character set. But there's not much to do about this and it's unlikely.
- */
- if (!(cs= get_charset(charset_number, MYF(0))))
- { /*
- Generate an unusable command (=> syntax error) is probably the best
- thing we can do here.
- */
- error= my_b_printf(&cache, ":=???%s\n", print_event_info->delimiter);
- }
- else
- error= my_b_printf(&cache, ":=_%s %s COLLATE `%s`%s\n",
- cs->csname, hex_str, cs->name,
- print_event_info->delimiter);
- my_free(hex_str);
- if (unlikely(error))
- goto err;
- break;
- }
- case ROW_RESULT:
- default:
- DBUG_ASSERT(0);
- break;
- }
- }
-
- return cache.flush_data();
-err:
- return 1;
-}
-#endif
-
-
-/*
- User_var_log_event::do_apply_event()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int User_var_log_event::do_apply_event(rpl_group_info *rgi)
-{
- Item *it= 0;
- CHARSET_INFO *charset;
- DBUG_ENTER("User_var_log_event::do_apply_event");
- query_id_t sav_query_id= 0; /* memorize orig id when deferred applying */
-
- if (rgi->deferred_events_collecting)
- {
- set_deferred(current_thd->query_id);
- DBUG_RETURN(rgi->deferred_events->add(this));
- }
- else if (is_deferred())
- {
- sav_query_id= current_thd->query_id;
- current_thd->query_id= query_id; /* recreating original time context */
- }
-
- if (!(charset= get_charset(charset_number, MYF(MY_WME))))
- {
- rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
- ER_THD(thd, ER_SLAVE_FATAL_ERROR),
- "Invalid character set for User var event");
- DBUG_RETURN(1);
- }
- LEX_CSTRING user_var_name;
- user_var_name.str= name;
- user_var_name.length= name_len;
- double real_val;
- longlong int_val;
-
- if (is_null)
- {
- it= new (thd->mem_root) Item_null(thd);
- }
- else
- {
- switch (type) {
- case REAL_RESULT:
- if (val_len != 8)
- {
- rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
- ER_THD(thd, ER_SLAVE_FATAL_ERROR),
- "Invalid variable length at User var event");
- return 1;
- }
- float8get(real_val, val);
- it= new (thd->mem_root) Item_float(thd, real_val, 0);
- val= (char*) &real_val; // Pointer to value in native format
- val_len= 8;
- break;
- case INT_RESULT:
- if (val_len != 8)
- {
- rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
- ER_THD(thd, ER_SLAVE_FATAL_ERROR),
- "Invalid variable length at User var event");
- return 1;
- }
- int_val= (longlong) uint8korr(val);
- it= new (thd->mem_root) Item_int(thd, int_val);
- val= (char*) &int_val; // Pointer to value in native format
- val_len= 8;
- break;
- case DECIMAL_RESULT:
- {
- if (val_len < 3)
- {
- rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
- ER_THD(thd, ER_SLAVE_FATAL_ERROR),
- "Invalid variable length at User var event");
- return 1;
- }
- Item_decimal *dec= new (thd->mem_root) Item_decimal(thd, (uchar*) val+2, val[0], val[1]);
- it= dec;
- val= (char *)dec->val_decimal(NULL);
- val_len= sizeof(my_decimal);
- break;
- }
- case STRING_RESULT:
- it= new (thd->mem_root) Item_string(thd, val, (uint)val_len, charset);
- break;
- case ROW_RESULT:
- default:
- DBUG_ASSERT(0);
- DBUG_RETURN(0);
- }
- }
-
- Item_func_set_user_var *e= new (thd->mem_root) Item_func_set_user_var(thd, &user_var_name, it);
- /*
- Item_func_set_user_var can't substitute something else on its place =>
- 0 can be passed as last argument (reference on item)
-
- Fix_fields() can fail, in which case a call of update_hash() might
- crash the server, so if fix fields fails, we just return with an
- error.
- */
- if (e->fix_fields(thd, 0))
- DBUG_RETURN(1);
-
- /*
- A variable can just be considered as a table with
- a single record and with a single column. Thus, like
- a column value, it could always have IMPLICIT derivation.
- */
- e->update_hash((void*) val, val_len, type, charset,
- (flags & User_var_log_event::UNSIGNED_F));
- if (!is_deferred())
- free_root(thd->mem_root, 0);
- else
- current_thd->query_id= sav_query_id; /* restore current query's context */
-
- DBUG_RETURN(0);
-}
-
-int User_var_log_event::do_update_pos(rpl_group_info *rgi)
-{
- rgi->inc_event_relay_log_pos();
- return 0;
-}
-
-Log_event::enum_skip_reason
-User_var_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- /*
- It is a common error to set the slave skip counter to 1 instead
- of 2 when recovering from an insert which used a auto increment,
- rand, or user var. Therefore, if the slave skip counter is 1, we
- just say that this event should be skipped by ignoring it, meaning
- that we do not change the value of the slave skip counter since it
- will be decreased by the following insert event.
- */
- return continue_group(rgi);
-}
-#endif /* !MYSQL_CLIENT */
-
-#ifdef HAVE_REPLICATION
-#ifdef MYSQL_CLIENT
-bool Unknown_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- Write_on_release_cache cache(&print_event_info->head_cache, file_arg);
-
- if (what != ENCRYPTED)
- {
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\n# Unknown event\n"))
- goto err;
- }
- else if (my_b_printf(&cache, "# Encrypted event\n"))
- goto err;
-
- return cache.flush_data();
-err:
- return 1;
-}
-#endif
-
-/**************************************************************************
- Stop_log_event methods
-**************************************************************************/
-
-/*
- Stop_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Stop_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F, this);
-
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_write_string(&cache, "\tStop\n"))
- return 1;
- return cache.flush_data();
-}
-#endif /* MYSQL_CLIENT */
-
-
-#ifndef MYSQL_CLIENT
-/*
- The master stopped. We used to clean up all temporary tables but
- this is useless as, as the master has shut down properly, it has
- written all DROP TEMPORARY TABLE (prepared statements' deletion is
- TODO only when we binlog prep stmts). We used to clean up
- slave_load_tmpdir, but this is useless as it has been cleared at the
- end of LOAD DATA INFILE. So we have nothing to do here. The place
- were we must do this cleaning is in
- Start_log_event_v3::do_apply_event(), not here. Because if we come
- here, the master was sane.
-
- This must only be called from the Slave SQL thread, since it calls
- Relay_log_info::flush().
-*/
-
-int Stop_log_event::do_update_pos(rpl_group_info *rgi)
-{
- int error= 0;
- Relay_log_info *rli= rgi->rli;
- DBUG_ENTER("Stop_log_event::do_update_pos");
- /*
- We do not want to update master_log pos because we get a rotate event
- before stop, so by now group_master_log_name is set to the next log.
- If we updated it, we will have incorrect master coordinates and this
- could give false triggers in MASTER_POS_WAIT() that we have reached
- the target position when in fact we have not.
- */
- if (rli->get_flag(Relay_log_info::IN_TRANSACTION))
- rgi->inc_event_relay_log_pos();
- else if (!rgi->is_parallel_exec)
- {
- rpl_global_gtid_slave_state->record_and_update_gtid(thd, rgi);
- rli->inc_group_relay_log_pos(0, rgi);
- if (rli->flush())
- error= 1;
- }
- DBUG_RETURN(error);
-}
-
-#endif /* !MYSQL_CLIENT */
-#endif /* HAVE_REPLICATION */
-
-
/**************************************************************************
Create_file_log_event methods
**************************************************************************/
@@ -9739,75 +2939,6 @@ int Stop_log_event::do_update_pos(rpl_group_info *rgi)
Create_file_log_event ctor
*/
-#ifndef MYSQL_CLIENT
-Create_file_log_event::
-Create_file_log_event(THD* thd_arg, sql_exchange* ex,
- const char* db_arg, const char* table_name_arg,
- List<Item>& fields_arg,
- bool is_concurrent_arg,
- enum enum_duplicates handle_dup,
- bool ignore,
- uchar* block_arg, uint block_len_arg, bool using_trans)
- :Load_log_event(thd_arg, ex, db_arg, table_name_arg, fields_arg,
- is_concurrent_arg,
- handle_dup, ignore, using_trans),
- fake_base(0), block(block_arg), event_buf(0), block_len(block_len_arg),
- file_id(thd_arg->file_id = mysql_bin_log.next_file_id())
-{
- DBUG_ENTER("Create_file_log_event");
- sql_ex.force_new_format();
- DBUG_VOID_RETURN;
-}
-
-
-/*
- Create_file_log_event::write_data_body()
-*/
-
-bool Create_file_log_event::write_data_body()
-{
- bool res;
- if ((res= Load_log_event::write_data_body()) || fake_base)
- return res;
- return write_data("", 1) ||
- write_data(block, block_len);
-}
-
-
-/*
- Create_file_log_event::write_data_header()
-*/
-
-bool Create_file_log_event::write_data_header()
-{
- bool res;
- uchar buf[CREATE_FILE_HEADER_LEN];
- if ((res= Load_log_event::write_data_header()) || fake_base)
- return res;
- int4store(buf + CF_FILE_ID_OFFSET, file_id);
- return write_data(buf, CREATE_FILE_HEADER_LEN) != 0;
-}
-
-
-/*
- Create_file_log_event::write_base()
-*/
-
-bool Create_file_log_event::write_base()
-{
- bool res;
- fake_base= 1; // pretend we are Load event
- res= write();
- fake_base= 0;
- return res;
-}
-
-#endif /* !MYSQL_CLIENT */
-
-/*
- Create_file_log_event ctor
-*/
-
Create_file_log_event::Create_file_log_event(const char* buf, uint len,
const Format_description_log_event* description_event)
:Load_log_event(buf,0,description_event),fake_base(0),block(0),inited_from_old(0)
@@ -9817,7 +2948,7 @@ Create_file_log_event::Create_file_log_event(const char* buf, uint len,
uint header_len= description_event->common_header_len;
uint8 load_header_len= description_event->post_header_len[LOAD_EVENT-1];
uint8 create_file_header_len= description_event->post_header_len[CREATE_FILE_EVENT-1];
- if (!(event_buf= (char*) my_memdup(buf, len, MYF(MY_WME))) ||
+ if (!(event_buf= (char*) my_memdup(PSI_INSTRUMENT_ME, buf, len, MYF(MY_WME))) ||
copy_log_event(event_buf,len,
(((uchar)buf[EVENT_TYPE_OFFSET] == LOAD_EVENT) ?
load_header_len + header_len :
@@ -9859,172 +2990,6 @@ Create_file_log_event::Create_file_log_event(const char* buf, uint len,
}
-/*
- Create_file_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Create_file_log_event::print(FILE* file,
- PRINT_EVENT_INFO* print_event_info,
- bool enable_local)
-{
- if (print_event_info->short_form)
- {
- if (enable_local && check_fname_outside_temp_buf())
- return Load_log_event::print(file, print_event_info);
- return 0;
- }
-
- Write_on_release_cache cache(&print_event_info->head_cache, file);
-
- if (enable_local)
- {
- if (Load_log_event::print(file, print_event_info,
- !check_fname_outside_temp_buf()))
- goto err;
-
- /**
- reduce the size of io cache so that the write function is called
- for every call to my_b_printf().
- */
- DBUG_EXECUTE_IF ("simulate_create_event_write_error",
- {(&cache)->write_pos= (&cache)->write_end;
- DBUG_SET("+d,simulate_file_write_error");});
- /*
- That one is for "file_id: etc" below: in mysqlbinlog we want the #, in
- SHOW BINLOG EVENTS we don't.
- */
- if (my_b_write_byte(&cache, '#'))
- goto err;
- }
-
- if (my_b_printf(&cache, " file_id: %d block_len: %d\n", file_id, block_len))
- goto err;
-
- return cache.flush_data();
-err:
- return 1;
-
-}
-
-
-bool Create_file_log_event::print(FILE* file,
- PRINT_EVENT_INFO* print_event_info)
-{
- return print(file, print_event_info, 0);
-}
-#endif /* MYSQL_CLIENT */
-
-
-/*
- Create_file_log_event::pack_info()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Create_file_log_event::pack_info(Protocol *protocol)
-{
- char buf[SAFE_NAME_LEN*2 + 30 + 21*2], *pos;
- pos= strmov(buf, "db=");
- memcpy(pos, db, db_len);
- pos= strmov(pos + db_len, ";table=");
- memcpy(pos, table_name, table_name_len);
- pos= strmov(pos + table_name_len, ";file_id=");
- pos= int10_to_str((long) file_id, pos, 10);
- pos= strmov(pos, ";block_len=");
- pos= int10_to_str((long) block_len, pos, 10);
- protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
-}
-#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
-
-
-/**
- Create_file_log_event::do_apply_event()
- Constructor for Create_file_log_event to intantiate an event
- from the relay log on the slave.
-
- @retval
- 0 Success
- @retval
- 1 Failure
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Create_file_log_event::do_apply_event(rpl_group_info *rgi)
-{
- char fname_buf[FN_REFLEN];
- char *ext;
- int fd = -1;
- IO_CACHE file;
- Log_event_writer lew(&file, 0);
- int error = 1;
- Relay_log_info const *rli= rgi->rli;
-
- THD_STAGE_INFO(thd, stage_making_temp_file_create_before_load_data);
- bzero((char*)&file, sizeof(file));
- ext= slave_load_file_stem(fname_buf, file_id, server_id, ".info",
- &rli->mi->connection_name);
- /* old copy may exist already */
- mysql_file_delete(key_file_log_event_info, fname_buf, MYF(0));
- if ((fd= mysql_file_create(key_file_log_event_info,
- fname_buf, CREATE_MODE,
- O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
- MYF(MY_WME))) < 0 ||
- init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0,
- MYF(MY_WME|MY_NABP)))
- {
- rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
- "Error in Create_file event: could not open file '%s'",
- fname_buf);
- goto err;
- }
-
- // a trick to avoid allocating another buffer
- fname= fname_buf;
- fname_len= (uint) (strmov(ext, ".data") - fname);
- writer= &lew;
- if (write_base())
- {
- strmov(ext, ".info"); // to have it right in the error message
- rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
- "Error in Create_file event: could not write to file '%s'",
- fname_buf);
- goto err;
- }
- end_io_cache(&file);
- mysql_file_close(fd, MYF(0));
-
- // fname_buf now already has .data, not .info, because we did our trick
- /* old copy may exist already */
- mysql_file_delete(key_file_log_event_data, fname_buf, MYF(0));
- if ((fd= mysql_file_create(key_file_log_event_data,
- fname_buf, CREATE_MODE,
- O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
- MYF(MY_WME))) < 0)
- {
- rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
- "Error in Create_file event: could not open file '%s'",
- fname_buf);
- goto err;
- }
- if (mysql_file_write(fd, (uchar*) block, block_len, MYF(MY_WME+MY_NABP)))
- {
- rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
- "Error in Create_file event: write to '%s' failed",
- fname_buf);
- goto err;
- }
- error=0; // Everything is ok
-
-err:
- if (unlikely(error))
- end_io_cache(&file);
- if (likely(fd >= 0))
- mysql_file_close(fd, MYF(0));
- return error != 0;
-}
-#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
-
-
/**************************************************************************
Append_block_log_event methods
**************************************************************************/
@@ -10033,23 +2998,6 @@ err:
Append_block_log_event ctor
*/
-#ifndef MYSQL_CLIENT
-Append_block_log_event::Append_block_log_event(THD *thd_arg,
- const char *db_arg,
- uchar *block_arg,
- uint block_len_arg,
- bool using_trans)
- :Log_event(thd_arg,0, using_trans), block(block_arg),
- block_len(block_len_arg), file_id(thd_arg->file_id), db(db_arg)
-{
-}
-#endif
-
-
-/*
- Append_block_log_event ctor
-*/
-
Append_block_log_event::Append_block_log_event(const char* buf, uint len,
const Format_description_log_event* description_event)
:Log_event(buf, description_event),block(0)
@@ -10068,140 +3016,6 @@ Append_block_log_event::Append_block_log_event(const char* buf, uint len,
}
-/*
- Append_block_log_event::write()
-*/
-
-#ifndef MYSQL_CLIENT
-bool Append_block_log_event::write()
-{
- uchar buf[APPEND_BLOCK_HEADER_LEN];
- int4store(buf + AB_FILE_ID_OFFSET, file_id);
- return write_header(APPEND_BLOCK_HEADER_LEN + block_len) ||
- write_data(buf, APPEND_BLOCK_HEADER_LEN) ||
- write_data(block, block_len) ||
- write_footer();
-}
-#endif
-
-
-/*
- Append_block_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Append_block_log_event::print(FILE* file,
- PRINT_EVENT_INFO* print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- Write_on_release_cache cache(&print_event_info->head_cache, file);
-
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\n#%s: file_id: %d block_len: %d\n",
- get_type_str(), file_id, block_len))
- goto err;
-
- return cache.flush_data();
-err:
- return 1;
-}
-#endif /* MYSQL_CLIENT */
-
-
-/*
- Append_block_log_event::pack_info()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Append_block_log_event::pack_info(Protocol *protocol)
-{
- char buf[256];
- uint length;
- length= (uint) sprintf(buf, ";file_id=%u;block_len=%u", file_id, block_len);
- protocol->store(buf, length, &my_charset_bin);
-}
-
-
-/*
- Append_block_log_event::get_create_or_append()
-*/
-
-int Append_block_log_event::get_create_or_append() const
-{
- return 0; /* append to the file, fail if not exists */
-}
-
-/*
- Append_block_log_event::do_apply_event()
-*/
-
-int Append_block_log_event::do_apply_event(rpl_group_info *rgi)
-{
- char fname[FN_REFLEN];
- int fd;
- int error = 1;
- Relay_log_info const *rli= rgi->rli;
- DBUG_ENTER("Append_block_log_event::do_apply_event");
-
- THD_STAGE_INFO(thd, stage_making_temp_file_append_before_load_data);
- slave_load_file_stem(fname, file_id, server_id, ".data",
- &rli->mi->cmp_connection_name);
- if (get_create_or_append())
- {
- /*
- Usually lex_start() is called by mysql_parse(), but we need it here
- as the present method does not call mysql_parse().
- */
- lex_start(thd);
- thd->reset_for_next_command();
- /* old copy may exist already */
- mysql_file_delete(key_file_log_event_data, fname, MYF(0));
- if ((fd= mysql_file_create(key_file_log_event_data,
- fname, CREATE_MODE,
- O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
- MYF(MY_WME))) < 0)
- {
- rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
- "Error in %s event: could not create file '%s'",
- get_type_str(), fname);
- goto err;
- }
- }
- else if ((fd= mysql_file_open(key_file_log_event_data,
- fname,
- O_WRONLY | O_APPEND | O_BINARY | O_NOFOLLOW,
- MYF(MY_WME))) < 0)
- {
- rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
- "Error in %s event: could not open file '%s'",
- get_type_str(), fname);
- goto err;
- }
-
- DBUG_EXECUTE_IF("remove_slave_load_file_before_write",
- {
- my_delete(fname, MYF(0));
- });
-
- if (mysql_file_write(fd, (uchar*) block, block_len, MYF(MY_WME+MY_NABP)))
- {
- rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
- "Error in %s event: write to '%s' failed",
- get_type_str(), fname);
- goto err;
- }
- error=0;
-
-err:
- if (fd >= 0)
- mysql_file_close(fd, MYF(0));
- DBUG_RETURN(error);
-}
-#endif
-
-
/**************************************************************************
Delete_file_log_event methods
**************************************************************************/
@@ -10210,18 +3024,6 @@ err:
Delete_file_log_event ctor
*/
-#ifndef MYSQL_CLIENT
-Delete_file_log_event::Delete_file_log_event(THD *thd_arg, const char* db_arg,
- bool using_trans)
- :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id), db(db_arg)
-{
-}
-#endif
-
-/*
- Delete_file_log_event ctor
-*/
-
Delete_file_log_event::Delete_file_log_event(const char* buf, uint len,
const Format_description_log_event* description_event)
:Log_event(buf, description_event),file_id(0)
@@ -10234,76 +3036,6 @@ Delete_file_log_event::Delete_file_log_event(const char* buf, uint len,
}
-/*
- Delete_file_log_event::write()
-*/
-
-#ifndef MYSQL_CLIENT
-bool Delete_file_log_event::write()
-{
- uchar buf[DELETE_FILE_HEADER_LEN];
- int4store(buf + DF_FILE_ID_OFFSET, file_id);
- return write_header(sizeof(buf)) ||
- write_data(buf, sizeof(buf)) ||
- write_footer();
-}
-#endif
-
-
-/*
- Delete_file_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Delete_file_log_event::print(FILE* file,
- PRINT_EVENT_INFO* print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- Write_on_release_cache cache(&print_event_info->head_cache, file);
-
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\n#Delete_file: file_id=%u\n", file_id))
- return 1;
-
- return cache.flush_data();
-}
-#endif /* MYSQL_CLIENT */
-
-/*
- Delete_file_log_event::pack_info()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Delete_file_log_event::pack_info(Protocol *protocol)
-{
- char buf[64];
- uint length;
- length= (uint) sprintf(buf, ";file_id=%u", (uint) file_id);
- protocol->store(buf, (int32) length, &my_charset_bin);
-}
-#endif
-
-/*
- Delete_file_log_event::do_apply_event()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Delete_file_log_event::do_apply_event(rpl_group_info *rgi)
-{
- char fname[FN_REFLEN+10];
- Relay_log_info const *rli= rgi->rli;
- char *ext= slave_load_file_stem(fname, file_id, server_id, ".data",
- &rli->mi->cmp_connection_name);
- mysql_file_delete(key_file_log_event_data, fname, MYF(MY_WME));
- strmov(ext, ".info");
- mysql_file_delete(key_file_log_event_info, fname, MYF(MY_WME));
- return 0;
-}
-#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
-
-
/**************************************************************************
Execute_load_log_event methods
**************************************************************************/
@@ -10312,20 +3044,6 @@ int Delete_file_log_event::do_apply_event(rpl_group_info *rgi)
Execute_load_log_event ctor
*/
-#ifndef MYSQL_CLIENT
-Execute_load_log_event::Execute_load_log_event(THD *thd_arg,
- const char* db_arg,
- bool using_trans)
- :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id), db(db_arg)
-{
-}
-#endif
-
-
-/*
- Execute_load_log_event ctor
-*/
-
Execute_load_log_event::Execute_load_log_event(const char* buf, uint len,
const Format_description_log_event* description_event)
:Log_event(buf, description_event), file_id(0)
@@ -10338,167 +3056,10 @@ Execute_load_log_event::Execute_load_log_event(const char* buf, uint len,
}
-/*
- Execute_load_log_event::write()
-*/
-
-#ifndef MYSQL_CLIENT
-bool Execute_load_log_event::write()
-{
- uchar buf[EXEC_LOAD_HEADER_LEN];
- int4store(buf + EL_FILE_ID_OFFSET, file_id);
- return write_header(sizeof(buf)) ||
- write_data(buf, sizeof(buf)) ||
- write_footer();
-}
-#endif
-
-
-/*
- Execute_load_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Execute_load_log_event::print(FILE* file,
- PRINT_EVENT_INFO* print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- Write_on_release_cache cache(&print_event_info->head_cache, file);
-
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\n#Exec_load: file_id=%d\n",
- file_id))
- return 1;
-
- return cache.flush_data();
-}
-#endif
-
-/*
- Execute_load_log_event::pack_info()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Execute_load_log_event::pack_info(Protocol *protocol)
-{
- char buf[64];
- uint length;
- length= (uint) sprintf(buf, ";file_id=%u", (uint) file_id);
- protocol->store(buf, (int32) length, &my_charset_bin);
-}
-
-
-/*
- Execute_load_log_event::do_apply_event()
-*/
-
-int Execute_load_log_event::do_apply_event(rpl_group_info *rgi)
-{
- char fname[FN_REFLEN+10];
- char *ext;
- int fd;
- int error= 1;
- IO_CACHE file;
- Load_log_event *lev= 0;
- Relay_log_info const *rli= rgi->rli;
-
- ext= slave_load_file_stem(fname, file_id, server_id, ".info",
- &rli->mi->cmp_connection_name);
- if ((fd= mysql_file_open(key_file_log_event_info,
- fname, O_RDONLY | O_BINARY | O_NOFOLLOW,
- MYF(MY_WME))) < 0 ||
- init_io_cache(&file, fd, IO_SIZE, READ_CACHE, (my_off_t)0, 0,
- MYF(MY_WME|MY_NABP)))
- {
- rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
- "Error in Exec_load event: could not open file '%s'",
- fname);
- goto err;
- }
- if (!(lev= (Load_log_event*)
- Log_event::read_log_event(&file,
- rli->relay_log.description_event_for_exec,
- opt_slave_sql_verify_checksum)) ||
- lev->get_type_code() != NEW_LOAD_EVENT)
- {
- rli->report(ERROR_LEVEL, 0, rgi->gtid_info(), "Error in Exec_load event: "
- "file '%s' appears corrupted", fname);
- goto err;
- }
- lev->thd = thd;
- /*
- lev->do_apply_event should use rli only for errors i.e. should
- not advance rli's position.
-
- lev->do_apply_event is the place where the table is loaded (it
- calls mysql_load()).
- */
-
- if (lev->do_apply_event(0,rgi,1))
- {
- /*
- We want to indicate the name of the file that could not be loaded
- (SQL_LOADxxx).
- But as we are here we are sure the error is in rli->last_slave_error and
- rli->last_slave_errno (example of error: duplicate entry for key), so we
- don't want to overwrite it with the filename.
- What we want instead is add the filename to the current error message.
- */
- char *tmp= my_strdup(rli->last_error().message, MYF(MY_WME));
- if (tmp)
- {
- rli->report(ERROR_LEVEL, rli->last_error().number, rgi->gtid_info(),
- "%s. Failed executing load from '%s'", tmp, fname);
- my_free(tmp);
- }
- goto err;
- }
- /*
- We have an open file descriptor to the .info file; we need to close it
- or Windows will refuse to delete the file in mysql_file_delete().
- */
- if (fd >= 0)
- {
- mysql_file_close(fd, MYF(0));
- end_io_cache(&file);
- fd= -1;
- }
- mysql_file_delete(key_file_log_event_info, fname, MYF(MY_WME));
- memcpy(ext, ".data", 6);
- mysql_file_delete(key_file_log_event_data, fname, MYF(MY_WME));
- error = 0;
-
-err:
- delete lev;
- if (fd >= 0)
- {
- mysql_file_close(fd, MYF(0));
- end_io_cache(&file);
- }
- return error;
-}
-
-#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
-
-
/**************************************************************************
Begin_load_query_log_event methods
**************************************************************************/
-#ifndef MYSQL_CLIENT
-Begin_load_query_log_event::
-Begin_load_query_log_event(THD* thd_arg, const char* db_arg, uchar* block_arg,
- uint block_len_arg, bool using_trans)
- :Append_block_log_event(thd_arg, db_arg, block_arg, block_len_arg,
- using_trans)
-{
- file_id= thd_arg->file_id= mysql_bin_log.next_file_id();
-}
-#endif
-
-
Begin_load_query_log_event::
Begin_load_query_log_event(const char* buf, uint len,
const Format_description_log_event* desc_event)
@@ -10507,49 +3068,11 @@ Begin_load_query_log_event(const char* buf, uint len,
}
-#if defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Begin_load_query_log_event::get_create_or_append() const
-{
- return 1; /* create the file */
-}
-#endif /* defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
-
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-Log_event::enum_skip_reason
-Begin_load_query_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- /*
- If the slave skip counter is 1, then we should not start executing
- on the next event.
- */
- return continue_group(rgi);
-}
-#endif
-
-
/**************************************************************************
Execute_load_query_log_event methods
**************************************************************************/
-#ifndef MYSQL_CLIENT
-Execute_load_query_log_event::
-Execute_load_query_log_event(THD *thd_arg, const char* query_arg,
- ulong query_length_arg, uint fn_pos_start_arg,
- uint fn_pos_end_arg,
- enum_load_dup_handling dup_handling_arg,
- bool using_trans, bool direct, bool suppress_use,
- int errcode):
- Query_log_event(thd_arg, query_arg, query_length_arg, using_trans, direct,
- suppress_use, errcode),
- file_id(thd_arg->file_id), fn_pos_start(fn_pos_start_arg),
- fn_pos_end(fn_pos_end_arg), dup_handling(dup_handling_arg)
-{
-}
-#endif /* !MYSQL_CLIENT */
-
-
Execute_load_query_log_event::
Execute_load_query_log_event(const char* buf, uint event_len,
const Format_description_log_event* desc_event):
@@ -10579,165 +3102,6 @@ ulong Execute_load_query_log_event::get_post_header_size_for_derived()
}
-#ifndef MYSQL_CLIENT
-bool
-Execute_load_query_log_event::write_post_header_for_derived()
-{
- uchar buf[EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN];
- int4store(buf, file_id);
- int4store(buf + 4, fn_pos_start);
- int4store(buf + 4 + 4, fn_pos_end);
- *(buf + 4 + 4 + 4)= (uchar) dup_handling;
- return write_data(buf, EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN);
-}
-#endif
-
-
-#ifdef MYSQL_CLIENT
-bool Execute_load_query_log_event::print(FILE* file,
- PRINT_EVENT_INFO* print_event_info)
-{
- return print(file, print_event_info, 0);
-}
-
-/**
- Prints the query as LOAD DATA LOCAL and with rewritten filename.
-*/
-bool Execute_load_query_log_event::print(FILE* file,
- PRINT_EVENT_INFO* print_event_info,
- const char *local_fname)
-{
- Write_on_release_cache cache(&print_event_info->head_cache, file);
-
- if (print_query_header(&cache, print_event_info))
- goto err;
-
- /**
- reduce the size of io cache so that the write function is called
- for every call to my_b_printf().
- */
- DBUG_EXECUTE_IF ("simulate_execute_event_write_error",
- {(&cache)->write_pos= (&cache)->write_end;
- DBUG_SET("+d,simulate_file_write_error");});
-
- if (local_fname)
- {
- if (my_b_write(&cache, (uchar*) query, fn_pos_start) ||
- my_b_write_string(&cache, " LOCAL INFILE ") ||
- pretty_print_str(&cache, local_fname, (int)strlen(local_fname)))
- goto err;
-
- if (dup_handling == LOAD_DUP_REPLACE)
- if (my_b_write_string(&cache, " REPLACE"))
- goto err;
-
- if (my_b_write_string(&cache, " INTO") ||
- my_b_write(&cache, (uchar*) query + fn_pos_end, q_len-fn_pos_end) ||
- my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
- goto err;
- }
- else
- {
- if (my_b_write(&cache, (uchar*) query, q_len) ||
- my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
- goto err;
- }
-
- if (!print_event_info->short_form)
- my_b_printf(&cache, "# file_id: %d \n", file_id);
-
- return cache.flush_data();
-err:
- return 1;
-}
-#endif
-
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Execute_load_query_log_event::pack_info(Protocol *protocol)
-{
- char buf_mem[1024];
- String buf(buf_mem, sizeof(buf_mem), system_charset_info);
- buf.real_alloc(9 + db_len + q_len + 10 + 21);
- if (db && db_len)
- {
- if (buf.append(STRING_WITH_LEN("use ")) ||
- append_identifier(protocol->thd, &buf, db, db_len) ||
- buf.append(STRING_WITH_LEN("; ")))
- return;
- }
- if (query && q_len && buf.append(query, q_len))
- return;
- if (buf.append(" ;file_id=") ||
- buf.append_ulonglong(file_id))
- return;
- protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
-}
-
-
-int
-Execute_load_query_log_event::do_apply_event(rpl_group_info *rgi)
-{
- char *p;
- char *buf;
- char *fname;
- char *fname_end;
- int error;
- Relay_log_info const *rli= rgi->rli;
-
- buf= (char*) my_malloc(q_len + 1 - (fn_pos_end - fn_pos_start) +
- (FN_REFLEN + 10) + 10 + 8 + 5, MYF(MY_WME));
-
- DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error", my_free(buf); buf= NULL;);
-
- /* Replace filename and LOCAL keyword in query before executing it */
- if (buf == NULL)
- {
- rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, rgi->gtid_info(),
- ER_THD(rgi->thd, ER_SLAVE_FATAL_ERROR), "Not enough memory");
- return 1;
- }
-
- p= buf;
- memcpy(p, query, fn_pos_start);
- p+= fn_pos_start;
- fname= (p= strmake(p, STRING_WITH_LEN(" INFILE \'")));
- p= slave_load_file_stem(p, file_id, server_id, ".data",
- &rli->mi->cmp_connection_name);
- fname_end= p= strend(p); // Safer than p=p+5
- *(p++)='\'';
- switch (dup_handling) {
- case LOAD_DUP_IGNORE:
- p= strmake(p, STRING_WITH_LEN(" IGNORE"));
- break;
- case LOAD_DUP_REPLACE:
- p= strmake(p, STRING_WITH_LEN(" REPLACE"));
- break;
- default:
- /* Ordinary load data */
- break;
- }
- p= strmake(p, STRING_WITH_LEN(" INTO "));
- p= strmake(p, query+fn_pos_end, q_len-fn_pos_end);
-
- error= Query_log_event::do_apply_event(rgi, buf, (uint32)(p-buf));
-
- /* Forging file name for deletion in same buffer */
- *fname_end= 0;
-
- /*
- If there was an error the slave is going to stop, leave the
- file so that we can re-execute this event at START SLAVE.
- */
- if (unlikely(!error))
- mysql_file_delete(key_file_log_event_data, fname, MYF(MY_WME));
-
- my_free(buf);
- return error;
-}
-#endif
-
-
/**************************************************************************
sql_ex_info methods
**************************************************************************/
@@ -10792,105 +3156,12 @@ const char *sql_ex_info::init(const char *buf, const char *buf_end,
return buf;
}
-#ifndef MYSQL_CLIENT
-/*
- write_str()
-*/
-
-static bool write_str(Log_event_writer *writer, const char *str, uint length)
-{
- uchar tmp[1];
- tmp[0]= (uchar) length;
- return (writer->write_data(tmp, sizeof(tmp)) ||
- writer->write_data((uchar*) str, length));
-}
-
-/*
- sql_ex_info::write_data()
-*/
-
-bool sql_ex_info::write_data(Log_event_writer *writer)
-{
- if (new_format())
- {
- return write_str(writer, field_term, field_term_len) ||
- write_str(writer, enclosed, enclosed_len) ||
- write_str(writer, line_term, line_term_len) ||
- write_str(writer, line_start, line_start_len) ||
- write_str(writer, escaped, escaped_len) ||
- writer->write_data((uchar*) &opt_flags, 1);
- }
- else
- {
- uchar old_ex[7];
- old_ex[0]= *field_term;
- old_ex[1]= *enclosed;
- old_ex[2]= *line_term;
- old_ex[3]= *line_start;
- old_ex[4]= *escaped;
- old_ex[5]= opt_flags;
- old_ex[6]= empty_flags;
- return writer->write_data(old_ex, sizeof(old_ex));
- }
-}
-
/**************************************************************************
Rows_log_event member functions
**************************************************************************/
-Rows_log_event::Rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid,
- MY_BITMAP const *cols, bool is_transactional,
- Log_event_type event_type)
- : Log_event(thd_arg, 0, is_transactional),
- m_row_count(0),
- m_table(tbl_arg),
- m_table_id(tid),
- m_width(tbl_arg ? tbl_arg->s->fields : 1),
- m_rows_buf(0), m_rows_cur(0), m_rows_end(0), m_flags(0),
- m_type(event_type), m_extra_row_data(0)
-#ifdef HAVE_REPLICATION
- , m_curr_row(NULL), m_curr_row_end(NULL),
- m_key(NULL), m_key_info(NULL), m_key_nr(0),
- master_had_triggers(0)
-#endif
-{
- /*
- We allow a special form of dummy event when the table, and cols
- are null and the table id is ~0UL. This is a temporary
- solution, to be able to terminate a started statement in the
- binary log: the extraneous events will be removed in the future.
- */
- DBUG_ASSERT((tbl_arg && tbl_arg->s && tid != ~0UL) ||
- (!tbl_arg && !cols && tid == ~0UL));
-
- if (thd_arg->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS)
- set_flags(NO_FOREIGN_KEY_CHECKS_F);
- if (thd_arg->variables.option_bits & OPTION_RELAXED_UNIQUE_CHECKS)
- set_flags(RELAXED_UNIQUE_CHECKS_F);
- if (thd_arg->variables.option_bits & OPTION_NO_CHECK_CONSTRAINT_CHECKS)
- set_flags(NO_CHECK_CONSTRAINT_CHECKS_F);
- /* if my_bitmap_init fails, caught in is_valid() */
- if (likely(!my_bitmap_init(&m_cols,
- m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
- m_width,
- false)))
- {
- /* Cols can be zero if this is a dummy binrows event */
- if (likely(cols != NULL))
- {
- memcpy(m_cols.bitmap, cols->bitmap, no_bytes_in_map(cols));
- create_last_word_mask(&m_cols);
- }
- }
- else
- {
- // Needed because my_bitmap_init() does not set it to null on failure
- m_cols.bitmap= 0;
- }
-}
-#endif
Rows_log_event::Rows_log_event(const char *buf, uint event_len,
const Format_description_log_event
@@ -10979,7 +3250,7 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len,
/* Just store/use the first tag of this type, skip others */
if (likely(!m_extra_row_data))
{
- m_extra_row_data= (uchar*) my_malloc(infoLen,
+ m_extra_row_data= (uchar*) my_malloc(PSI_INSTRUMENT_ME, infoLen,
MYF(MY_WME));
if (likely(m_extra_row_data != NULL))
{
@@ -11068,7 +3339,7 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len,
DBUG_PRINT("info",("m_table_id: %llu m_flags: %d m_width: %lu data_size: %lu",
m_table_id, m_flags, m_width, (ulong) data_size));
- m_rows_buf= (uchar*) my_malloc(data_size, MYF(MY_WME));
+ m_rows_buf= (uchar*) my_malloc(PSI_INSTRUMENT_ME, data_size, MYF(MY_WME));
if (likely((bool)m_rows_buf))
{
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
@@ -11091,7 +3362,7 @@ void Rows_log_event::uncompress_buf()
if (!un_len)
return;
- uchar *new_buf= (uchar*) my_malloc(ALIGN_SIZE(un_len), MYF(MY_WME));
+ uchar *new_buf= (uchar*) my_malloc(PSI_INSTRUMENT_ME, ALIGN_SIZE(un_len), MYF(MY_WME));
if (new_buf)
{
if(!binlog_buf_uncompress((char *)m_rows_buf, (char *)new_buf,
@@ -11160,1150 +3431,10 @@ int Rows_log_event::get_data_size()
}
-#ifndef MYSQL_CLIENT
-int Rows_log_event::do_add_row_data(uchar *row_data, size_t length)
-{
- /*
- When the table has a primary key, we would probably want, by default, to
- log only the primary key value instead of the entire "before image". This
- would save binlog space. TODO
- */
- DBUG_ENTER("Rows_log_event::do_add_row_data");
- DBUG_PRINT("enter", ("row_data:%p length: %lu", row_data,
- (ulong) length));
-
- /*
- If length is zero, there is nothing to write, so we just
- return. Note that this is not an optimization, since calling
- realloc() with size 0 means free().
- */
- if (length == 0)
- {
- m_row_count++;
- DBUG_RETURN(0);
- }
-
- /*
- Don't print debug messages when running valgrind since they can
- trigger false warnings.
- */
-#ifndef HAVE_valgrind
- DBUG_DUMP("row_data", row_data, MY_MIN(length, 32));
-#endif
-
- DBUG_ASSERT(m_rows_buf <= m_rows_cur);
- DBUG_ASSERT(!m_rows_buf || (m_rows_end && m_rows_buf < m_rows_end));
- DBUG_ASSERT(m_rows_cur <= m_rows_end);
-
- /* The cast will always work since m_rows_cur <= m_rows_end */
- if (static_cast<size_t>(m_rows_end - m_rows_cur) <= length)
- {
- size_t const block_size= 1024;
- size_t cur_size= m_rows_cur - m_rows_buf;
- DBUG_EXECUTE_IF("simulate_too_big_row_case1",
- cur_size= UINT_MAX32 - (block_size * 10);
- length= UINT_MAX32 - (block_size * 10););
- DBUG_EXECUTE_IF("simulate_too_big_row_case2",
- cur_size= UINT_MAX32 - (block_size * 10);
- length= block_size * 10;);
- DBUG_EXECUTE_IF("simulate_too_big_row_case3",
- cur_size= block_size * 10;
- length= UINT_MAX32 - (block_size * 10););
- DBUG_EXECUTE_IF("simulate_too_big_row_case4",
- cur_size= UINT_MAX32 - (block_size * 10);
- length= (block_size * 10) - block_size + 1;);
- size_t remaining_space= UINT_MAX32 - cur_size;
- /* Check that the new data fits within remaining space and we can add
- block_size without wrapping.
- */
- if (cur_size > UINT_MAX32 || length > remaining_space ||
- ((length + block_size) > remaining_space))
- {
- sql_print_error("The row data is greater than 4GB, which is too big to "
- "write to the binary log.");
- DBUG_RETURN(ER_BINLOG_ROW_LOGGING_FAILED);
- }
- size_t const new_alloc=
- block_size * ((cur_size + length + block_size - 1) / block_size);
-
- uchar* const new_buf= (uchar*)my_realloc((uchar*)m_rows_buf, new_alloc,
- MYF(MY_ALLOW_ZERO_PTR|MY_WME));
- if (unlikely(!new_buf))
- DBUG_RETURN(HA_ERR_OUT_OF_MEM);
-
- /* If the memory moved, we need to move the pointers */
- if (new_buf != m_rows_buf)
- {
- m_rows_buf= new_buf;
- m_rows_cur= m_rows_buf + cur_size;
- }
-
- /*
- The end pointer should always be changed to point to the end of
- the allocated memory.
- */
- m_rows_end= m_rows_buf + new_alloc;
- }
-
- DBUG_ASSERT(m_rows_cur + length <= m_rows_end);
- memcpy(m_rows_cur, row_data, length);
- m_rows_cur+= length;
- m_row_count++;
- DBUG_RETURN(0);
-}
-#endif
-
-#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
-
-/**
- Restores empty table list as it was before trigger processing.
-
- @note We have a lot of ASSERTS that check the lists when we close tables.
- There was the same problem with MERGE MYISAM tables and so here we try to
- go the same way.
-*/
-static void restore_empty_query_table_list(LEX *lex)
-{
- if (lex->first_not_own_table())
- (*lex->first_not_own_table()->prev_global)= NULL;
- lex->query_tables= NULL;
- lex->query_tables_last= &lex->query_tables;
-}
-
-
-int Rows_log_event::do_apply_event(rpl_group_info *rgi)
-{
- Relay_log_info const *rli= rgi->rli;
- TABLE* table;
- DBUG_ENTER("Rows_log_event::do_apply_event(Relay_log_info*)");
- int error= 0;
- /*
- If m_table_id == ~0ULL, then we have a dummy event that does not
- contain any data. In that case, we just remove all tables in the
- tables_to_lock list, close the thread tables, and return with
- success.
- */
- if (m_table_id == ~0ULL)
- {
- /*
- This one is supposed to be set: just an extra check so that
- nothing strange has happened.
- */
- DBUG_ASSERT(get_flags(STMT_END_F));
-
- rgi->slave_close_thread_tables(thd);
- thd->clear_error();
- DBUG_RETURN(0);
- }
-
- /*
- 'thd' has been set by exec_relay_log_event(), just before calling
- do_apply_event(). We still check here to prevent future coding
- errors.
- */
- DBUG_ASSERT(rgi->thd == thd);
-
- /*
- If there is no locks taken, this is the first binrow event seen
- after the table map events. We should then lock all the tables
- used in the transaction and proceed with execution of the actual
- event.
- */
- if (!thd->lock)
- {
- /*
- Lock_tables() reads the contents of thd->lex, so they must be
- initialized.
-
- We also call the THD::reset_for_next_command(), since this
- is the logical start of the next "statement". Note that this
- call might reset the value of current_stmt_binlog_format, so
- we need to do any changes to that value after this function.
- */
- delete_explain_query(thd->lex);
- lex_start(thd);
- thd->reset_for_next_command();
- /*
- The current statement is just about to begin and
- has not yet modified anything. Note, all.modified is reset
- by THD::reset_for_next_command().
- */
- thd->transaction.stmt.modified_non_trans_table= FALSE;
- thd->transaction.stmt.m_unsafe_rollback_flags&= ~THD_TRANS::DID_WAIT;
- /*
- This is a row injection, so we flag the "statement" as
- such. Note that this code is called both when the slave does row
- injections and when the BINLOG statement is used to do row
- injections.
- */
- thd->lex->set_stmt_row_injection();
-
- /*
- There are a few flags that are replicated with each row event.
- Make sure to set/clear them before executing the main body of
- the event.
- */
- if (get_flags(NO_FOREIGN_KEY_CHECKS_F))
- thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS;
- else
- thd->variables.option_bits&= ~OPTION_NO_FOREIGN_KEY_CHECKS;
-
- if (get_flags(RELAXED_UNIQUE_CHECKS_F))
- thd->variables.option_bits|= OPTION_RELAXED_UNIQUE_CHECKS;
- else
- thd->variables.option_bits&= ~OPTION_RELAXED_UNIQUE_CHECKS;
-
- if (get_flags(NO_CHECK_CONSTRAINT_CHECKS_F))
- thd->variables.option_bits|= OPTION_NO_CHECK_CONSTRAINT_CHECKS;
- else
- thd->variables.option_bits&= ~OPTION_NO_CHECK_CONSTRAINT_CHECKS;
-
- /* A small test to verify that objects have consistent types */
- DBUG_ASSERT(sizeof(thd->variables.option_bits) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
-
- DBUG_EXECUTE_IF("rows_log_event_before_open_table",
- {
- const char action[] = "now SIGNAL before_open_table WAIT_FOR go_ahead_sql";
- DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(action)));
- };);
-
- if (slave_run_triggers_for_rbr)
- {
- LEX *lex= thd->lex;
- uint8 new_trg_event_map= get_trg_event_map();
-
- /*
- Trigger's procedures work with global table list. So we have to add
- rgi->tables_to_lock content there to get trigger's in the list.
-
- Then restore_empty_query_table_list() restore the list as it was
- */
- DBUG_ASSERT(lex->query_tables == NULL);
- if ((lex->query_tables= rgi->tables_to_lock))
- rgi->tables_to_lock->prev_global= &lex->query_tables;
-
- for (TABLE_LIST *tables= rgi->tables_to_lock; tables;
- tables= tables->next_global)
- {
- tables->trg_event_map= new_trg_event_map;
- lex->query_tables_last= &tables->next_global;
- }
- }
- if (unlikely(open_and_lock_tables(thd, rgi->tables_to_lock, FALSE, 0)))
- {
-#ifdef WITH_WSREP
- if (WSREP(thd))
- {
- WSREP_WARN("BF applier failed to open_and_lock_tables: %u, fatal: %d "
- "wsrep = (exec_mode: %d conflict_state: %d seqno: %lld)",
- thd->get_stmt_da()->sql_errno(),
- thd->is_fatal_error,
- thd->wsrep_cs().mode(),
- thd->wsrep_trx().state(),
- (long long) wsrep_thd_trx_seqno(thd));
- }
-#endif /* WITH_WSREP */
- if (thd->is_error() &&
- !is_parallel_retry_error(rgi, error= thd->get_stmt_da()->sql_errno()))
- {
- /*
- Error reporting borrowed from Query_log_event with many excessive
- simplifications.
- We should not honour --slave-skip-errors at this point as we are
- having severe errors which should not be skipped.
- */
- rli->report(ERROR_LEVEL, error, rgi->gtid_info(),
- "Error executing row event: '%s'",
- (error ? thd->get_stmt_da()->message() :
- "unexpected success or fatal error"));
- thd->is_slave_error= 1;
- }
- /* remove trigger's tables */
- goto err;
- }
-
- /*
- When the open and locking succeeded, we check all tables to
- ensure that they still have the correct type.
- */
-
- {
- DBUG_PRINT("debug", ("Checking compability of tables to lock - tables_to_lock: %p",
- rgi->tables_to_lock));
-
- /**
- When using RBR and MyISAM MERGE tables the base tables that make
- up the MERGE table can be appended to the list of tables to lock.
-
- Thus, we just check compatibility for those that tables that have
- a correspondent table map event (ie, those that are actually going
- to be accessed while applying the event). That's why the loop stops
- at rli->tables_to_lock_count .
-
- NOTE: The base tables are added here are removed when
- close_thread_tables is called.
- */
- TABLE_LIST *table_list_ptr= rgi->tables_to_lock;
- for (uint i=0 ; table_list_ptr && (i < rgi->tables_to_lock_count);
- table_list_ptr= table_list_ptr->next_global, i++)
- {
- /*
- Below if condition takes care of skipping base tables that
- make up the MERGE table (which are added by open_tables()
- call). They are added next to the merge table in the list.
- For eg: If RPL_TABLE_LIST is t3->t1->t2 (where t1 and t2
- are base tables for merge table 't3'), open_tables will modify
- the list by adding t1 and t2 again immediately after t3 in the
- list (*not at the end of the list*). New table_to_lock list will
- look like t3->t1'->t2'->t1->t2 (where t1' and t2' are TABLE_LIST
- objects added by open_tables() call). There is no flag(or logic) in
- open_tables() that can skip adding these base tables to the list.
- So the logic here should take care of skipping them.
-
- tables_to_lock_count logic will take care of skipping base tables
- that are added at the end of the list.
- For eg: If RPL_TABLE_LIST is t1->t2->t3, open_tables will modify
- the list into t1->t2->t3->t1'->t2'. t1' and t2' will be skipped
- because tables_to_lock_count logic in this for loop.
- */
- if (table_list_ptr->parent_l)
- continue;
- /*
- We can use a down cast here since we know that every table added
- to the tables_to_lock is a RPL_TABLE_LIST (or child table which is
- skipped above).
- */
- RPL_TABLE_LIST *ptr= static_cast<RPL_TABLE_LIST*>(table_list_ptr);
- DBUG_ASSERT(ptr->m_tabledef_valid);
- TABLE *conv_table;
- if (!ptr->m_tabledef.compatible_with(thd, rgi, ptr->table, &conv_table))
- {
- DBUG_PRINT("debug", ("Table: %s.%s is not compatible with master",
- ptr->table->s->db.str,
- ptr->table->s->table_name.str));
- /*
- We should not honour --slave-skip-errors at this point as we are
- having severe errors which should not be skiped.
- */
- thd->is_slave_error= 1;
- /* remove trigger's tables */
- error= ERR_BAD_TABLE_DEF;
- goto err;
- }
- DBUG_PRINT("debug", ("Table: %s.%s is compatible with master"
- " - conv_table: %p",
- ptr->table->s->db.str,
- ptr->table->s->table_name.str, conv_table));
- ptr->m_conv_table= conv_table;
- }
- }
-
- /*
- ... and then we add all the tables to the table map and but keep
- them in the tables to lock list.
-
- We also invalidate the query cache for all the tables, since
- they will now be changed.
-
- TODO [/Matz]: Maybe the query cache should not be invalidated
- here? It might be that a table is not changed, even though it
- was locked for the statement. We do know that each
- Rows_log_event contain at least one row, so after processing one
- Rows_log_event, we can invalidate the query cache for the
- associated table.
- */
- TABLE_LIST *ptr= rgi->tables_to_lock;
- for (uint i=0 ; ptr && (i < rgi->tables_to_lock_count); ptr= ptr->next_global, i++)
- {
- /*
- Please see comment in above 'for' loop to know the reason
- for this if condition
- */
- if (ptr->parent_l)
- continue;
- rgi->m_table_map.set_table(ptr->table_id, ptr->table);
- /*
- Following is passing flag about triggers on the server. The problem was
- to pass it between table map event and row event. I do it via extended
- TABLE_LIST (RPL_TABLE_LIST) but row event uses only TABLE so I need to
- find somehow the corresponding TABLE_LIST.
- */
- if (m_table_id == ptr->table_id)
- {
- ptr->table->master_had_triggers=
- ((RPL_TABLE_LIST*)ptr)->master_had_triggers;
- }
- }
-
-#ifdef HAVE_QUERY_CACHE
-#ifdef WITH_WSREP
- /*
- Moved invalidation right before the call to rows_event_stmt_cleanup(),
- to avoid query cache being polluted with stale entries,
- */
- if (! (WSREP(thd) && wsrep_thd_is_applying(thd)))
- {
-#endif /* WITH_WSREP */
- query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock);
-#ifdef WITH_WSREP
- }
-#endif /* WITH_WSREP */
-#endif
- }
-
- table= m_table= rgi->m_table_map.get_table(m_table_id);
-
- DBUG_PRINT("debug", ("m_table:%p, m_table_id: %llu%s",
- m_table, m_table_id,
- table && master_had_triggers ?
- " (master had triggers)" : ""));
- if (table)
- {
- master_had_triggers= table->master_had_triggers;
- bool transactional_table= table->file->has_transactions();
- /*
- table == NULL means that this table should not be replicated
- (this was set up by Table_map_log_event::do_apply_event()
- which tested replicate-* rules).
- */
-
- /*
- It's not needed to set_time() but
- 1) it continues the property that "Time" in SHOW PROCESSLIST shows how
- much slave is behind
- 2) it will be needed when we allow replication from a table with no
- TIMESTAMP column to a table with one.
- So we call set_time(), like in SBR. Presently it changes nothing.
- */
- thd->set_time(when, when_sec_part);
-
- if (m_width == table->s->fields && bitmap_is_set_all(&m_cols))
- set_flags(COMPLETE_ROWS_F);
-
- /*
- Set tables write and read sets.
-
- Read_set contains all slave columns (in case we are going to fetch
- a complete record from slave)
-
- Write_set equals the m_cols bitmap sent from master but it can be
- longer if slave has extra columns.
- */
-
- DBUG_PRINT_BITSET("debug", "Setting table's read_set from: %s", &m_cols);
-
- bitmap_set_all(table->read_set);
- if (get_general_type_code() == DELETE_ROWS_EVENT ||
- get_general_type_code() == UPDATE_ROWS_EVENT)
- bitmap_intersect(table->read_set,&m_cols);
-
- bitmap_set_all(table->write_set);
- table->rpl_write_set= table->write_set;
-
- /* WRITE ROWS EVENTS store the bitmap in m_cols instead of m_cols_ai */
- MY_BITMAP *after_image= ((get_general_type_code() == UPDATE_ROWS_EVENT) ?
- &m_cols_ai : &m_cols);
- bitmap_intersect(table->write_set, after_image);
-
- this->slave_exec_mode= slave_exec_mode_options; // fix the mode
-
- // Do event specific preparations
- error= do_before_row_operations(rli);
-
- /*
- Bug#56662 Assertion failed: next_insert_id == 0, file handler.cc
- Don't allow generation of auto_increment value when processing
- rows event by setting 'MODE_NO_AUTO_VALUE_ON_ZERO'. The exception
- to this rule happens when the auto_inc column exists on some
- extra columns on the slave. In that case, do not force
- MODE_NO_AUTO_VALUE_ON_ZERO.
- */
- sql_mode_t saved_sql_mode= thd->variables.sql_mode;
- if (!is_auto_inc_in_extra_columns())
- thd->variables.sql_mode= MODE_NO_AUTO_VALUE_ON_ZERO;
-
- // row processing loop
-
- /*
- set the initial time of this ROWS statement if it was not done
- before in some other ROWS event.
- */
- rgi->set_row_stmt_start_timestamp();
-
- THD_STAGE_INFO(thd, stage_executing);
- do
- {
- /* in_use can have been set to NULL in close_tables_for_reopen */
- THD* old_thd= table->in_use;
- if (!table->in_use)
- table->in_use= thd;
-
- error= do_exec_row(rgi);
-
- if (unlikely(error))
- DBUG_PRINT("info", ("error: %s", HA_ERR(error)));
- DBUG_ASSERT(error != HA_ERR_RECORD_DELETED);
-
- table->in_use = old_thd;
-
- if (unlikely(error))
- {
- int actual_error= convert_handler_error(error, thd, table);
- bool idempotent_error= (idempotent_error_code(error) &&
- (slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT));
- bool ignored_error= (idempotent_error == 0 ?
- ignored_error_code(actual_error) : 0);
-
-#ifdef WITH_WSREP
- if (WSREP(thd) && wsrep_ignored_error_code(this, actual_error))
- {
- idempotent_error= true;
- thd->wsrep_has_ignored_error= true;
- }
-#endif /* WITH_WSREP */
- if (idempotent_error || ignored_error)
- {
- if (global_system_variables.log_warnings)
- slave_rows_error_report(WARNING_LEVEL, error, rgi, thd, table,
- get_type_str(),
- RPL_LOG_NAME, log_pos);
- thd->clear_error(1);
- error= 0;
- if (idempotent_error == 0)
- break;
- }
- }
-
- /*
- If m_curr_row_end was not set during event execution (e.g., because
- of errors) we can't proceed to the next row. If the error is transient
- (i.e., error==0 at this point) we must call unpack_current_row() to set
- m_curr_row_end.
- */
-
- DBUG_PRINT("info", ("curr_row: %p; curr_row_end: %p; rows_end:%p",
- m_curr_row, m_curr_row_end, m_rows_end));
-
- if (!m_curr_row_end && likely(!error))
- error= unpack_current_row(rgi);
-
- m_curr_row= m_curr_row_end;
-
- if (likely(error == 0) && !transactional_table)
- thd->transaction.all.modified_non_trans_table=
- thd->transaction.stmt.modified_non_trans_table= TRUE;
- } // row processing loop
- while (error == 0 && (m_curr_row != m_rows_end));
-
- /*
- Restore the sql_mode after the rows event is processed.
- */
- thd->variables.sql_mode= saved_sql_mode;
-
- {/**
- The following failure injecion works in cooperation with tests
- setting @@global.debug= 'd,stop_slave_middle_group'.
- The sql thread receives the killed status and will proceed
- to shutdown trying to finish incomplete events group.
- */
- DBUG_EXECUTE_IF("stop_slave_middle_group",
- if (thd->transaction.all.modified_non_trans_table)
- const_cast<Relay_log_info*>(rli)->abort_slave= 1;);
- }
-
- if (unlikely(error= do_after_row_operations(rli, error)) &&
- ignored_error_code(convert_handler_error(error, thd, table)))
- {
-
- if (global_system_variables.log_warnings)
- slave_rows_error_report(WARNING_LEVEL, error, rgi, thd, table,
- get_type_str(),
- RPL_LOG_NAME, log_pos);
- thd->clear_error(1);
- error= 0;
- }
- } // if (table)
-
-
- if (unlikely(error))
- {
- slave_rows_error_report(ERROR_LEVEL, error, rgi, thd, table,
- get_type_str(),
- RPL_LOG_NAME, log_pos);
- /*
- @todo We should probably not call
- reset_current_stmt_binlog_format_row() from here.
-
- Note: this applies to log_event_old.cc too.
- /Sven
- */
- thd->reset_current_stmt_binlog_format_row();
- thd->is_slave_error= 1;
- /* remove trigger's tables */
- goto err;
- }
-
- /* remove trigger's tables */
- if (slave_run_triggers_for_rbr)
- restore_empty_query_table_list(thd->lex);
-
-#if defined(WITH_WSREP) && defined(HAVE_QUERY_CACHE)
- if (WSREP(thd) && wsrep_thd_is_applying(thd))
- {
- query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock);
- }
-#endif /* WITH_WSREP && HAVE_QUERY_CACHE */
-
- if (unlikely(get_flags(STMT_END_F) &&
- (error= rows_event_stmt_cleanup(rgi, thd))))
- slave_rows_error_report(ERROR_LEVEL,
- thd->is_error() ? 0 : error,
- rgi, thd, table,
- get_type_str(),
- RPL_LOG_NAME, log_pos);
- DBUG_RETURN(error);
-
-err:
- if (slave_run_triggers_for_rbr)
- restore_empty_query_table_list(thd->lex);
- rgi->slave_close_thread_tables(thd);
- DBUG_RETURN(error);
-}
-
-Log_event::enum_skip_reason
-Rows_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- /*
- If the slave skip counter is 1 and this event does not end a
- statement, then we should not start executing on the next event.
- Otherwise, we defer the decision to the normal skipping logic.
- */
- if (rgi->rli->slave_skip_counter == 1 && !get_flags(STMT_END_F))
- return Log_event::EVENT_SKIP_IGNORE;
- else
- return Log_event::do_shall_skip(rgi);
-}
-
-/**
- The function is called at Rows_log_event statement commit time,
- normally from Rows_log_event::do_update_pos() and possibly from
- Query_log_event::do_apply_event() of the COMMIT.
- The function commits the last statement for engines, binlog and
- releases resources have been allocated for the statement.
-
- @retval 0 Ok.
- @retval non-zero Error at the commit.
- */
-
-static int rows_event_stmt_cleanup(rpl_group_info *rgi, THD * thd)
-{
- int error;
- DBUG_ENTER("rows_event_stmt_cleanup");
-
- {
- /*
- This is the end of a statement or transaction, so close (and
- unlock) the tables we opened when processing the
- Table_map_log_event starting the statement.
-
- OBSERVER. This will clear *all* mappings, not only those that
- are open for the table. There is not good handle for on-close
- actions for tables.
-
- NOTE. Even if we have no table ('table' == 0) we still need to be
- here, so that we increase the group relay log position. If we didn't, we
- could have a group relay log position which lags behind "forever"
- (assume the last master's transaction is ignored by the slave because of
- replicate-ignore rules).
- */
- error= thd->binlog_flush_pending_rows_event(TRUE);
-
- /*
- If this event is not in a transaction, the call below will, if some
- transactional storage engines are involved, commit the statement into
- them and flush the pending event to binlog.
- If this event is in a transaction, the call will do nothing, but a
- Xid_log_event will come next which will, if some transactional engines
- are involved, commit the transaction and flush the pending event to the
- binlog.
- If there was a deadlock the transaction should have been rolled back
- already. So there should be no need to rollback the transaction.
- */
- DBUG_ASSERT(! thd->transaction_rollback_request);
- error|= (int)(error ? trans_rollback_stmt(thd) : trans_commit_stmt(thd));
-
- /*
- Now what if this is not a transactional engine? we still need to
- flush the pending event to the binlog; we did it with
- thd->binlog_flush_pending_rows_event(). Note that we imitate
- what is done for real queries: a call to
- ha_autocommit_or_rollback() (sometimes only if involves a
- transactional engine), and a call to be sure to have the pending
- event flushed.
- */
-
- /*
- @todo We should probably not call
- reset_current_stmt_binlog_format_row() from here.
-
- Note: this applies to log_event_old.cc too
-
- Btw, the previous comment about transactional engines does not
- seem related to anything that happens here.
- /Sven
- */
- thd->reset_current_stmt_binlog_format_row();
-
- /*
- Reset modified_non_trans_table that we have set in
- rows_log_event::do_apply_event()
- */
- if (!thd->in_multi_stmt_transaction_mode())
- {
- thd->transaction.all.modified_non_trans_table= 0;
- thd->transaction.all.m_unsafe_rollback_flags&= ~THD_TRANS::DID_WAIT;
- }
-
- rgi->cleanup_context(thd, 0);
- }
- DBUG_RETURN(error);
-}
-
-/**
- The method either increments the relay log position or
- commits the current statement and increments the master group
- possition if the event is STMT_END_F flagged and
- the statement corresponds to the autocommit query (i.e replicated
- without wrapping in BEGIN/COMMIT)
-
- @retval 0 Success
- @retval non-zero Error in the statement commit
- */
-int
-Rows_log_event::do_update_pos(rpl_group_info *rgi)
-{
- Relay_log_info *rli= rgi->rli;
- int error= 0;
- DBUG_ENTER("Rows_log_event::do_update_pos");
-
- DBUG_PRINT("info", ("flags: %s",
- get_flags(STMT_END_F) ? "STMT_END_F " : ""));
-
- if (get_flags(STMT_END_F))
- {
- /*
- Indicate that a statement is finished.
- Step the group log position if we are not in a transaction,
- otherwise increase the event log position.
- */
- error= rli->stmt_done(log_pos, thd, rgi);
- /*
- Clear any errors in thd->net.last_err*. It is not known if this is
- needed or not. It is believed that any errors that may exist in
- thd->net.last_err* are allowed. Examples of errors are "key not
- found", which is produced in the test case rpl_row_conflicts.test
- */
- thd->clear_error();
- }
- else
- {
- rgi->inc_event_relay_log_pos();
- }
-
- DBUG_RETURN(error);
-}
-
-#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
-
-#ifndef MYSQL_CLIENT
-bool Rows_log_event::write_data_header()
-{
- uchar buf[ROWS_HEADER_LEN_V2]; // No need to init the buffer
- DBUG_ASSERT(m_table_id != ~0ULL);
- DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master",
- {
- int4store(buf + 0, m_table_id);
- int2store(buf + 4, m_flags);
- return (write_data(buf, 6));
- });
- int6store(buf + RW_MAPID_OFFSET, m_table_id);
- int2store(buf + RW_FLAGS_OFFSET, m_flags);
- return write_data(buf, ROWS_HEADER_LEN);
-}
-
-bool Rows_log_event::write_data_body()
-{
- /*
- Note that this should be the number of *bits*, not the number of
- bytes.
- */
- uchar sbuf[MAX_INT_WIDTH];
- my_ptrdiff_t const data_size= m_rows_cur - m_rows_buf;
- bool res= false;
- uchar *const sbuf_end= net_store_length(sbuf, (size_t) m_width);
- DBUG_ASSERT(static_cast<size_t>(sbuf_end - sbuf) <= sizeof(sbuf));
-
- DBUG_DUMP("m_width", sbuf, (size_t) (sbuf_end - sbuf));
- res= res || write_data(sbuf, (size_t) (sbuf_end - sbuf));
-
- DBUG_DUMP("m_cols", (uchar*) m_cols.bitmap, no_bytes_in_map(&m_cols));
- res= res || write_data((uchar*)m_cols.bitmap, no_bytes_in_map(&m_cols));
- /*
- TODO[refactor write]: Remove the "down cast" here (and elsewhere).
- */
- if (get_general_type_code() == UPDATE_ROWS_EVENT)
- {
- DBUG_DUMP("m_cols_ai", (uchar*) m_cols_ai.bitmap,
- no_bytes_in_map(&m_cols_ai));
- res= res || write_data((uchar*)m_cols_ai.bitmap,
- no_bytes_in_map(&m_cols_ai));
- }
- DBUG_DUMP("rows", m_rows_buf, data_size);
- res= res || write_data(m_rows_buf, (size_t) data_size);
-
- return res;
-
-}
-
-bool Rows_log_event::write_compressed()
-{
- uchar *m_rows_buf_tmp = m_rows_buf;
- uchar *m_rows_cur_tmp = m_rows_cur;
- bool ret = true;
- uint32 comlen, alloc_size;
- comlen= alloc_size= binlog_get_compress_len((uint32)(m_rows_cur_tmp - m_rows_buf_tmp));
- m_rows_buf = (uchar *)my_safe_alloca(alloc_size);
- if(m_rows_buf &&
- !binlog_buf_compress((const char *)m_rows_buf_tmp, (char *)m_rows_buf,
- (uint32)(m_rows_cur_tmp - m_rows_buf_tmp), &comlen))
- {
- m_rows_cur= comlen + m_rows_buf;
- ret= Log_event::write();
- }
- my_safe_afree(m_rows_buf, alloc_size);
- m_rows_buf= m_rows_buf_tmp;
- m_rows_cur= m_rows_cur_tmp;
- return ret;
-}
-#endif
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Rows_log_event::pack_info(Protocol *protocol)
-{
- char buf[256];
- char const *const flagstr=
- get_flags(STMT_END_F) ? " flags: STMT_END_F" : "";
- size_t bytes= my_snprintf(buf, sizeof(buf),
- "table_id: %llu%s", m_table_id, flagstr);
- protocol->store(buf, bytes, &my_charset_bin);
-}
-#endif
-
-#ifdef MYSQL_CLIENT
-
-const char str_binlog[]= "\nBINLOG '\n";
-const char fmt_delim[]= "'%s\n";
-const char fmt_n_delim[]= "\n'%s";
-const char fmt_frag[]= "\nSET @binlog_fragment_%d ='\n";
-const char fmt_binlog2[]= "BINLOG @binlog_fragment_0, @binlog_fragment_1%s\n";
-
-/**
- Print an event "body" cache to @c file possibly in two fragments.
- Each fragement is optionally per @c do_wrap to produce an SQL statement.
-
- @param file a file to print to
- @param body the "body" IO_CACHE of event
- @param do_wrap whether to wrap base64-encoded strings with
- SQL cover.
- @param delimiter delimiter string
-
- @param is_verbose MDEV-10362 workraround parameter to pass
- info on presence of verbose printout in cache encoded data
-
- The function signals on any error through setting @c body->error to -1.
-*/
-bool copy_cache_to_file_wrapped(IO_CACHE *body,
- FILE *file,
- bool do_wrap,
- const char *delimiter,
- bool is_verbose)
-{
- const my_off_t cache_size= my_b_tell(body);
-
- if (reinit_io_cache(body, READ_CACHE, 0L, FALSE, FALSE))
- goto err;
-
- if (!do_wrap)
- {
- my_b_copy_to_file(body, file, SIZE_T_MAX);
- }
- else if (4 + sizeof(str_binlog) + cache_size + sizeof(fmt_delim) >
- opt_binlog_rows_event_max_encoded_size)
- {
- /*
- 2 fragments can always represent near 1GB row-based
- base64-encoded event as two strings each of size less than
- max(max_allowed_packet). Greater number of fragments does not
- save from potential need to tweak (increase) @@max_allowed_packet
- before to process the fragments. So 2 is safe and enough.
-
- Split the big query when its packet size's estimation exceeds a
- limit. The estimate includes the maximum packet header
- contribution of non-compressed packet.
- */
- my_fprintf(file, fmt_frag, 0);
- if (my_b_copy_to_file(body, file, (size_t) cache_size/2 + 1))
- goto err;
- my_fprintf(file, fmt_n_delim, delimiter);
-
- my_fprintf(file, fmt_frag, 1);
- if (my_b_copy_to_file(body, file, SIZE_T_MAX))
- goto err;
- if (!is_verbose)
- my_fprintf(file, fmt_delim, delimiter);
-
- my_fprintf(file, fmt_binlog2, delimiter);
- }
- else
- {
- my_fprintf(file, str_binlog);
- if (my_b_copy_to_file(body, file, SIZE_T_MAX))
- goto err;
- if (!is_verbose)
- my_fprintf(file, fmt_delim, delimiter);
- }
- reinit_io_cache(body, WRITE_CACHE, 0, FALSE, TRUE);
-
- return false;
-
-err:
- body->error = -1;
- return true;
-}
-
-
-/**
- Print an event "body" cache to @c file possibly in two fragments.
- Each fragement is optionally per @c do_wrap to produce an SQL statement.
-
- @param file a file to print to
- @param body the "body" IO_CACHE of event
- @param do_wrap whether to wrap base64-encoded strings with
- SQL cover.
- @param delimiter delimiter string
-
- The function signals on any error through setting @c body->error to -1.
-*/
-bool copy_cache_to_string_wrapped(IO_CACHE *cache,
- LEX_STRING *to,
- bool do_wrap,
- const char *delimiter,
- bool is_verbose)
-{
- const my_off_t cache_size= my_b_tell(cache);
- // contribution to total size estimate of formating
- const size_t fmt_size=
- sizeof(str_binlog) + 2*(sizeof(fmt_frag) + 2 /* %d */) +
- sizeof(fmt_delim) + sizeof(fmt_n_delim) +
- sizeof(fmt_binlog2) +
- 3*PRINT_EVENT_INFO::max_delimiter_size;
-
- if (reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE))
- goto err;
-
- if (!(to->str= (char*) my_malloc((size_t)cache->end_of_file + fmt_size,
- MYF(0))))
- {
- perror("Out of memory: can't allocate memory in "
- "copy_cache_to_string_wrapped().");
- goto err;
- }
-
- if (!do_wrap)
- {
- if (my_b_read(cache, (uchar*) to->str,
- (to->length= (size_t)cache->end_of_file)))
- goto err;
- }
- else if (4 + sizeof(str_binlog) + cache_size + sizeof(fmt_delim) >
- opt_binlog_rows_event_max_encoded_size)
- {
- /*
- 2 fragments can always represent near 1GB row-based
- base64-encoded event as two strings each of size less than
- max(max_allowed_packet). Greater number of fragments does not
- save from potential need to tweak (increase) @@max_allowed_packet
- before to process the fragments. So 2 is safe and enough.
-
- Split the big query when its packet size's estimation exceeds a
- limit. The estimate includes the maximum packet header
- contribution of non-compressed packet.
- */
- char *str= to->str;
- size_t add_to_len;
-
- str += (to->length= sprintf(str, fmt_frag, 0));
- if (my_b_read(cache, (uchar*) str, (uint32) (cache_size/2 + 1)))
- goto err;
- str += (add_to_len = (uint32) (cache_size/2 + 1));
- to->length += add_to_len;
- str += (add_to_len= sprintf(str, fmt_n_delim, delimiter));
- to->length += add_to_len;
-
- str += (add_to_len= sprintf(str, fmt_frag, 1));
- to->length += add_to_len;
- if (my_b_read(cache, (uchar*) str, uint32(cache->end_of_file - (cache_size/2 + 1))))
- goto err;
- str += (add_to_len= uint32(cache->end_of_file - (cache_size/2 + 1)));
- to->length += add_to_len;
- if (!is_verbose)
- {
- str += (add_to_len= sprintf(str , fmt_delim, delimiter));
- to->length += add_to_len;
- }
- to->length += sprintf(str, fmt_binlog2, delimiter);
- }
- else
- {
- char *str= to->str;
-
- str += (to->length= sprintf(str, str_binlog));
- if (my_b_read(cache, (uchar*) str, (size_t)cache->end_of_file))
- goto err;
- str += cache->end_of_file;
- to->length += (size_t)cache->end_of_file;
- if (!is_verbose)
- to->length += sprintf(str , fmt_delim, delimiter);
- }
-
- reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE);
-
- return false;
-
-err:
- cache->error= -1;
- return true;
-}
-
-/**
- The function invokes base64 encoder to run on the current
- event string and store the result into two caches.
- When the event ends the current statement the caches are is copied into
- the argument file.
- Copying is also concerned how to wrap the event, specifically to produce
- a valid SQL syntax.
- When the encoded data size is within max(MAX_ALLOWED_PACKET)
- a regular BINLOG query is composed. Otherwise it is build as fragmented
-
- SET @binlog_fragment_0='...';
- SET @binlog_fragment_1='...';
- BINLOG @binlog_fragment_0, @binlog_fragment_1;
-
- where fragments are represented by a pair of indexed user
- "one shot" variables.
-
- @note
- If any changes made don't forget to duplicate them to
- Old_rows_log_event as long as it's supported.
-
- @param file pointer to IO_CACHE
- @param print_event_info pointer to print_event_info specializing
- what out of and how to print the event
- @param name the name of a table that the event operates on
-
- The function signals on any error of cache access through setting
- that cache's @c error to -1.
-*/
-bool Rows_log_event::print_helper(FILE *file,
- PRINT_EVENT_INFO *print_event_info,
- char const *const name)
-{
- IO_CACHE *const head= &print_event_info->head_cache;
- IO_CACHE *const body= &print_event_info->body_cache;
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- IO_CACHE *const sql= &print_event_info->review_sql_cache;
-#endif
- bool do_print_encoded=
- print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER &&
- print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS &&
- !print_event_info->short_form;
- bool const last_stmt_event= get_flags(STMT_END_F);
-
- if (!print_event_info->short_form)
- {
- char llbuff[22];
-
- print_header(head, print_event_info, !last_stmt_event);
- if (my_b_printf(head, "\t%s: table id %s%s\n",
- name, ullstr(m_table_id, llbuff),
- last_stmt_event ? " flags: STMT_END_F" : ""))
- goto err;
- }
- if (!print_event_info->short_form || print_event_info->print_row_count)
- if (print_base64(body, print_event_info, do_print_encoded))
- goto err;
-
- if (last_stmt_event)
- {
- if (!is_flashback)
- {
- if (copy_event_cache_to_file_and_reinit(head, file) ||
- copy_cache_to_file_wrapped(body, file, do_print_encoded,
- print_event_info->delimiter,
- print_event_info->verbose))
- goto err;
- }
- else
- {
- LEX_STRING tmp_str;
-
- if (copy_event_cache_to_string_and_reinit(head, &tmp_str))
- return 1;
- output_buf.append(tmp_str.str, tmp_str.length); // Not \0 terminated);
- my_free(tmp_str.str);
-
- if (copy_cache_to_string_wrapped(body, &tmp_str, do_print_encoded,
- print_event_info->delimiter,
- print_event_info->verbose))
- return 1;
- output_buf.append(tmp_str.str, tmp_str.length);
- my_free(tmp_str.str);
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- if (copy_event_cache_to_string_and_reinit(sql, &tmp_str))
- return 1;
- output_buf.append(tmp_str.str, tmp_str.length);
- my_free(tmp_str.str);
-#endif
- }
- }
-
- return 0;
-err:
- return 1;
-}
-#endif
-
/**************************************************************************
Annotate_rows_log_event member functions
**************************************************************************/
-#ifndef MYSQL_CLIENT
-Annotate_rows_log_event::Annotate_rows_log_event(THD *thd,
- bool using_trans,
- bool direct)
- : Log_event(thd, 0, using_trans),
- m_save_thd_query_txt(0),
- m_save_thd_query_len(0),
- m_saved_thd_query(false),
- m_used_query_txt(0)
-{
- m_query_txt= thd->query();
- m_query_len= thd->query_length();
- if (direct)
- cache_type= Log_event::EVENT_NO_CACHE;
-}
-#endif
-
Annotate_rows_log_event::Annotate_rows_log_event(const char *buf,
uint event_len,
const Format_description_log_event *desc)
@@ -12344,103 +3475,6 @@ bool Annotate_rows_log_event::is_valid() const
return (m_query_txt != NULL && m_query_len != 0);
}
-#ifndef MYSQL_CLIENT
-bool Annotate_rows_log_event::write_data_header()
-{
- return 0;
-}
-#endif
-
-#ifndef MYSQL_CLIENT
-bool Annotate_rows_log_event::write_data_body()
-{
- return write_data(m_query_txt, m_query_len);
-}
-#endif
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-void Annotate_rows_log_event::pack_info(Protocol* protocol)
-{
- if (m_query_txt && m_query_len)
- protocol->store(m_query_txt, m_query_len, &my_charset_bin);
-}
-#endif
-
-#ifdef MYSQL_CLIENT
-bool Annotate_rows_log_event::print(FILE *file, PRINT_EVENT_INFO *pinfo)
-{
- char *pbeg; // beginning of the next line
- char *pend; // end of the next line
- uint cnt= 0; // characters counter
-
- if (!pinfo->short_form)
- {
- if (print_header(&pinfo->head_cache, pinfo, TRUE) ||
- my_b_printf(&pinfo->head_cache, "\tAnnotate_rows:\n"))
- goto err;
- }
- else if (my_b_printf(&pinfo->head_cache, "# Annotate_rows:\n"))
- goto err;
-
- for (pbeg= m_query_txt; ; pbeg= pend)
- {
- // skip all \r's and \n's at the beginning of the next line
- for (;; pbeg++)
- {
- if (++cnt > m_query_len)
- return 0;
-
- if (*pbeg != '\r' && *pbeg != '\n')
- break;
- }
-
- // find end of the next line
- for (pend= pbeg + 1;
- ++cnt <= m_query_len && *pend != '\r' && *pend != '\n';
- pend++)
- ;
-
- // print next line
- if (my_b_write(&pinfo->head_cache, (const uchar*) "#Q> ", 4) ||
- my_b_write(&pinfo->head_cache, (const uchar*) pbeg, pend - pbeg) ||
- my_b_write(&pinfo->head_cache, (const uchar*) "\n", 1))
- goto err;
- }
-
- return 0;
-err:
- return 1;
-}
-#endif
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-int Annotate_rows_log_event::do_apply_event(rpl_group_info *rgi)
-{
- rgi->free_annotate_event();
- m_save_thd_query_txt= thd->query();
- m_save_thd_query_len= thd->query_length();
- m_saved_thd_query= true;
- m_used_query_txt= 1;
- thd->set_query(m_query_txt, m_query_len);
- return 0;
-}
-#endif
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-int Annotate_rows_log_event::do_update_pos(rpl_group_info *rgi)
-{
- rgi->inc_event_relay_log_pos();
- return 0;
-}
-#endif
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-Log_event::enum_skip_reason
-Annotate_rows_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- return continue_group(rgi);
-}
-#endif
/**************************************************************************
Table_map_log_event member functions and support functions
@@ -12478,142 +3512,6 @@ Annotate_rows_log_event::do_shall_skip(rpl_group_info *rgi)
type used is uint32.
*/
-#if !defined(MYSQL_CLIENT)
-/**
- Save the field metadata based on the real_type of the field.
- The metadata saved depends on the type of the field. Some fields
- store a single byte for pack_length() while others store two bytes
- for field_length (max length).
-
- @retval 0 Ok.
-
- @todo
- We may want to consider changing the encoding of the information.
- Currently, the code attempts to minimize the number of bytes written to
- the tablemap. There are at least two other alternatives; 1) using
- net_store_length() to store the data allowing it to choose the number of
- bytes that are appropriate thereby making the code much easier to
- maintain (only 1 place to change the encoding), or 2) use a fixed number
- of bytes for each field. The problem with option 1 is that net_store_length()
- will use one byte if the value < 251, but 3 bytes if it is > 250. Thus,
- for fields like CHAR which can be no larger than 255 characters, the method
- will use 3 bytes when the value is > 250. Further, every value that is
- encoded using 2 parts (e.g., pack_length, field_length) will be numerically
- > 250 therefore will use 3 bytes for eah value. The problem with option 2
- is less wasteful for space but does waste 1 byte for every field that does
- not encode 2 parts.
-*/
-int Table_map_log_event::save_field_metadata()
-{
- DBUG_ENTER("Table_map_log_event::save_field_metadata");
- int index= 0;
- for (unsigned int i= 0 ; i < m_table->s->fields ; i++)
- {
- DBUG_PRINT("debug", ("field_type: %d", m_coltype[i]));
- index+= m_table->s->field[i]->save_field_metadata(&m_field_metadata[index]);
- }
- DBUG_RETURN(index);
-}
-#endif /* !defined(MYSQL_CLIENT) */
-
-/*
- Constructor used to build an event for writing to the binary log.
- Mats says tbl->s lives longer than this event so it's ok to copy pointers
- (tbl->s->db etc) and not pointer content.
- */
-#if !defined(MYSQL_CLIENT)
-Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid,
- bool is_transactional)
- : Log_event(thd, 0, is_transactional),
- m_table(tbl),
- m_dbnam(tbl->s->db.str),
- m_dblen(m_dbnam ? tbl->s->db.length : 0),
- m_tblnam(tbl->s->table_name.str),
- m_tbllen(tbl->s->table_name.length),
- m_colcnt(tbl->s->fields),
- m_memory(NULL),
- m_table_id(tid),
- m_flags(TM_BIT_LEN_EXACT_F),
- m_data_size(0),
- m_field_metadata(0),
- m_field_metadata_size(0),
- m_null_bits(0),
- m_meta_memory(NULL)
-{
- uchar cbuf[MAX_INT_WIDTH];
- uchar *cbuf_end;
- DBUG_ENTER("Table_map_log_event::Table_map_log_event(TABLE)");
- DBUG_ASSERT(m_table_id != ~0ULL);
- /*
- In TABLE_SHARE, "db" and "table_name" are 0-terminated (see this comment in
- table.cc / alloc_table_share():
- Use the fact the key is db/0/table_name/0
- As we rely on this let's assert it.
- */
- DBUG_ASSERT((tbl->s->db.str == 0) ||
- (tbl->s->db.str[tbl->s->db.length] == 0));
- DBUG_ASSERT(tbl->s->table_name.str[tbl->s->table_name.length] == 0);
-
-
- m_data_size= TABLE_MAP_HEADER_LEN;
- DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master", m_data_size= 6;);
- m_data_size+= m_dblen + 2; // Include length and terminating \0
- m_data_size+= m_tbllen + 2; // Include length and terminating \0
- cbuf_end= net_store_length(cbuf, (size_t) m_colcnt);
- DBUG_ASSERT(static_cast<size_t>(cbuf_end - cbuf) <= sizeof(cbuf));
- m_data_size+= (cbuf_end - cbuf) + m_colcnt; // COLCNT and column types
-
- if (tbl->triggers)
- m_flags|= TM_BIT_HAS_TRIGGERS_F;
-
- /* If malloc fails, caught in is_valid() */
- if ((m_memory= (uchar*) my_malloc(m_colcnt, MYF(MY_WME))))
- {
- m_coltype= reinterpret_cast<uchar*>(m_memory);
- for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
- m_coltype[i]= m_table->field[i]->binlog_type();
- }
-
- /*
- Calculate a bitmap for the results of maybe_null() for all columns.
- The bitmap is used to determine when there is a column from the master
- that is not on the slave and is null and thus not in the row data during
- replication.
- */
- uint num_null_bytes= (m_table->s->fields + 7) / 8;
- m_data_size+= num_null_bytes;
- m_meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME),
- &m_null_bits, num_null_bytes,
- &m_field_metadata, (m_colcnt * 2),
- NULL);
-
- bzero(m_field_metadata, (m_colcnt * 2));
-
- /*
- Create an array for the field metadata and store it.
- */
- m_field_metadata_size= save_field_metadata();
- DBUG_ASSERT(m_field_metadata_size <= (m_colcnt * 2));
-
- /*
- Now set the size of the data to the size of the field metadata array
- plus one or three bytes (see pack.c:net_store_length) for number of
- elements in the field metadata array.
- */
- if (m_field_metadata_size < 251)
- m_data_size+= m_field_metadata_size + 1;
- else
- m_data_size+= m_field_metadata_size + 3;
-
- bzero(m_null_bits, num_null_bytes);
- for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
- if (m_table->field[i]->maybe_null())
- m_null_bits[(i / 8)]+= 1 << (i % 8);
-
- DBUG_VOID_RETURN;
-}
-#endif /* !defined(MYSQL_CLIENT) */
-
/*
Constructor used by slave to read the event from the binary log.
*/
@@ -12630,14 +3528,17 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
m_colcnt(0), m_coltype(0),
m_memory(NULL), m_table_id(ULONGLONG_MAX), m_flags(0),
m_data_size(0), m_field_metadata(0), m_field_metadata_size(0),
- m_null_bits(0), m_meta_memory(NULL)
+ m_null_bits(0), m_meta_memory(NULL),
+ m_optional_metadata_len(0), m_optional_metadata(NULL)
{
+ unsigned int bytes_read= 0;
DBUG_ENTER("Table_map_log_event::Table_map_log_event(const char*,uint,...)");
uint8 common_header_len= description_event->common_header_len;
uint8 post_header_len= description_event->post_header_len[TABLE_MAP_EVENT-1];
DBUG_PRINT("info",("event_len: %u common_header_len: %d post_header_len: %d",
event_len, common_header_len, post_header_len));
+
/*
Don't print debug messages when running valgrind since they can
trigger false warnings.
@@ -12646,8 +3547,8 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
DBUG_DUMP("event buffer", (uchar*) buf, event_len);
#endif
- if (event_len < (uint)(common_header_len + post_header_len))
- DBUG_VOID_RETURN;
+ if (event_len < (uint)(common_header_len + post_header_len))
+ DBUG_VOID_RETURN;
/* Read the post-header */
const char *post_start= buf + common_header_len;
@@ -12696,7 +3597,7 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
m_colcnt, (long) (ptr_colcnt-(const uchar*)vpart)));
/* Allocate mem for all fields in one go. If fails, caught in is_valid() */
- m_memory= (uchar*) my_multi_malloc(MYF(MY_WME),
+ m_memory= (uchar*) my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME),
&m_dbnam, (uint) m_dblen + 1,
&m_tblnam, (uint) m_tbllen + 1,
&m_coltype, (uint) m_colcnt,
@@ -12712,16 +3613,17 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
ptr_after_colcnt= ptr_after_colcnt + m_colcnt;
VALIDATE_BYTES_READ(ptr_after_colcnt, buf, event_len);
m_field_metadata_size= net_field_length(&ptr_after_colcnt);
- if(m_field_metadata_size <= (m_colcnt * 2))
+ if (m_field_metadata_size <= (m_colcnt * 2))
{
uint num_null_bytes= (m_colcnt + 7) / 8;
- m_meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME),
+ m_meta_memory= (uchar *)my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME),
&m_null_bits, num_null_bytes,
&m_field_metadata, m_field_metadata_size,
NULL);
memcpy(m_field_metadata, ptr_after_colcnt, m_field_metadata_size);
ptr_after_colcnt= (uchar*)ptr_after_colcnt + m_field_metadata_size;
memcpy(m_null_bits, ptr_after_colcnt, num_null_bytes);
+ ptr_after_colcnt= (unsigned char*)ptr_after_colcnt + num_null_bytes;
}
else
{
@@ -12730,7 +3632,27 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
m_memory= NULL;
DBUG_VOID_RETURN;
}
+
+ bytes_read= (uint) (ptr_after_colcnt - (uchar *)buf);
+
+ /* After null_bits field, there are some new fields for extra metadata. */
+ if (bytes_read < event_len)
+ {
+ m_optional_metadata_len= event_len - bytes_read;
+ m_optional_metadata=
+ static_cast<unsigned char*>(my_malloc(PSI_INSTRUMENT_ME, m_optional_metadata_len, MYF(MY_WME)));
+ memcpy(m_optional_metadata, ptr_after_colcnt, m_optional_metadata_len);
+ }
}
+#ifdef MYSQL_SERVER
+ if (!m_table)
+ DBUG_VOID_RETURN;
+ binlog_type_info_array= (Binlog_type_info *)thd->alloc(m_table->s->fields *
+ sizeof(Binlog_type_info));
+ for (uint i= 0; i < m_table->s->fields; i++)
+ binlog_type_info_array[i]= m_table->field[i]->binlog_type_info();
+#endif
+
DBUG_VOID_RETURN;
}
#endif
@@ -12739,1635 +3661,270 @@ Table_map_log_event::~Table_map_log_event()
{
my_free(m_meta_memory);
my_free(m_memory);
+ my_free(m_optional_metadata);
+ m_optional_metadata= NULL;
}
+/**
+ Parses SIGNEDNESS field.
-#ifdef MYSQL_CLIENT
-
-/*
- Rewrite database name for the event to name specified by new_db
- SYNOPSIS
- new_db Database name to change to
- new_len Length
- desc Event describing binlog that we're writing to.
-
- DESCRIPTION
- Reset db name. This function assumes that temp_buf member contains event
- representation taken from a binary log. It resets m_dbnam and m_dblen and
- rewrites temp_buf with new db name.
-
- RETURN
- 0 - Success
- other - Error
-*/
-
-int Table_map_log_event::rewrite_db(const char* new_db, size_t new_len,
- const Format_description_log_event* desc)
-{
- DBUG_ENTER("Table_map_log_event::rewrite_db");
- DBUG_ASSERT(temp_buf);
-
- uint header_len= MY_MIN(desc->common_header_len,
- LOG_EVENT_MINIMAL_HEADER_LEN) + TABLE_MAP_HEADER_LEN;
- int len_diff;
-
- if (!(len_diff= (int)(new_len - m_dblen)))
- {
- memcpy((void*) (temp_buf + header_len + 1), new_db, m_dblen + 1);
- memcpy((void*) m_dbnam, new_db, m_dblen + 1);
- DBUG_RETURN(0);
- }
-
- // Create new temp_buf
- ulong event_cur_len= uint4korr(temp_buf + EVENT_LEN_OFFSET);
- ulong event_new_len= event_cur_len + len_diff;
- char* new_temp_buf= (char*) my_malloc(event_new_len, MYF(MY_WME));
-
- if (!new_temp_buf)
- {
- sql_print_error("Table_map_log_event::rewrite_db: "
- "failed to allocate new temp_buf (%d bytes required)",
- event_new_len);
- DBUG_RETURN(-1);
- }
-
- // Rewrite temp_buf
- char* ptr= new_temp_buf;
- size_t cnt= 0;
-
- // Copy header and change event length
- memcpy(ptr, temp_buf, header_len);
- int4store(ptr + EVENT_LEN_OFFSET, event_new_len);
- ptr += header_len;
- cnt += header_len;
-
- // Write new db name length and new name
- DBUG_ASSERT(new_len < 0xff);
- *ptr++ = (char)new_len;
- memcpy(ptr, new_db, new_len + 1);
- ptr += new_len + 1;
- cnt += m_dblen + 2;
-
- // Copy rest part
- memcpy(ptr, temp_buf + cnt, event_cur_len - cnt);
-
- // Reregister temp buf
- free_temp_buf();
- register_temp_buf(new_temp_buf, TRUE);
-
- // Reset m_dbnam and m_dblen members
- m_dblen= new_len;
-
- // m_dbnam resides in m_memory together with m_tblnam and m_coltype
- uchar* memory= m_memory;
- char const* tblnam= m_tblnam;
- uchar* coltype= m_coltype;
-
- m_memory= (uchar*) my_multi_malloc(MYF(MY_WME),
- &m_dbnam, (uint) m_dblen + 1,
- &m_tblnam, (uint) m_tbllen + 1,
- &m_coltype, (uint) m_colcnt,
- NullS);
-
- if (!m_memory)
- {
- sql_print_error("Table_map_log_event::rewrite_db: "
- "failed to allocate new m_memory (%d + %d + %d bytes required)",
- m_dblen + 1, m_tbllen + 1, m_colcnt);
- DBUG_RETURN(-1);
- }
-
- memcpy((void*)m_dbnam, new_db, m_dblen + 1);
- memcpy((void*)m_tblnam, tblnam, m_tbllen + 1);
- memcpy(m_coltype, coltype, m_colcnt);
-
- my_free(memory);
- DBUG_RETURN(0);
-}
-#endif /* MYSQL_CLIENT */
-
-
-/*
- Return value is an error code, one of:
-
- -1 Failure to open table [from open_tables()]
- 0 Success
- 1 No room for more tables [from set_table()]
- 2 Out of memory [from set_table()]
- 3 Wrong table definition
- 4 Daisy-chaining RBR with SBR not possible
+ @param[out] vec stores the signedness flags extracted from field.
+ @param[in] field SIGNEDNESS field in table_map_event.
+ @param[in] length length of the field
*/
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-
-enum enum_tbl_map_status
+static void parse_signedness(std::vector<bool> &vec,
+ unsigned char *field, unsigned int length)
{
- /* no duplicate identifier found */
- OK_TO_PROCESS= 0,
-
- /* this table map must be filtered out */
- FILTERED_OUT= 1,
-
- /* identifier mapping table with different properties */
- SAME_ID_MAPPING_DIFFERENT_TABLE= 2,
-
- /* a duplicate identifier was found mapping the same table */
- SAME_ID_MAPPING_SAME_TABLE= 3
-};
-
-/*
- Checks if this table map event should be processed or not. First
- it checks the filtering rules, and then looks for duplicate identifiers
- in the existing list of rli->tables_to_lock.
-
- It checks that there hasn't been any corruption by verifying that there
- are no duplicate entries with different properties.
-
- In some cases, some binary logs could get corrupted, showing several
- tables mapped to the same table_id, 0 (see: BUG#56226). Thus we do this
- early sanity check for such cases and avoid that the server crashes
- later.
-
- In some corner cases, the master logs duplicate table map events, i.e.,
- same id, same database name, same table name (see: BUG#37137). This is
- different from the above as it's the same table that is mapped again
- to the same identifier. Thus we cannot just check for same ids and
- assume that the event is corrupted we need to check every property.
-
- NOTE: in the event that BUG#37137 ever gets fixed, this extra check
- will still be valid because we would need to support old binary
- logs anyway.
-
- @param rli The relay log info reference.
- @param table_list A list element containing the table to check against.
- @return OK_TO_PROCESS
- if there was no identifier already in rli->tables_to_lock
-
- FILTERED_OUT
- if the event is filtered according to the filtering rules
-
- SAME_ID_MAPPING_DIFFERENT_TABLE
- if the same identifier already maps a different table in
- rli->tables_to_lock
-
- SAME_ID_MAPPING_SAME_TABLE
- if the same identifier already maps the same table in
- rli->tables_to_lock.
-*/
-static enum_tbl_map_status
-check_table_map(rpl_group_info *rgi, RPL_TABLE_LIST *table_list)
-{
- DBUG_ENTER("check_table_map");
- enum_tbl_map_status res= OK_TO_PROCESS;
- Relay_log_info *rli= rgi->rli;
- if ((rgi->thd->slave_thread /* filtering is for slave only */ ||
- IF_WSREP((WSREP(rgi->thd) && rgi->thd->wsrep_applier), 0)) &&
- (!rli->mi->rpl_filter->db_ok(table_list->db.str) ||
- (rli->mi->rpl_filter->is_on() && !rli->mi->rpl_filter->tables_ok("", table_list))))
- res= FILTERED_OUT;
- else
+ for (unsigned int i= 0; i < length; i++)
{
- RPL_TABLE_LIST *ptr= static_cast<RPL_TABLE_LIST*>(rgi->tables_to_lock);
- for(uint i=0 ; ptr && (i< rgi->tables_to_lock_count);
- ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_local), i++)
- {
- if (ptr->table_id == table_list->table_id)
- {
-
- if (cmp(&ptr->db, &table_list->db) ||
- cmp(&ptr->alias, &table_list->table_name) ||
- ptr->lock_type != TL_WRITE) // the ::do_apply_event always sets TL_WRITE
- res= SAME_ID_MAPPING_DIFFERENT_TABLE;
- else
- res= SAME_ID_MAPPING_SAME_TABLE;
-
- break;
- }
- }
+ for (unsigned char c= 0x80; c != 0; c>>= 1)
+ vec.push_back(field[i] & c);
}
-
- DBUG_PRINT("debug", ("check of table map ended up with: %u", res));
-
- DBUG_RETURN(res);
}
-int Table_map_log_event::do_apply_event(rpl_group_info *rgi)
-{
- RPL_TABLE_LIST *table_list;
- char *db_mem, *tname_mem, *ptr;
- size_t dummy_len, db_mem_length, tname_mem_length;
- void *memory;
- Rpl_filter *filter;
- Relay_log_info const *rli= rgi->rli;
- DBUG_ENTER("Table_map_log_event::do_apply_event(Relay_log_info*)");
-
- /* Step the query id to mark what columns that are actually used. */
- thd->set_query_id(next_query_id());
-
- if (!(memory= my_multi_malloc(MYF(MY_WME),
- &table_list, (uint) sizeof(RPL_TABLE_LIST),
- &db_mem, (uint) NAME_LEN + 1,
- &tname_mem, (uint) NAME_LEN + 1,
- 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;
-
- /* 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 };
-
- table_list->init_one_table(&tmp_db_name, &tmp_tbl_name, 0, TL_WRITE);
- table_list->table_id= DBUG_EVALUATE_IF("inject_tblmap_same_id_maps_diff_table", 0, m_table_id);
- table_list->updating= 1;
- table_list->required_type= TABLE_TYPE_NORMAL;
-
- DBUG_PRINT("debug", ("table: %s is mapped to %llu",
- table_list->table_name.str,
- table_list->table_id));
- table_list->master_had_triggers= ((m_flags & TM_BIT_HAS_TRIGGERS_F) ? 1 : 0);
- DBUG_PRINT("debug", ("table->master_had_triggers=%d",
- (int)table_list->master_had_triggers));
-
- enum_tbl_map_status tblmap_status= check_table_map(rgi, table_list);
- if (tblmap_status == OK_TO_PROCESS)
- {
- DBUG_ASSERT(thd->lex->query_tables != table_list);
-
- /*
- Use placement new to construct the table_def instance in the
- memory allocated for it inside table_list.
-
- The memory allocated by the table_def structure (i.e., not the
- memory allocated *for* the table_def structure) is released
- inside Relay_log_info::clear_tables_to_lock() by calling the
- table_def destructor explicitly.
- */
- new (&table_list->m_tabledef)
- table_def(m_coltype, m_colcnt,
- m_field_metadata, m_field_metadata_size,
- m_null_bits, m_flags);
- table_list->m_tabledef_valid= TRUE;
- table_list->m_conv_table= NULL;
- table_list->open_type= OT_BASE_ONLY;
-
- /*
- We record in the slave's information that the table should be
- locked by linking the table into the list of tables to lock.
- */
- table_list->next_global= table_list->next_local= rgi->tables_to_lock;
- rgi->tables_to_lock= table_list;
- rgi->tables_to_lock_count++;
- /* 'memory' is freed in clear_tables_to_lock */
- }
- else // FILTERED_OUT, SAME_ID_MAPPING_*
- {
- /*
- If mapped already but with different properties, we raise an
- error.
- If mapped already but with same properties we skip the event.
- If filtered out we skip the event.
-
- In all three cases, we need to free the memory previously
- allocated.
- */
- if (tblmap_status == SAME_ID_MAPPING_DIFFERENT_TABLE)
- {
- /*
- Something bad has happened. We need to stop the slave as strange things
- could happen if we proceed: slave crash, wrong table being updated, ...
- As a consequence we push an error in this case.
- */
-
- char buf[256];
-
- my_snprintf(buf, sizeof(buf),
- "Found table map event mapping table id %u which "
- "was already mapped but with different settings.",
- table_list->table_id);
-
- if (thd->slave_thread)
- rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, rgi->gtid_info(),
- ER_THD(thd, ER_SLAVE_FATAL_ERROR), buf);
- else
- /*
- For the cases in which a 'BINLOG' statement is set to
- execute in a user session
- */
- my_error(ER_SLAVE_FATAL_ERROR, MYF(0), buf);
- }
-
- my_free(memory);
- }
-
- DBUG_RETURN(tblmap_status == SAME_ID_MAPPING_DIFFERENT_TABLE);
-}
-
-Log_event::enum_skip_reason
-Table_map_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- /*
- If the slave skip counter is 1, then we should not start executing
- on the next event.
- */
- return continue_group(rgi);
-}
-
-int Table_map_log_event::do_update_pos(rpl_group_info *rgi)
-{
- rgi->inc_event_relay_log_pos();
- return 0;
-}
-
-#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
-
-#ifndef MYSQL_CLIENT
-bool Table_map_log_event::write_data_header()
-{
- DBUG_ASSERT(m_table_id != ~0ULL);
- uchar buf[TABLE_MAP_HEADER_LEN];
- DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master",
- {
- int4store(buf + 0, m_table_id);
- int2store(buf + 4, m_flags);
- return (write_data(buf, 6));
- });
- int6store(buf + TM_MAPID_OFFSET, m_table_id);
- int2store(buf + TM_FLAGS_OFFSET, m_flags);
- return write_data(buf, TABLE_MAP_HEADER_LEN);
-}
-
-bool Table_map_log_event::write_data_body()
-{
- DBUG_ASSERT(m_dbnam != NULL);
- DBUG_ASSERT(m_tblnam != NULL);
- /* We use only one byte per length for storage in event: */
- DBUG_ASSERT(m_dblen <= MY_MIN(NAME_LEN, 255));
- DBUG_ASSERT(m_tbllen <= MY_MIN(NAME_LEN, 255));
-
- uchar const dbuf[]= { (uchar) m_dblen };
- uchar const tbuf[]= { (uchar) m_tbllen };
-
- uchar cbuf[MAX_INT_WIDTH];
- uchar *const cbuf_end= net_store_length(cbuf, (size_t) m_colcnt);
- DBUG_ASSERT(static_cast<size_t>(cbuf_end - cbuf) <= sizeof(cbuf));
-
- /*
- Store the size of the field metadata.
- */
- uchar mbuf[MAX_INT_WIDTH];
- uchar *const mbuf_end= net_store_length(mbuf, m_field_metadata_size);
-
- return write_data(dbuf, sizeof(dbuf)) ||
- write_data(m_dbnam, m_dblen+1) ||
- write_data(tbuf, sizeof(tbuf)) ||
- write_data(m_tblnam, m_tbllen+1) ||
- write_data(cbuf, (size_t) (cbuf_end - cbuf)) ||
- write_data(m_coltype, m_colcnt) ||
- write_data(mbuf, (size_t) (mbuf_end - mbuf)) ||
- write_data(m_field_metadata, m_field_metadata_size),
- write_data(m_null_bits, (m_colcnt + 7) / 8);
- }
-#endif
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+/**
+ Parses DEFAULT_CHARSET field.
-/*
- Print some useful information for the SHOW BINARY LOG information
- field.
+ @param[out] default_charset stores collation numbers extracted from field.
+ @param[in] field DEFAULT_CHARSET field in table_map_event.
+ @param[in] length length of the field
*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Table_map_log_event::pack_info(Protocol *protocol)
+static void parse_default_charset(Table_map_log_event::Optional_metadata_fields::
+ Default_charset &default_charset,
+ unsigned char *field, unsigned int length)
{
- char buf[256];
- size_t bytes= my_snprintf(buf, sizeof(buf),
- "table_id: %llu (%s.%s)",
- m_table_id, m_dbnam, m_tblnam);
- protocol->store(buf, bytes, &my_charset_bin);
-}
-#endif
+ unsigned char* p= field;
-
-#endif
-
-
-#ifdef MYSQL_CLIENT
-bool Table_map_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
-{
- if (!print_event_info->short_form)
+ default_charset.default_charset= net_field_length(&p);
+ while (p < field + length)
{
- char llbuff[22];
-
- print_header(&print_event_info->head_cache, print_event_info, TRUE);
- if (my_b_printf(&print_event_info->head_cache,
- "\tTable_map: %`s.%`s mapped to number %s%s\n",
- m_dbnam, m_tblnam, ullstr(m_table_id, llbuff),
- ((m_flags & TM_BIT_HAS_TRIGGERS_F) ?
- " (has triggers)" : "")))
- goto err;
- }
- if (!print_event_info->short_form || print_event_info->print_row_count)
- {
- bool do_print_encoded=
- print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER &&
- print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS &&
- !print_event_info->short_form;
-
- if (print_base64(&print_event_info->body_cache, print_event_info,
- do_print_encoded) ||
- copy_event_cache_to_file_and_reinit(&print_event_info->head_cache,
- file))
- goto err;
- }
+ unsigned int col_index= net_field_length(&p);
+ unsigned int col_charset= net_field_length(&p);
- return 0;
-err:
- return 1;
+ default_charset.charset_pairs.push_back(std::make_pair(col_index,
+ col_charset));
+ }
}
-#endif
-/**************************************************************************
- Write_rows_log_event member functions
-**************************************************************************/
+/**
+ Parses COLUMN_CHARSET field.
-/*
- Constructor used to build an event for writing to the binary log.
+ @param[out] vec stores collation numbers extracted from field.
+ @param[in] field COLUMN_CHARSET field in table_map_event.
+ @param[in] length length of the field
*/
-#if !defined(MYSQL_CLIENT)
-Write_rows_log_event::Write_rows_log_event(THD *thd_arg, TABLE *tbl_arg,
- ulong tid_arg,
- bool is_transactional)
- :Rows_log_event(thd_arg, tbl_arg, tid_arg, tbl_arg->rpl_write_set,
- is_transactional, WRITE_ROWS_EVENT_V1)
+static void parse_column_charset(std::vector<unsigned int> &vec,
+ unsigned char *field, unsigned int length)
{
-}
+ unsigned char* p= field;
-Write_rows_compressed_log_event::Write_rows_compressed_log_event(
- THD *thd_arg,
- TABLE *tbl_arg,
- ulong tid_arg,
- bool is_transactional)
- : Write_rows_log_event(thd_arg, tbl_arg, tid_arg, is_transactional)
-{
- m_type = WRITE_ROWS_COMPRESSED_EVENT_V1;
+ while (p < field + length)
+ vec.push_back(net_field_length(&p));
}
-bool Write_rows_compressed_log_event::write()
-{
- return Rows_log_event::write_compressed();
-}
-#endif
+/**
+ Parses COLUMN_NAME field.
-/*
- Constructor used by slave to read the event from the binary log.
+ @param[out] vec stores column names extracted from field.
+ @param[in] field COLUMN_NAME field in table_map_event.
+ @param[in] length length of the field
*/
-#ifdef HAVE_REPLICATION
-Write_rows_log_event::Write_rows_log_event(const char *buf, uint event_len,
- const Format_description_log_event
- *description_event)
-: Rows_log_event(buf, event_len, description_event)
-{
-}
-
-Write_rows_compressed_log_event::Write_rows_compressed_log_event(
- const char *buf, uint event_len,
- const Format_description_log_event
- *description_event)
-: Write_rows_log_event(buf, event_len, description_event)
-{
- uncompress_buf();
-}
-#endif
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-int
-Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability *const)
-{
- int error= 0;
-
- /*
- Increment the global status insert count variable
- */
- if (get_flags(STMT_END_F))
- status_var_increment(thd->status_var.com_stat[SQLCOM_INSERT]);
-
- /**
- todo: to introduce a property for the event (handler?) which forces
- applying the event in the replace (idempotent) fashion.
- */
- if (slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT)
- {
- /*
- We are using REPLACE semantics and not INSERT IGNORE semantics
- when writing rows, that is: new rows replace old rows. We need to
- inform the storage engine that it should use this behaviour.
- */
-
- /* Tell the storage engine that we are using REPLACE semantics. */
- thd->lex->duplicates= DUP_REPLACE;
-
- /*
- Pretend we're executing a REPLACE command: this is needed for
- InnoDB since it is not (properly) checking the lex->duplicates flag.
- */
- thd->lex->sql_command= SQLCOM_REPLACE;
- /*
- Do not raise the error flag in case of hitting to an unique attribute
- */
- m_table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
- /*
- The following is needed in case if we have AFTER DELETE triggers.
- */
- m_table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
- m_table->file->extra(HA_EXTRA_IGNORE_NO_KEY);
- }
- if (slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers )
- m_table->prepare_triggers_for_insert_stmt_or_event();
-
- /* Honor next number column if present */
- m_table->next_number_field= m_table->found_next_number_field;
- /*
- * Fixed Bug#45999, In RBR, Store engine of Slave auto-generates new
- * sequence numbers for auto_increment fields if the values of them are 0.
- * If generateing a sequence number is decided by the values of
- * table->auto_increment_field_not_null and SQL_MODE(if includes
- * MODE_NO_AUTO_VALUE_ON_ZERO) in update_auto_increment function.
- * SQL_MODE of slave sql thread is always consistency with master's.
- * In RBR, auto_increment fields never are NULL, except if the auto_inc
- * column exists only on the slave side (i.e., in an extra column
- * on the slave's table).
- */
- if (!is_auto_inc_in_extra_columns())
- m_table->auto_increment_field_not_null= TRUE;
- else
- {
- /*
- Here we have checked that there is an extra field
- on this server's table that has an auto_inc column.
-
- Mark that the auto_increment field is null and mark
- the read and write set bits.
-
- (There can only be one AUTO_INC column, it is always
- indexed and it cannot have a DEFAULT value).
- */
- m_table->auto_increment_field_not_null= FALSE;
- m_table->mark_auto_increment_column();
- }
-
- return error;
-}
-
-int
-Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability *const,
- int error)
+static void parse_column_name(std::vector<std::string> &vec,
+ unsigned char *field, unsigned int length)
{
- int local_error= 0;
-
- /**
- Clear the write_set bit for auto_inc field that only
- existed on the destination table as an extra column.
- */
- if (is_auto_inc_in_extra_columns())
- {
- bitmap_clear_bit(m_table->rpl_write_set,
- m_table->next_number_field->field_index);
- bitmap_clear_bit(m_table->read_set,
- m_table->next_number_field->field_index);
+ unsigned char* p= field;
- if (get_flags(STMT_END_F))
- m_table->file->ha_release_auto_increment();
- }
- m_table->next_number_field=0;
- m_table->auto_increment_field_not_null= FALSE;
- if (slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT)
- {
- m_table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
- m_table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
- /*
- resetting the extra with
- table->file->extra(HA_EXTRA_NO_IGNORE_NO_KEY);
- fires bug#27077
- explanation: file->reset() performs this duty
- ultimately. Still todo: fix
- */
- }
- if (unlikely((local_error= m_table->file->ha_end_bulk_insert())))
+ while (p < field + length)
{
- m_table->file->print_error(local_error, MYF(0));
+ unsigned len= net_field_length(&p);
+ vec.push_back(std::string(reinterpret_cast<char *>(p), len));
+ p+= len;
}
- return error? error : local_error;
-}
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-
-bool Rows_log_event::process_triggers(trg_event_type event,
- trg_action_time_type time_type,
- bool old_row_is_record1)
-{
- bool result;
- DBUG_ENTER("Rows_log_event::process_triggers");
- m_table->triggers->mark_fields_used(event);
- if (slave_run_triggers_for_rbr == SLAVE_RUN_TRIGGERS_FOR_RBR_YES)
- {
- tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */
- result= m_table->triggers->process_triggers(thd, event,
- time_type, old_row_is_record1);
- reenable_binlog(thd);
- }
- else
- result= m_table->triggers->process_triggers(thd, event,
- time_type, old_row_is_record1);
-
- DBUG_RETURN(result);
-}
-/*
- Check if there are more UNIQUE keys after the given key.
-*/
-static int
-last_uniq_key(TABLE *table, uint keyno)
-{
- while (++keyno < table->s->keys)
- if (table->key_info[keyno].flags & HA_NOSAME)
- return 0;
- return 1;
}
/**
- Check if an error is a duplicate key error.
+ Parses SET_STR_VALUE/ENUM_STR_VALUE field.
- This function is used to check if an error code is one of the
- duplicate key error, i.e., and error code for which it is sensible
- to do a <code>get_dup_key()</code> to retrieve the duplicate key.
-
- @param errcode The error code to check.
-
- @return <code>true</code> if the error code is such that
- <code>get_dup_key()</code> will return true, <code>false</code>
- otherwise.
+ @param[out] vec stores SET/ENUM column's string values extracted from
+ field. Each SET/ENUM column's string values are stored
+ into a string separate vector. All of them are stored
+ in 'vec'.
+ @param[in] field COLUMN_NAME field in table_map_event.
+ @param[in] length length of the field
*/
-bool
-is_duplicate_key_error(int errcode)
-{
- switch (errcode)
- {
- case HA_ERR_FOUND_DUPP_KEY:
- case HA_ERR_FOUND_DUPP_UNIQUE:
- return true;
- }
- return false;
-}
-
-/**
- Write the current row into event's table.
-
- The row is located in the row buffer, pointed by @c m_curr_row member.
- Number of columns of the row is stored in @c m_width member (it can be
- different from the number of columns in the table to which we insert).
- Bitmap @c m_cols indicates which columns are present in the row. It is assumed
- that event's table is already open and pointed by @c m_table.
-
- If the same record already exists in the table it can be either overwritten
- or an error is reported depending on the value of @c overwrite flag
- (error reporting not yet implemented). Note that the matching record can be
- different from the row we insert if we use primary keys to identify records in
- the table.
-
- The row to be inserted can contain values only for selected columns. The
- missing columns are filled with default values using @c prepare_record()
- function. If a matching record is found in the table and @c overwritte is
- true, the missing columns are taken from it.
-
- @param rli Relay log info (needed for row unpacking).
- @param overwrite
- Shall we overwrite if the row already exists or signal
- error (currently ignored).
-
- @returns Error code on failure, 0 on success.
-
- This method, if successful, sets @c m_curr_row_end pointer to point at the
- next row in the rows buffer. This is done when unpacking the row to be
- inserted.
-
- @note If a matching record is found, it is either updated using
- @c ha_update_row() or first deleted and then new record written.
-*/
-
-int
-Rows_log_event::write_row(rpl_group_info *rgi,
- const bool overwrite)
+static void parse_set_str_value(std::vector<Table_map_log_event::
+ Optional_metadata_fields::str_vector> &vec,
+ unsigned char *field, unsigned int length)
{
- DBUG_ENTER("write_row");
- DBUG_ASSERT(m_table != NULL && thd != NULL);
+ unsigned char* p= field;
- TABLE *table= m_table; // pointer to event's table
- int error;
- int UNINIT_VAR(keynum);
- const bool invoke_triggers=
- slave_run_triggers_for_rbr && !master_had_triggers && table->triggers;
- auto_afree_ptr<char> key(NULL);
-
- prepare_record(table, m_width, true);
-
- /* unpack row into table->record[0] */
- if (unlikely((error= unpack_current_row(rgi))))
- {
- table->file->print_error(error, MYF(0));
- DBUG_RETURN(error);
- }
-
- if (m_curr_row == m_rows_buf && !invoke_triggers)
+ while (p < field + length)
{
- /*
- This table has no triggers so we can do bulk insert.
-
- This is the first row to be inserted, we estimate the rows with
- the size of the first row and use that value to initialize
- storage engine for bulk insertion.
- */
- /* this is the first row to be inserted, we estimate the rows with
- the size of the first row and use that value to initialize
- storage engine for bulk insertion */
- DBUG_ASSERT(!(m_curr_row > m_curr_row_end));
- ha_rows estimated_rows= 0;
- if (m_curr_row < m_curr_row_end)
- estimated_rows= (m_rows_end - m_curr_row) / (m_curr_row_end - m_curr_row);
- else if (m_curr_row == m_curr_row_end)
- estimated_rows= 1;
-
- table->file->ha_start_bulk_insert(estimated_rows);
- }
+ unsigned int count= net_field_length(&p);
- /*
- Explicitly set the auto_inc to null to make sure that
- it gets an auto_generated value.
- */
- if (is_auto_inc_in_extra_columns())
- m_table->next_number_field->set_null();
-
- DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
- DBUG_PRINT_BITSET("debug", "rpl_write_set: %s", table->rpl_write_set);
- DBUG_PRINT_BITSET("debug", "read_set: %s", table->read_set);
-
- if (invoke_triggers &&
- unlikely(process_triggers(TRG_EVENT_INSERT, TRG_ACTION_BEFORE, TRUE)))
- {
- DBUG_RETURN(HA_ERR_GENERIC); // in case if error is not set yet
- }
-
- // Handle INSERT.
- if (table->versioned(VERS_TIMESTAMP))
- {
- ulong sec_part;
- bitmap_set_bit(table->read_set, table->vers_start_field()->field_index);
- table->file->column_bitmaps_signal();
- // Check whether a row came from unversioned table and fix vers fields.
- if (table->vers_start_field()->get_timestamp(&sec_part) == 0 && sec_part == 0)
- table->vers_update_fields();
- }
-
- /*
- Try to write record. If a corresponding record already exists in the table,
- we try to change it using ha_update_row() if possible. Otherwise we delete
- it and repeat the whole process again.
-
- TODO: Add safety measures against infinite looping.
- */
-
- if (table->s->sequence)
- error= update_sequence();
- else while (unlikely(error= table->file->ha_write_row(table->record[0])))
- {
- if (error == HA_ERR_LOCK_DEADLOCK ||
- error == HA_ERR_LOCK_WAIT_TIMEOUT ||
- (keynum= table->file->get_dup_key(error)) < 0 ||
- !overwrite)
+ vec.push_back(std::vector<std::string>());
+ for (unsigned int i= 0; i < count; i++)
{
- DBUG_PRINT("info",("get_dup_key returns %d)", keynum));
- /*
- Deadlock, waiting for lock or just an error from the handler
- such as HA_ERR_FOUND_DUPP_KEY when overwrite is false.
- Retrieval of the duplicate key number may fail
- - either because the error was not "duplicate key" error
- - or because the information which key is not available
- */
- table->file->print_error(error, MYF(0));
- DBUG_RETURN(error);
- }
- /*
- We need to retrieve the old row into record[1] to be able to
- either update or delete the offending record. We either:
-
- - use rnd_pos() with a row-id (available as dupp_row) to the
- offending row, if that is possible (MyISAM and Blackhole), or else
-
- - use index_read_idx() with the key that is duplicated, to
- retrieve the offending row.
- */
- if (table->file->ha_table_flags() & HA_DUPLICATE_POS)
- {
- DBUG_PRINT("info",("Locating offending record using rnd_pos()"));
-
- if ((error= table->file->ha_rnd_init_with_error(0)))
- {
- DBUG_RETURN(error);
- }
-
- error= table->file->ha_rnd_pos(table->record[1], table->file->dup_ref);
- if (unlikely(error))
- {
- DBUG_PRINT("info",("rnd_pos() returns error %d",error));
- table->file->print_error(error, MYF(0));
- DBUG_RETURN(error);
- }
- table->file->ha_rnd_end();
- }
- else
- {
- DBUG_PRINT("info",("Locating offending record using index_read_idx()"));
-
- if (table->file->extra(HA_EXTRA_FLUSH_CACHE))
- {
- DBUG_PRINT("info",("Error when setting HA_EXTRA_FLUSH_CACHE"));
- DBUG_RETURN(my_errno);
- }
-
- if (key.get() == NULL)
- {
- key.assign(static_cast<char*>(my_alloca(table->s->max_unique_length)));
- if (key.get() == NULL)
- {
- DBUG_PRINT("info",("Can't allocate key buffer"));
- DBUG_RETURN(ENOMEM);
- }
- }
-
- key_copy((uchar*)key.get(), table->record[0], table->key_info + keynum,
- 0);
- error= table->file->ha_index_read_idx_map(table->record[1], keynum,
- (const uchar*)key.get(),
- HA_WHOLE_KEY,
- HA_READ_KEY_EXACT);
- if (unlikely(error))
- {
- DBUG_PRINT("info",("index_read_idx() returns %s", HA_ERR(error)));
- table->file->print_error(error, MYF(0));
- DBUG_RETURN(error);
- }
- }
-
- /*
- Now, record[1] should contain the offending row. That
- will enable us to update it or, alternatively, delete it (so
- that we can insert the new row afterwards).
- */
-
- /*
- If row is incomplete we will use the record found to fill
- missing columns.
- */
- if (!get_flags(COMPLETE_ROWS_F))
- {
- restore_record(table,record[1]);
- error= unpack_current_row(rgi);
- }
-
- DBUG_PRINT("debug",("preparing for update: before and after image"));
- DBUG_DUMP("record[1] (before)", table->record[1], table->s->reclength);
- DBUG_DUMP("record[0] (after)", table->record[0], table->s->reclength);
-
- /*
- REPLACE is defined as either INSERT or DELETE + INSERT. If
- possible, we can replace it with an UPDATE, but that will not
- work on InnoDB if FOREIGN KEY checks are necessary.
-
- I (Matz) am not sure of the reason for the last_uniq_key()
- check as, but I'm guessing that it's something along the
- following lines.
-
- Suppose that we got the duplicate key to be a key that is not
- the last unique key for the table and we perform an update:
- then there might be another key for which the unique check will
- fail, so we're better off just deleting the row and inserting
- the correct row.
-
- Additionally we don't use UPDATE if rbr triggers should be invoked -
- when triggers are used we want a simple and predictable execution path.
- */
- if (last_uniq_key(table, keynum) && !invoke_triggers &&
- !table->file->referenced_by_foreign_key())
- {
- DBUG_PRINT("info",("Updating row using ha_update_row()"));
- error= table->file->ha_update_row(table->record[1],
- table->record[0]);
- switch (error) {
-
- case HA_ERR_RECORD_IS_THE_SAME:
- DBUG_PRINT("info",("ignoring HA_ERR_RECORD_IS_THE_SAME error from"
- " ha_update_row()"));
- error= 0;
-
- case 0:
- break;
-
- default:
- DBUG_PRINT("info",("ha_update_row() returns error %d",error));
- table->file->print_error(error, MYF(0));
- }
-
- DBUG_RETURN(error);
- }
- else
- {
- DBUG_PRINT("info",("Deleting offending row and trying to write new one again"));
- if (invoke_triggers &&
- unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE,
- TRUE)))
- error= HA_ERR_GENERIC; // in case if error is not set yet
- else
- {
- if (unlikely((error= table->file->ha_delete_row(table->record[1]))))
- {
- DBUG_PRINT("info",("ha_delete_row() returns error %d",error));
- table->file->print_error(error, MYF(0));
- DBUG_RETURN(error);
- }
- if (invoke_triggers &&
- unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_AFTER,
- TRUE)))
- DBUG_RETURN(HA_ERR_GENERIC); // in case if error is not set yet
- }
- /* Will retry ha_write_row() with the offending row removed. */
+ unsigned len1= net_field_length(&p);
+ vec.back().push_back(std::string(reinterpret_cast<char *>(p), len1));
+ p+= len1;
}
}
-
- if (invoke_triggers &&
- unlikely(process_triggers(TRG_EVENT_INSERT, TRG_ACTION_AFTER, TRUE)))
- error= HA_ERR_GENERIC; // in case if error is not set yet
-
- DBUG_RETURN(error);
}
+/**
+ Parses GEOMETRY_TYPE field.
-int Rows_log_event::update_sequence()
+ @param[out] vec stores geometry column's types extracted from field.
+ @param[in] field GEOMETRY_TYPE field in table_map_event.
+ @param[in] length length of the field
+ */
+static void parse_geometry_type(std::vector<unsigned int> &vec,
+ unsigned char *field, unsigned int length)
{
- TABLE *table= m_table; // pointer to event's table
+ unsigned char* p= field;
- if (!bitmap_is_set(table->rpl_write_set, MIN_VALUE_FIELD_NO))
- {
- /* This event come from a setval function executed on the master.
- Update the sequence next_number and round, like we do with setval()
- */
- my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
- table->read_set);
- longlong nextval= table->field[NEXT_FIELD_NO]->val_int();
- longlong round= table->field[ROUND_FIELD_NO]->val_int();
- dbug_tmp_restore_column_map(table->read_set, old_map);
-
- return table->s->sequence->set_value(table, nextval, round, 0) > 0;
- }
-
- /*
- Update all fields in table and update the active sequence, like with
- ALTER SEQUENCE
- */
- return table->file->ha_write_row(table->record[0]);
+ while (p < field + length)
+ vec.push_back(net_field_length(&p));
}
+/**
+ Parses SIMPLE_PRIMARY_KEY field.
-#endif
-
-int
-Write_rows_log_event::do_exec_row(rpl_group_info *rgi)
+ @param[out] vec stores primary key's column information extracted from
+ field. Each column has an index and a prefix which are
+ stored as a unit_pair. prefix is always 0 for
+ SIMPLE_PRIMARY_KEY field.
+ @param[in] field SIMPLE_PRIMARY_KEY field in table_map_event.
+ @param[in] length length of the field
+ */
+static void parse_simple_pk(std::vector<Table_map_log_event::
+ Optional_metadata_fields::uint_pair> &vec,
+ unsigned char *field, unsigned int length)
{
- DBUG_ASSERT(m_table != NULL);
- const char *tmp= thd->get_proc_info();
- const char *message= "Write_rows_log_event::write_row()";
- int error;
-
-#ifdef WSREP_PROC_INFO
- my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
- "Write_rows_log_event::write_row(%lld)",
- (long long) wsrep_thd_trx_seqno(thd));
- message= thd->wsrep_info;
-#endif /* WSREP_PROC_INFO */
-
- thd_proc_info(thd, message);
- error= write_row(rgi, slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT);
- thd_proc_info(thd, tmp);
-
- if (unlikely(error) && unlikely(!thd->is_error()))
- {
- DBUG_ASSERT(0);
- my_error(ER_UNKNOWN_ERROR, MYF(0));
- }
+ unsigned char* p= field;
- return error;
+ while (p < field + length)
+ vec.push_back(std::make_pair(net_field_length(&p), 0));
}
-#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
+/**
+ Parses PRIMARY_KEY_WITH_PREFIX field.
-#ifdef MYSQL_CLIENT
-bool Write_rows_log_event::print(FILE *file, PRINT_EVENT_INFO* print_event_info)
-{
- DBUG_EXECUTE_IF("simulate_cache_read_error",
- {DBUG_SET("+d,simulate_my_b_fill_error");});
- return Rows_log_event::print_helper(file, print_event_info, is_flashback ? "Delete_rows" : "Write_rows");
-}
+ @param[out] vec stores primary key's column information extracted from
+ field. Each column has an index and a prefix which are
+ stored as a unit_pair.
+ @param[in] field PRIMARY_KEY_WITH_PREFIX field in table_map_event.
+ @param[in] length length of the field
+ */
-bool Write_rows_compressed_log_event::print(FILE *file,
- PRINT_EVENT_INFO* print_event_info)
+static void parse_pk_with_prefix(std::vector<Table_map_log_event::
+ Optional_metadata_fields::uint_pair> &vec,
+ unsigned char *field, unsigned int length)
{
- char *new_buf;
- ulong len;
- bool is_malloc = false;
- if(!row_log_event_uncompress(glob_description_event,
- checksum_alg == BINLOG_CHECKSUM_ALG_CRC32,
- temp_buf, UINT_MAX32, NULL, 0, &is_malloc, &new_buf, &len))
- {
- free_temp_buf();
- register_temp_buf(new_buf, true);
- if (Rows_log_event::print_helper(file, print_event_info,
- "Write_compressed_rows"))
- goto err;
- }
- else
+ unsigned char* p= field;
+
+ while (p < field + length)
{
- if (my_b_printf(&print_event_info->head_cache,
- "ERROR: uncompress write_compressed_rows failed\n"))
- goto err;
+ unsigned int col_index= net_field_length(&p);
+ unsigned int col_prefix= net_field_length(&p);
+ vec.push_back(std::make_pair(col_index, col_prefix));
}
-
- return 0;
-err:
- return 1;
-}
-#endif
-
-
-#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
-uint8 Write_rows_log_event::get_trg_event_map()
-{
- return trg2bit(TRG_EVENT_INSERT) | trg2bit(TRG_EVENT_UPDATE) |
- trg2bit(TRG_EVENT_DELETE);
}
-#endif
-/**************************************************************************
- Delete_rows_log_event member functions
-**************************************************************************/
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-/*
- Compares table->record[0] and table->record[1]
-
- Returns TRUE if different.
-*/
-static bool record_compare(TABLE *table)
+Table_map_log_event::Optional_metadata_fields::
+Optional_metadata_fields(unsigned char* optional_metadata,
+ unsigned int optional_metadata_len)
{
- bool result= FALSE;
- /**
- Compare full record only if:
- - there are no blob fields (otherwise we would also need
- to compare blobs contents as well);
- - there are no varchar fields (otherwise we would also need
- to compare varchar contents as well);
- - there are no null fields, otherwise NULLed fields
- contents (i.e., the don't care bytes) may show arbitrary
- values, depending on how each engine handles internally.
- */
- if ((table->s->blob_fields +
- table->s->varchar_fields +
- table->s->null_fields) == 0)
- {
- result= cmp_record(table,record[1]);
- goto record_compare_exit;
- }
+ unsigned char* field= optional_metadata;
- /* Compare null bits */
- if (memcmp(table->null_flags,
- table->null_flags+table->s->rec_buff_length,
- table->s->null_bytes))
- {
- result= TRUE; // Diff in NULL value
- goto record_compare_exit;
- }
+ if (optional_metadata == NULL)
+ return;
- /* Compare fields */
- for (Field **ptr=table->field ; *ptr ; ptr++)
+ while (field < optional_metadata + optional_metadata_len)
{
- if (table->versioned() && (*ptr)->vers_sys_field())
- {
- continue;
- }
- /**
- We only compare field contents that are not null.
- NULL fields (i.e., their null bits) were compared
- earlier.
- */
- if (!(*(ptr))->is_null())
- {
- if ((*ptr)->cmp_binary_offset(table->s->rec_buff_length))
- {
- result= TRUE;
- goto record_compare_exit;
- }
- }
- }
+ unsigned int len;
+ Optional_metadata_field_type type=
+ static_cast<Optional_metadata_field_type>(field[0]);
-record_compare_exit:
- return result;
-}
-
-
-/**
- Find the best key to use when locating the row in @c find_row().
-
- A primary key is preferred if it exists; otherwise a unique index is
- preferred. Else we pick the index with the smalles rec_per_key value.
-
- If a suitable key is found, set @c m_key, @c m_key_nr and @c m_key_info
- member fields appropriately.
-
- @returns Error code on failure, 0 on success.
-*/
-int Rows_log_event::find_key()
-{
- uint i, best_key_nr, last_part;
- KEY *key, *UNINIT_VAR(best_key);
- ulong UNINIT_VAR(best_rec_per_key), tmp;
- DBUG_ENTER("Rows_log_event::find_key");
- DBUG_ASSERT(m_table);
+ // Get length and move field to the value.
+ field++;
+ len= net_field_length(&field);
- best_key_nr= MAX_KEY;
-
- /*
- Keys are sorted so that any primary key is first, followed by unique keys,
- followed by any other. So we will automatically pick the primary key if
- it exists.
- */
- for (i= 0, key= m_table->key_info; i < m_table->s->keys; i++, key++)
- {
- if (!m_table->s->keys_in_use.is_set(i))
- continue;
- /*
- We cannot use a unique key with NULL-able columns to uniquely identify
- a row (but we can still select it for range scan below if nothing better
- is available).
- */
- if ((key->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
+ switch(type)
{
- best_key_nr= i;
- best_key= key;
+ case SIGNEDNESS:
+ parse_signedness(m_signedness, field, len);
break;
+ case DEFAULT_CHARSET:
+ parse_default_charset(m_default_charset, field, len);
+ break;
+ case COLUMN_CHARSET:
+ parse_column_charset(m_column_charset, field, len);
+ break;
+ case COLUMN_NAME:
+ parse_column_name(m_column_name, field, len);
+ break;
+ case SET_STR_VALUE:
+ parse_set_str_value(m_set_str_value, field, len);
+ break;
+ case ENUM_STR_VALUE:
+ parse_set_str_value(m_enum_str_value, field, len);
+ break;
+ case GEOMETRY_TYPE:
+ parse_geometry_type(m_geometry_type, field, len);
+ break;
+ case SIMPLE_PRIMARY_KEY:
+ parse_simple_pk(m_primary_key, field, len);
+ break;
+ case PRIMARY_KEY_WITH_PREFIX:
+ parse_pk_with_prefix(m_primary_key, field, len);
+ break;
+ case ENUM_AND_SET_DEFAULT_CHARSET:
+ parse_default_charset(m_enum_and_set_default_charset, field, len);
+ break;
+ case ENUM_AND_SET_COLUMN_CHARSET:
+ parse_column_charset(m_enum_and_set_column_charset, field, len);
+ break;
+ default:
+ DBUG_ASSERT(0);
}
- /*
- We can only use a non-unique key if it allows range scans (ie. skip
- FULLTEXT indexes and such).
- */
- last_part= key->user_defined_key_parts - 1;
- DBUG_PRINT("info", ("Index %s rec_per_key[%u]= %lu",
- key->name.str, last_part, key->rec_per_key[last_part]));
- if (!(m_table->file->index_flags(i, last_part, 1) & HA_READ_NEXT))
- continue;
-
- tmp= key->rec_per_key[last_part];
- if (best_key_nr == MAX_KEY || (tmp > 0 && tmp < best_rec_per_key))
- {
- best_key_nr= i;
- best_key= key;
- best_rec_per_key= tmp;
- }
- }
-
- if (best_key_nr == MAX_KEY)
- {
- m_key_info= NULL;
- DBUG_RETURN(0);
+ // next field
+ field+= len;
}
-
- // Allocate buffer for key searches
- m_key= (uchar *) my_malloc(best_key->key_length, MYF(MY_WME));
- if (m_key == NULL)
- DBUG_RETURN(HA_ERR_OUT_OF_MEM);
- m_key_info= best_key;
- m_key_nr= best_key_nr;
-
- DBUG_RETURN(0);;
}
-/*
- Check if we are already spending too much time on this statement.
- if we are, warn user that it might be because table does not have
- a PK, but only if the warning was not printed before for this STMT.
-
- @param type The event type code.
- @param table_name The name of the table that the slave is
- operating.
- @param is_index_scan States whether the slave is doing an index scan
- or not.
- @param rli The relay metadata info.
-*/
-static inline
-void issue_long_find_row_warning(Log_event_type type,
- const char *table_name,
- bool is_index_scan,
- rpl_group_info *rgi)
-{
- if ((global_system_variables.log_warnings > 1 &&
- !rgi->is_long_find_row_note_printed()))
- {
- ulonglong now= microsecond_interval_timer();
- ulonglong stmt_ts= rgi->get_row_stmt_start_timestamp();
-
- DBUG_EXECUTE_IF("inject_long_find_row_note",
- stmt_ts-=(LONG_FIND_ROW_THRESHOLD*2*HRTIME_RESOLUTION););
-
- longlong delta= (now - stmt_ts)/HRTIME_RESOLUTION;
-
- if (delta > LONG_FIND_ROW_THRESHOLD)
- {
- rgi->set_long_find_row_note_printed();
- const char* evt_type= LOG_EVENT_IS_DELETE_ROW(type) ? " DELETE" : "n UPDATE";
- const char* scan_type= is_index_scan ? "scanning an index" : "scanning the table";
-
- sql_print_information("The slave is applying a ROW event on behalf of a%s statement "
- "on table %s and is currently taking a considerable amount "
- "of time (%lld seconds). This is due to the fact that it is %s "
- "while looking up records to be processed. Consider adding a "
- "primary key (or unique key) to the table to improve "
- "performance.",
- evt_type, table_name, (long) delta, scan_type);
- }
- }
-}
+/**************************************************************************
+ Write_rows_log_event member functions
+**************************************************************************/
/*
- HA_ERR_KEY_NOT_FOUND is a fatal error normally, but it's an expected
- error in speculate optimistic mode, so use something non-fatal instead
-*/
-static int row_not_found_error(rpl_group_info *rgi)
+ Constructor used by slave to read the event from the binary log.
+ */
+#ifdef HAVE_REPLICATION
+Write_rows_log_event::Write_rows_log_event(const char *buf, uint event_len,
+ const Format_description_log_event
+ *description_event)
+: Rows_log_event(buf, event_len, description_event)
{
- return rgi->speculation != rpl_group_info::SPECULATE_OPTIMISTIC
- ? HA_ERR_KEY_NOT_FOUND : HA_ERR_RECORD_CHANGED;
}
-/**
- Locate the current row in event's table.
-
- The current row is pointed by @c m_curr_row. Member @c m_width tells
- how many columns are there in the row (this can be differnet from
- the number of columns in the table). It is assumed that event's
- table is already open and pointed by @c m_table.
-
- If a corresponding record is found in the table it is stored in
- @c m_table->record[0]. Note that when record is located based on a primary
- key, it is possible that the record found differs from the row being located.
-
- If no key is specified or table does not have keys, a table scan is used to
- find the row. In that case the row should be complete and contain values for
- all columns. However, it can still be shorter than the table, i.e. the table
- can contain extra columns not present in the row. It is also possible that
- the table has fewer columns than the row being located.
-
- @returns Error code on failure, 0 on success.
-
- @post In case of success @c m_table->record[0] contains the record found.
- Also, the internal "cursor" of the table is positioned at the record found.
-
- @note If the engine allows random access of the records, a combination of
- @c position() and @c rnd_pos() will be used.
-
- Note that one MUST call ha_index_or_rnd_end() after this function if
- it returns 0 as we must leave the row position in the handler intact
- for any following update/delete command.
-*/
-
-int Rows_log_event::find_row(rpl_group_info *rgi)
+Write_rows_compressed_log_event::Write_rows_compressed_log_event(
+ const char *buf, uint event_len,
+ const Format_description_log_event
+ *description_event)
+: Write_rows_log_event(buf, event_len, description_event)
{
- DBUG_ENTER("Rows_log_event::find_row");
-
- DBUG_ASSERT(m_table && m_table->in_use != NULL);
-
- TABLE *table= m_table;
- int error= 0;
- bool is_table_scan= false, is_index_scan= false;
-
- /*
- rpl_row_tabledefs.test specifies that
- if the extra field on the slave does not have a default value
- and this is okay with Delete or Update events.
- Todo: fix wl3228 hld that requires defauls for all types of events
- */
-
- prepare_record(table, m_width, FALSE);
- error= unpack_current_row(rgi);
-
- m_vers_from_plain= false;
- if (table->versioned())
- {
- Field *row_end= table->vers_end_field();
- DBUG_ASSERT(table->read_set);
- bitmap_set_bit(table->read_set, row_end->field_index);
- // check whether master table is unversioned
- if (row_end->val_int() == 0)
- {
- bitmap_set_bit(table->write_set, row_end->field_index);
- // Plain source table may have a PRIMARY KEY. And row_end is always
- // a part of PRIMARY KEY. Set it to max value for engine to find it in
- // index. Needed for an UPDATE/DELETE cases.
- table->vers_end_field()->set_max();
- m_vers_from_plain= true;
- }
- table->file->column_bitmaps_signal();
- }
-
- DBUG_PRINT("info",("looking for the following record"));
- DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
-
- if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION) &&
- table->s->primary_key < MAX_KEY)
- {
- /*
- Use a more efficient method to fetch the record given by
- table->record[0] if the engine allows it. We first compute a
- row reference using the position() member function (it will be
- stored in table->file->ref) and the use rnd_pos() to position
- the "cursor" (i.e., record[0] in this case) at the correct row.
-
- TODO: Add a check that the correct record has been fetched by
- comparing with the original record. Take into account that the
- record on the master and slave can be of different
- length. Something along these lines should work:
-
- ADD>>> store_record(table,record[1]);
- int error= table->file->ha_rnd_pos(table->record[0],
- table->file->ref);
- ADD>>> DBUG_ASSERT(memcmp(table->record[1], table->record[0],
- table->s->reclength) == 0);
-
- */
- int error;
- DBUG_PRINT("info",("locating record using primary key (position)"));
-
- error= table->file->ha_rnd_pos_by_record(table->record[0]);
- if (unlikely(error))
- {
- DBUG_PRINT("info",("rnd_pos returns error %d",error));
- if (error == HA_ERR_KEY_NOT_FOUND)
- error= row_not_found_error(rgi);
- table->file->print_error(error, MYF(0));
- }
- DBUG_RETURN(error);
- }
-
- // We can't use position() - try other methods.
-
- /*
- We need to retrieve all fields
- TODO: Move this out from this function to main loop
- */
- table->use_all_columns();
-
- /*
- Save copy of the record in table->record[1]. It might be needed
- later if linear search is used to find exact match.
- */
- store_record(table,record[1]);
-
- if (m_key_info)
- {
- DBUG_PRINT("info",("locating record using key #%u [%s] (index_read)",
- m_key_nr, m_key_info->name.str));
- /* We use this to test that the correct key is used in test cases. */
- DBUG_EXECUTE_IF("slave_crash_if_wrong_index",
- if(0 != strcmp(m_key_info->name.str,"expected_key")) abort(););
-
- /* The key is active: search the table using the index */
- if (!table->file->inited &&
- (error= table->file->ha_index_init(m_key_nr, FALSE)))
- {
- DBUG_PRINT("info",("ha_index_init returns error %d",error));
- table->file->print_error(error, MYF(0));
- goto end;
- }
-
- /* Fill key data for the row */
-
- DBUG_ASSERT(m_key);
- key_copy(m_key, table->record[0], m_key_info, 0);
-
- /*
- Don't print debug messages when running valgrind since they can
- trigger false warnings.
- */
-#ifndef HAVE_valgrind
- DBUG_DUMP("key data", m_key, m_key_info->key_length);
-#endif
-
- /*
- We need to set the null bytes to ensure that the filler bit are
- all set when returning. There are storage engines that just set
- the necessary bits on the bytes and don't set the filler bits
- correctly.
- */
- if (table->s->null_bytes > 0)
- table->record[0][table->s->null_bytes - 1]|=
- 256U - (1U << table->s->last_null_bit_pos);
-
- if (unlikely((error= table->file->ha_index_read_map(table->record[0],
- m_key,
- HA_WHOLE_KEY,
- HA_READ_KEY_EXACT))))
- {
- DBUG_PRINT("info",("no record matching the key found in the table"));
- if (error == HA_ERR_KEY_NOT_FOUND)
- error= row_not_found_error(rgi);
- table->file->print_error(error, MYF(0));
- table->file->ha_index_end();
- goto end;
- }
-
- /*
- Don't print debug messages when running valgrind since they can
- trigger false warnings.
- */
-#ifndef HAVE_valgrind
- DBUG_PRINT("info",("found first matching record"));
- DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
-#endif
- /*
- Below is a minor "optimization". If the key (i.e., key number
- 0) has the HA_NOSAME flag set, we know that we have found the
- correct record (since there can be no duplicates); otherwise, we
- have to compare the record with the one found to see if it is
- the correct one.
-
- CAVEAT! This behaviour is essential for the replication of,
- e.g., the mysql.proc table since the correct record *shall* be
- found using the primary key *only*. There shall be no
- comparison of non-PK columns to decide if the correct record is
- found. I can see no scenario where it would be incorrect to
- chose the row to change only using a PK or an UNNI.
- */
- if (table->key_info->flags & HA_NOSAME)
- {
- /* Unique does not have non nullable part */
- if (!(table->key_info->flags & (HA_NULL_PART_KEY)))
- {
- error= 0;
- goto end;
- }
- else
- {
- KEY *keyinfo= table->key_info;
- /*
- Unique has nullable part. We need to check if there is any
- field in the BI image that is null and part of UNNI.
- */
- bool null_found= FALSE;
- for (uint i=0; i < keyinfo->user_defined_key_parts && !null_found; i++)
- {
- uint fieldnr= keyinfo->key_part[i].fieldnr - 1;
- Field **f= table->field+fieldnr;
- null_found= (*f)->is_null();
- }
-
- if (!null_found)
- {
- error= 0;
- goto end;
- }
-
- /* else fall through to index scan */
- }
- }
-
- is_index_scan=true;
-
- /*
- In case key is not unique, we still have to iterate over records found
- and find the one which is identical to the row given. A copy of the
- record we are looking for is stored in record[1].
- */
- DBUG_PRINT("info",("non-unique index, scanning it to find matching record"));
- /* We use this to test that the correct key is used in test cases. */
- DBUG_EXECUTE_IF("slave_crash_if_index_scan", abort(););
-
- while (record_compare(table))
- {
- while ((error= table->file->ha_index_next(table->record[0])))
- {
- DBUG_PRINT("info",("no record matching the given row found"));
- table->file->print_error(error, MYF(0));
- table->file->ha_index_end();
- goto end;
- }
- }
- }
- else
- {
- DBUG_PRINT("info",("locating record using table scan (rnd_next)"));
- /* We use this to test that the correct key is used in test cases. */
- DBUG_EXECUTE_IF("slave_crash_if_table_scan", abort(););
-
- /* We don't have a key: search the table using rnd_next() */
- if (unlikely((error= table->file->ha_rnd_init_with_error(1))))
- {
- DBUG_PRINT("info",("error initializing table scan"
- " (ha_rnd_init returns %d)",error));
- goto end;
- }
-
- is_table_scan= true;
-
- /* Continue until we find the right record or have made a full loop */
- do
- {
- error= table->file->ha_rnd_next(table->record[0]);
-
- if (unlikely(error))
- DBUG_PRINT("info", ("error: %s", HA_ERR(error)));
- switch (error) {
-
- case 0:
- DBUG_DUMP("record found", table->record[0], table->s->reclength);
- break;
-
- case HA_ERR_END_OF_FILE:
- DBUG_PRINT("info", ("Record not found"));
- table->file->ha_rnd_end();
- goto end;
-
- default:
- DBUG_PRINT("info", ("Failed to get next record"
- " (rnd_next returns %d)",error));
- table->file->print_error(error, MYF(0));
- table->file->ha_rnd_end();
- goto end;
- }
- }
- while (record_compare(table));
-
- /*
- Note: above record_compare will take into accout all record fields
- which might be incorrect in case a partial row was given in the event
- */
-
- DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == 0);
- }
-
-end:
- if (is_table_scan || is_index_scan)
- issue_long_find_row_warning(get_general_type_code(), m_table->alias.c_ptr(),
- is_index_scan, rgi);
- table->default_column_bitmaps();
- DBUG_RETURN(error);
+ uncompress_buf();
}
-
#endif
-/*
- Constructor used to build an event for writing to the binary log.
- */
-
-#ifndef MYSQL_CLIENT
-Delete_rows_log_event::Delete_rows_log_event(THD *thd_arg, TABLE *tbl_arg,
- ulong tid, bool is_transactional)
- : Rows_log_event(thd_arg, tbl_arg, tid, tbl_arg->read_set, is_transactional,
- DELETE_ROWS_EVENT_V1)
-{
-}
-
-Delete_rows_compressed_log_event::Delete_rows_compressed_log_event(
- THD *thd_arg, TABLE *tbl_arg,
- ulong tid_arg,
- bool is_transactional)
- : Delete_rows_log_event(thd_arg, tbl_arg, tid_arg, is_transactional)
-{
- m_type= DELETE_ROWS_COMPRESSED_EVENT_V1;
-}
-bool Delete_rows_compressed_log_event::write()
-{
- return Rows_log_event::write_compressed();
-}
-#endif /* #if !defined(MYSQL_CLIENT) */
+/**************************************************************************
+ Delete_rows_log_event member functions
+**************************************************************************/
/*
Constructor used by slave to read the event from the binary log.
@@ -14390,199 +3947,10 @@ Delete_rows_compressed_log_event::Delete_rows_compressed_log_event(
}
#endif
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-
-int
-Delete_rows_log_event::do_before_row_operations(const Slave_reporting_capability *const)
-{
- /*
- Increment the global status delete count variable
- */
- if (get_flags(STMT_END_F))
- status_var_increment(thd->status_var.com_stat[SQLCOM_DELETE]);
-
- if ((m_table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION) &&
- m_table->s->primary_key < MAX_KEY)
- {
- /*
- We don't need to allocate any memory for m_key since it is not used.
- */
- return 0;
- }
- if (slave_run_triggers_for_rbr && !master_had_triggers)
- m_table->prepare_triggers_for_delete_stmt_or_event();
-
- return find_key();
-}
-
-int
-Delete_rows_log_event::do_after_row_operations(const Slave_reporting_capability *const,
- int error)
-{
- m_table->file->ha_index_or_rnd_end();
- my_free(m_key);
- m_key= NULL;
- m_key_info= NULL;
-
- return error;
-}
-
-int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi)
-{
- int error;
- const char *tmp= thd->get_proc_info();
- const char *message= "Delete_rows_log_event::find_row()";
- const bool invoke_triggers=
- slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers;
- DBUG_ASSERT(m_table != NULL);
-
-#ifdef WSREP_PROC_INFO
- my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
- "Delete_rows_log_event::find_row(%lld)",
- (long long) wsrep_thd_trx_seqno(thd));
- message= thd->wsrep_info;
-#endif /* WSREP_PROC_INFO */
-
- thd_proc_info(thd, message);
- if (likely(!(error= find_row(rgi))))
- {
- /*
- Delete the record found, located in record[0]
- */
- message= "Delete_rows_log_event::ha_delete_row()";
-#ifdef WSREP_PROC_INFO
- snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
- "Delete_rows_log_event::ha_delete_row(%lld)",
- (long long) wsrep_thd_trx_seqno(thd));
- message= thd->wsrep_info;
-#endif
- thd_proc_info(thd, message);
-
- if (invoke_triggers &&
- unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE, FALSE)))
- error= HA_ERR_GENERIC; // in case if error is not set yet
- if (likely(!error))
- {
- m_table->mark_columns_per_binlog_row_image();
- if (m_vers_from_plain && m_table->versioned(VERS_TIMESTAMP))
- {
- Field *end= m_table->vers_end_field();
- bitmap_set_bit(m_table->write_set, end->field_index);
- store_record(m_table, record[1]);
- end->set_time();
- error= m_table->file->ha_update_row(m_table->record[1],
- m_table->record[0]);
- }
- else
- {
- error= m_table->file->ha_delete_row(m_table->record[0]);
- }
- m_table->default_column_bitmaps();
- }
- if (invoke_triggers && likely(!error) &&
- unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_AFTER, FALSE)))
- error= HA_ERR_GENERIC; // in case if error is not set yet
- m_table->file->ha_index_or_rnd_end();
- }
- thd_proc_info(thd, tmp);
- return error;
-}
-
-#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
-
-#ifdef MYSQL_CLIENT
-bool Delete_rows_log_event::print(FILE *file,
- PRINT_EVENT_INFO* print_event_info)
-{
- return Rows_log_event::print_helper(file, print_event_info, is_flashback ? "Write_rows" : "Delete_rows");
-}
-
-bool Delete_rows_compressed_log_event::print(FILE *file,
- PRINT_EVENT_INFO* print_event_info)
-{
- char *new_buf;
- ulong len;
- bool is_malloc = false;
- if(!row_log_event_uncompress(glob_description_event,
- checksum_alg == BINLOG_CHECKSUM_ALG_CRC32,
- temp_buf, UINT_MAX32, NULL, 0, &is_malloc, &new_buf, &len))
- {
- free_temp_buf();
- register_temp_buf(new_buf, true);
- if (Rows_log_event::print_helper(file, print_event_info,
- "Delete_compressed_rows"))
- goto err;
- }
- else
- {
- if (my_b_printf(&print_event_info->head_cache,
- "ERROR: uncompress delete_compressed_rows failed\n"))
- goto err;
- }
-
- return 0;
-err:
- return 1;
-}
-#endif
-
-
-#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
-uint8 Delete_rows_log_event::get_trg_event_map()
-{
- return trg2bit(TRG_EVENT_DELETE);
-}
-#endif
-
/**************************************************************************
Update_rows_log_event member functions
**************************************************************************/
-/*
- Constructor used to build an event for writing to the binary log.
- */
-#if !defined(MYSQL_CLIENT)
-Update_rows_log_event::Update_rows_log_event(THD *thd_arg, TABLE *tbl_arg,
- ulong tid,
- bool is_transactional)
-: Rows_log_event(thd_arg, tbl_arg, tid, tbl_arg->read_set, is_transactional,
- UPDATE_ROWS_EVENT_V1)
-{
- init(tbl_arg->rpl_write_set);
-}
-
-Update_rows_compressed_log_event::Update_rows_compressed_log_event(THD *thd_arg, TABLE *tbl_arg,
- ulong tid,
- bool is_transactional)
-: Update_rows_log_event(thd_arg, tbl_arg, tid, is_transactional)
-{
- m_type = UPDATE_ROWS_COMPRESSED_EVENT_V1;
-}
-
-bool Update_rows_compressed_log_event::write()
-{
- return Rows_log_event::write_compressed();
-}
-
-void Update_rows_log_event::init(MY_BITMAP const *cols)
-{
- /* if my_bitmap_init fails, caught in is_valid() */
- if (likely(!my_bitmap_init(&m_cols_ai,
- m_width <= sizeof(m_bitbuf_ai)*8 ? m_bitbuf_ai : NULL,
- m_width,
- false)))
- {
- /* Cols can be zero if this is a dummy binrows event */
- if (likely(cols != NULL))
- {
- memcpy(m_cols_ai.bitmap, cols->bitmap, no_bytes_in_map(cols));
- create_last_word_mask(&m_cols_ai);
- }
- }
-}
-#endif /* !defined(MYSQL_CLIENT) */
-
-
Update_rows_log_event::~Update_rows_log_event()
{
if (m_cols_ai.bitmap)
@@ -14616,202 +3984,6 @@ Update_rows_compressed_log_event::Update_rows_compressed_log_event(
}
#endif
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-
-int
-Update_rows_log_event::do_before_row_operations(const Slave_reporting_capability *const)
-{
- /*
- Increment the global status update count variable
- */
- if (get_flags(STMT_END_F))
- status_var_increment(thd->status_var.com_stat[SQLCOM_UPDATE]);
-
- int err;
- if ((err= find_key()))
- return err;
-
- if (slave_run_triggers_for_rbr && !master_had_triggers)
- m_table->prepare_triggers_for_update_stmt_or_event();
-
- return 0;
-}
-
-int
-Update_rows_log_event::do_after_row_operations(const Slave_reporting_capability *const,
- int error)
-{
- /*error= ToDo:find out what this should really be, this triggers close_scan in nbd, returning error?*/
- m_table->file->ha_index_or_rnd_end();
- my_free(m_key); // Free for multi_malloc
- m_key= NULL;
- m_key_info= NULL;
-
- return error;
-}
-
-int
-Update_rows_log_event::do_exec_row(rpl_group_info *rgi)
-{
- const bool invoke_triggers=
- slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers;
- const char *tmp= thd->get_proc_info();
- const char *message= "Update_rows_log_event::find_row()";
- DBUG_ASSERT(m_table != NULL);
-
-#ifdef WSREP_PROC_INFO
- my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
- "Update_rows_log_event::find_row(%lld)",
- (long long) wsrep_thd_trx_seqno(thd));
- message= thd->wsrep_info;
-#endif /* WSREP_PROC_INFO */
-
- thd_proc_info(thd, message);
- int error= find_row(rgi);
- if (unlikely(error))
- {
- /*
- We need to read the second image in the event of error to be
- able to skip to the next pair of updates
- */
- if ((m_curr_row= m_curr_row_end))
- unpack_current_row(rgi, &m_cols_ai);
- thd_proc_info(thd, tmp);
- return error;
- }
-
- /*
- This is the situation after locating BI:
-
- ===|=== before image ====|=== after image ===|===
- ^ ^
- m_curr_row m_curr_row_end
-
- BI found in the table is stored in record[0]. We copy it to record[1]
- and unpack AI to record[0].
- */
-
- store_record(m_table,record[1]);
-
- m_curr_row= m_curr_row_end;
- message= "Update_rows_log_event::unpack_current_row()";
-#ifdef WSREP_PROC_INFO
- my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
- "Update_rows_log_event::unpack_current_row(%lld)",
- (long long) wsrep_thd_trx_seqno(thd));
- message= thd->wsrep_info;
-#endif /* WSREP_PROC_INFO */
-
- /* this also updates m_curr_row_end */
- thd_proc_info(thd, message);
- if (unlikely((error= unpack_current_row(rgi, &m_cols_ai))))
- goto err;
-
- /*
- Now we have the right row to update. The old row (the one we're
- looking for) is in record[1] and the new row is in record[0].
- */
-#ifndef HAVE_valgrind
- /*
- Don't print debug messages when running valgrind since they can
- trigger false warnings.
- */
- DBUG_PRINT("info",("Updating row in table"));
- DBUG_DUMP("old record", m_table->record[1], m_table->s->reclength);
- DBUG_DUMP("new values", m_table->record[0], m_table->s->reclength);
-#endif
-
- message= "Update_rows_log_event::ha_update_row()";
-#ifdef WSREP_PROC_INFO
- my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
- "Update_rows_log_event::ha_update_row(%lld)",
- (long long) wsrep_thd_trx_seqno(thd));
- message= thd->wsrep_info;
-#endif /* WSREP_PROC_INFO */
-
- thd_proc_info(thd, message);
- if (invoke_triggers &&
- unlikely(process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_BEFORE, TRUE)))
- {
- error= HA_ERR_GENERIC; // in case if error is not set yet
- goto err;
- }
-
- // Temporary fix to find out why it fails [/Matz]
- memcpy(m_table->read_set->bitmap, m_cols.bitmap, (m_table->read_set->n_bits + 7) / 8);
- memcpy(m_table->write_set->bitmap, m_cols_ai.bitmap, (m_table->write_set->n_bits + 7) / 8);
-
- m_table->mark_columns_per_binlog_row_image();
- if (m_vers_from_plain && m_table->versioned(VERS_TIMESTAMP))
- m_table->vers_update_fields();
- error= m_table->file->ha_update_row(m_table->record[1], m_table->record[0]);
- if (unlikely(error == HA_ERR_RECORD_IS_THE_SAME))
- error= 0;
- if (m_vers_from_plain && m_table->versioned(VERS_TIMESTAMP))
- {
- store_record(m_table, record[2]);
- error= vers_insert_history_row(m_table);
- restore_record(m_table, record[2]);
- }
- m_table->default_column_bitmaps();
-
- if (invoke_triggers && likely(!error) &&
- unlikely(process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE)))
- error= HA_ERR_GENERIC; // in case if error is not set yet
-
- thd_proc_info(thd, tmp);
-
-err:
- m_table->file->ha_index_or_rnd_end();
- return error;
-}
-
-#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
-
-#ifdef MYSQL_CLIENT
-bool Update_rows_log_event::print(FILE *file,
- PRINT_EVENT_INFO* print_event_info)
-{
- return Rows_log_event::print_helper(file, print_event_info, "Update_rows");
-}
-
-bool
-Update_rows_compressed_log_event::print(FILE *file,
- PRINT_EVENT_INFO *print_event_info)
-{
- char *new_buf;
- ulong len;
- bool is_malloc= false;
- if(!row_log_event_uncompress(glob_description_event,
- checksum_alg == BINLOG_CHECKSUM_ALG_CRC32,
- temp_buf, UINT_MAX32, NULL, 0, &is_malloc, &new_buf, &len))
- {
- free_temp_buf();
- register_temp_buf(new_buf, true);
- if (Rows_log_event::print_helper(file, print_event_info,
- "Update_compressed_rows"))
- goto err;
- }
- else
- {
- if (my_b_printf(&print_event_info->head_cache,
- "ERROR: uncompress update_compressed_rows failed\n"))
- goto err;
- }
-
- return 0;
-err:
- return 1;
-}
-#endif
-
-#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
-uint8 Update_rows_log_event::get_trg_event_map()
-{
- return trg2bit(TRG_EVENT_UPDATE);
-}
-#endif
-
Incident_log_event::Incident_log_event(const char *buf, uint event_len,
const Format_description_log_event *descr_event)
: Log_event(buf, descr_event)
@@ -14848,7 +4020,7 @@ Incident_log_event::Incident_log_event(const char *buf, uint event_len,
m_incident= INCIDENT_NONE;
DBUG_VOID_RETURN;
}
- if (!(m_message.str= (char*) my_malloc(len+1, MYF(MY_WME))))
+ if (!(m_message.str= (char*) my_malloc(key_memory_log_event, len+1, MYF(MY_WME))))
{
/* Mark this event invalid */
m_incident= INCIDENT_NONE;
@@ -14881,123 +4053,6 @@ Incident_log_event::description() const
}
-#ifndef MYSQL_CLIENT
-void Incident_log_event::pack_info(Protocol *protocol)
-{
- char buf[256];
- size_t bytes;
- if (m_message.length > 0)
- bytes= my_snprintf(buf, sizeof(buf), "#%d (%s)",
- m_incident, description());
- else
- bytes= my_snprintf(buf, sizeof(buf), "#%d (%s): %s",
- m_incident, description(), m_message.str);
- protocol->store(buf, bytes, &my_charset_bin);
-}
-#endif /* MYSQL_CLIENT */
-
-
-#if defined(WITH_WSREP) && !defined(MYSQL_CLIENT)
-/*
- read the first event from (*buf). The size of the (*buf) is (*buf_len).
- At the end (*buf) is shitfed to point to the following event or NULL and
- (*buf_len) will be changed to account just being read bytes of the 1st event.
-*/
-#define WSREP_MAX_ALLOWED_PACKET 1024*1024*1024 // current protocol max
-
-Log_event* wsrep_read_log_event(
- char **arg_buf, size_t *arg_buf_len,
- const Format_description_log_event *description_event)
-{
- char *head= (*arg_buf);
- uint data_len = uint4korr(head + EVENT_LEN_OFFSET);
- char *buf= (*arg_buf);
- const char *error= 0;
- Log_event *res= 0;
- DBUG_ENTER("wsrep_read_log_event");
-
- if (data_len > WSREP_MAX_ALLOWED_PACKET)
- {
- error = "Event too big";
- goto err;
- }
-
- res= Log_event::read_log_event(buf, data_len, &error, description_event, false);
-
-err:
- if (!res)
- {
- DBUG_ASSERT(error != 0);
- sql_print_error("Error in Log_event::read_log_event(): "
- "'%s', data_len: %d, event_type: %d",
- error,data_len,(uchar)head[EVENT_TYPE_OFFSET]);
- }
- (*arg_buf)+= data_len;
- (*arg_buf_len)-= data_len;
- DBUG_RETURN(res);
-}
-#endif
-
-
-#ifdef MYSQL_CLIENT
-bool Incident_log_event::print(FILE *file,
- PRINT_EVENT_INFO *print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- Write_on_release_cache cache(&print_event_info->head_cache, file);
-
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\n# Incident: %s\nRELOAD DATABASE; # Shall generate syntax error\n", description()))
- return 1;
- return cache.flush_data();
-}
-#endif
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int
-Incident_log_event::do_apply_event(rpl_group_info *rgi)
-{
- Relay_log_info const *rli= rgi->rli;
- DBUG_ENTER("Incident_log_event::do_apply_event");
-
- if (ignored_error_code(ER_SLAVE_INCIDENT))
- {
- DBUG_PRINT("info", ("Ignoring Incident"));
- DBUG_RETURN(0);
- }
-
- rli->report(ERROR_LEVEL, ER_SLAVE_INCIDENT, NULL,
- ER_THD(rgi->thd, ER_SLAVE_INCIDENT),
- description(),
- m_message.length > 0 ? m_message.str : "<none>");
- DBUG_RETURN(1);
-}
-#endif
-
-#ifdef MYSQL_SERVER
-bool
-Incident_log_event::write_data_header()
-{
- DBUG_ENTER("Incident_log_event::write_data_header");
- DBUG_PRINT("enter", ("m_incident: %d", m_incident));
- uchar buf[sizeof(int16)];
- int2store(buf, (int16) m_incident);
- DBUG_RETURN(write_data(buf, sizeof(buf)));
-}
-
-bool
-Incident_log_event::write_data_body()
-{
- uchar tmp[1];
- DBUG_ENTER("Incident_log_event::write_data_body");
- tmp[0]= (uchar) m_message.length;
- DBUG_RETURN(write_data(tmp, sizeof(tmp)) ||
- write_data(m_message.str, m_message.length));
-}
-#endif
-
Ignorable_log_event::Ignorable_log_event(const char *buf,
const Format_description_log_event
*descr_event,
@@ -15013,154 +4068,8 @@ Ignorable_log_event::~Ignorable_log_event()
{
}
-#ifndef MYSQL_CLIENT
-/* Pack info for its unrecognized ignorable event */
-void Ignorable_log_event::pack_info(Protocol *protocol)
-{
- char buf[256];
- size_t bytes;
- bytes= my_snprintf(buf, sizeof(buf), "# Ignorable event type %d (%s)",
- number, description);
- protocol->store(buf, bytes, &my_charset_bin);
-}
-#endif
-
-#ifdef MYSQL_CLIENT
-/* Print for its unrecognized ignorable event */
-bool Ignorable_log_event::print(FILE *file,
- PRINT_EVENT_INFO *print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- if (print_header(&print_event_info->head_cache, print_event_info, FALSE) ||
- my_b_printf(&print_event_info->head_cache, "\tIgnorable\n") ||
- my_b_printf(&print_event_info->head_cache,
- "# Ignorable event type %d (%s)\n", number, description) ||
- copy_event_cache_to_file_and_reinit(&print_event_info->head_cache,
- file))
- return 1;
- return 0;
-}
-#endif
-
-
-#ifdef MYSQL_CLIENT
-/**
- The default values for these variables should be values that are
- *incorrect*, i.e., values that cannot occur in an event. This way,
- they will always be printed for the first event.
-*/
-st_print_event_info::st_print_event_info()
-{
- myf const flags = MYF(MY_WME | MY_NABP);
- /*
- Currently we only use static PRINT_EVENT_INFO objects, so zeroed at
- program's startup, but these explicit bzero() is for the day someone
- creates dynamic instances.
- */
- bzero(db, sizeof(db));
- bzero(charset, sizeof(charset));
- bzero(time_zone_str, sizeof(time_zone_str));
- delimiter[0]= ';';
- delimiter[1]= 0;
- flags2_inited= 0;
- sql_mode_inited= 0;
- row_events= 0;
- sql_mode= 0;
- auto_increment_increment= 0;
- auto_increment_offset= 0;
- charset_inited= 0;
- lc_time_names_number= ~0;
- charset_database_number= ILLEGAL_CHARSET_INFO_NUMBER;
- thread_id= 0;
- server_id= 0;
- domain_id= 0;
- thread_id_printed= false;
- server_id_printed= false;
- domain_id_printed= false;
- allow_parallel= true;
- allow_parallel_printed= false;
- found_row_event= false;
- print_row_count= false;
- short_form= false;
- skip_replication= 0;
- printed_fd_event=FALSE;
- file= 0;
- base64_output_mode=BASE64_OUTPUT_UNSPEC;
- open_cached_file(&head_cache, NULL, NULL, 0, flags);
- open_cached_file(&body_cache, NULL, NULL, 0, flags);
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- open_cached_file(&review_sql_cache, NULL, NULL, 0, flags);
-#endif
-}
-
-
-bool copy_event_cache_to_string_and_reinit(IO_CACHE *cache, LEX_STRING *to)
-{
- reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE);
- if (cache->end_of_file > SIZE_T_MAX ||
- !(to->str= (char*) my_malloc((to->length= (size_t)cache->end_of_file), MYF(0))))
- {
- perror("Out of memory: can't allocate memory in copy_event_cache_to_string_and_reinit().");
- goto err;
- }
- if (my_b_read(cache, (uchar*) to->str, to->length))
- {
- my_free(to->str);
- perror("Can't read data from IO_CACHE");
- return true;
- }
- reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE);
- return false;
-
-err:
- to->str= 0;
- to->length= 0;
- return true;
-}
-#endif /* MYSQL_CLIENT */
-
bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache, FILE *file)
{
return (my_b_copy_all_to_file(cache, file) ||
reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE));
}
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-Heartbeat_log_event::Heartbeat_log_event(const char* buf, uint event_len,
- const Format_description_log_event* description_event)
- :Log_event(buf, description_event)
-{
- uint8 header_size= description_event->common_header_len;
- ident_len = event_len - header_size;
- set_if_smaller(ident_len,FN_REFLEN-1);
- log_ident= buf + header_size;
-}
-#endif
-
-#if defined(MYSQL_SERVER)
-/**
- Check if we should write event to the relay log
-
- This is used to skip events that is only supported by MySQL
-
- Return:
- 0 ok
- 1 Don't write event
-*/
-
-bool event_that_should_be_ignored(const char *buf)
-{
- uint event_type= (uchar)buf[EVENT_TYPE_OFFSET];
- if (event_type == GTID_LOG_EVENT ||
- event_type == ANONYMOUS_GTID_LOG_EVENT ||
- event_type == PREVIOUS_GTIDS_LOG_EVENT ||
- event_type == TRANSACTION_CONTEXT_EVENT ||
- event_type == VIEW_CHANGE_EVENT ||
- event_type == XA_PREPARE_LOG_EVENT ||
- (uint2korr(buf + FLAGS_OFFSET) & LOG_EVENT_IGNORABLE_F))
- return 1;
- return 0;
-}
-#endif /* MYSQL_SERVER */
diff --git a/sql/log_event.h b/sql/log_event.h
index dbd2f4ab348..b634c6e2c94 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
- Copyright (c) 2009, 2017, MariaDB Corporation.
+ Copyright (c) 2009, 2020, 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
@@ -35,6 +35,11 @@
#include <my_bitmap.h>
#include "rpl_constants.h"
+#include <vector>
+#include <string>
+#include <functional>
+#include <memory>
+#include <map>
#ifdef MYSQL_CLIENT
#include "sql_const.h"
@@ -217,6 +222,7 @@ class String;
#define GTID_HEADER_LEN 19
#define GTID_LIST_HEADER_LEN 4
#define START_ENCRYPTION_HEADER_LEN 0
+#define XA_PREPARE_HEADER_LEN 0
/*
Max number of possible extra bytes in a replication event compared to a
@@ -659,6 +665,7 @@ enum Log_event_type
/* MySQL 5.7 events, ignored by MariaDB */
TRANSACTION_CONTEXT_EVENT= 36,
VIEW_CHANGE_EVENT= 37,
+ /* not ignored */
XA_PREPARE_LOG_EVENT= 38,
/*
@@ -791,7 +798,6 @@ enum Int_event_type
INVALID_INT_EVENT = 0, LAST_INSERT_ID_EVENT = 1, INSERT_ID_EVENT = 2
};
-
#ifdef MYSQL_SERVER
class String;
class MYSQL_BIN_LOG;
@@ -881,6 +887,7 @@ typedef struct st_print_event_info
statement for it.
*/
bool skip_replication;
+ bool print_table_metadata;
/*
These two caches are used by the row-based replication events to
@@ -1352,7 +1359,8 @@ public:
static void *operator new(size_t size)
{
- return (void*) my_malloc((uint)size, MYF(MY_WME|MY_FAE));
+ extern PSI_memory_key key_memory_log_event;
+ return my_malloc(key_memory_log_event, size, MYF(MY_WME|MY_FAE));
}
static void operator delete(void *ptr, size_t)
@@ -2223,24 +2231,16 @@ public:
****************************************************************************/
struct sql_ex_info
{
- sql_ex_info():
- cached_new_format(-1),
- field_term_len(0),
- enclosed_len(0),
- line_term_len(0),
- line_start_len(0),
- escaped_len(0),
- empty_flags(0)
- {} /* Remove gcc warning */
const char* field_term;
const char* enclosed;
const char* line_term;
const char* line_start;
const char* escaped;
- int cached_new_format;
- uint8 field_term_len,enclosed_len,line_term_len,line_start_len, escaped_len;
+ int cached_new_format= -1;
+ uint8 field_term_len= 0, enclosed_len= 0, line_term_len= 0,
+ line_start_len= 0, escaped_len= 0;
char opt_flags;
- char empty_flags;
+ char empty_flags= 0;
// store in new format even if old is possible
void force_new_format() { cached_new_format = 1;}
@@ -3025,6 +3025,32 @@ private:
#endif
};
+
+class Xid_apply_log_event: public Log_event
+{
+public:
+#ifdef MYSQL_SERVER
+ Xid_apply_log_event(THD* thd_arg):
+ Log_event(thd_arg, 0, TRUE) {}
+#endif
+ Xid_apply_log_event(const char* buf,
+ const Format_description_log_event *description_event):
+ Log_event(buf, description_event) {}
+
+ ~Xid_apply_log_event() {}
+ bool is_valid() const { return 1; }
+private:
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+ virtual int do_commit()= 0;
+ virtual int do_apply_event(rpl_group_info *rgi);
+ int do_record_gtid(THD *thd, rpl_group_info *rgi, bool in_trans,
+ void **out_hton);
+ enum_skip_reason do_shall_skip(rpl_group_info *rgi);
+ virtual const char* get_query()= 0;
+#endif
+};
+
+
/**
@class Xid_log_event
@@ -3037,18 +3063,22 @@ private:
typedef ulonglong my_xid; // this line is the same as in handler.h
#endif
-class Xid_log_event: public Log_event
+class Xid_log_event: public Xid_apply_log_event
{
- public:
- my_xid xid;
+public:
+ my_xid xid;
#ifdef MYSQL_SERVER
Xid_log_event(THD* thd_arg, my_xid x, bool direct):
- Log_event(thd_arg, 0, TRUE), xid(x)
+ Xid_apply_log_event(thd_arg), xid(x)
{
if (direct)
cache_type= Log_event::EVENT_NO_CACHE;
}
+ const char* get_query()
+ {
+ return "COMMIT /* implicit, from Xid_log_event */";
+ }
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
@@ -3064,15 +3094,172 @@ class Xid_log_event: public Log_event
#ifdef MYSQL_SERVER
bool write();
#endif
- bool is_valid() const { return 1; }
private:
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
- virtual int do_apply_event(rpl_group_info *rgi);
- enum_skip_reason do_shall_skip(rpl_group_info *rgi);
+ int do_commit();
+#endif
+};
+
+
+/**
+ @class XA_prepare_log_event
+
+ Similar to Xid_log_event except that
+ - it is specific to XA transaction
+ - it carries out the prepare logics rather than the final committing
+ when @c one_phase member is off. The latter option is only for
+ compatibility with the upstream.
+
+ From the groupping perspective the event finalizes the current
+ "prepare" group that is started with Gtid_log_event similarly to the
+ regular replicated transaction.
+*/
+
+/**
+ Function serializes XID which is characterized by by four last arguments
+ of the function.
+ Serialized XID is presented in valid hex format and is returned to
+ the caller in a buffer pointed by the first argument.
+ The buffer size provived by the caller must be not less than
+ 8 + 2 * XIDDATASIZE + 4 * sizeof(XID::formatID) + 1, see
+ {MYSQL_,}XID definitions.
+
+ @param buf pointer to a buffer allocated for storing serialized data
+ @param fmt formatID value
+ @param gln gtrid_length value
+ @param bln bqual_length value
+ @param dat data value
+
+ @return the value of the buffer pointer
+*/
+
+inline char *serialize_xid(char *buf, long fmt, long gln, long bln,
+ const char *dat)
+{
+ int i;
+ char *c= buf;
+ /*
+ Build a string consisting of the hex format representation of XID
+ as passed through fmt,gln,bln,dat argument:
+ X'hex11hex12...hex1m',X'hex21hex22...hex2n',11
+ and store it into buf.
+ */
+ c[0]= 'X';
+ c[1]= '\'';
+ c+= 2;
+ for (i= 0; i < gln; i++)
+ {
+ c[0]=_dig_vec_lower[((uchar*) dat)[i] >> 4];
+ c[1]=_dig_vec_lower[((uchar*) dat)[i] & 0x0f];
+ c+= 2;
+ }
+ c[0]= '\'';
+ c[1]= ',';
+ c[2]= 'X';
+ c[3]= '\'';
+ c+= 4;
+
+ for (; i < gln + bln; i++)
+ {
+ c[0]=_dig_vec_lower[((uchar*) dat)[i] >> 4];
+ c[1]=_dig_vec_lower[((uchar*) dat)[i] & 0x0f];
+ c+= 2;
+ }
+ c[0]= '\'';
+ sprintf(c+1, ",%lu", fmt);
+
+ return buf;
+}
+
+/*
+ The size of the string containing serialized Xid representation
+ is computed as a sum of
+ eight as the number of formatting symbols (X'',X'',)
+ plus 2 x XIDDATASIZE (2 due to hex format),
+ plus space for decimal digits of XID::formatID,
+ plus one for 0x0.
+*/
+static const uint ser_buf_size=
+ 8 + 2 * MYSQL_XIDDATASIZE + 4 * sizeof(long) + 1;
+
+struct event_mysql_xid_t : MYSQL_XID
+{
+ char buf[ser_buf_size];
+ char *serialize()
+ {
+ return serialize_xid(buf, formatID, gtrid_length, bqual_length, data);
+ }
+};
+
+#ifndef MYSQL_CLIENT
+struct event_xid_t : XID
+{
+ char buf[ser_buf_size];
+
+ char *serialize(char *buf_arg)
+ {
+ return serialize_xid(buf_arg, formatID, gtrid_length, bqual_length, data);
+ }
+ char *serialize()
+ {
+ return serialize(buf);
+ }
+};
+#endif
+
+class XA_prepare_log_event: public Xid_apply_log_event
+{
+protected:
+
+ /* Constant contributor to subheader in write() by members of XID struct. */
+ static const int xid_subheader_no_data= 12;
+ event_mysql_xid_t m_xid;
+ void *xid;
+ bool one_phase;
+
+public:
+#ifdef MYSQL_SERVER
+ XA_prepare_log_event(THD* thd_arg, XID *xid_arg, bool one_phase_arg):
+ Xid_apply_log_event(thd_arg), xid(xid_arg), one_phase(one_phase_arg)
+ {
+ cache_type= Log_event::EVENT_NO_CACHE;
+ }
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol* protocol);
+#endif /* HAVE_REPLICATION */
+#else
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+#endif
+ XA_prepare_log_event(const char* buf,
+ const Format_description_log_event *description_event);
+ ~XA_prepare_log_event() {}
+ Log_event_type get_type_code() { return XA_PREPARE_LOG_EVENT; }
+ bool is_valid() const { return m_xid.formatID != -1; }
+ int get_data_size()
+ {
+ return xid_subheader_no_data + m_xid.gtrid_length + m_xid.bqual_length;
+ }
+
+#ifdef MYSQL_SERVER
+ bool write();
+#endif
+
+private:
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+ char query[sizeof("XA COMMIT ONE PHASE") + 1 + ser_buf_size];
+ int do_commit();
+ const char* get_query()
+ {
+ sprintf(query,
+ (one_phase ? "XA COMMIT %s ONE PHASE" : "XA PREPARE %s"),
+ m_xid.serialize());
+ return query;
+ }
#endif
};
+
/**
@class User_var_log_event
@@ -3385,8 +3572,12 @@ public:
uint64 seq_no;
uint64 commit_id;
uint32 domain_id;
+#ifdef MYSQL_SERVER
+ event_xid_t xid;
+#else
+ event_mysql_xid_t xid;
+#endif
uchar flags2;
-
/* Flags2. */
/* FL_STANDALONE is set when there is no terminating COMMIT event. */
@@ -3413,6 +3604,10 @@ public:
static const uchar FL_WAITED= 16;
/* FL_DDL is set for event group containing DDL. */
static const uchar FL_DDL= 32;
+ /* FL_PREPARED_XA is set for XA transaction. */
+ static const uchar FL_PREPARED_XA= 64;
+ /* FL_"COMMITTED or ROLLED-BACK"_XA is set for XA transaction. */
+ static const uchar FL_COMPLETED_XA= 128;
#ifdef MYSQL_SERVER
Gtid_log_event(THD *thd_arg, uint64 seq_no, uint32 domain_id, bool standalone,
@@ -4071,6 +4266,18 @@ private:
ninth is in the least significant bit of the second byte, and so
on. </td>
</tr>
+ <tr>
+ <td>optional metadata fields</td>
+ <td>optional metadata fields are stored in Type, Length, Value(TLV) format.
+ Type takes 1 byte. Length is a packed integer value. Values takes
+ Length bytes.
+ </td>
+ <td>There are some optional metadata defined. They are listed in the table
+ @ref Table_table_map_event_optional_metadata. Optional metadata fields
+ follow null_bits. Whether binlogging an optional metadata is decided by the
+ server. The order is not defined, so they can be binlogged in any order.
+ </td>
+ </tr>
</table>
@@ -4276,6 +4483,123 @@ private:
</tr>
</table>
+ The table below lists all optional metadata types, along with the numerical
+ identifier for it and the size and interpretation of meta-data used
+ to describe the type.
+
+ @anchor Table_table_map_event_optional_metadata
+ <table>
+ <caption>Table_map_event optional metadata types: numerical identifier and
+ metadata. Optional metadata fields are stored in TLV fields.
+ Format of values are described in this table. </caption>
+ <tr>
+ <th>Type</th>
+ <th>Description</th>
+ <th>Format</th>
+ </tr>
+ <tr>
+ <td>SIGNEDNESS</td>
+ <td>signedness of numeric colums. This is included for all values of
+ binlog_row_metadata.</td>
+ <td>For each numeric column, a bit indicates whether the numeric
+ colunm has unsigned flag. 1 means it is unsigned. The number of
+ bytes needed for this is int((column_count + 7) / 8). The order is
+ the same as the order of column_type field.</td>
+ </tr>
+ <tr>
+ <td>DEFAULT_CHARSET</td>
+ <td>Charsets of character columns. It has a default charset for
+ the case that most of character columns have same charset and the
+ most used charset is binlogged as default charset.Collation
+ numbers are binlogged for identifying charsets. They are stored in
+ packed length format. Either DEFAULT_CHARSET or COLUMN_CHARSET is
+ included for all values of binlog_row_metadata.</td>
+ <td>Default charset's collation is logged first. The charsets which are not
+ same to default charset are logged following default charset. They are
+ logged as column index and charset collation number pair sequence. The
+ column index is counted only in all character columns. The order is same to
+ the order of column_type
+ field. </td>
+ </tr>
+ <tr>
+ <td>COLUMN_CHARSET</td>
+ <td>Charsets of character columns. For the case that most of columns have
+ different charsets, this field is logged. It is never logged with
+ DEFAULT_CHARSET together. Either DEFAULT_CHARSET or COLUMN_CHARSET is
+ included for all values of binlog_row_metadata.</td>
+ <td>It is a collation number sequence for all character columns.</td>
+ </tr>
+ <tr>
+ <td>COLUMN_NAME</td>
+ <td>Names of columns. This is only included if
+ binlog_row_metadata=FULL.</td>
+ <td>A sequence of column names. For each column name, 1 byte for
+ the string length in bytes is followed by a string without null
+ terminator.</td>
+ </tr>
+ <tr>
+ <td>SET_STR_VALUE</td>
+ <td>The string values of SET columns. This is only included if
+ binlog_row_metadata=FULL.</td>
+ <td>For each SET column, a pack_length representing the value
+ count is followed by a sequence of length and string pairs. length
+ is the byte count in pack_length format. The string has no null
+ terminator.</td>
+ </tr>
+ <tr>
+ <td>ENUM_STR_VALUE</td>
+ <td>The string values is ENUM columns. This is only included
+ if binlog_row_metadata=FULL.</td>
+ <td>The format is the same as SET_STR_VALUE.</td>
+ </tr>
+ <tr>
+ <td>GEOMETRY_TYPE</td>
+ <td>The real type of geometry columns. This is only included
+ if binlog_row_metadata=FULL.</td>
+ <td>A sequence of real type of geometry columns are stored in pack_length
+ format. </td>
+ </tr>
+ <tr>
+ <td>SIMPLE_PRIMARY_KEY</td>
+ <td>The primary key without any prefix. This is only included
+ if binlog_row_metadata=FULL and there is a primary key where every
+ key part covers an entire column.</td>
+ <td>A sequence of column indexes. The indexes are stored in pack_length
+ format.</td>
+ </tr>
+ <tr>
+ <td>PRIMARY_KEY_WITH_PREFIX</td>
+ <td>The primary key with some prefix. It doesn't appear together with
+ SIMPLE_PRIMARY_KEY. This is only included if
+ binlog_row_metadata=FULL and there is a primary key where some key
+ part covers a prefix of the column.</td>
+ <td>A sequence of column index and prefix length pairs. Both
+ column index and prefix length are in pack_length format. Prefix length
+ 0 means that the whole column value is used.</td>
+ </tr>
+ <tr>
+ <td>ENUM_AND_SET_DEFAULT_CHARSET</td>
+ <td>Charsets of ENUM and SET columns. It has the same layout as
+ DEFAULT_CHARSET. If there are SET or ENUM columns and
+ binlog_row_metadata=FULL, exactly one of
+ ENUM_AND_SET_DEFAULT_CHARSET and ENUM_AND_SET_COLUMN_CHARSET
+ appears (the encoder chooses the representation that uses the
+ least amount of space). Otherwise, none of them appears.</td>
+ <td>The same format as for DEFAULT_CHARSET, except it counts ENUM
+ and SET columns rather than character columns.</td>
+ </tr>
+ <tr>
+ <td>ENUM_AND_SET_COLUMN_CHARSET</td>
+ <td>Charsets of ENUM and SET columns. It has the same layout as
+ COLUMN_CHARSET. If there are SET or ENUM columns and
+ binlog_row_metadata=FULL, exactly one of
+ ENUM_AND_SET_DEFAULT_CHARSET and ENUM_AND_SET_COLUMN_CHARSET
+ appears (the encoder chooses the representation that uses the
+ least amount of space). Otherwise, none of them appears.</td>
+ <td>The same format as for COLUMN_CHARSET, except it counts ENUM
+ and SET columns rather than character columns.</td>
+ </tr>
+ </table>
*/
class Table_map_log_event : public Log_event
{
@@ -4311,6 +4635,124 @@ public:
};
typedef uint16 flag_set;
+ /**
+ DEFAULT_CHARSET and COLUMN_CHARSET don't appear together, and
+ ENUM_AND_SET_DEFAULT_CHARSET and ENUM_AND_SET_COLUMN_CHARSET don't
+ appear together. They are just alternative ways to pack character
+ set information. When binlogging, it logs character sets in the
+ way that occupies least storage.
+
+ SIMPLE_PRIMARY_KEY and PRIMARY_KEY_WITH_PREFIX don't appear together.
+ SIMPLE_PRIMARY_KEY is for the primary keys which only use whole values of
+ pk columns. PRIMARY_KEY_WITH_PREFIX is
+ for the primary keys which just use part value of pk columns.
+ */
+ enum Optional_metadata_field_type
+ {
+ SIGNEDNESS = 1, // UNSIGNED flag of numeric columns
+ DEFAULT_CHARSET, /* Character set of string columns, optimized to
+ minimize space when many columns have the
+ same charset. */
+ COLUMN_CHARSET, /* Character set of string columns, optimized to
+ minimize space when columns have many
+ different charsets. */
+ COLUMN_NAME,
+ SET_STR_VALUE, // String value of SET columns
+ ENUM_STR_VALUE, // String value of ENUM columns
+ GEOMETRY_TYPE, // Real type of geometry columns
+ SIMPLE_PRIMARY_KEY, // Primary key without prefix
+ PRIMARY_KEY_WITH_PREFIX, // Primary key with prefix
+ ENUM_AND_SET_DEFAULT_CHARSET, /* Character set of enum and set
+ columns, optimized to minimize
+ space when many columns have the
+ same charset. */
+ ENUM_AND_SET_COLUMN_CHARSET, /* Character set of enum and set
+ columns, optimized to minimize
+ space when many columns have the
+ same charset. */
+ };
+ /**
+ Metadata_fields organizes m_optional_metadata into a structured format which
+ is easy to access.
+ */
+ // Values for binlog_row_metadata sysvar
+ enum enum_binlog_row_metadata
+ {
+ BINLOG_ROW_METADATA_NO_LOG= 0,
+ BINLOG_ROW_METADATA_MINIMAL= 1,
+ BINLOG_ROW_METADATA_FULL= 2
+ };
+ struct Optional_metadata_fields
+ {
+ typedef std::pair<unsigned int, unsigned int> uint_pair;
+ typedef std::vector<std::string> str_vector;
+
+ struct Default_charset
+ {
+ Default_charset() : default_charset(0) {}
+ bool empty() const { return default_charset == 0; }
+
+ // Default charset for the columns which are not in charset_pairs.
+ unsigned int default_charset;
+
+ /* The uint_pair means <column index, column charset number>. */
+ std::vector<uint_pair> charset_pairs;
+ };
+
+ // Contents of DEFAULT_CHARSET field is converted into Default_charset.
+ Default_charset m_default_charset;
+ // Contents of ENUM_AND_SET_DEFAULT_CHARSET are converted into
+ // Default_charset.
+ Default_charset m_enum_and_set_default_charset;
+ std::vector<bool> m_signedness;
+ // Character set number of every string column
+ std::vector<unsigned int> m_column_charset;
+ // Character set number of every ENUM or SET column.
+ std::vector<unsigned int> m_enum_and_set_column_charset;
+ std::vector<std::string> m_column_name;
+ // each str_vector stores values of one enum/set column
+ std::vector<str_vector> m_enum_str_value;
+ std::vector<str_vector> m_set_str_value;
+ std::vector<unsigned int> m_geometry_type;
+ /*
+ The uint_pair means <column index, prefix length>. Prefix length is 0 if
+ whole column value is used.
+ */
+ std::vector<uint_pair> m_primary_key;
+
+ /*
+ It parses m_optional_metadata and populates into above variables.
+
+ @param[in] optional_metadata points to the begin of optional metadata
+ fields in table_map_event.
+ @param[in] optional_metadata_len length of optional_metadata field.
+ */
+ Optional_metadata_fields(unsigned char* optional_metadata,
+ unsigned int optional_metadata_len);
+ };
+
+ /**
+ Print column metadata. Its format looks like:
+ # Columns(colume_name type, colume_name type, ...)
+ if colume_name field is not logged into table_map_log_event, then
+ only type is printed.
+
+ @@param[out] file the place where colume metadata is printed
+ @@param[in] The metadata extracted from optional metadata fields
+ */
+ void print_columns(IO_CACHE *file,
+ const Optional_metadata_fields &fields);
+ /**
+ Print primary information. Its format looks like:
+ # Primary Key(colume_name, column_name(prifix), ...)
+ if colume_name field is not logged into table_map_log_event, then
+ colume index is printed.
+
+ @@param[out] file the place where primary key is printed
+ @@param[in] The metadata extracted from optional metadata fields
+ */
+ void print_primary_key(IO_CACHE *file,
+ const Optional_metadata_fields &fields);
/* Special constants representing sets of flags */
enum
@@ -4377,6 +4819,51 @@ private:
#ifdef MYSQL_SERVER
TABLE *m_table;
+ Binlog_type_info *binlog_type_info_array;
+
+
+ // Metadata fields buffer
+ StringBuffer<1024> m_metadata_buf;
+
+ /**
+ Capture the optional metadata fields which should be logged into
+ table_map_log_event and serialize them into m_metadata_buf.
+ */
+ void init_metadata_fields();
+ bool init_signedness_field();
+ /**
+ Capture and serialize character sets. Character sets for
+ character columns (TEXT etc) and character sets for ENUM and SET
+ columns are stored in different metadata fields. The reason is
+ that TEXT character sets are included even when
+ binlog_row_metadata=MINIMAL, whereas ENUM and SET character sets
+ are included only when binlog_row_metadata=FULL.
+
+ @param include_type Predicate to determine if a given Field object
+ is to be included in the metadata field.
+
+ @param default_charset_type Type code when storing in "default
+ charset" format. (See comment above Table_maps_log_event in
+ libbinlogevents/include/rows_event.h)
+
+ @param column_charset_type Type code when storing in "column
+ charset" format. (See comment above Table_maps_log_event in
+ libbinlogevents/include/rows_event.h)
+ */
+ bool init_charset_field(bool(* include_type)(Binlog_type_info *, Field *),
+ Optional_metadata_field_type default_charset_type,
+ Optional_metadata_field_type column_charset_type);
+ bool init_column_name_field();
+ bool init_set_str_value_field();
+ bool init_enum_str_value_field();
+ bool init_geometry_type_field();
+ bool init_primary_key_field();
+#endif
+
+#ifdef MYSQL_CLIENT
+ class Charset_iterator;
+ class Default_charset_iterator;
+ class Column_charset_iterator;
#endif
char const *m_dbnam;
size_t m_dblen;
@@ -4398,6 +4885,8 @@ private:
ulong m_field_metadata_size;
uchar *m_null_bits;
uchar *m_meta_memory;
+ unsigned int m_optional_metadata_len;
+ unsigned char *m_optional_metadata;
};
@@ -4589,6 +5078,12 @@ public:
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual uint8 get_trg_event_map()= 0;
+
+ inline bool do_invoke_trigger()
+ {
+ return (slave_run_triggers_for_rbr && !master_had_triggers) ||
+ slave_run_triggers_for_rbr == SLAVE_RUN_TRIGGERS_FOR_RBR_ENFORCE;
+ }
#endif
protected:
@@ -5071,11 +5566,12 @@ public:
Incident_log_event(THD *thd_arg, Incident incident, const LEX_CSTRING *msg)
: Log_event(thd_arg, 0, FALSE), m_incident(incident)
{
+ extern PSI_memory_key key_memory_Incident_log_event_message;
DBUG_ENTER("Incident_log_event::Incident_log_event");
DBUG_PRINT("enter", ("m_incident: %d", m_incident));
m_message.length= 0;
- if (unlikely(!(m_message.str= (char*) my_malloc(msg->length+1,
- MYF(MY_WME)))))
+ if (!(m_message.str= (char*) my_malloc(key_memory_Incident_log_event_message,
+ msg->length + 1, MYF(MY_WME))))
{
/* Mark this event invalid */
m_incident= INCIDENT_NONE;
@@ -5272,5 +5768,4 @@ int row_log_event_uncompress(const Format_description_log_event *description_eve
const char *src, ulong src_len, char* buf, ulong buf_size, bool* is_malloc,
char **dst, ulong *newlen);
-
#endif /* _log_event_h */
diff --git a/sql/log_event_client.cc b/sql/log_event_client.cc
new file mode 100644
index 00000000000..faec2a29407
--- /dev/null
+++ b/sql/log_event_client.cc
@@ -0,0 +1,3928 @@
+/*
+ Copyright (c) 2000, 2018, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2020, 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 MYSQL_CLIENT
+#error MYSQL_CLIENT must be defined here
+#endif
+
+#ifdef MYSQL_SERVER
+#error MYSQL_SERVER must not be defined here
+#endif
+
+
+static bool pretty_print_str(IO_CACHE* cache, const char* str,
+ size_t len, bool identifier)
+{
+ const char* end = str + len;
+ if (my_b_write_byte(cache, identifier ? '`' : '\''))
+ goto err;
+
+ while (str < end)
+ {
+ char c;
+ int error;
+
+ switch ((c=*str++)) {
+ case '\n': error= my_b_write(cache, (uchar*)"\\n", 2); break;
+ case '\r': error= my_b_write(cache, (uchar*)"\\r", 2); break;
+ case '\\': error= my_b_write(cache, (uchar*)"\\\\", 2); break;
+ case '\b': error= my_b_write(cache, (uchar*)"\\b", 2); break;
+ case '\t': error= my_b_write(cache, (uchar*)"\\t", 2); break;
+ case '\'': error= my_b_write(cache, (uchar*)"\\'", 2); break;
+ case 0 : error= my_b_write(cache, (uchar*)"\\0", 2); break;
+ default:
+ error= my_b_write_byte(cache, c);
+ break;
+ }
+ if (unlikely(error))
+ goto err;
+ }
+ return my_b_write_byte(cache, identifier ? '`' : '\'');
+
+err:
+ return 1;
+}
+
+/**
+ Print src as an string enclosed with "'"
+
+ @param[out] cache IO_CACHE where the string will be printed.
+ @param[in] str the string will be printed.
+ @param[in] len length of the string.
+*/
+static inline bool pretty_print_str(IO_CACHE* cache, const char* str,
+ size_t len)
+{
+ return pretty_print_str(cache, str, len, false);
+}
+
+/**
+ Print src as an identifier enclosed with "`"
+
+ @param[out] cache IO_CACHE where the identifier will be printed.
+ @param[in] str the string will be printed.
+ @param[in] len length of the string.
+ */
+static inline bool pretty_print_identifier(IO_CACHE* cache, const char* str,
+ size_t len)
+{
+ return pretty_print_str(cache, str, len, true);
+}
+
+
+
+/**
+ Prints a "session_var=value" string. Used by mysqlbinlog to print some SET
+ commands just before it prints a query.
+*/
+
+static bool print_set_option(IO_CACHE* file, uint32 bits_changed,
+ uint32 option, uint32 flags, const char* name,
+ bool* need_comma)
+{
+ if (bits_changed & option)
+ {
+ if (*need_comma)
+ if (my_b_write(file, (uchar*)", ", 2))
+ goto err;
+ if (my_b_printf(file, "%s=%d", name, MY_TEST(flags & option)))
+ goto err;
+ *need_comma= 1;
+ }
+ return 0;
+err:
+ return 1;
+}
+
+
+static bool hexdump_minimal_header_to_io_cache(IO_CACHE *file,
+ my_off_t offset,
+ uchar *ptr)
+{
+ DBUG_ASSERT(LOG_EVENT_MINIMAL_HEADER_LEN == 19);
+
+ /*
+ Pretty-print the first LOG_EVENT_MINIMAL_HEADER_LEN (19) bytes of the
+ common header, which contains the basic information about the log event.
+ Every event will have at least this much header, but events could contain
+ more headers (which must be printed by other methods, if desired).
+ */
+ char emit_buf[120]; // Enough for storing one line
+ size_t emit_buf_written;
+
+ if (my_b_printf(file,
+ "# "
+ "|Timestamp "
+ "|Type "
+ "|Master ID "
+ "|Size "
+ "|Master Pos "
+ "|Flags\n"))
+ goto err;
+ emit_buf_written=
+ my_snprintf(emit_buf, sizeof(emit_buf),
+ "# %8llx " /* Position */
+ "|%02x %02x %02x %02x " /* Timestamp */
+ "|%02x " /* Type */
+ "|%02x %02x %02x %02x " /* Master ID */
+ "|%02x %02x %02x %02x " /* Size */
+ "|%02x %02x %02x %02x " /* Master Pos */
+ "|%02x %02x\n", /* Flags */
+ (ulonglong) offset, /* Position */
+ ptr[0], ptr[1], ptr[2], ptr[3], /* Timestamp */
+ ptr[4], /* Type */
+ ptr[5], ptr[6], ptr[7], ptr[8], /* Master ID */
+ ptr[9], ptr[10], ptr[11], ptr[12], /* Size */
+ ptr[13], ptr[14], ptr[15], ptr[16], /* Master Pos */
+ ptr[17], ptr[18]); /* Flags */
+
+ DBUG_ASSERT(static_cast<size_t>(emit_buf_written) < sizeof(emit_buf));
+ if (my_b_write(file, reinterpret_cast<uchar*>(emit_buf), emit_buf_written) ||
+ my_b_write(file, (uchar*)"#\n", 2))
+ goto err;
+
+ return 0;
+err:
+ return 1;
+}
+
+
+/*
+ The number of bytes to print per line. Should be an even number,
+ and "hexdump -C" uses 16, so we'll duplicate that here.
+*/
+#define HEXDUMP_BYTES_PER_LINE 16
+
+static void format_hex_line(char *emit_buff)
+{
+ memset(emit_buff + 1, ' ',
+ 1 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
+ HEXDUMP_BYTES_PER_LINE);
+ emit_buff[0]= '#';
+ emit_buff[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 1]= '|';
+ emit_buff[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
+ HEXDUMP_BYTES_PER_LINE]= '|';
+ emit_buff[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
+ HEXDUMP_BYTES_PER_LINE + 1]= '\n';
+ emit_buff[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
+ HEXDUMP_BYTES_PER_LINE + 2]= '\0';
+}
+
+static bool hexdump_data_to_io_cache(IO_CACHE *file,
+ my_off_t offset,
+ uchar *ptr,
+ my_off_t size)
+{
+ /*
+ 2 = '# '
+ 8 = address
+ 2 = ' '
+ (HEXDUMP_BYTES_PER_LINE * 3 + 1) = Each byte prints as two hex digits,
+ plus a space
+ 2 = ' |'
+ HEXDUMP_BYTES_PER_LINE = text representation
+ 2 = '|\n'
+ 1 = '\0'
+ */
+ char emit_buffer[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
+ HEXDUMP_BYTES_PER_LINE + 2 + 1 ];
+ char *h,*c;
+ my_off_t i;
+
+ if (size == 0)
+ return 0; // ok, nothing to do
+
+ format_hex_line(emit_buffer);
+ /*
+ Print the rest of the event (without common header)
+ */
+ my_off_t starting_offset = offset;
+ for (i= 0,
+ c= emit_buffer + 2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2,
+ h= emit_buffer + 2 + 8 + 2;
+ i < size;
+ i++, ptr++)
+ {
+ my_snprintf(h, 4, "%02x ", *ptr);
+ h+= 3;
+
+ *c++= my_isprint(&my_charset_bin, *ptr) ? *ptr : '.';
+
+ /* Print in groups of HEXDUMP_BYTES_PER_LINE characters. */
+ if ((i % HEXDUMP_BYTES_PER_LINE) == (HEXDUMP_BYTES_PER_LINE - 1))
+ {
+ /* remove \0 left after printing hex byte representation */
+ *h= ' ';
+ /* prepare space to print address */
+ memset(emit_buffer + 2, ' ', 8);
+ /* print address */
+ size_t const emit_buf_written= my_snprintf(emit_buffer + 2, 9, "%8llx",
+ (ulonglong) starting_offset);
+ /* remove \0 left after printing address */
+ emit_buffer[2 + emit_buf_written]= ' ';
+ if (my_b_write(file, reinterpret_cast<uchar*>(emit_buffer),
+ sizeof(emit_buffer) - 1))
+ goto err;
+ c= emit_buffer + 2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2;
+ h= emit_buffer + 2 + 8 + 2;
+ format_hex_line(emit_buffer);
+ starting_offset+= HEXDUMP_BYTES_PER_LINE;
+ }
+ else if ((i % (HEXDUMP_BYTES_PER_LINE / 2))
+ == ((HEXDUMP_BYTES_PER_LINE / 2) - 1))
+ {
+ /*
+ In the middle of the group of HEXDUMP_BYTES_PER_LINE, emit an extra
+ space in the hex string, to make two groups.
+ */
+ *h++= ' ';
+ }
+
+ }
+
+ /*
+ There is still data left in our buffer, which means that the previous
+ line was not perfectly HEXDUMP_BYTES_PER_LINE characters, so write an
+ incomplete line, with spaces to pad out to the same length as a full
+ line would be, to make things more readable.
+ */
+ if (h != emit_buffer + 2 + 8 + 2)
+ {
+ *h= ' ';
+ *c++= '|'; *c++= '\n';
+ memset(emit_buffer + 2, ' ', 8);
+ size_t const emit_buf_written= my_snprintf(emit_buffer + 2, 9, "%8llx",
+ (ulonglong) starting_offset);
+ emit_buffer[2 + emit_buf_written]= ' ';
+ /* pad unprinted area */
+ memset(h, ' ',
+ (HEXDUMP_BYTES_PER_LINE * 3 + 1) - (h - (emit_buffer + 2 + 8 + 2)));
+ if (my_b_write(file, reinterpret_cast<uchar*>(emit_buffer),
+ c - emit_buffer))
+ goto err;
+ }
+ if (my_b_write(file, (uchar*)"#\n", 2))
+ goto err;
+
+ return 0;
+err:
+ return 1;
+}
+
+static inline bool is_numeric_type(uint type)
+{
+ switch (type)
+ {
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
+
+static inline bool is_character_type(uint type)
+{
+ switch (type)
+ {
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_BLOB:
+ // Base class is blob for geom type
+ case MYSQL_TYPE_GEOMETRY:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline bool is_enum_or_set_type(uint type) {
+ return type == MYSQL_TYPE_ENUM || type == MYSQL_TYPE_SET;
+}
+
+
+/*
+ Log_event::print_header()
+*/
+
+bool Log_event::print_header(IO_CACHE* file,
+ PRINT_EVENT_INFO* print_event_info,
+ bool is_more __attribute__((unused)))
+{
+ char llbuff[22];
+ my_off_t hexdump_from= print_event_info->hexdump_from;
+ DBUG_ENTER("Log_event::print_header");
+
+ if (my_b_write_byte(file, '#') ||
+ print_timestamp(file) ||
+ my_b_printf(file, " server id %lu end_log_pos %s ", (ulong) server_id,
+ llstr(log_pos,llbuff)))
+ goto err;
+
+ /* print the checksum */
+
+ if (checksum_alg != BINLOG_CHECKSUM_ALG_OFF &&
+ checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF)
+ {
+ char checksum_buf[BINLOG_CHECKSUM_LEN * 2 + 4]; // to fit to "%p "
+ size_t const bytes_written=
+ my_snprintf(checksum_buf, sizeof(checksum_buf), "0x%08x ", crc);
+ if (my_b_printf(file, "%s ", get_type(&binlog_checksum_typelib,
+ checksum_alg)) ||
+ my_b_printf(file, checksum_buf, bytes_written))
+ goto err;
+ }
+
+ /* mysqlbinlog --hexdump */
+ if (print_event_info->hexdump_from)
+ {
+ my_b_write_byte(file, '\n');
+ uchar *ptr= (uchar*)temp_buf;
+ my_off_t size= uint4korr(ptr + EVENT_LEN_OFFSET);
+ my_off_t hdr_len= get_header_len(print_event_info->common_header_len);
+
+ size-= hdr_len;
+
+ if (my_b_printf(file, "# Position\n"))
+ goto err;
+
+ /* Write the header, nicely formatted by field. */
+ if (hexdump_minimal_header_to_io_cache(file, hexdump_from, ptr))
+ goto err;
+
+ ptr+= hdr_len;
+ hexdump_from+= hdr_len;
+
+ /* Print the rest of the data, mimicking "hexdump -C" output. */
+ if (hexdump_data_to_io_cache(file, hexdump_from, ptr, size))
+ goto err;
+
+ /*
+ Prefix the next line so that the output from print_helper()
+ will appear as a comment.
+ */
+ if (my_b_write(file, (uchar*)"# Event: ", 9))
+ goto err;
+ }
+
+ DBUG_RETURN(0);
+
+err:
+ DBUG_RETURN(1);
+}
+
+
+/**
+ Prints a quoted string to io cache.
+ Control characters are displayed as hex sequence, e.g. \x00
+ Single-quote and backslash characters are escaped with a \
+
+ @param[in] file IO cache
+ @param[in] prt Pointer to string
+ @param[in] length String length
+*/
+
+static void
+my_b_write_quoted(IO_CACHE *file, const uchar *ptr, uint length)
+{
+ const uchar *s;
+ my_b_write_byte(file, '\'');
+ for (s= ptr; length > 0 ; s++, length--)
+ {
+ if (*s > 0x1F)
+ my_b_write_byte(file, *s);
+ else if (*s == '\'')
+ my_b_write(file, (uchar*)"\\'", 2);
+ else if (*s == '\\')
+ my_b_write(file, (uchar*)"\\\\", 2);
+ else
+ {
+ uchar hex[10];
+ size_t len= my_snprintf((char*) hex, sizeof(hex), "%s%02x", "\\x", *s);
+ my_b_write(file, hex, len);
+ }
+ }
+ my_b_write_byte(file, '\'');
+}
+
+
+/**
+ Prints a bit string to io cache in format b'1010'.
+
+ @param[in] file IO cache
+ @param[in] ptr Pointer to string
+ @param[in] nbits Number of bits
+*/
+static void
+my_b_write_bit(IO_CACHE *file, const uchar *ptr, uint nbits)
+{
+ uint bitnum, nbits8= ((nbits + 7) / 8) * 8, skip_bits= nbits8 - nbits;
+ my_b_write(file, (uchar*)"b'", 2);
+ for (bitnum= skip_bits ; bitnum < nbits8; bitnum++)
+ {
+ int is_set= (ptr[(bitnum) / 8] >> (7 - bitnum % 8)) & 0x01;
+ my_b_write_byte(file, (is_set ? '1' : '0'));
+ }
+ my_b_write_byte(file, '\'');
+}
+
+
+/**
+ Prints a packed string to io cache.
+ The string consists of length packed to 1 or 2 bytes,
+ followed by string data itself.
+
+ @param[in] file IO cache
+ @param[in] ptr Pointer to string
+ @param[in] length String size
+
+ @retval - number of bytes scanned.
+*/
+static size_t
+my_b_write_quoted_with_length(IO_CACHE *file, const uchar *ptr, uint length)
+{
+ if (length < 256)
+ {
+ length= *ptr;
+ my_b_write_quoted(file, ptr + 1, length);
+ return length + 1;
+ }
+ else
+ {
+ length= uint2korr(ptr);
+ my_b_write_quoted(file, ptr + 2, length);
+ return length + 2;
+ }
+}
+
+
+/**
+ Prints a 32-bit number in both signed and unsigned representation
+
+ @param[in] file IO cache
+ @param[in] sl Signed number
+ @param[in] ul Unsigned number
+*/
+static bool
+my_b_write_sint32_and_uint32(IO_CACHE *file, int32 si, uint32 ui)
+{
+ bool res= my_b_printf(file, "%d", si);
+ if (si < 0)
+ if (my_b_printf(file, " (%u)", ui))
+ res= 1;
+ return res;
+}
+
+
+/**
+ Print a packed value of the given SQL type into IO cache
+
+ @param[in] file IO cache
+ @param[in] ptr Pointer to string
+ @param[in] type Column type
+ @param[in] meta Column meta information
+ @param[out] typestr SQL type string buffer (for verbose output)
+ @param[out] typestr_length Size of typestr
+
+ @retval - number of bytes scanned from ptr.
+ Except in case of NULL, in which case we return 1 to indicate ok
+*/
+
+static size_t
+log_event_print_value(IO_CACHE *file, PRINT_EVENT_INFO *print_event_info,
+ const uchar *ptr, uint type, uint meta,
+ char *typestr, size_t typestr_length)
+{
+ uint32 length= 0;
+
+ if (type == MYSQL_TYPE_STRING)
+ {
+ if (meta >= 256)
+ {
+ uint byte0= meta >> 8;
+ uint byte1= meta & 0xFF;
+
+ if ((byte0 & 0x30) != 0x30)
+ {
+ /* a long CHAR() field: see #37426 */
+ length= byte1 | (((byte0 & 0x30) ^ 0x30) << 4);
+ type= byte0 | 0x30;
+ }
+ else
+ length = meta & 0xFF;
+ }
+ else
+ length= meta;
+ }
+
+ switch (type) {
+ case MYSQL_TYPE_LONG:
+ {
+ strmake(typestr, "INT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ int32 si= sint4korr(ptr);
+ uint32 ui= uint4korr(ptr);
+ my_b_write_sint32_and_uint32(file, si, ui);
+ return 4;
+ }
+
+ case MYSQL_TYPE_TINY:
+ {
+ strmake(typestr, "TINYINT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ my_b_write_sint32_and_uint32(file, (int) (signed char) *ptr,
+ (uint) (unsigned char) *ptr);
+ return 1;
+ }
+
+ case MYSQL_TYPE_SHORT:
+ {
+ strmake(typestr, "SHORTINT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ int32 si= (int32) sint2korr(ptr);
+ uint32 ui= (uint32) uint2korr(ptr);
+ my_b_write_sint32_and_uint32(file, si, ui);
+ return 2;
+ }
+
+ case MYSQL_TYPE_INT24:
+ {
+ strmake(typestr, "MEDIUMINT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ int32 si= sint3korr(ptr);
+ uint32 ui= uint3korr(ptr);
+ my_b_write_sint32_and_uint32(file, si, ui);
+ return 3;
+ }
+
+ case MYSQL_TYPE_LONGLONG:
+ {
+ strmake(typestr, "LONGINT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ char tmp[64];
+ size_t length;
+ longlong si= sint8korr(ptr);
+ length= (longlong10_to_str(si, tmp, -10) - tmp);
+ my_b_write(file, (uchar*)tmp, length);
+ if (si < 0)
+ {
+ ulonglong ui= uint8korr(ptr);
+ longlong10_to_str((longlong) ui, tmp, 10);
+ my_b_printf(file, " (%s)", tmp);
+ }
+ return 8;
+ }
+
+ case MYSQL_TYPE_NEWDECIMAL:
+ {
+ uint precision= meta >> 8;
+ uint decimals= meta & 0xFF;
+ my_snprintf(typestr, typestr_length, "DECIMAL(%d,%d)",
+ precision, decimals);
+ if (!ptr)
+ goto return_null;
+
+ uint bin_size= my_decimal_get_binary_size(precision, decimals);
+ my_decimal dec((const uchar *) ptr, precision, decimals);
+ int length= DECIMAL_MAX_STR_LENGTH;
+ char buff[DECIMAL_MAX_STR_LENGTH + 1];
+ decimal2string(&dec, buff, &length, 0, 0, 0);
+ my_b_write(file, (uchar*)buff, length);
+ return bin_size;
+ }
+
+ case MYSQL_TYPE_FLOAT:
+ {
+ strmake(typestr, "FLOAT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ float fl;
+ float4get(fl, ptr);
+ char tmp[320];
+ sprintf(tmp, "%-20g", (double) fl);
+ my_b_printf(file, "%s", tmp); /* my_snprintf doesn't support %-20g */
+ return 4;
+ }
+
+ case MYSQL_TYPE_DOUBLE:
+ {
+ double dbl;
+ strmake(typestr, "DOUBLE", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ float8get(dbl, ptr);
+ char tmp[320];
+ sprintf(tmp, "%-.20g", dbl); /* strmake doesn't support %-20g */
+ my_b_printf(file, tmp, "%s");
+ return 8;
+ }
+
+ case MYSQL_TYPE_BIT:
+ {
+ /* Meta-data: bit_len, bytes_in_rec, 2 bytes */
+ uint nbits= ((meta >> 8) * 8) + (meta & 0xFF);
+ my_snprintf(typestr, typestr_length, "BIT(%d)", nbits);
+ if (!ptr)
+ goto return_null;
+
+ length= (nbits + 7) / 8;
+ my_b_write_bit(file, ptr, nbits);
+ return length;
+ }
+
+ case MYSQL_TYPE_TIMESTAMP:
+ {
+ strmake(typestr, "TIMESTAMP", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ uint32 i32= uint4korr(ptr);
+ my_b_printf(file, "%d", i32);
+ return 4;
+ }
+
+ case MYSQL_TYPE_TIMESTAMP2:
+ {
+ my_snprintf(typestr, typestr_length, "TIMESTAMP(%d)", meta);
+ if (!ptr)
+ goto return_null;
+
+ char buf[MAX_DATE_STRING_REP_LENGTH];
+ struct timeval tm;
+ my_timestamp_from_binary(&tm, ptr, meta);
+ int buflen= my_timeval_to_str(&tm, buf, meta);
+ my_b_write(file, (uchar*)buf, buflen);
+ return my_timestamp_binary_length(meta);
+ }
+
+ case MYSQL_TYPE_DATETIME:
+ {
+ strmake(typestr, "DATETIME", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ ulong d, t;
+ uint64 i64= uint8korr(ptr); /* YYYYMMDDhhmmss */
+ d= (ulong) (i64 / 1000000);
+ t= (ulong) (i64 % 1000000);
+
+ my_b_printf(file, "'%04d-%02d-%02d %02d:%02d:%02d'",
+ (int) (d / 10000), (int) (d % 10000) / 100, (int) (d % 100),
+ (int) (t / 10000), (int) (t % 10000) / 100, (int) t % 100);
+ return 8;
+ }
+
+ case MYSQL_TYPE_DATETIME2:
+ {
+ my_snprintf(typestr, typestr_length, "DATETIME(%d)", meta);
+ if (!ptr)
+ goto return_null;
+
+ char buf[MAX_DATE_STRING_REP_LENGTH];
+ MYSQL_TIME ltime;
+ longlong packed= my_datetime_packed_from_binary(ptr, meta);
+ TIME_from_longlong_datetime_packed(&ltime, packed);
+ int buflen= my_datetime_to_str(&ltime, buf, meta);
+ my_b_write_quoted(file, (uchar *) buf, buflen);
+ return my_datetime_binary_length(meta);
+ }
+
+ case MYSQL_TYPE_TIME:
+ {
+ strmake(typestr, "TIME", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ int32 tmp= sint3korr(ptr);
+ int32 i32= tmp >= 0 ? tmp : - tmp;
+ const char *sign= tmp < 0 ? "-" : "";
+ my_b_printf(file, "'%s%02d:%02d:%02d'",
+ sign, i32 / 10000, (i32 % 10000) / 100, i32 % 100, i32);
+ return 3;
+ }
+
+ case MYSQL_TYPE_TIME2:
+ {
+ my_snprintf(typestr, typestr_length, "TIME(%d)", meta);
+ if (!ptr)
+ goto return_null;
+
+ char buf[MAX_DATE_STRING_REP_LENGTH];
+ MYSQL_TIME ltime;
+ longlong packed= my_time_packed_from_binary(ptr, meta);
+ TIME_from_longlong_time_packed(&ltime, packed);
+ int buflen= my_time_to_str(&ltime, buf, meta);
+ my_b_write_quoted(file, (uchar *) buf, buflen);
+ return my_time_binary_length(meta);
+ }
+
+ case MYSQL_TYPE_NEWDATE:
+ {
+ strmake(typestr, "DATE", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ uint32 tmp= uint3korr(ptr);
+ int part;
+ char buf[11];
+ char *pos= &buf[10]; // start from '\0' to the beginning
+
+ /* Copied from field.cc */
+ *pos--=0; // End NULL
+ part=(int) (tmp & 31);
+ *pos--= (char) ('0'+part%10);
+ *pos--= (char) ('0'+part/10);
+ *pos--= ':';
+ part=(int) (tmp >> 5 & 15);
+ *pos--= (char) ('0'+part%10);
+ *pos--= (char) ('0'+part/10);
+ *pos--= ':';
+ part=(int) (tmp >> 9);
+ *pos--= (char) ('0'+part%10); part/=10;
+ *pos--= (char) ('0'+part%10); part/=10;
+ *pos--= (char) ('0'+part%10); part/=10;
+ *pos= (char) ('0'+part);
+ my_b_printf(file , "'%s'", buf);
+ return 3;
+ }
+
+ case MYSQL_TYPE_DATE:
+ {
+ strmake(typestr, "DATE", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ uint i32= uint3korr(ptr);
+ my_b_printf(file , "'%04d:%02d:%02d'",
+ (int)(i32 / (16L * 32L)), (int)(i32 / 32L % 16L),
+ (int)(i32 % 32L));
+ return 3;
+ }
+
+ case MYSQL_TYPE_YEAR:
+ {
+ strmake(typestr, "YEAR", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ uint32 i32= *ptr;
+ my_b_printf(file, "%04d", i32+ 1900);
+ return 1;
+ }
+
+ case MYSQL_TYPE_ENUM:
+ switch (meta & 0xFF) {
+ case 1:
+ strmake(typestr, "ENUM(1 byte)", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ my_b_printf(file, "%d", (int) *ptr);
+ return 1;
+ case 2:
+ {
+ strmake(typestr, "ENUM(2 bytes)", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ int32 i32= uint2korr(ptr);
+ my_b_printf(file, "%d", i32);
+ return 2;
+ }
+ default:
+ my_b_printf(file, "!! Unknown ENUM packlen=%d", meta & 0xFF);
+ return 0;
+ }
+ break;
+
+ case MYSQL_TYPE_SET:
+ my_snprintf(typestr, typestr_length, "SET(%d bytes)", meta & 0xFF);
+ if (!ptr)
+ goto return_null;
+
+ my_b_write_bit(file, ptr , (meta & 0xFF) * 8);
+ return meta & 0xFF;
+
+ case MYSQL_TYPE_BLOB:
+ switch (meta) {
+ case 1:
+ strmake(typestr, "TINYBLOB/TINYTEXT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ length= *ptr;
+ my_b_write_quoted(file, ptr + 1, length);
+ return length + 1;
+ case 2:
+ strmake(typestr, "BLOB/TEXT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ length= uint2korr(ptr);
+ my_b_write_quoted(file, ptr + 2, length);
+ return length + 2;
+ case 3:
+ strmake(typestr, "MEDIUMBLOB/MEDIUMTEXT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ length= uint3korr(ptr);
+ my_b_write_quoted(file, ptr + 3, length);
+ return length + 3;
+ case 4:
+ strmake(typestr, "LONGBLOB/LONGTEXT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ length= uint4korr(ptr);
+ my_b_write_quoted(file, ptr + 4, length);
+ return length + 4;
+ default:
+ my_b_printf(file, "!! Unknown BLOB packlen=%d", length);
+ return 0;
+ }
+
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ length= meta;
+ my_snprintf(typestr, typestr_length, "VARSTRING(%d)", length);
+ if (!ptr)
+ goto return_null;
+
+ return my_b_write_quoted_with_length(file, ptr, length);
+
+ case MYSQL_TYPE_STRING:
+ my_snprintf(typestr, typestr_length, "STRING(%d)", length);
+ if (!ptr)
+ goto return_null;
+
+ return my_b_write_quoted_with_length(file, ptr, length);
+
+ case MYSQL_TYPE_DECIMAL:
+ print_event_info->flush_for_error();
+ fprintf(stderr, "\nError: Found Old DECIMAL (mysql-4.1 or earlier). "
+ "Not enough metadata to display the value.\n");
+ break;
+ default:
+ print_event_info->flush_for_error();
+ fprintf(stderr,
+ "\nError: Don't know how to handle column type: %d meta: %d (%04x)\n",
+ type, meta, meta);
+ break;
+ }
+ *typestr= 0;
+ return 0;
+
+return_null:
+ return my_b_write(file, (uchar*) "NULL", 4) ? 0 : 1;
+}
+
+
+/**
+ Print a packed row into IO cache
+
+ @param[in] file IO cache
+ @param[in] td Table definition
+ @param[in] print_event_into Print parameters
+ @param[in] cols_bitmap Column bitmaps.
+ @param[in] value Pointer to packed row
+ @param[in] prefix Row's SQL clause ("SET", "WHERE", etc)
+
+ @retval 0 error
+ # number of bytes scanned.
+*/
+
+
+size_t
+Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td,
+ PRINT_EVENT_INFO *print_event_info,
+ MY_BITMAP *cols_bitmap,
+ const uchar *value, const uchar *prefix,
+ const my_bool no_fill_output)
+{
+ const uchar *value0= value;
+ const uchar *null_bits= value;
+ uint null_bit_index= 0;
+ char typestr[64]= "";
+
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ /* Storing the review SQL */
+ IO_CACHE *review_sql= &print_event_info->review_sql_cache;
+ LEX_STRING review_str;
+#endif
+
+ /*
+ Skip metadata bytes which gives the information about nullabity of master
+ columns. Master writes one bit for each affected column.
+ */
+
+ value+= (bitmap_bits_set(cols_bitmap) + 7) / 8;
+
+ if (!no_fill_output)
+ if (my_b_printf(file, "%s", prefix))
+ goto err;
+
+ for (uint i= 0; i < (uint)td->size(); i ++)
+ {
+ size_t size;
+ int is_null= (null_bits[null_bit_index / 8]
+ >> (null_bit_index % 8)) & 0x01;
+
+ if (bitmap_is_set(cols_bitmap, i) == 0)
+ continue;
+
+ if (!no_fill_output)
+ if (my_b_printf(file, "### @%d=", static_cast<int>(i + 1)))
+ goto err;
+
+ if (!is_null)
+ {
+ size_t fsize= td->calc_field_size((uint)i, (uchar*) value);
+ if (value + fsize > m_rows_end)
+ {
+ if (!no_fill_output)
+ if (my_b_printf(file, "***Corrupted replication event was detected."
+ " Not printing the value***\n"))
+ goto err;
+ value+= fsize;
+ return 0;
+ }
+ }
+
+ if (!no_fill_output)
+ {
+ size= log_event_print_value(file, print_event_info, is_null? NULL: value,
+ td->type(i), td->field_metadata(i),
+ typestr, sizeof(typestr));
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ if (need_flashback_review)
+ {
+ String tmp_str, hex_str;
+ IO_CACHE tmp_cache;
+
+ // Using a tmp IO_CACHE to get the value output
+ open_cached_file(&tmp_cache, NULL, NULL, 0, MYF(MY_WME | MY_NABP));
+ size= log_event_print_value(&tmp_cache, print_event_info,
+ is_null ? NULL: value,
+ td->type(i), td->field_metadata(i),
+ typestr, sizeof(typestr));
+ error= copy_event_cache_to_string_and_reinit(&tmp_cache, &review_str);
+ close_cached_file(&tmp_cache);
+ if (unlikely(error))
+ return 0;
+
+ switch (td->type(i)) // Converting a string to HEX format
+ {
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_BLOB:
+ // Avoid write_pos changed to a new area
+ // tmp_str.free();
+ tmp_str.append(review_str.str + 1, review_str.length - 2); // Removing quotation marks
+ if (hex_str.alloc(tmp_str.length()*2+1)) // If out of memory
+ {
+ fprintf(stderr, "\nError: Out of memory. "
+ "Could not print correct binlog event.\n");
+ exit(1);
+ }
+ octet2hex((char*) hex_str.ptr(), tmp_str.ptr(), tmp_str.length());
+ if (my_b_printf(review_sql, ", UNHEX('%s')", hex_str.ptr()))
+ goto err;
+ break;
+ default:
+ tmp_str.free();
+ if (tmp_str.append(review_str.str, review_str.length) ||
+ my_b_printf(review_sql, ", %s", tmp_str.ptr()))
+ goto err;
+ break;
+ }
+ my_free(revieww_str.str);
+ }
+#endif
+ }
+ else
+ {
+ IO_CACHE tmp_cache;
+ open_cached_file(&tmp_cache, NULL, NULL, 0, MYF(MY_WME | MY_NABP));
+ size= log_event_print_value(&tmp_cache, print_event_info,
+ is_null ? NULL: value,
+ td->type(i), td->field_metadata(i),
+ typestr, sizeof(typestr));
+ close_cached_file(&tmp_cache);
+ }
+
+ if (!size)
+ goto err;
+
+ if (!is_null)
+ value+= size;
+
+ if (print_event_info->verbose > 1 && !no_fill_output)
+ {
+ if (my_b_write(file, (uchar*)" /* ", 4) ||
+ my_b_printf(file, "%s ", typestr) ||
+ my_b_printf(file, "meta=%d nullable=%d is_null=%d ",
+ td->field_metadata(i),
+ td->maybe_null(i), is_null) ||
+ my_b_write(file, (uchar*)"*/", 2))
+ goto err;
+ }
+
+ if (!no_fill_output)
+ if (my_b_write_byte(file, '\n'))
+ goto err;
+
+ null_bit_index++;
+ }
+ return value - value0;
+
+err:
+ return 0;
+}
+
+
+/**
+ Exchange the SET part and WHERE part for the Update events.
+ Revert the operations order for the Write and Delete events.
+ And then revert the events order from the last one to the first one.
+
+ @param[in] print_event_info PRINT_EVENT_INFO
+ @param[in] rows_buff Packed event buff
+*/
+
+void Rows_log_event::change_to_flashback_event(PRINT_EVENT_INFO *print_event_info,
+ uchar *rows_buff, Log_event_type ev_type)
+{
+ Table_map_log_event *map;
+ table_def *td;
+ DYNAMIC_ARRAY rows_arr;
+ uchar *swap_buff1;
+ uchar *rows_pos= rows_buff + m_rows_before_size;
+
+ if (!(map= print_event_info->m_table_map.get_table(m_table_id)) ||
+ !(td= map->create_table_def()))
+ return;
+
+ /* If the write rows event contained no values for the AI */
+ if (((get_general_type_code() == WRITE_ROWS_EVENT) && (m_rows_buf==m_rows_end)))
+ goto end;
+
+ (void) my_init_dynamic_array(PSI_NOT_INSTRUMENTED, &rows_arr, sizeof(LEX_STRING), 8, 8, MYF(0));
+
+ for (uchar *value= m_rows_buf; value < m_rows_end; )
+ {
+ uchar *start_pos= value;
+ size_t length1= 0;
+ if (!(length1= print_verbose_one_row(NULL, td, print_event_info,
+ &m_cols, value,
+ (const uchar*) "", TRUE)))
+ {
+ fprintf(stderr, "\nError row length: %zu\n", length1);
+ exit(1);
+ }
+ value+= length1;
+
+ swap_buff1= (uchar *) my_malloc(PSI_NOT_INSTRUMENTED, length1, MYF(0));
+ if (!swap_buff1)
+ {
+ fprintf(stderr, "\nError: Out of memory. "
+ "Could not exchange to flashback event.\n");
+ exit(1);
+ }
+ memcpy(swap_buff1, start_pos, length1);
+
+ // For Update_event, we have the second part
+ size_t length2= 0;
+ if (ev_type == UPDATE_ROWS_EVENT ||
+ ev_type == UPDATE_ROWS_EVENT_V1)
+ {
+ if (!(length2= print_verbose_one_row(NULL, td, print_event_info,
+ &m_cols, value,
+ (const uchar*) "", TRUE)))
+ {
+ fprintf(stderr, "\nError row length: %zu\n", length2);
+ exit(1);
+ }
+ value+= length2;
+
+ void *swap_buff2= my_malloc(PSI_NOT_INSTRUMENTED, length2, MYF(0));
+ if (!swap_buff2)
+ {
+ fprintf(stderr, "\nError: Out of memory. "
+ "Could not exchange to flashback event.\n");
+ exit(1);
+ }
+ memcpy(swap_buff2, start_pos + length1, length2); // WHERE part
+
+ /* Swap SET and WHERE part */
+ memcpy(start_pos, swap_buff2, length2);
+ memcpy(start_pos + length2, swap_buff1, length1);
+ my_free(swap_buff2);
+ }
+
+ my_free(swap_buff1);
+
+ /* Copying one row into a buff, and pushing into the array */
+ LEX_STRING one_row;
+
+ one_row.length= length1 + length2;
+ one_row.str= (char *) my_malloc(PSI_NOT_INSTRUMENTED, one_row.length, MYF(0));
+ memcpy(one_row.str, start_pos, one_row.length);
+ if (one_row.str == NULL || push_dynamic(&rows_arr, (uchar *) &one_row))
+ {
+ fprintf(stderr, "\nError: Out of memory. "
+ "Could not push flashback event into array.\n");
+ exit(1);
+ }
+ }
+
+ /* Copying rows from the end to the begining into event */
+ for (uint i= rows_arr.elements; i > 0; --i)
+ {
+ LEX_STRING *one_row= dynamic_element(&rows_arr, i - 1, LEX_STRING*);
+
+ memcpy(rows_pos, (uchar *)one_row->str, one_row->length);
+ rows_pos+= one_row->length;
+ my_free(one_row->str);
+ }
+ delete_dynamic(&rows_arr);
+
+end:
+ delete td;
+}
+
+/**
+ Calc length of a packed value of the given SQL type
+
+ @param[in] ptr Pointer to string
+ @param[in] type Column type
+ @param[in] meta Column meta information
+
+ @retval - number of bytes scanned from ptr.
+ Except in case of NULL, in which case we return 1 to indicate ok
+*/
+
+static size_t calc_field_event_length(const uchar *ptr, uint type, uint meta)
+{
+ uint32 length= 0;
+
+ if (type == MYSQL_TYPE_STRING)
+ {
+ if (meta >= 256)
+ {
+ uint byte0= meta >> 8;
+ uint byte1= meta & 0xFF;
+
+ if ((byte0 & 0x30) != 0x30)
+ {
+ /* a long CHAR() field: see #37426 */
+ length= byte1 | (((byte0 & 0x30) ^ 0x30) << 4);
+ type= byte0 | 0x30;
+ }
+ else
+ length = meta & 0xFF;
+ }
+ else
+ length= meta;
+ }
+
+ switch (type) {
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_TIMESTAMP:
+ return 4;
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_YEAR:
+ return 1;
+ case MYSQL_TYPE_SHORT:
+ return 2;
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_DATE:
+ return 3;
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_DATETIME:
+ return 8;
+ case MYSQL_TYPE_NEWDECIMAL:
+ {
+ uint precision= meta >> 8;
+ uint decimals= meta & 0xFF;
+ uint bin_size= my_decimal_get_binary_size(precision, decimals);
+ return bin_size;
+ }
+ case MYSQL_TYPE_FLOAT:
+ return 4;
+ case MYSQL_TYPE_DOUBLE:
+ return 8;
+ case MYSQL_TYPE_BIT:
+ {
+ /* Meta-data: bit_len, bytes_in_rec, 2 bytes */
+ uint nbits= ((meta >> 8) * 8) + (meta & 0xFF);
+ length= (nbits + 7) / 8;
+ return length;
+ }
+ case MYSQL_TYPE_TIMESTAMP2:
+ return my_timestamp_binary_length(meta);
+ case MYSQL_TYPE_DATETIME2:
+ return my_datetime_binary_length(meta);
+ case MYSQL_TYPE_TIME2:
+ return my_time_binary_length(meta);
+ case MYSQL_TYPE_ENUM:
+ switch (meta & 0xFF) {
+ case 1:
+ case 2:
+ return (meta & 0xFF);
+ default:
+ /* Unknown ENUM packlen=%d", meta & 0xFF */
+ return 0;
+ }
+ break;
+ case MYSQL_TYPE_SET:
+ return meta & 0xFF;
+ case MYSQL_TYPE_BLOB:
+ switch (meta) {
+ default:
+ return 0;
+ case 1:
+ return *ptr + 1;
+ case 2:
+ return uint2korr(ptr) + 2;
+ case 3:
+ return uint3korr(ptr) + 3;
+ case 4:
+ return uint4korr(ptr) + 4;
+ }
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ length= meta;
+ /* fall through */
+ case MYSQL_TYPE_STRING:
+ if (length < 256)
+ return (uint) *ptr + 1;
+ return uint2korr(ptr) + 2;
+ case MYSQL_TYPE_DECIMAL:
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+size_t
+Rows_log_event::calc_row_event_length(table_def *td,
+ PRINT_EVENT_INFO *print_event_info,
+ MY_BITMAP *cols_bitmap,
+ const uchar *value)
+{
+ const uchar *value0= value;
+ const uchar *null_bits= value;
+ uint null_bit_index= 0;
+
+ /*
+ Skip metadata bytes which gives the information about nullabity of master
+ columns. Master writes one bit for each affected column.
+ */
+
+ value+= (bitmap_bits_set(cols_bitmap) + 7) / 8;
+
+ for (uint i= 0; i < (uint)td->size(); i ++)
+ {
+ int is_null;
+ is_null= (null_bits[null_bit_index / 8] >> (null_bit_index % 8)) & 0x01;
+
+ if (bitmap_is_set(cols_bitmap, i) == 0)
+ continue;
+
+ if (!is_null)
+ {
+ size_t size;
+ size_t fsize= td->calc_field_size((uint)i, (uchar*) value);
+ if (value + fsize > m_rows_end)
+ {
+ /* Corrupted replication event was detected, skipping entry */
+ return 0;
+ }
+ if (!(size= calc_field_event_length(value, td->type(i),
+ td->field_metadata(i))))
+ return 0;
+ value+= size;
+ }
+ null_bit_index++;
+ }
+ return value - value0;
+}
+
+
+/**
+ Calculate how many rows there are in the event
+
+ @param[in] file IO cache
+ @param[in] print_event_into Print parameters
+*/
+
+void Rows_log_event::count_row_events(PRINT_EVENT_INFO *print_event_info)
+{
+ Table_map_log_event *map;
+ table_def *td;
+ uint row_events;
+ Log_event_type general_type_code= get_general_type_code();
+
+ switch (general_type_code) {
+ case WRITE_ROWS_EVENT:
+ case DELETE_ROWS_EVENT:
+ row_events= 1;
+ break;
+ case UPDATE_ROWS_EVENT:
+ row_events= 2;
+ break;
+ default:
+ DBUG_ASSERT(0); /* Not possible */
+ return;
+ }
+
+ if (!(map= print_event_info->m_table_map.get_table(m_table_id)) ||
+ !(td= map->create_table_def()))
+ {
+ /* Row event for unknown table */
+ return;
+ }
+
+ for (const uchar *value= m_rows_buf; value < m_rows_end; )
+ {
+ size_t length;
+ print_event_info->row_events++;
+
+ /* Print the first image */
+ if (!(length= calc_row_event_length(td, print_event_info,
+ &m_cols, value)))
+ break;
+ value+= length;
+ DBUG_ASSERT(value <= m_rows_end);
+
+ /* Print the second image (for UPDATE only) */
+ if (row_events == 2)
+ {
+ if (!(length= calc_row_event_length(td, print_event_info,
+ &m_cols_ai, value)))
+ break;
+ value+= length;
+ DBUG_ASSERT(value <= m_rows_end);
+ }
+ }
+ delete td;
+}
+
+
+/**
+ Print a row event into IO cache in human readable form (in SQL format)
+
+ @param[in] file IO cache
+ @param[in] print_event_into Print parameters
+*/
+
+bool Rows_log_event::print_verbose(IO_CACHE *file,
+ PRINT_EVENT_INFO *print_event_info)
+{
+ Table_map_log_event *map;
+ table_def *td= 0;
+ const char *sql_command, *sql_clause1, *sql_clause2;
+ const char *sql_command_short __attribute__((unused));
+ Log_event_type general_type_code= get_general_type_code();
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ IO_CACHE *review_sql= &print_event_info->review_sql_cache;
+#endif
+
+ if (m_extra_row_data)
+ {
+ uint8 extra_data_len= m_extra_row_data[EXTRA_ROW_INFO_LEN_OFFSET];
+ uint8 extra_payload_len= extra_data_len - EXTRA_ROW_INFO_HDR_BYTES;
+ assert(extra_data_len >= EXTRA_ROW_INFO_HDR_BYTES);
+
+ if (my_b_printf(file, "### Extra row data format: %u, len: %u :",
+ m_extra_row_data[EXTRA_ROW_INFO_FORMAT_OFFSET],
+ extra_payload_len))
+ goto err;
+ if (extra_payload_len)
+ {
+ /*
+ Buffer for hex view of string, including '0x' prefix,
+ 2 hex chars / byte and trailing 0
+ */
+ const int buff_len= 2 + (256 * 2) + 1;
+ char buff[buff_len];
+ str_to_hex(buff, (const char*) &m_extra_row_data[EXTRA_ROW_INFO_HDR_BYTES],
+ extra_payload_len);
+ if (my_b_printf(file, "%s", buff))
+ goto err;
+ }
+ if (my_b_printf(file, "\n"))
+ goto err;
+ }
+
+ switch (general_type_code) {
+ case WRITE_ROWS_EVENT:
+ sql_command= "INSERT INTO";
+ sql_clause1= "### SET\n";
+ sql_clause2= NULL;
+ sql_command_short= "I";
+ break;
+ case DELETE_ROWS_EVENT:
+ sql_command= "DELETE FROM";
+ sql_clause1= "### WHERE\n";
+ sql_clause2= NULL;
+ sql_command_short= "D";
+ break;
+ case UPDATE_ROWS_EVENT:
+ sql_command= "UPDATE";
+ sql_clause1= "### WHERE\n";
+ sql_clause2= "### SET\n";
+ sql_command_short= "U";
+ break;
+ default:
+ sql_command= sql_clause1= sql_clause2= NULL;
+ sql_command_short= "";
+ DBUG_ASSERT(0); /* Not possible */
+ }
+
+ if (!(map= print_event_info->m_table_map.get_table(m_table_id)) ||
+ !(td= map->create_table_def()))
+ {
+ return (my_b_printf(file, "### Row event for unknown table #%lu",
+ (ulong) m_table_id));
+ }
+
+ /* If the write rows event contained no values for the AI */
+ if (((general_type_code == WRITE_ROWS_EVENT) && (m_rows_buf==m_rows_end)))
+ {
+ if (my_b_printf(file, "### INSERT INTO %`s.%`s VALUES ()\n",
+ map->get_db_name(), map->get_table_name()))
+ goto err;
+ goto end;
+ }
+
+ for (const uchar *value= m_rows_buf; value < m_rows_end; )
+ {
+ size_t length;
+ print_event_info->row_events++;
+
+ if (my_b_printf(file, "### %s %`s.%`s\n",
+ sql_command,
+ map->get_db_name(), map->get_table_name()))
+ goto err;
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ if (need_flashback_review)
+ if (my_b_printf(review_sql, "\nINSERT INTO `%s`.`%s` VALUES ('%s'",
+ map->get_review_dbname(), map->get_review_tablename(),
+ sql_command_short))
+ goto err;
+#endif
+
+ /* Print the first image */
+ if (!(length= print_verbose_one_row(file, td, print_event_info,
+ &m_cols, value,
+ (const uchar*) sql_clause1)))
+ goto err;
+ value+= length;
+
+ /* Print the second image (for UPDATE only) */
+ if (sql_clause2)
+ {
+ if (!(length= print_verbose_one_row(file, td, print_event_info,
+ &m_cols_ai, value,
+ (const uchar*) sql_clause2)))
+ goto err;
+ value+= length;
+ }
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ else
+ {
+ if (need_flashback_review)
+ for (size_t i= 0; i < td->size(); i ++)
+ if (my_b_printf(review_sql, ", NULL"))
+ goto err;
+ }
+
+ if (need_flashback_review)
+ if (my_b_printf(review_sql, ")%s\n", print_event_info->delimiter))
+ goto err;
+#endif
+ }
+
+end:
+ delete td;
+ return 0;
+err:
+ delete td;
+ return 1;
+}
+
+void free_table_map_log_event(Table_map_log_event *event)
+{
+ delete event;
+}
+
+/**
+ Encode the event, optionally per 'do_print_encoded' arg store the
+ result into the argument cache; optionally per event_info's
+ 'verbose' print into the cache a verbose representation of the event.
+ Note, no extra wrapping is done to the being io-cached data, like
+ to producing a BINLOG query. It's left for a routine that extracts from
+ the cache.
+
+ @param file pointer to IO_CACHE
+ @param print_event_info pointer to print_event_info specializing
+ what out of and how to print the event
+ @param do_print_encoded whether to store base64-encoded event
+ into @file.
+*/
+bool Log_event::print_base64(IO_CACHE* file,
+ PRINT_EVENT_INFO* print_event_info,
+ bool do_print_encoded)
+{
+ uchar *ptr= (uchar *)temp_buf;
+ uint32 size= uint4korr(ptr + EVENT_LEN_OFFSET);
+ DBUG_ENTER("Log_event::print_base64");
+
+ if (is_flashback)
+ {
+ uint tmp_size= size;
+ Rows_log_event *ev= NULL;
+ Log_event_type ev_type = (enum Log_event_type) ptr[EVENT_TYPE_OFFSET];
+ if (checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF &&
+ checksum_alg != BINLOG_CHECKSUM_ALG_OFF)
+ tmp_size-= BINLOG_CHECKSUM_LEN; // checksum is displayed through the header
+ switch (ev_type) {
+ case WRITE_ROWS_EVENT:
+ ptr[EVENT_TYPE_OFFSET]= DELETE_ROWS_EVENT;
+ ev= new Delete_rows_log_event((const char*) ptr, tmp_size,
+ glob_description_event);
+ ev->change_to_flashback_event(print_event_info, ptr, ev_type);
+ break;
+ case WRITE_ROWS_EVENT_V1:
+ ptr[EVENT_TYPE_OFFSET]= DELETE_ROWS_EVENT_V1;
+ ev= new Delete_rows_log_event((const char*) ptr, tmp_size,
+ glob_description_event);
+ ev->change_to_flashback_event(print_event_info, ptr, ev_type);
+ break;
+ case DELETE_ROWS_EVENT:
+ ptr[EVENT_TYPE_OFFSET]= WRITE_ROWS_EVENT;
+ ev= new Write_rows_log_event((const char*) ptr, tmp_size,
+ glob_description_event);
+ ev->change_to_flashback_event(print_event_info, ptr, ev_type);
+ break;
+ case DELETE_ROWS_EVENT_V1:
+ ptr[EVENT_TYPE_OFFSET]= WRITE_ROWS_EVENT_V1;
+ ev= new Write_rows_log_event((const char*) ptr, tmp_size,
+ glob_description_event);
+ ev->change_to_flashback_event(print_event_info, ptr, ev_type);
+ break;
+ case UPDATE_ROWS_EVENT:
+ case UPDATE_ROWS_EVENT_V1:
+ ev= new Update_rows_log_event((const char*) ptr, tmp_size,
+ glob_description_event);
+ ev->change_to_flashback_event(print_event_info, ptr, ev_type);
+ break;
+ default:
+ break;
+ }
+ delete ev;
+ }
+
+ if (do_print_encoded)
+ {
+ size_t const tmp_str_sz= my_base64_needed_encoded_length((int) size);
+ char *tmp_str;
+ if (!(tmp_str= (char *) my_malloc(PSI_NOT_INSTRUMENTED, tmp_str_sz, MYF(MY_WME))))
+ goto err;
+
+ if (my_base64_encode(ptr, (size_t) size, tmp_str))
+ {
+ DBUG_ASSERT(0);
+ }
+
+ my_b_printf(file, "%s\n", tmp_str);
+ my_free(tmp_str);
+ }
+
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ if (print_event_info->verbose || print_event_info->print_row_count ||
+ need_flashback_review)
+#else
+ // Flashback need the table_map to parse the event
+ if (print_event_info->verbose || print_event_info->print_row_count ||
+ is_flashback)
+#endif
+ {
+ Rows_log_event *ev= NULL;
+ Log_event_type et= (Log_event_type) ptr[EVENT_TYPE_OFFSET];
+
+ if (checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF &&
+ checksum_alg != BINLOG_CHECKSUM_ALG_OFF)
+ size-= BINLOG_CHECKSUM_LEN; // checksum is displayed through the header
+
+ switch (et)
+ {
+ case TABLE_MAP_EVENT:
+ {
+ Table_map_log_event *map;
+ map= new Table_map_log_event((const char*) ptr, size,
+ glob_description_event);
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ if (need_flashback_review)
+ {
+ map->set_review_dbname(m_review_dbname.ptr());
+ map->set_review_tablename(m_review_tablename.ptr());
+ }
+#endif
+ print_event_info->m_table_map.set_table(map->get_table_id(), map);
+ break;
+ }
+ case WRITE_ROWS_EVENT:
+ case WRITE_ROWS_EVENT_V1:
+ {
+ ev= new Write_rows_log_event((const char*) ptr, size,
+ glob_description_event);
+ break;
+ }
+ case DELETE_ROWS_EVENT:
+ case DELETE_ROWS_EVENT_V1:
+ {
+ ev= new Delete_rows_log_event((const char*) ptr, size,
+ glob_description_event);
+ break;
+ }
+ case UPDATE_ROWS_EVENT:
+ case UPDATE_ROWS_EVENT_V1:
+ {
+ ev= new Update_rows_log_event((const char*) ptr, size,
+ glob_description_event);
+ break;
+ }
+ case WRITE_ROWS_COMPRESSED_EVENT:
+ case WRITE_ROWS_COMPRESSED_EVENT_V1:
+ {
+ ev= new Write_rows_compressed_log_event((const char*) ptr, size,
+ glob_description_event);
+ break;
+ }
+ case UPDATE_ROWS_COMPRESSED_EVENT:
+ case UPDATE_ROWS_COMPRESSED_EVENT_V1:
+ {
+ ev= new Update_rows_compressed_log_event((const char*) ptr, size,
+ glob_description_event);
+ break;
+ }
+ case DELETE_ROWS_COMPRESSED_EVENT:
+ case DELETE_ROWS_COMPRESSED_EVENT_V1:
+ {
+ ev= new Delete_rows_compressed_log_event((const char*) ptr, size,
+ glob_description_event);
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (ev)
+ {
+ bool error= 0;
+
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ ev->need_flashback_review= need_flashback_review;
+ if (print_event_info->verbose)
+ {
+ if (ev->print_verbose(file, print_event_info))
+ goto err;
+ }
+ else
+ {
+ IO_CACHE tmp_cache;
+
+ if (open_cached_file(&tmp_cache, NULL, NULL, 0,
+ MYF(MY_WME | MY_NABP)))
+ {
+ delete ev;
+ goto err;
+ }
+
+ error= ev->print_verbose(&tmp_cache, print_event_info);
+ close_cached_file(&tmp_cache);
+ if (unlikely(error))
+ {
+ delete ev;
+ goto err;
+ }
+ }
+#else
+ if (print_event_info->verbose)
+ {
+ /*
+ Verbose event printout can't start before encoded data
+ got enquoted. This is done at this point though multi-row
+ statement remain vulnerable.
+ TODO: fix MDEV-10362 to remove this workaround.
+ */
+ if (print_event_info->base64_output_mode !=
+ BASE64_OUTPUT_DECODE_ROWS)
+ my_b_printf(file, "'%s\n", print_event_info->delimiter);
+ error= ev->print_verbose(file, print_event_info);
+ }
+ else
+ {
+ ev->count_row_events(print_event_info);
+ }
+#endif
+ delete ev;
+ if (unlikely(error))
+ goto err;
+ }
+ }
+ DBUG_RETURN(0);
+
+err:
+ DBUG_RETURN(1);
+}
+
+
+/*
+ Log_event::print_timestamp()
+*/
+
+bool Log_event::print_timestamp(IO_CACHE* file, time_t* ts)
+{
+ struct tm *res;
+ time_t my_when= when;
+ DBUG_ENTER("Log_event::print_timestamp");
+ if (!ts)
+ ts = &my_when;
+ res=localtime(ts);
+
+ DBUG_RETURN(my_b_printf(file,"%02d%02d%02d %2d:%02d:%02d",
+ res->tm_year % 100,
+ res->tm_mon+1,
+ res->tm_mday,
+ res->tm_hour,
+ res->tm_min,
+ res->tm_sec));
+}
+
+
+/**
+ Query_log_event::print().
+
+ @todo
+ print the catalog ??
+*/
+bool Query_log_event::print_query_header(IO_CACHE* file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ // TODO: print the catalog ??
+ char buff[64], *end; // Enough for SET TIMESTAMP
+ bool different_db= 1;
+ uint32 tmp;
+
+ if (!print_event_info->short_form)
+ {
+ if (print_header(file, print_event_info, FALSE) ||
+ my_b_printf(file,
+ "\t%s\tthread_id=%lu\texec_time=%lu\terror_code=%d\n",
+ get_type_str(), (ulong) thread_id, (ulong) exec_time,
+ error_code))
+ goto err;
+ }
+
+ if ((flags & LOG_EVENT_SUPPRESS_USE_F))
+ {
+ if (!is_trans_keyword())
+ print_event_info->db[0]= '\0';
+ }
+ else if (db)
+ {
+ different_db= memcmp(print_event_info->db, db, db_len + 1);
+ if (different_db)
+ memcpy(print_event_info->db, db, db_len + 1);
+ if (db[0] && different_db)
+ if (my_b_printf(file, "use %`s%s\n", db, print_event_info->delimiter))
+ goto err;
+ }
+
+ end=int10_to_str((long) when, strmov(buff,"SET TIMESTAMP="),10);
+ if (when_sec_part && when_sec_part <= TIME_MAX_SECOND_PART)
+ {
+ *end++= '.';
+ end=int10_to_str(when_sec_part, end, 10);
+ }
+ end= strmov(end, print_event_info->delimiter);
+ *end++='\n';
+ if (my_b_write(file, (uchar*) buff, (uint) (end-buff)))
+ goto err;
+ if ((!print_event_info->thread_id_printed ||
+ ((flags & LOG_EVENT_THREAD_SPECIFIC_F) &&
+ thread_id != print_event_info->thread_id)))
+ {
+ // If --short-form, print deterministic value instead of pseudo_thread_id.
+ if (my_b_printf(file,"SET @@session.pseudo_thread_id=%lu%s\n",
+ short_form ? 999999999 : (ulong)thread_id,
+ print_event_info->delimiter))
+ goto err;
+ print_event_info->thread_id= thread_id;
+ print_event_info->thread_id_printed= 1;
+ }
+
+ /*
+ If flags2_inited==0, this is an event from 3.23 or 4.0; nothing to
+ print (remember we don't produce mixed relay logs so there cannot be
+ 5.0 events before that one so there is nothing to reset).
+ */
+ if (likely(flags2_inited)) /* likely as this will mainly read 5.0 logs */
+ {
+ /* tmp is a bitmask of bits which have changed. */
+ if (likely(print_event_info->flags2_inited))
+ /* All bits which have changed */
+ tmp= (print_event_info->flags2) ^ flags2;
+ else /* that's the first Query event we read */
+ {
+ print_event_info->flags2_inited= 1;
+ tmp= ~((uint32)0); /* all bits have changed */
+ }
+
+ if (unlikely(tmp)) /* some bits have changed */
+ {
+ bool need_comma= 0;
+ if (my_b_write_string(file, "SET ") ||
+ print_set_option(file, tmp, OPTION_NO_FOREIGN_KEY_CHECKS, ~flags2,
+ "@@session.foreign_key_checks", &need_comma)||
+ print_set_option(file, tmp, OPTION_AUTO_IS_NULL, flags2,
+ "@@session.sql_auto_is_null", &need_comma) ||
+ print_set_option(file, tmp, OPTION_RELAXED_UNIQUE_CHECKS, ~flags2,
+ "@@session.unique_checks", &need_comma) ||
+ print_set_option(file, tmp, OPTION_NOT_AUTOCOMMIT, ~flags2,
+ "@@session.autocommit", &need_comma) ||
+ print_set_option(file, tmp, OPTION_NO_CHECK_CONSTRAINT_CHECKS,
+ ~flags2,
+ "@@session.check_constraint_checks", &need_comma) ||
+ my_b_printf(file,"%s\n", print_event_info->delimiter))
+ goto err;
+ print_event_info->flags2= flags2;
+ }
+ }
+
+ /*
+ Now the session variables;
+ it's more efficient to pass SQL_MODE as a number instead of a
+ comma-separated list.
+ FOREIGN_KEY_CHECKS, SQL_AUTO_IS_NULL, UNIQUE_CHECKS are session-only
+ variables (they have no global version; they're not listed in
+ sql_class.h), The tests below work for pure binlogs or pure relay
+ logs. Won't work for mixed relay logs but we don't create mixed
+ relay logs (that is, there is no relay log with a format change
+ except within the 3 first events, which mysqlbinlog handles
+ gracefully). So this code should always be good.
+ */
+
+ if (likely(sql_mode_inited) &&
+ (unlikely(print_event_info->sql_mode != sql_mode ||
+ !print_event_info->sql_mode_inited)))
+ {
+ char llbuff[22];
+ if (my_b_printf(file,"SET @@session.sql_mode=%s%s\n",
+ ullstr(sql_mode, llbuff), print_event_info->delimiter))
+ goto err;
+ print_event_info->sql_mode= sql_mode;
+ print_event_info->sql_mode_inited= 1;
+ }
+ if (print_event_info->auto_increment_increment != auto_increment_increment ||
+ print_event_info->auto_increment_offset != auto_increment_offset)
+ {
+ if (my_b_printf(file,"SET @@session.auto_increment_increment=%lu, @@session.auto_increment_offset=%lu%s\n",
+ auto_increment_increment,auto_increment_offset,
+ print_event_info->delimiter))
+ goto err;
+ print_event_info->auto_increment_increment= auto_increment_increment;
+ print_event_info->auto_increment_offset= auto_increment_offset;
+ }
+
+ /* TODO: print the catalog when we feature SET CATALOG */
+
+ if (likely(charset_inited) &&
+ (unlikely(!print_event_info->charset_inited ||
+ memcmp(print_event_info->charset, charset, 6))))
+ {
+ CHARSET_INFO *cs_info= get_charset(uint2korr(charset), MYF(MY_WME));
+ if (cs_info)
+ {
+ /* for mysql client */
+ if (my_b_printf(file, "/*!\\C %s */%s\n",
+ cs_info->csname, print_event_info->delimiter))
+ goto err;
+ }
+ if (my_b_printf(file,"SET "
+ "@@session.character_set_client=%d,"
+ "@@session.collation_connection=%d,"
+ "@@session.collation_server=%d"
+ "%s\n",
+ uint2korr(charset),
+ uint2korr(charset+2),
+ uint2korr(charset+4),
+ print_event_info->delimiter))
+ goto err;
+ memcpy(print_event_info->charset, charset, 6);
+ print_event_info->charset_inited= 1;
+ }
+ if (time_zone_len)
+ {
+ if (memcmp(print_event_info->time_zone_str,
+ time_zone_str, time_zone_len+1))
+ {
+ if (my_b_printf(file,"SET @@session.time_zone='%s'%s\n",
+ time_zone_str, print_event_info->delimiter))
+ goto err;
+ memcpy(print_event_info->time_zone_str, time_zone_str, time_zone_len+1);
+ }
+ }
+ if (lc_time_names_number != print_event_info->lc_time_names_number)
+ {
+ if (my_b_printf(file, "SET @@session.lc_time_names=%d%s\n",
+ lc_time_names_number, print_event_info->delimiter))
+ goto err;
+ print_event_info->lc_time_names_number= lc_time_names_number;
+ }
+ if (charset_database_number != print_event_info->charset_database_number)
+ {
+ if (charset_database_number)
+ {
+ if (my_b_printf(file, "SET @@session.collation_database=%d%s\n",
+ charset_database_number, print_event_info->delimiter))
+ goto err;
+ }
+ else if (my_b_printf(file, "SET @@session.collation_database=DEFAULT%s\n",
+ print_event_info->delimiter))
+ goto err;
+ print_event_info->charset_database_number= charset_database_number;
+ }
+ return 0;
+
+err:
+ return 1;
+}
+
+
+bool Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file, 0, this);
+
+ /**
+ reduce the size of io cache so that the write function is called
+ for every call to my_b_write().
+ */
+ DBUG_EXECUTE_IF ("simulate_file_write_error",
+ {(&cache)->write_pos= (&cache)->write_end- 500;});
+ if (print_query_header(&cache, print_event_info))
+ goto err;
+ if (!is_flashback)
+ {
+ if (my_b_write(&cache, (uchar*) query, q_len) ||
+ my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
+ goto err;
+ }
+ else // is_flashback == 1
+ {
+ if (strcmp("BEGIN", query) == 0)
+ {
+ if (my_b_write(&cache, (uchar*) "COMMIT", 6) ||
+ my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
+ goto err;
+ }
+ else if (strcmp("COMMIT", query) == 0)
+ {
+ if (my_b_write(&cache, (uchar*) "BEGIN", 5) ||
+ my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
+ goto err;
+ }
+ }
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+bool Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ DBUG_ENTER("Start_log_event_v3::print");
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F);
+
+ if (!print_event_info->short_form)
+ {
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\tStart: binlog v %d, server v %s created ",
+ binlog_version, server_version) ||
+ print_timestamp(&cache))
+ goto err;
+ if (created)
+ if (my_b_printf(&cache," at startup"))
+ goto err;
+ if (my_b_printf(&cache, "\n"))
+ goto err;
+ if (flags & LOG_EVENT_BINLOG_IN_USE_F)
+ if (my_b_printf(&cache,
+ "# Warning: this binlog is either in use or was not "
+ "closed properly.\n"))
+ goto err;
+ }
+ if (!is_artificial_event() && created)
+ {
+#ifdef WHEN_WE_HAVE_THE_RESET_CONNECTION_SQL_COMMAND
+ /*
+ This is for mysqlbinlog: like in replication, we want to delete the stale
+ tmp files left by an unclean shutdown of mysqld (temporary tables)
+ and rollback unfinished transaction.
+ Probably this can be done with RESET CONNECTION (syntax to be defined).
+ */
+ if (my_b_printf(&cache,"RESET CONNECTION%s\n",
+ print_event_info->delimiter))
+ goto err;
+#else
+ if (my_b_printf(&cache,"ROLLBACK%s\n", print_event_info->delimiter))
+ goto err;
+#endif
+ }
+ if (temp_buf &&
+ print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER &&
+ !print_event_info->short_form)
+ {
+ /* BINLOG is matched with the delimiter below on the same level */
+ bool do_print_encoded=
+ print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS;
+ if (do_print_encoded)
+ my_b_printf(&cache, "BINLOG '\n");
+
+ if (print_base64(&cache, print_event_info, do_print_encoded))
+ goto err;
+
+ if (do_print_encoded)
+ my_b_printf(&cache, "'%s\n", print_event_info->delimiter);
+
+ print_event_info->printed_fd_event= TRUE;
+ }
+ DBUG_RETURN(cache.flush_data());
+err:
+ DBUG_RETURN(1);
+}
+
+
+bool Start_encryption_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file);
+ StringBuffer<1024> buf;
+ buf.append(STRING_WITH_LEN("# Encryption scheme: "));
+ buf.append_ulonglong(crypto_scheme);
+ buf.append(STRING_WITH_LEN(", key_version: "));
+ buf.append_ulonglong(key_version);
+ buf.append(STRING_WITH_LEN(", nonce: "));
+ buf.append_hex(nonce, BINLOG_NONCE_LENGTH);
+ buf.append(STRING_WITH_LEN("\n# The rest of the binlog is encrypted!\n"));
+ if (my_b_write(&cache, (uchar*)buf.ptr(), buf.length()))
+ return 1;
+ return (cache.flush_data());
+}
+
+
+bool Load_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ return print(file, print_event_info, 0);
+}
+
+
+bool Load_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info,
+ bool commented)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file_arg);
+ bool different_db= 1;
+ DBUG_ENTER("Load_log_event::print");
+
+ if (!print_event_info->short_form)
+ {
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\tQuery\tthread_id=%ld\texec_time=%ld\n",
+ thread_id, exec_time))
+ goto err;
+ }
+
+ if (db)
+ {
+ /*
+ If the database is different from the one of the previous statement, we
+ need to print the "use" command, and we update the last_db.
+ But if commented, the "use" is going to be commented so we should not
+ update the last_db.
+ */
+ if ((different_db= memcmp(print_event_info->db, db, db_len + 1)) &&
+ !commented)
+ memcpy(print_event_info->db, db, db_len + 1);
+ }
+
+ if (db && db[0] && different_db)
+ if (my_b_printf(&cache, "%suse %`s%s\n",
+ commented ? "# " : "",
+ db, print_event_info->delimiter))
+ goto err;
+
+ if (flags & LOG_EVENT_THREAD_SPECIFIC_F)
+ if (my_b_printf(&cache,"%sSET @@session.pseudo_thread_id=%lu%s\n",
+ commented ? "# " : "", (ulong)thread_id,
+ print_event_info->delimiter))
+ goto err;
+ if (my_b_printf(&cache, "%sLOAD DATA ",
+ commented ? "# " : ""))
+ goto err;
+ if (check_fname_outside_temp_buf())
+ if (my_b_write_string(&cache, "LOCAL "))
+ goto err;
+ if (my_b_printf(&cache, "INFILE '%-*s' ", fname_len, fname))
+ goto err;
+
+ if (sql_ex.opt_flags & REPLACE_FLAG)
+ {
+ if (my_b_write_string(&cache, "REPLACE "))
+ goto err;
+ }
+ else if (sql_ex.opt_flags & IGNORE_FLAG)
+ if (my_b_write_string(&cache, "IGNORE "))
+ goto err;
+
+ if (my_b_printf(&cache, "INTO TABLE `%s`", table_name) ||
+ my_b_write_string(&cache, " FIELDS TERMINATED BY ") ||
+ pretty_print_str(&cache, sql_ex.field_term, sql_ex.field_term_len))
+ goto err;
+
+ if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG)
+ if (my_b_write_string(&cache, " OPTIONALLY "))
+ goto err;
+ if (my_b_write_string(&cache, " ENCLOSED BY ") ||
+ pretty_print_str(&cache, sql_ex.enclosed, sql_ex.enclosed_len) ||
+ my_b_write_string(&cache, " ESCAPED BY ") ||
+ pretty_print_str(&cache, sql_ex.escaped, sql_ex.escaped_len) ||
+ my_b_write_string(&cache, " LINES TERMINATED BY ") ||
+ pretty_print_str(&cache, sql_ex.line_term, sql_ex.line_term_len))
+ goto err;
+
+ if (sql_ex.line_start)
+ {
+ if (my_b_write_string(&cache," STARTING BY ") ||
+ pretty_print_str(&cache, sql_ex.line_start, sql_ex.line_start_len))
+ goto err;
+ }
+ if ((long) skip_lines > 0)
+ if (my_b_printf(&cache, " IGNORE %ld LINES", (long) skip_lines))
+ goto err;
+
+ if (num_fields)
+ {
+ uint i;
+ const char* field = fields;
+ if (my_b_write_string(&cache, " ("))
+ goto err;
+ for (i = 0; i < num_fields; i++)
+ {
+ if (i)
+ if (my_b_write_byte(&cache, ','))
+ goto err;
+ if (my_b_printf(&cache, "%`s", field))
+ goto err;
+ field += field_lens[i] + 1;
+ }
+ if (my_b_write_byte(&cache, ')'))
+ goto err;
+ }
+
+ if (my_b_printf(&cache, "%s\n", print_event_info->delimiter))
+ goto err;
+ DBUG_RETURN(cache.flush_data());
+err:
+ DBUG_RETURN(1);
+}
+
+
+bool Rotate_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ char buf[22];
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F);
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tRotate to "))
+ goto err;
+ if (new_log_ident)
+ if (my_b_write(&cache, (uchar*) new_log_ident, (uint)ident_len))
+ goto err;
+ if (my_b_printf(&cache, " pos: %s\n", llstr(pos, buf)))
+ goto err;
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+bool Binlog_checkpoint_log_event::print(FILE *file,
+ PRINT_EVENT_INFO *print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F);
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tBinlog checkpoint ") ||
+ my_b_write(&cache, (uchar*)binlog_file_name, binlog_file_len) ||
+ my_b_write_byte(&cache, '\n'))
+ return 1;
+ return cache.flush_data();
+}
+
+
+bool
+Gtid_list_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F);
+ char buf[21];
+ uint32 i;
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\tGtid list ["))
+ goto err;
+
+ for (i= 0; i < count; ++i)
+ {
+ longlong10_to_str(list[i].seq_no, buf, 10);
+ if (my_b_printf(&cache, "%u-%u-%s", list[i].domain_id,
+ list[i].server_id, buf))
+ goto err;
+ if (i < count-1)
+ if (my_b_printf(&cache, ",\n# "))
+ goto err;
+ }
+ if (my_b_printf(&cache, "]\n"))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+bool Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ char llbuff[22];
+ const char *UNINIT_VAR(msg);
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F);
+
+ if (!print_event_info->short_form)
+ {
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tIntvar\n"))
+ goto err;
+ }
+
+ if (my_b_printf(&cache, "SET "))
+ goto err;
+ switch (type) {
+ case LAST_INSERT_ID_EVENT:
+ msg="LAST_INSERT_ID";
+ break;
+ case INSERT_ID_EVENT:
+ msg="INSERT_ID";
+ break;
+ case INVALID_INT_EVENT:
+ default: // cannot happen
+ msg="INVALID_INT";
+ break;
+ }
+ if (my_b_printf(&cache, "%s=%s%s\n",
+ msg, llstr(val,llbuff), print_event_info->delimiter))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+bool Rand_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F);
+
+ char llbuff[22],llbuff2[22];
+ if (!print_event_info->short_form)
+ {
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tRand\n"))
+ goto err;
+ }
+ if (my_b_printf(&cache, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s%s\n",
+ llstr(seed1, llbuff),llstr(seed2, llbuff2),
+ print_event_info->delimiter))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+bool Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F, this);
+
+ if (!print_event_info->short_form)
+ {
+ char buf[64];
+ longlong10_to_str(xid, buf, 10);
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\tXid = %s\n", buf))
+ goto err;
+ }
+ if (my_b_printf(&cache, is_flashback ? "BEGIN%s\n" : "COMMIT%s\n",
+ print_event_info->delimiter))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+bool User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F);
+
+ if (!print_event_info->short_form)
+ {
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tUser_var\n"))
+ goto err;
+ }
+
+ if (my_b_write_string(&cache, "SET @") ||
+ my_b_write_backtick_quote(&cache, name, name_len))
+ goto err;
+
+ if (is_null)
+ {
+ if (my_b_printf(&cache, ":=NULL%s\n", print_event_info->delimiter))
+ goto err;
+ }
+ else
+ {
+ switch (type) {
+ case REAL_RESULT:
+ double real_val;
+ char real_buf[FMT_G_BUFSIZE(14)];
+ float8get(real_val, val);
+ sprintf(real_buf, "%.14g", real_val);
+ if (my_b_printf(&cache, ":=%s%s\n", real_buf,
+ print_event_info->delimiter))
+ goto err;
+ break;
+ case INT_RESULT:
+ char int_buf[22];
+ longlong10_to_str(uint8korr(val), int_buf,
+ ((flags & User_var_log_event::UNSIGNED_F) ? 10 : -10));
+ if (my_b_printf(&cache, ":=%s%s\n", int_buf,
+ print_event_info->delimiter))
+ goto err;
+ break;
+ case DECIMAL_RESULT:
+ {
+ char str_buf[200];
+ int str_len= sizeof(str_buf) - 1;
+ int precision= (int)val[0];
+ int scale= (int)val[1];
+ decimal_digit_t dec_buf[10];
+ decimal_t dec;
+ dec.len= 10;
+ dec.buf= dec_buf;
+
+ bin2decimal((uchar*) val+2, &dec, precision, scale);
+ decimal2string(&dec, str_buf, &str_len, 0, 0, 0);
+ str_buf[str_len]= 0;
+ if (my_b_printf(&cache, ":=%s%s\n", str_buf,
+ print_event_info->delimiter))
+ goto err;
+ break;
+ }
+ case STRING_RESULT:
+ {
+ /*
+ Let's express the string in hex. That's the most robust way. If we
+ print it in character form instead, we need to escape it with
+ character_set_client which we don't know (we will know it in 5.0, but
+ in 4.1 we don't know it easily when we are printing
+ User_var_log_event). Explanation why we would need to bother with
+ character_set_client (quoting Bar):
+ > Note, the parser doesn't switch to another unescaping mode after
+ > it has met a character set introducer.
+ > For example, if an SJIS client says something like:
+ > SET @a= _ucs2 \0a\0b'
+ > the string constant is still unescaped according to SJIS, not
+ > according to UCS2.
+ */
+ char *hex_str;
+ CHARSET_INFO *cs;
+ bool error;
+
+ // 2 hex digits / byte
+ hex_str= (char *) my_malloc(PSI_NOT_INSTRUMENTED, 2 * val_len + 1 + 3, MYF(MY_WME));
+ if (!hex_str)
+ goto err;
+ str_to_hex(hex_str, val, val_len);
+ /*
+ For proper behaviour when mysqlbinlog|mysql, we need to explicitly
+ specify the variable's collation. It will however cause problems when
+ people want to mysqlbinlog|mysql into another server not supporting the
+ character set. But there's not much to do about this and it's unlikely.
+ */
+ if (!(cs= get_charset(charset_number, MYF(0))))
+ { /*
+ Generate an unusable command (=> syntax error) is probably the best
+ thing we can do here.
+ */
+ error= my_b_printf(&cache, ":=???%s\n", print_event_info->delimiter);
+ }
+ else
+ error= my_b_printf(&cache, ":=_%s %s COLLATE `%s`%s\n",
+ cs->csname, hex_str, cs->name,
+ print_event_info->delimiter);
+ my_free(hex_str);
+ if (unlikely(error))
+ goto err;
+ break;
+ }
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ break;
+ }
+ }
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+#ifdef HAVE_REPLICATION
+
+bool Unknown_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file_arg);
+
+ if (what != ENCRYPTED)
+ {
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\n# Unknown event\n"))
+ goto err;
+ }
+ else if (my_b_printf(&cache, "# Encrypted event\n"))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+bool Stop_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F, this);
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tStop\n"))
+ return 1;
+ return cache.flush_data();
+}
+
+#endif
+
+
+bool Create_file_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info,
+ bool enable_local)
+{
+ if (print_event_info->short_form)
+ {
+ if (enable_local && check_fname_outside_temp_buf())
+ return Load_log_event::print(file, print_event_info);
+ return 0;
+ }
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file);
+
+ if (enable_local)
+ {
+ if (Load_log_event::print(file, print_event_info,
+ !check_fname_outside_temp_buf()))
+ goto err;
+
+ /**
+ reduce the size of io cache so that the write function is called
+ for every call to my_b_printf().
+ */
+ DBUG_EXECUTE_IF ("simulate_create_event_write_error",
+ {(&cache)->write_pos= (&cache)->write_end;
+ DBUG_SET("+d,simulate_file_write_error");});
+ /*
+ That one is for "file_id: etc" below: in mysqlbinlog we want the #, in
+ SHOW BINLOG EVENTS we don't.
+ */
+ if (my_b_write_byte(&cache, '#'))
+ goto err;
+ }
+
+ if (my_b_printf(&cache, " file_id: %d block_len: %d\n", file_id, block_len))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
+
+}
+
+
+bool Create_file_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ return print(file, print_event_info, 0);
+}
+
+
+/*
+ Append_block_log_event::print()
+*/
+
+bool Append_block_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file);
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\n#%s: file_id: %d block_len: %d\n",
+ get_type_str(), file_id, block_len))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+/*
+ Delete_file_log_event::print()
+*/
+
+bool Delete_file_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file);
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\n#Delete_file: file_id=%u\n", file_id))
+ return 1;
+
+ return cache.flush_data();
+}
+
+/*
+ Execute_load_log_event::print()
+*/
+
+bool Execute_load_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file);
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\n#Exec_load: file_id=%d\n",
+ file_id))
+ return 1;
+
+ return cache.flush_data();
+}
+
+bool Execute_load_query_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ return print(file, print_event_info, 0);
+}
+
+/**
+ Prints the query as LOAD DATA LOCAL and with rewritten filename.
+*/
+bool Execute_load_query_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info,
+ const char *local_fname)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file);
+
+ if (print_query_header(&cache, print_event_info))
+ goto err;
+
+ /**
+ reduce the size of io cache so that the write function is called
+ for every call to my_b_printf().
+ */
+ DBUG_EXECUTE_IF ("simulate_execute_event_write_error",
+ {(&cache)->write_pos= (&cache)->write_end;
+ DBUG_SET("+d,simulate_file_write_error");});
+
+ if (local_fname)
+ {
+ if (my_b_write(&cache, (uchar*) query, fn_pos_start) ||
+ my_b_write_string(&cache, " LOCAL INFILE ") ||
+ pretty_print_str(&cache, local_fname, (int)strlen(local_fname)))
+ goto err;
+
+ if (dup_handling == LOAD_DUP_REPLACE)
+ if (my_b_write_string(&cache, " REPLACE"))
+ goto err;
+
+ if (my_b_write_string(&cache, " INTO") ||
+ my_b_write(&cache, (uchar*) query + fn_pos_end, q_len-fn_pos_end) ||
+ my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
+ goto err;
+ }
+ else
+ {
+ if (my_b_write(&cache, (uchar*) query, q_len) ||
+ my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
+ goto err;
+ }
+
+ if (!print_event_info->short_form)
+ my_b_printf(&cache, "# file_id: %d \n", file_id);
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+
+const char str_binlog[]= "\nBINLOG '\n";
+const char fmt_delim[]= "'%s\n";
+const char fmt_n_delim[]= "\n'%s";
+const char fmt_frag[]= "\nSET @binlog_fragment_%d ='\n";
+const char fmt_binlog2[]= "BINLOG @binlog_fragment_0, @binlog_fragment_1%s\n";
+
+/**
+ Print an event "body" cache to @c file possibly in two fragments.
+ Each fragement is optionally per @c do_wrap to produce an SQL statement.
+
+ @param file a file to print to
+ @param body the "body" IO_CACHE of event
+ @param do_wrap whether to wrap base64-encoded strings with
+ SQL cover.
+ @param delimiter delimiter string
+
+ @param is_verbose MDEV-10362 workraround parameter to pass
+ info on presence of verbose printout in cache encoded data
+
+ The function signals on any error through setting @c body->error to -1.
+*/
+bool copy_cache_to_file_wrapped(IO_CACHE *body,
+ FILE *file,
+ bool do_wrap,
+ const char *delimiter,
+ bool is_verbose)
+{
+ const my_off_t cache_size= my_b_tell(body);
+
+ if (reinit_io_cache(body, READ_CACHE, 0L, FALSE, FALSE))
+ goto err;
+
+ if (!do_wrap)
+ {
+ my_b_copy_to_file(body, file, SIZE_T_MAX);
+ }
+ else if (4 + sizeof(str_binlog) + cache_size + sizeof(fmt_delim) >
+ opt_binlog_rows_event_max_encoded_size)
+ {
+ /*
+ 2 fragments can always represent near 1GB row-based
+ base64-encoded event as two strings each of size less than
+ max(max_allowed_packet). Greater number of fragments does not
+ save from potential need to tweak (increase) @@max_allowed_packet
+ before to process the fragments. So 2 is safe and enough.
+
+ Split the big query when its packet size's estimation exceeds a
+ limit. The estimate includes the maximum packet header
+ contribution of non-compressed packet.
+ */
+ my_fprintf(file, fmt_frag, 0);
+ if (my_b_copy_to_file(body, file, (size_t) cache_size/2 + 1))
+ goto err;
+ my_fprintf(file, fmt_n_delim, delimiter);
+
+ my_fprintf(file, fmt_frag, 1);
+ if (my_b_copy_to_file(body, file, SIZE_T_MAX))
+ goto err;
+ if (!is_verbose)
+ my_fprintf(file, fmt_delim, delimiter);
+
+ my_fprintf(file, fmt_binlog2, delimiter);
+ }
+ else
+ {
+ my_fprintf(file, str_binlog);
+ if (my_b_copy_to_file(body, file, SIZE_T_MAX))
+ goto err;
+ if (!is_verbose)
+ my_fprintf(file, fmt_delim, delimiter);
+ }
+ reinit_io_cache(body, WRITE_CACHE, 0, FALSE, TRUE);
+
+ return false;
+
+err:
+ body->error = -1;
+ return true;
+}
+
+
+/**
+ Print an event "body" cache to @c file possibly in two fragments.
+ Each fragement is optionally per @c do_wrap to produce an SQL statement.
+
+ @param file a file to print to
+ @param body the "body" IO_CACHE of event
+ @param do_wrap whether to wrap base64-encoded strings with
+ SQL cover.
+ @param delimiter delimiter string
+
+ The function signals on any error through setting @c body->error to -1.
+*/
+bool copy_cache_to_string_wrapped(IO_CACHE *cache,
+ LEX_STRING *to,
+ bool do_wrap,
+ const char *delimiter,
+ bool is_verbose)
+{
+ const my_off_t cache_size= my_b_tell(cache);
+ // contribution to total size estimate of formating
+ const size_t fmt_size=
+ sizeof(str_binlog) + 2*(sizeof(fmt_frag) + 2 /* %d */) +
+ sizeof(fmt_delim) + sizeof(fmt_n_delim) +
+ sizeof(fmt_binlog2) +
+ 3*PRINT_EVENT_INFO::max_delimiter_size;
+
+ if (reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE))
+ goto err;
+
+ if (!(to->str= (char*) my_malloc(PSI_NOT_INSTRUMENTED, (size_t)cache->end_of_file + fmt_size,
+ MYF(0))))
+ {
+ perror("Out of memory: can't allocate memory in "
+ "copy_cache_to_string_wrapped().");
+ goto err;
+ }
+
+ if (!do_wrap)
+ {
+ if (my_b_read(cache, (uchar*) to->str,
+ (to->length= (size_t)cache->end_of_file)))
+ goto err;
+ }
+ else if (4 + sizeof(str_binlog) + cache_size + sizeof(fmt_delim) >
+ opt_binlog_rows_event_max_encoded_size)
+ {
+ /*
+ 2 fragments can always represent near 1GB row-based
+ base64-encoded event as two strings each of size less than
+ max(max_allowed_packet). Greater number of fragments does not
+ save from potential need to tweak (increase) @@max_allowed_packet
+ before to process the fragments. So 2 is safe and enough.
+
+ Split the big query when its packet size's estimation exceeds a
+ limit. The estimate includes the maximum packet header
+ contribution of non-compressed packet.
+ */
+ char *str= to->str;
+ size_t add_to_len;
+
+ str += (to->length= sprintf(str, fmt_frag, 0));
+ if (my_b_read(cache, (uchar*) str, (uint32) (cache_size/2 + 1)))
+ goto err;
+ str += (add_to_len = (uint32) (cache_size/2 + 1));
+ to->length += add_to_len;
+ str += (add_to_len= sprintf(str, fmt_n_delim, delimiter));
+ to->length += add_to_len;
+
+ str += (add_to_len= sprintf(str, fmt_frag, 1));
+ to->length += add_to_len;
+ if (my_b_read(cache, (uchar*) str, uint32(cache->end_of_file - (cache_size/2 + 1))))
+ goto err;
+ str += (add_to_len= uint32(cache->end_of_file - (cache_size/2 + 1)));
+ to->length += add_to_len;
+ if (!is_verbose)
+ {
+ str += (add_to_len= sprintf(str , fmt_delim, delimiter));
+ to->length += add_to_len;
+ }
+ to->length += sprintf(str, fmt_binlog2, delimiter);
+ }
+ else
+ {
+ char *str= to->str;
+
+ str += (to->length= sprintf(str, str_binlog));
+ if (my_b_read(cache, (uchar*) str, (size_t)cache->end_of_file))
+ goto err;
+ str += cache->end_of_file;
+ to->length += (size_t)cache->end_of_file;
+ if (!is_verbose)
+ to->length += sprintf(str , fmt_delim, delimiter);
+ }
+
+ reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE);
+
+ return false;
+
+err:
+ cache->error= -1;
+ return true;
+}
+
+/**
+ The function invokes base64 encoder to run on the current
+ event string and store the result into two caches.
+ When the event ends the current statement the caches are is copied into
+ the argument file.
+ Copying is also concerned how to wrap the event, specifically to produce
+ a valid SQL syntax.
+ When the encoded data size is within max(MAX_ALLOWED_PACKET)
+ a regular BINLOG query is composed. Otherwise it is build as fragmented
+
+ SET @binlog_fragment_0='...';
+ SET @binlog_fragment_1='...';
+ BINLOG @binlog_fragment_0, @binlog_fragment_1;
+
+ where fragments are represented by a pair of indexed user
+ "one shot" variables.
+
+ @note
+ If any changes made don't forget to duplicate them to
+ Old_rows_log_event as long as it's supported.
+
+ @param file pointer to IO_CACHE
+ @param print_event_info pointer to print_event_info specializing
+ what out of and how to print the event
+ @param name the name of a table that the event operates on
+
+ The function signals on any error of cache access through setting
+ that cache's @c error to -1.
+*/
+bool Rows_log_event::print_helper(FILE *file,
+ PRINT_EVENT_INFO *print_event_info,
+ char const *const name)
+{
+ IO_CACHE *const head= &print_event_info->head_cache;
+ IO_CACHE *const body= &print_event_info->body_cache;
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ IO_CACHE *const sql= &print_event_info->review_sql_cache;
+#endif
+ bool do_print_encoded=
+ print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER &&
+ print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS &&
+ !print_event_info->short_form;
+ bool const last_stmt_event= get_flags(STMT_END_F);
+
+ if (!print_event_info->short_form)
+ {
+ char llbuff[22];
+
+ print_header(head, print_event_info, !last_stmt_event);
+ if (my_b_printf(head, "\t%s: table id %s%s\n",
+ name, ullstr(m_table_id, llbuff),
+ last_stmt_event ? " flags: STMT_END_F" : ""))
+ goto err;
+ }
+ if (!print_event_info->short_form || print_event_info->print_row_count)
+ if (print_base64(body, print_event_info, do_print_encoded))
+ goto err;
+
+ if (last_stmt_event)
+ {
+ if (!is_flashback)
+ {
+ if (copy_event_cache_to_file_and_reinit(head, file) ||
+ copy_cache_to_file_wrapped(body, file, do_print_encoded,
+ print_event_info->delimiter,
+ print_event_info->verbose))
+ goto err;
+ }
+ else
+ {
+ LEX_STRING tmp_str;
+
+ if (copy_event_cache_to_string_and_reinit(head, &tmp_str))
+ return 1;
+ output_buf.append(tmp_str.str, tmp_str.length); // Not \0 terminated);
+ my_free(tmp_str.str);
+
+ if (copy_cache_to_string_wrapped(body, &tmp_str, do_print_encoded,
+ print_event_info->delimiter,
+ print_event_info->verbose))
+ return 1;
+ output_buf.append(tmp_str.str, tmp_str.length);
+ my_free(tmp_str.str);
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ if (copy_event_cache_to_string_and_reinit(sql, &tmp_str))
+ return 1;
+ output_buf.append(tmp_str.str, tmp_str.length);
+ my_free(tmp_str.str);
+#endif
+ }
+ }
+
+ return 0;
+err:
+ return 1;
+}
+
+
+bool Annotate_rows_log_event::print(FILE *file, PRINT_EVENT_INFO *pinfo)
+{
+ char *pbeg; // beginning of the next line
+ char *pend; // end of the next line
+ uint cnt= 0; // characters counter
+
+ if (!pinfo->short_form)
+ {
+ if (print_header(&pinfo->head_cache, pinfo, TRUE) ||
+ my_b_printf(&pinfo->head_cache, "\tAnnotate_rows:\n"))
+ goto err;
+ }
+ else if (my_b_printf(&pinfo->head_cache, "# Annotate_rows:\n"))
+ goto err;
+
+ for (pbeg= m_query_txt; ; pbeg= pend)
+ {
+ // skip all \r's and \n's at the beginning of the next line
+ for (;; pbeg++)
+ {
+ if (++cnt > m_query_len)
+ return 0;
+
+ if (*pbeg != '\r' && *pbeg != '\n')
+ break;
+ }
+
+ // find end of the next line
+ for (pend= pbeg + 1;
+ ++cnt <= m_query_len && *pend != '\r' && *pend != '\n';
+ pend++)
+ ;
+
+ // print next line
+ if (my_b_write(&pinfo->head_cache, (const uchar*) "#Q> ", 4) ||
+ my_b_write(&pinfo->head_cache, (const uchar*) pbeg, pend - pbeg) ||
+ my_b_write(&pinfo->head_cache, (const uchar*) "\n", 1))
+ goto err;
+ }
+
+ return 0;
+err:
+ return 1;
+}
+
+
+/*
+ Rewrite database name for the event to name specified by new_db
+ SYNOPSIS
+ new_db Database name to change to
+ new_len Length
+ desc Event describing binlog that we're writing to.
+
+ DESCRIPTION
+ Reset db name. This function assumes that temp_buf member contains event
+ representation taken from a binary log. It resets m_dbnam and m_dblen and
+ rewrites temp_buf with new db name.
+
+ RETURN
+ 0 - Success
+ other - Error
+*/
+
+int Table_map_log_event::rewrite_db(const char* new_db, size_t new_len,
+ const Format_description_log_event* desc)
+{
+ DBUG_ENTER("Table_map_log_event::rewrite_db");
+ DBUG_ASSERT(temp_buf);
+
+ uint header_len= MY_MIN(desc->common_header_len,
+ LOG_EVENT_MINIMAL_HEADER_LEN) + TABLE_MAP_HEADER_LEN;
+ int len_diff;
+
+ if (!(len_diff= (int)(new_len - m_dblen)))
+ {
+ memcpy((void*) (temp_buf + header_len + 1), new_db, m_dblen + 1);
+ memcpy((void*) m_dbnam, new_db, m_dblen + 1);
+ DBUG_RETURN(0);
+ }
+
+ // Create new temp_buf
+ ulong event_cur_len= uint4korr(temp_buf + EVENT_LEN_OFFSET);
+ ulong event_new_len= event_cur_len + len_diff;
+ char* new_temp_buf= (char*) my_malloc(PSI_NOT_INSTRUMENTED, event_new_len, MYF(MY_WME));
+
+ if (!new_temp_buf)
+ {
+ sql_print_error("Table_map_log_event::rewrite_db: "
+ "failed to allocate new temp_buf (%d bytes required)",
+ event_new_len);
+ DBUG_RETURN(-1);
+ }
+
+ // Rewrite temp_buf
+ char* ptr= new_temp_buf;
+ size_t cnt= 0;
+
+ // Copy header and change event length
+ memcpy(ptr, temp_buf, header_len);
+ int4store(ptr + EVENT_LEN_OFFSET, event_new_len);
+ ptr += header_len;
+ cnt += header_len;
+
+ // Write new db name length and new name
+ DBUG_ASSERT(new_len < 0xff);
+ *ptr++ = (char)new_len;
+ memcpy(ptr, new_db, new_len + 1);
+ ptr += new_len + 1;
+ cnt += m_dblen + 2;
+
+ // Copy rest part
+ memcpy(ptr, temp_buf + cnt, event_cur_len - cnt);
+
+ // Reregister temp buf
+ free_temp_buf();
+ register_temp_buf(new_temp_buf, TRUE);
+
+ // Reset m_dbnam and m_dblen members
+ m_dblen= new_len;
+
+ // m_dbnam resides in m_memory together with m_tblnam and m_coltype
+ uchar* memory= m_memory;
+ char const* tblnam= m_tblnam;
+ uchar* coltype= m_coltype;
+
+ m_memory= (uchar*) my_multi_malloc(PSI_NOT_INSTRUMENTED, MYF(MY_WME),
+ &m_dbnam, (uint) m_dblen + 1,
+ &m_tblnam, (uint) m_tbllen + 1,
+ &m_coltype, (uint) m_colcnt,
+ NullS);
+
+ if (!m_memory)
+ {
+ sql_print_error("Table_map_log_event::rewrite_db: "
+ "failed to allocate new m_memory (%d + %d + %d bytes required)",
+ m_dblen + 1, m_tbllen + 1, m_colcnt);
+ DBUG_RETURN(-1);
+ }
+
+ memcpy((void*)m_dbnam, new_db, m_dblen + 1);
+ memcpy((void*)m_tblnam, tblnam, m_tbllen + 1);
+ memcpy(m_coltype, coltype, m_colcnt);
+
+ my_free(memory);
+ DBUG_RETURN(0);
+}
+
+
+bool Table_map_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
+{
+ if (!print_event_info->short_form)
+ {
+ char llbuff[22];
+
+ print_header(&print_event_info->head_cache, print_event_info, TRUE);
+ if (my_b_printf(&print_event_info->head_cache,
+ "\tTable_map: %`s.%`s mapped to number %s%s\n",
+ m_dbnam, m_tblnam, ullstr(m_table_id, llbuff),
+ ((m_flags & TM_BIT_HAS_TRIGGERS_F) ?
+ " (has triggers)" : "")))
+ goto err;
+ }
+ if (!print_event_info->short_form || print_event_info->print_row_count)
+ {
+
+ if (print_event_info->print_table_metadata)
+ {
+ Optional_metadata_fields fields(m_optional_metadata,
+ m_optional_metadata_len);
+
+ print_columns(&print_event_info->head_cache, fields);
+ print_primary_key(&print_event_info->head_cache, fields);
+ }
+ bool do_print_encoded=
+ print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER &&
+ print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS &&
+ !print_event_info->short_form;
+
+ if (print_base64(&print_event_info->body_cache, print_event_info,
+ do_print_encoded) ||
+ copy_event_cache_to_file_and_reinit(&print_event_info->head_cache,
+ file))
+ goto err;
+ }
+
+ return 0;
+err:
+ return 1;
+}
+
+/**
+ Interface for iterator over charset columns.
+*/
+class Table_map_log_event::Charset_iterator
+{
+ public:
+ typedef Table_map_log_event::Optional_metadata_fields::Default_charset
+ Default_charset;
+ virtual const CHARSET_INFO *next()= 0;
+ virtual ~Charset_iterator(){};
+ /**
+ Factory method to create an instance of the appropriate subclass.
+ */
+ static std::unique_ptr<Charset_iterator> create_charset_iterator(
+ const Default_charset &default_charset,
+ const std::vector<uint> &column_charset);
+};
+
+/**
+ Implementation of charset iterator for the DEFAULT_CHARSET type.
+*/
+class Table_map_log_event::Default_charset_iterator : public Charset_iterator
+{
+ public:
+ Default_charset_iterator(const Default_charset &default_charset)
+ : m_iterator(default_charset.charset_pairs.begin()),
+ m_end(default_charset.charset_pairs.end()),
+ m_column_index(0),
+ m_default_charset_info(
+ get_charset(default_charset.default_charset, 0)) {}
+
+ const CHARSET_INFO *next() override {
+ const CHARSET_INFO *ret;
+ if (m_iterator != m_end && m_iterator->first == m_column_index) {
+ ret = get_charset(m_iterator->second, 0);
+ m_iterator++;
+ } else
+ ret = m_default_charset_info;
+ m_column_index++;
+ return ret;
+ }
+ ~Default_charset_iterator(){};
+
+ private:
+ std::vector<Optional_metadata_fields::uint_pair>::const_iterator m_iterator,
+ m_end;
+ uint m_column_index;
+ const CHARSET_INFO *m_default_charset_info;
+};
+//Table_map_log_event::Default_charset_iterator::~Default_charset_iterator(){int a=8;a++; a--;};
+/**
+ Implementation of charset iterator for the COLUMNT_CHARSET type.
+*/
+class Table_map_log_event::Column_charset_iterator : public Charset_iterator
+{
+ public:
+ Column_charset_iterator(const std::vector<uint> &column_charset)
+ : m_iterator(column_charset.begin()), m_end(column_charset.end()) {}
+
+ const CHARSET_INFO *next() override {
+ const CHARSET_INFO *ret = nullptr;
+ if (m_iterator != m_end) {
+ ret = get_charset(*m_iterator, 0);
+ m_iterator++;
+ }
+ return ret;
+ }
+
+ ~Column_charset_iterator(){};
+ private:
+ std::vector<uint>::const_iterator m_iterator;
+ std::vector<uint>::const_iterator m_end;
+};
+//Table_map_log_event::Column_charset_iterator::~Column_charset_iterator(){int a=8;a++; a--;};
+
+std::unique_ptr<Table_map_log_event::Charset_iterator>
+Table_map_log_event::Charset_iterator::create_charset_iterator(
+ const Default_charset &default_charset,
+ const std::vector<uint> &column_charset)
+{
+ if (!default_charset.empty())
+ return std::unique_ptr<Charset_iterator>(
+ new Default_charset_iterator(default_charset));
+ else
+ return std::unique_ptr<Charset_iterator>(
+ new Column_charset_iterator(column_charset));
+}
+/**
+ return the string name of a type.
+
+ @param[in] type type of a column
+ @param[in|out] meta_ptr the meta_ptr of the column. If the type doesn't have
+ metadata, it will not change meta_ptr, otherwise
+ meta_ptr will be moved to the end of the column's
+ metadat.
+ @param[in] cs charset of the column if it is a character column.
+ @param[out] typestr buffer to storing the string name of the type
+ @param[in] typestr_length length of typestr
+ @param[in] geometry_type internal geometry_type
+ */
+static void get_type_name(uint type, unsigned char** meta_ptr,
+ const CHARSET_INFO *cs, char *typestr,
+ uint typestr_length, unsigned int geometry_type)
+{
+ switch (type) {
+ case MYSQL_TYPE_LONG:
+ my_snprintf(typestr, typestr_length, "%s", "INT");
+ break;
+ case MYSQL_TYPE_TINY:
+ my_snprintf(typestr, typestr_length, "TINYINT");
+ break;
+ case MYSQL_TYPE_SHORT:
+ my_snprintf(typestr, typestr_length, "SMALLINT");
+ break;
+ case MYSQL_TYPE_INT24:
+ my_snprintf(typestr, typestr_length, "MEDIUMINT");
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ my_snprintf(typestr, typestr_length, "BIGINT");
+ break;
+ case MYSQL_TYPE_NEWDECIMAL:
+ my_snprintf(typestr, typestr_length, "DECIMAL(%d,%d)",
+ (*meta_ptr)[0], (*meta_ptr)[1]);
+ (*meta_ptr)+= 2;
+ break;
+ case MYSQL_TYPE_FLOAT:
+ my_snprintf(typestr, typestr_length, "FLOAT");
+ (*meta_ptr)++;
+ break;
+ case MYSQL_TYPE_DOUBLE:
+ my_snprintf(typestr, typestr_length, "DOUBLE");
+ (*meta_ptr)++;
+ break;
+ case MYSQL_TYPE_BIT:
+ my_snprintf(typestr, typestr_length, "BIT(%d)",
+ (((*meta_ptr)[0])) + (*meta_ptr)[1]*8);
+ (*meta_ptr)+= 2;
+ break;
+ case MYSQL_TYPE_TIMESTAMP2:
+ if (**meta_ptr != 0)
+ my_snprintf(typestr, typestr_length, "TIMESTAMP(%d)", **meta_ptr);
+ else
+ my_snprintf(typestr, typestr_length, "TIMESTAMP");
+ (*meta_ptr)++;
+ break;
+ case MYSQL_TYPE_DATETIME2:
+ if (**meta_ptr != 0)
+ my_snprintf(typestr, typestr_length, "DATETIME(%d)", **meta_ptr);
+ else
+ my_snprintf(typestr, typestr_length, "DATETIME");
+ (*meta_ptr)++;
+ break;
+ case MYSQL_TYPE_TIME2:
+ if (**meta_ptr != 0)
+ my_snprintf(typestr, typestr_length, "TIME(%d)", **meta_ptr);
+ else
+ my_snprintf(typestr, typestr_length, "TIME");
+ (*meta_ptr)++;
+ break;
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_DATE:
+ my_snprintf(typestr, typestr_length, "DATE");
+ break;
+ case MYSQL_TYPE_YEAR:
+ my_snprintf(typestr, typestr_length, "YEAR");
+ break;
+ case MYSQL_TYPE_ENUM:
+ my_snprintf(typestr, typestr_length, "ENUM");
+ (*meta_ptr)+= 2;
+ break;
+ case MYSQL_TYPE_SET:
+ my_snprintf(typestr, typestr_length, "SET");
+ (*meta_ptr)+= 2;
+ break;
+ case MYSQL_TYPE_BLOB:
+ {
+ bool is_text= (cs && cs->number != my_charset_bin.number);
+ const char *names[5][2] = {
+ {"INVALID_BLOB(%d)", "INVALID_TEXT(%d)"},
+ {"TINYBLOB", "TINYTEXT"},
+ {"BLOB", "TEXT"},
+ {"MEDIUMBLOB", "MEDIUMTEXT"},
+ {"LONGBLOB", "LONGTEXT"}
+ };
+ unsigned char size= **meta_ptr;
+
+ if (size == 0 || size > 4)
+ my_snprintf(typestr, typestr_length, names[0][is_text], size);
+ else
+ my_snprintf(typestr, typestr_length, names[**meta_ptr][is_text]);
+
+ (*meta_ptr)++;
+ }
+ break;
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ if (cs && cs->number != my_charset_bin.number)
+ my_snprintf(typestr, typestr_length, "VARCHAR(%d)",
+ uint2korr(*meta_ptr)/cs->mbmaxlen);
+ else
+ my_snprintf(typestr, typestr_length, "VARBINARY(%d)",
+ uint2korr(*meta_ptr));
+
+ (*meta_ptr)+= 2;
+ break;
+ case MYSQL_TYPE_STRING:
+ {
+ uint byte0= (*meta_ptr)[0];
+ uint byte1= (*meta_ptr)[1];
+ uint len= (((byte0 & 0x30) ^ 0x30) << 4) | byte1;
+
+ if (cs && cs->number != my_charset_bin.number)
+ my_snprintf(typestr, typestr_length, "CHAR(%d)", len/cs->mbmaxlen);
+ else
+ my_snprintf(typestr, typestr_length, "BINARY(%d)", len);
+
+ (*meta_ptr)+= 2;
+ }
+ break;
+ case MYSQL_TYPE_GEOMETRY:
+ {
+ const char* names[8] = {
+ "GEOMETRY", "POINT", "LINESTRING", "POLYGON", "MULTIPOINT",
+ "MULTILINESTRING", "MULTIPOLYGON", "GEOMETRYCOLLECTION"
+ };
+ if (geometry_type < 8)
+ my_snprintf(typestr, typestr_length, names[geometry_type]);
+ else
+ my_snprintf(typestr, typestr_length, "INVALID_GEOMETRY_TYPE(%u)",
+ geometry_type);
+ (*meta_ptr)++;
+ }
+ break;
+ default:
+ *typestr= 0;
+ break;
+ }
+}
+
+void Table_map_log_event::print_columns(IO_CACHE *file,
+ const Optional_metadata_fields &fields)
+{
+ unsigned char* field_metadata_ptr= m_field_metadata;
+ std::vector<bool>::const_iterator signedness_it= fields.m_signedness.begin();
+
+ std::unique_ptr<Charset_iterator> charset_it =
+ Charset_iterator::create_charset_iterator(fields.m_default_charset,
+ fields.m_column_charset);
+ std::unique_ptr<Charset_iterator> enum_and_set_charset_it =
+ Charset_iterator::create_charset_iterator(
+ fields.m_enum_and_set_default_charset,
+ fields.m_enum_and_set_column_charset);
+ std::vector<std::string>::const_iterator col_names_it=
+ fields.m_column_name.begin();
+ std::vector<Optional_metadata_fields::str_vector>::const_iterator
+ set_str_values_it= fields.m_set_str_value.begin();
+ std::vector<Optional_metadata_fields::str_vector>::const_iterator
+ enum_str_values_it= fields.m_enum_str_value.begin();
+ std::vector<unsigned int>::const_iterator geometry_type_it=
+ fields.m_geometry_type.begin();
+
+ uint geometry_type= 0;
+
+ my_b_printf(file, "# Columns(");
+
+ for (unsigned long i= 0; i < m_colcnt; i++)
+ {
+ uint real_type = m_coltype[i];
+ if (real_type == MYSQL_TYPE_STRING &&
+ (*field_metadata_ptr == MYSQL_TYPE_ENUM ||
+ *field_metadata_ptr == MYSQL_TYPE_SET))
+ real_type= *field_metadata_ptr;
+
+ // Get current column's collation id if it is a character, enum,
+ // or set column
+ const CHARSET_INFO *cs = NULL;
+ if (is_character_type(real_type))
+ cs = charset_it->next();
+ else if (is_enum_or_set_type(real_type))
+ cs = enum_and_set_charset_it->next();
+
+ // Print column name
+ if (col_names_it != fields.m_column_name.end())
+ {
+ pretty_print_identifier(file, col_names_it->c_str(), col_names_it->size());
+ my_b_printf(file, " ");
+ col_names_it++;
+ }
+
+
+ // update geometry_type for geometry columns
+ if (real_type == MYSQL_TYPE_GEOMETRY)
+ {
+ geometry_type= (geometry_type_it != fields.m_geometry_type.end()) ?
+ *geometry_type_it++ : 0;
+ }
+
+ // print column type
+ const uint TYPE_NAME_LEN = 100;
+ char type_name[TYPE_NAME_LEN];
+ get_type_name(real_type, &field_metadata_ptr, cs, type_name,
+ TYPE_NAME_LEN, geometry_type);
+
+ if (type_name[0] == '\0')
+ {
+ my_b_printf(file, "INVALID_TYPE(%d)", real_type);
+ continue;
+ }
+ my_b_printf(file, "%s", type_name);
+
+ // Print UNSIGNED for numeric column
+ if (is_numeric_type(real_type) &&
+ signedness_it != fields.m_signedness.end())
+ {
+ if (*signedness_it == true)
+ my_b_printf(file, " UNSIGNED");
+ signedness_it++;
+ }
+
+ // if the column is not marked as 'null', print 'not null'
+ if (!(m_null_bits[(i / 8)] & (1 << (i % 8))))
+ my_b_printf(file, " NOT NULL");
+
+ // Print string values of SET and ENUM column
+ const Optional_metadata_fields::str_vector *str_values= NULL;
+ if (real_type == MYSQL_TYPE_ENUM &&
+ enum_str_values_it != fields.m_enum_str_value.end())
+ {
+ str_values= &(*enum_str_values_it);
+ enum_str_values_it++;
+ }
+ else if (real_type == MYSQL_TYPE_SET &&
+ set_str_values_it != fields.m_set_str_value.end())
+ {
+ str_values= &(*set_str_values_it);
+ set_str_values_it++;
+ }
+
+ if (str_values != NULL)
+ {
+ const char *separator= "(";
+ for (Optional_metadata_fields::str_vector::const_iterator it=
+ str_values->begin(); it != str_values->end(); it++)
+ {
+ my_b_printf(file, "%s", separator);
+ pretty_print_str(file, it->c_str(), it->size());
+ separator= ",";
+ }
+ my_b_printf(file, ")");
+ }
+ // Print column character set, except in text columns with binary collation
+ if (cs != NULL &&
+ (is_enum_or_set_type(real_type) || cs->number != my_charset_bin.number))
+ my_b_printf(file, " CHARSET %s COLLATE %s", cs->csname, cs->name);
+ if (i != m_colcnt - 1) my_b_printf(file, ",\n# ");
+ }
+ my_b_printf(file, ")");
+ my_b_printf(file, "\n");
+}
+
+void Table_map_log_event::print_primary_key
+ (IO_CACHE *file,const Optional_metadata_fields &fields)
+{
+ if (!fields.m_primary_key.empty())
+ {
+ my_b_printf(file, "# Primary Key(");
+
+ std::vector<Optional_metadata_fields::uint_pair>::const_iterator it=
+ fields.m_primary_key.begin();
+
+ for (; it != fields.m_primary_key.end(); it++)
+ {
+ if (it != fields.m_primary_key.begin())
+ my_b_printf(file, ", ");
+
+ // Print column name or column index
+ if (it->first >= fields.m_column_name.size())
+ my_b_printf(file, "%u", it->first);
+ else
+ my_b_printf(file, "%s", fields.m_column_name[it->first].c_str());
+
+ // Print prefix length
+ if (it->second != 0)
+ my_b_printf(file, "(%u)", it->second);
+ }
+
+ my_b_printf(file, ")\n");
+ }
+}
+
+
+bool Write_rows_log_event::print(FILE *file, PRINT_EVENT_INFO* print_event_info)
+{
+ DBUG_EXECUTE_IF("simulate_cache_read_error",
+ {DBUG_SET("+d,simulate_my_b_fill_error");});
+ return Rows_log_event::print_helper(file, print_event_info, is_flashback ? "Delete_rows" : "Write_rows");
+}
+
+bool Write_rows_compressed_log_event::print(FILE *file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ char *new_buf;
+ ulong len;
+ bool is_malloc = false;
+ if(!row_log_event_uncompress(glob_description_event,
+ checksum_alg == BINLOG_CHECKSUM_ALG_CRC32,
+ temp_buf, UINT_MAX32, NULL, 0, &is_malloc, &new_buf, &len))
+ {
+ free_temp_buf();
+ register_temp_buf(new_buf, true);
+ if (Rows_log_event::print_helper(file, print_event_info,
+ "Write_compressed_rows"))
+ goto err;
+ }
+ else
+ {
+ if (my_b_printf(&print_event_info->head_cache,
+ "ERROR: uncompress write_compressed_rows failed\n"))
+ goto err;
+ }
+
+ return 0;
+err:
+ return 1;
+}
+
+
+bool Delete_rows_log_event::print(FILE *file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ return Rows_log_event::print_helper(file, print_event_info, is_flashback ? "Write_rows" : "Delete_rows");
+}
+
+
+bool Delete_rows_compressed_log_event::print(FILE *file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ char *new_buf;
+ ulong len;
+ bool is_malloc = false;
+ if(!row_log_event_uncompress(glob_description_event,
+ checksum_alg == BINLOG_CHECKSUM_ALG_CRC32,
+ temp_buf, UINT_MAX32, NULL, 0, &is_malloc, &new_buf, &len))
+ {
+ free_temp_buf();
+ register_temp_buf(new_buf, true);
+ if (Rows_log_event::print_helper(file, print_event_info,
+ "Delete_compressed_rows"))
+ goto err;
+ }
+ else
+ {
+ if (my_b_printf(&print_event_info->head_cache,
+ "ERROR: uncompress delete_compressed_rows failed\n"))
+ goto err;
+ }
+
+ return 0;
+err:
+ return 1;
+}
+
+
+bool Update_rows_log_event::print(FILE *file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ return Rows_log_event::print_helper(file, print_event_info, "Update_rows");
+}
+
+bool
+Update_rows_compressed_log_event::print(FILE *file,
+ PRINT_EVENT_INFO *print_event_info)
+{
+ char *new_buf;
+ ulong len;
+ bool is_malloc= false;
+ if(!row_log_event_uncompress(glob_description_event,
+ checksum_alg == BINLOG_CHECKSUM_ALG_CRC32,
+ temp_buf, UINT_MAX32, NULL, 0, &is_malloc, &new_buf, &len))
+ {
+ free_temp_buf();
+ register_temp_buf(new_buf, true);
+ if (Rows_log_event::print_helper(file, print_event_info,
+ "Update_compressed_rows"))
+ goto err;
+ }
+ else
+ {
+ if (my_b_printf(&print_event_info->head_cache,
+ "ERROR: uncompress update_compressed_rows failed\n"))
+ goto err;
+ }
+
+ return 0;
+err:
+ return 1;
+}
+
+
+bool Incident_log_event::print(FILE *file,
+ PRINT_EVENT_INFO *print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file);
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\n# Incident: %s\nRELOAD DATABASE; # Shall generate syntax error\n", description()))
+ return 1;
+ return cache.flush_data();
+}
+
+
+/* Print for its unrecognized ignorable event */
+bool Ignorable_log_event::print(FILE *file,
+ PRINT_EVENT_INFO *print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ if (print_header(&print_event_info->head_cache, print_event_info, FALSE) ||
+ my_b_printf(&print_event_info->head_cache, "\tIgnorable\n") ||
+ my_b_printf(&print_event_info->head_cache,
+ "# Ignorable event type %d (%s)\n", number, description) ||
+ copy_event_cache_to_file_and_reinit(&print_event_info->head_cache,
+ file))
+ return 1;
+ return 0;
+}
+
+
+/**
+ The default values for these variables should be values that are
+ *incorrect*, i.e., values that cannot occur in an event. This way,
+ they will always be printed for the first event.
+*/
+st_print_event_info::st_print_event_info()
+{
+ myf const flags = MYF(MY_WME | MY_NABP);
+ /*
+ Currently we only use static PRINT_EVENT_INFO objects, so zeroed at
+ program's startup, but these explicit bzero() is for the day someone
+ creates dynamic instances.
+ */
+ bzero(db, sizeof(db));
+ bzero(charset, sizeof(charset));
+ bzero(time_zone_str, sizeof(time_zone_str));
+ delimiter[0]= ';';
+ delimiter[1]= 0;
+ flags2_inited= 0;
+ sql_mode_inited= 0;
+ row_events= 0;
+ sql_mode= 0;
+ auto_increment_increment= 0;
+ auto_increment_offset= 0;
+ charset_inited= 0;
+ lc_time_names_number= ~0;
+ charset_database_number= ILLEGAL_CHARSET_INFO_NUMBER;
+ thread_id= 0;
+ server_id= 0;
+ domain_id= 0;
+ thread_id_printed= false;
+ server_id_printed= false;
+ domain_id_printed= false;
+ allow_parallel= true;
+ allow_parallel_printed= false;
+ found_row_event= false;
+ print_row_count= false;
+ short_form= false;
+ skip_replication= 0;
+ printed_fd_event=FALSE;
+ file= 0;
+ base64_output_mode=BASE64_OUTPUT_UNSPEC;
+ open_cached_file(&head_cache, NULL, NULL, 0, flags);
+ open_cached_file(&body_cache, NULL, NULL, 0, flags);
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ open_cached_file(&review_sql_cache, NULL, NULL, 0, flags);
+#endif
+}
+
+
+bool copy_event_cache_to_string_and_reinit(IO_CACHE *cache, LEX_STRING *to)
+{
+ reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE);
+ if (cache->end_of_file > SIZE_T_MAX ||
+ !(to->str= (char*) my_malloc(PSI_NOT_INSTRUMENTED, (to->length= (size_t)cache->end_of_file), MYF(0))))
+ {
+ perror("Out of memory: can't allocate memory in copy_event_cache_to_string_and_reinit().");
+ goto err;
+ }
+ if (my_b_read(cache, (uchar*) to->str, to->length))
+ {
+ my_free(to->str);
+ perror("Can't read data from IO_CACHE");
+ return true;
+ }
+ reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE);
+ return false;
+
+err:
+ to->str= 0;
+ to->length= 0;
+ return true;
+}
+
+
+bool
+Gtid_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F, this);
+ char buf[21];
+ char buf2[21];
+
+ if (!print_event_info->short_form && !is_flashback)
+ {
+ print_header(&cache, print_event_info, FALSE);
+ longlong10_to_str(seq_no, buf, 10);
+ if (my_b_printf(&cache, "\tGTID %u-%u-%s", domain_id, server_id, buf))
+ goto err;
+ if (flags2 & FL_GROUP_COMMIT_ID)
+ {
+ longlong10_to_str(commit_id, buf2, 10);
+ if (my_b_printf(&cache, " cid=%s", buf2))
+ goto err;
+ }
+ if (flags2 & FL_DDL)
+ if (my_b_write_string(&cache, " ddl"))
+ goto err;
+ if (flags2 & FL_TRANSACTIONAL)
+ if (my_b_write_string(&cache, " trans"))
+ goto err;
+ if (flags2 & FL_WAITED)
+ if (my_b_write_string(&cache, " waited"))
+ goto err;
+ if (my_b_printf(&cache, "\n"))
+ goto err;
+
+ if (!print_event_info->allow_parallel_printed ||
+ print_event_info->allow_parallel != !!(flags2 & FL_ALLOW_PARALLEL))
+ {
+ if (my_b_printf(&cache,
+ "/*!100101 SET @@session.skip_parallel_replication=%u*/%s\n",
+ !(flags2 & FL_ALLOW_PARALLEL),
+ print_event_info->delimiter))
+ goto err;
+ print_event_info->allow_parallel= !!(flags2 & FL_ALLOW_PARALLEL);
+ print_event_info->allow_parallel_printed= true;
+ }
+
+ if (!print_event_info->domain_id_printed ||
+ print_event_info->domain_id != domain_id)
+ {
+ if (my_b_printf(&cache,
+ "/*!100001 SET @@session.gtid_domain_id=%u*/%s\n",
+ domain_id, print_event_info->delimiter))
+ goto err;
+ print_event_info->domain_id= domain_id;
+ print_event_info->domain_id_printed= true;
+ }
+
+ if (!print_event_info->server_id_printed ||
+ print_event_info->server_id != server_id)
+ {
+ if (my_b_printf(&cache, "/*!100001 SET @@session.server_id=%u*/%s\n",
+ server_id, print_event_info->delimiter))
+ goto err;
+ print_event_info->server_id= server_id;
+ print_event_info->server_id_printed= true;
+ }
+
+ if (!is_flashback)
+ if (my_b_printf(&cache, "/*!100001 SET @@session.gtid_seq_no=%s*/%s\n",
+ buf, print_event_info->delimiter))
+ goto err;
+ }
+ if ((flags2 & FL_PREPARED_XA) && !is_flashback)
+ {
+ my_b_write_string(&cache, "XA START ");
+ xid.serialize();
+ my_b_write(&cache, (uchar*) xid.buf, strlen(xid.buf));
+ if (my_b_printf(&cache, "%s\n", print_event_info->delimiter))
+ goto err;
+ }
+ else if (!(flags2 & FL_STANDALONE))
+ {
+ if (my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : "BEGIN\n%s\n",
+ print_event_info->delimiter))
+ goto err;
+ }
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+bool XA_prepare_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F, this);
+ m_xid.serialize();
+
+ if (!print_event_info->short_form)
+ {
+ print_header(&cache, print_event_info, FALSE);
+ if (my_b_printf(&cache, "\tXID = %s\n", m_xid.buf))
+ goto error;
+ }
+
+ if (my_b_printf(&cache, "XA PREPARE %s\n%s\n",
+ m_xid.buf, print_event_info->delimiter))
+ goto error;
+
+ return cache.flush_data();
+error:
+ return TRUE;
+}
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index e01488abbb3..c6ccfc5a2c0 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -32,6 +32,8 @@
#include "rpl_record_old.h"
#include "transaction.h"
+PSI_memory_key key_memory_log_event_old;
+
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
// Old implementation of do_apply_event()
@@ -899,7 +901,7 @@ int Delete_rows_log_event_old::do_before_row_operations(TABLE *table)
if (table->s->keys > 0)
{
- m_memory= (uchar*) my_multi_malloc(MYF(MY_WME),
+ m_memory= (uchar*) my_multi_malloc(key_memory_log_event_old, MYF(MY_WME),
&m_after_image,
(uint) table->s->reclength,
&m_key,
@@ -908,7 +910,7 @@ int Delete_rows_log_event_old::do_before_row_operations(TABLE *table)
}
else
{
- m_after_image= (uchar*) my_malloc(table->s->reclength, MYF(MY_WME));
+ m_after_image= (uchar*) my_malloc(key_memory_log_event_old, table->s->reclength, MYF(MY_WME));
m_memory= (uchar*)m_after_image;
m_key= NULL;
}
@@ -997,7 +999,7 @@ int Update_rows_log_event_old::do_before_row_operations(TABLE *table)
if (table->s->keys > 0)
{
- m_memory= (uchar*) my_multi_malloc(MYF(MY_WME),
+ m_memory= (uchar*) my_multi_malloc(key_memory_log_event_old, MYF(MY_WME),
&m_after_image,
(uint) table->s->reclength,
&m_key,
@@ -1006,7 +1008,7 @@ int Update_rows_log_event_old::do_before_row_operations(TABLE *table)
}
else
{
- m_after_image= (uchar*) my_malloc(table->s->reclength, MYF(MY_WME));
+ m_after_image= (uchar*) my_malloc(key_memory_log_event_old, table->s->reclength, MYF(MY_WME));
m_memory= m_after_image;
m_key= NULL;
}
@@ -1252,7 +1254,7 @@ Old_rows_log_event::Old_rows_log_event(const char *buf, uint event_len,
m_table_id, m_flags, m_width, data_size));
DBUG_DUMP("rows_data", (uchar*) ptr_rows_data, data_size);
- m_rows_buf= (uchar*) my_malloc(data_size, MYF(MY_WME));
+ m_rows_buf= (uchar*) my_malloc(key_memory_log_event_old, data_size, MYF(MY_WME));
if (likely((bool)m_rows_buf))
{
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
@@ -1326,7 +1328,7 @@ int Old_rows_log_event::do_add_row_data(uchar *row_data, size_t length)
my_ptrdiff_t const new_alloc=
block_size * ((cur_size + length + block_size - 1) / block_size);
- uchar* const new_buf= (uchar*)my_realloc((uchar*)m_rows_buf, (uint) new_alloc,
+ uchar* const new_buf= (uchar*)my_realloc(key_memory_log_event_old, (uchar*)m_rows_buf, (uint) new_alloc,
MYF(MY_ALLOW_ZERO_PTR|MY_WME));
if (unlikely(!new_buf))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
@@ -2555,7 +2557,7 @@ Delete_rows_log_event_old::do_before_row_operations(const Slave_reporting_capabi
if (m_table->s->keys > 0)
{
// Allocate buffer for key searches
- m_key= (uchar*)my_malloc(m_table->key_info->key_length, MYF(MY_WME));
+ m_key= (uchar*)my_malloc(key_memory_log_event_old, m_table->key_info->key_length, MYF(MY_WME));
if (!m_key)
return HA_ERR_OUT_OF_MEM;
}
@@ -2653,7 +2655,7 @@ Update_rows_log_event_old::do_before_row_operations(const Slave_reporting_capabi
if (m_table->s->keys > 0)
{
// Allocate buffer for key searches
- m_key= (uchar*)my_malloc(m_table->key_info->key_length, MYF(MY_WME));
+ m_key= (uchar*)my_malloc(key_memory_log_event_old, m_table->key_info->key_length, MYF(MY_WME));
if (!m_key)
return HA_ERR_OUT_OF_MEM;
}
diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc
new file mode 100644
index 00000000000..f7156013069
--- /dev/null
+++ b/sql/log_event_server.cc
@@ -0,0 +1,8471 @@
+/*
+ Copyright (c) 2000, 2019, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2019, 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-1335 USA */
+
+
+#include "mariadb.h"
+#include "sql_priv.h"
+
+#ifdef MYSQL_CLIENT
+#error MYSQL_CLIENT must not be defined here
+#endif
+
+#ifndef MYSQL_SERVER
+#error MYSQL_SERVER must be defined here
+#endif
+
+#include "unireg.h"
+#include "log_event.h"
+#include "sql_base.h" // close_thread_tables
+#include "sql_cache.h" // QUERY_CACHE_FLAGS_SIZE
+#include "sql_locale.h" // MY_LOCALE, my_locale_by_number, my_locale_en_US
+#include "key.h" // key_copy
+#include "lock.h" // mysql_unlock_tables
+#include "sql_parse.h" // mysql_test_parse_for_slave
+#include "tztime.h" // struct Time_zone
+#include "sql_load.h" // mysql_load
+#include "sql_db.h" // load_db_opt_by_name
+#include "slave.h"
+#include "rpl_rli.h"
+#include "rpl_mi.h"
+#include "rpl_filter.h"
+#include "rpl_record.h"
+#include "transaction.h"
+#include <my_dir.h>
+#include "sql_show.h" // append_identifier
+#include "debug_sync.h" // debug_sync
+#include <mysql/psi/mysql_statement.h>
+#include <strfunc.h>
+#include "compat56.h"
+#include "wsrep_mysqld.h"
+#include "sql_insert.h"
+
+#include <my_bitmap.h>
+#include "rpl_utility.h"
+#include "rpl_constants.h"
+#include "sql_digest.h"
+#include "zlib.h"
+
+
+#define log_cs &my_charset_latin1
+
+
+#if defined(HAVE_REPLICATION)
+static int rows_event_stmt_cleanup(rpl_group_info *rgi, THD* thd);
+
+static const char *HA_ERR(int i)
+{
+ /*
+ This function should only be called in case of an error
+ was detected
+ */
+ DBUG_ASSERT(i != 0);
+ switch (i) {
+ case HA_ERR_KEY_NOT_FOUND: return "HA_ERR_KEY_NOT_FOUND";
+ case HA_ERR_FOUND_DUPP_KEY: return "HA_ERR_FOUND_DUPP_KEY";
+ case HA_ERR_RECORD_CHANGED: return "HA_ERR_RECORD_CHANGED";
+ case HA_ERR_WRONG_INDEX: return "HA_ERR_WRONG_INDEX";
+ case HA_ERR_CRASHED: return "HA_ERR_CRASHED";
+ case HA_ERR_WRONG_IN_RECORD: return "HA_ERR_WRONG_IN_RECORD";
+ case HA_ERR_OUT_OF_MEM: return "HA_ERR_OUT_OF_MEM";
+ case HA_ERR_NOT_A_TABLE: return "HA_ERR_NOT_A_TABLE";
+ case HA_ERR_WRONG_COMMAND: return "HA_ERR_WRONG_COMMAND";
+ case HA_ERR_OLD_FILE: return "HA_ERR_OLD_FILE";
+ case HA_ERR_NO_ACTIVE_RECORD: return "HA_ERR_NO_ACTIVE_RECORD";
+ case HA_ERR_RECORD_DELETED: return "HA_ERR_RECORD_DELETED";
+ case HA_ERR_RECORD_FILE_FULL: return "HA_ERR_RECORD_FILE_FULL";
+ case HA_ERR_INDEX_FILE_FULL: return "HA_ERR_INDEX_FILE_FULL";
+ case HA_ERR_END_OF_FILE: return "HA_ERR_END_OF_FILE";
+ case HA_ERR_UNSUPPORTED: return "HA_ERR_UNSUPPORTED";
+ case HA_ERR_TO_BIG_ROW: return "HA_ERR_TO_BIG_ROW";
+ case HA_WRONG_CREATE_OPTION: return "HA_WRONG_CREATE_OPTION";
+ case HA_ERR_FOUND_DUPP_UNIQUE: return "HA_ERR_FOUND_DUPP_UNIQUE";
+ case HA_ERR_UNKNOWN_CHARSET: return "HA_ERR_UNKNOWN_CHARSET";
+ case HA_ERR_WRONG_MRG_TABLE_DEF: return "HA_ERR_WRONG_MRG_TABLE_DEF";
+ case HA_ERR_CRASHED_ON_REPAIR: return "HA_ERR_CRASHED_ON_REPAIR";
+ case HA_ERR_CRASHED_ON_USAGE: return "HA_ERR_CRASHED_ON_USAGE";
+ case HA_ERR_LOCK_WAIT_TIMEOUT: return "HA_ERR_LOCK_WAIT_TIMEOUT";
+ case HA_ERR_LOCK_TABLE_FULL: return "HA_ERR_LOCK_TABLE_FULL";
+ case HA_ERR_READ_ONLY_TRANSACTION: return "HA_ERR_READ_ONLY_TRANSACTION";
+ case HA_ERR_LOCK_DEADLOCK: return "HA_ERR_LOCK_DEADLOCK";
+ case HA_ERR_CANNOT_ADD_FOREIGN: return "HA_ERR_CANNOT_ADD_FOREIGN";
+ case HA_ERR_NO_REFERENCED_ROW: return "HA_ERR_NO_REFERENCED_ROW";
+ case HA_ERR_ROW_IS_REFERENCED: return "HA_ERR_ROW_IS_REFERENCED";
+ case HA_ERR_NO_SAVEPOINT: return "HA_ERR_NO_SAVEPOINT";
+ case HA_ERR_NON_UNIQUE_BLOCK_SIZE: return "HA_ERR_NON_UNIQUE_BLOCK_SIZE";
+ case HA_ERR_NO_SUCH_TABLE: return "HA_ERR_NO_SUCH_TABLE";
+ case HA_ERR_TABLE_EXIST: return "HA_ERR_TABLE_EXIST";
+ case HA_ERR_NO_CONNECTION: return "HA_ERR_NO_CONNECTION";
+ case HA_ERR_NULL_IN_SPATIAL: return "HA_ERR_NULL_IN_SPATIAL";
+ case HA_ERR_TABLE_DEF_CHANGED: return "HA_ERR_TABLE_DEF_CHANGED";
+ case HA_ERR_NO_PARTITION_FOUND: return "HA_ERR_NO_PARTITION_FOUND";
+ case HA_ERR_RBR_LOGGING_FAILED: return "HA_ERR_RBR_LOGGING_FAILED";
+ case HA_ERR_DROP_INDEX_FK: return "HA_ERR_DROP_INDEX_FK";
+ case HA_ERR_FOREIGN_DUPLICATE_KEY: return "HA_ERR_FOREIGN_DUPLICATE_KEY";
+ case HA_ERR_TABLE_NEEDS_UPGRADE: return "HA_ERR_TABLE_NEEDS_UPGRADE";
+ case HA_ERR_TABLE_READONLY: return "HA_ERR_TABLE_READONLY";
+ case HA_ERR_AUTOINC_READ_FAILED: return "HA_ERR_AUTOINC_READ_FAILED";
+ case HA_ERR_AUTOINC_ERANGE: return "HA_ERR_AUTOINC_ERANGE";
+ case HA_ERR_GENERIC: return "HA_ERR_GENERIC";
+ case HA_ERR_RECORD_IS_THE_SAME: return "HA_ERR_RECORD_IS_THE_SAME";
+ case HA_ERR_LOGGING_IMPOSSIBLE: return "HA_ERR_LOGGING_IMPOSSIBLE";
+ case HA_ERR_CORRUPT_EVENT: return "HA_ERR_CORRUPT_EVENT";
+ case HA_ERR_ROWS_EVENT_APPLY : return "HA_ERR_ROWS_EVENT_APPLY";
+ }
+ return "No Error!";
+}
+
+
+/*
+ Return true if an error caught during event execution is a temporary error
+ that will cause automatic retry of the event group during parallel
+ replication, false otherwise.
+
+ In parallel replication, conflicting transactions can occasionally cause
+ deadlocks; such errors are handled automatically by rolling back re-trying
+ the transactions, so should not pollute the error log.
+*/
+static bool
+is_parallel_retry_error(rpl_group_info *rgi, int err)
+{
+ if (!rgi->is_parallel_exec)
+ return false;
+ if (rgi->speculation == rpl_group_info::SPECULATE_OPTIMISTIC)
+ return true;
+ if (rgi->killed_for_retry &&
+ (err == ER_QUERY_INTERRUPTED || err == ER_CONNECTION_KILLED))
+ return true;
+ return has_temporary_error(rgi->thd);
+}
+
+
+/**
+ Error reporting facility for Rows_log_event::do_apply_event
+
+ @param level error, warning or info
+ @param ha_error HA_ERR_ code
+ @param rli pointer to the active Relay_log_info instance
+ @param thd pointer to the slave thread's thd
+ @param table pointer to the event's table object
+ @param type the type of the event
+ @param log_name the master binlog file name
+ @param pos the master binlog file pos (the next after the event)
+
+*/
+static void inline slave_rows_error_report(enum loglevel level, int ha_error,
+ rpl_group_info *rgi, THD *thd,
+ TABLE *table, const char * type,
+ const char *log_name, my_off_t pos)
+{
+ const char *handler_error= (ha_error ? HA_ERR(ha_error) : NULL);
+ char buff[MAX_SLAVE_ERRMSG], *slider;
+ const char *buff_end= buff + sizeof(buff);
+ size_t len;
+ Diagnostics_area::Sql_condition_iterator it=
+ thd->get_stmt_da()->sql_conditions();
+ Relay_log_info const *rli= rgi->rli;
+ const Sql_condition *err;
+ buff[0]= 0;
+ int errcode= thd->is_error() ? thd->get_stmt_da()->sql_errno() : 0;
+
+ /*
+ In parallel replication, deadlocks or other temporary errors can happen
+ occasionally in normal operation, they will be handled correctly and
+ automatically by re-trying the transactions. So do not pollute the error
+ log with messages about them.
+ */
+ if (is_parallel_retry_error(rgi, errcode))
+ return;
+
+ for (err= it++, slider= buff; err && slider < buff_end - 1;
+ slider += len, err= it++)
+ {
+ len= my_snprintf(slider, buff_end - slider,
+ " %s, Error_code: %d;", err->get_message_text(),
+ err->get_sql_errno());
+ }
+
+ if (ha_error != 0)
+ rli->report(level, errcode, rgi->gtid_info(),
+ "Could not execute %s event on table %s.%s;"
+ "%s handler error %s; "
+ "the event's master log %s, end_log_pos %llu",
+ type, table->s->db.str, table->s->table_name.str,
+ buff, handler_error == NULL ? "<unknown>" : handler_error,
+ log_name, pos);
+ else
+ rli->report(level, errcode, rgi->gtid_info(),
+ "Could not execute %s event on table %s.%s;"
+ "%s the event's master log %s, end_log_pos %llu",
+ type, table->s->db.str, table->s->table_name.str,
+ buff, log_name, pos);
+}
+#endif
+
+#if defined(HAVE_REPLICATION)
+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
+
+
+#if defined(HAVE_REPLICATION)
+
+inline int idempotent_error_code(int err_code)
+{
+ int ret= 0;
+
+ switch (err_code)
+ {
+ case 0:
+ ret= 1;
+ break;
+ /*
+ The following list of "idempotent" errors
+ means that an error from the list might happen
+ because of idempotent (more than once)
+ applying of a binlog file.
+ Notice, that binlog has a ddl operation its
+ second applying may cause
+
+ case HA_ERR_TABLE_DEF_CHANGED:
+ case HA_ERR_CANNOT_ADD_FOREIGN:
+
+ which are not included into to the list.
+
+ Note that HA_ERR_RECORD_DELETED is not in the list since
+ do_exec_row() should not return that error code.
+ */
+ case HA_ERR_RECORD_CHANGED:
+ case HA_ERR_KEY_NOT_FOUND:
+ case HA_ERR_END_OF_FILE:
+ case HA_ERR_FOUND_DUPP_KEY:
+ case HA_ERR_FOUND_DUPP_UNIQUE:
+ case HA_ERR_FOREIGN_DUPLICATE_KEY:
+ case HA_ERR_NO_REFERENCED_ROW:
+ case HA_ERR_ROW_IS_REFERENCED:
+ ret= 1;
+ break;
+ default:
+ ret= 0;
+ break;
+ }
+ return (ret);
+}
+
+/**
+ Ignore error code specified on command line.
+*/
+
+inline int ignored_error_code(int err_code)
+{
+ if (use_slave_mask && bitmap_is_set(&slave_error_mask, err_code))
+ {
+ statistic_increment(slave_skipped_errors, LOCK_status);
+ return 1;
+ }
+ return err_code == ER_SLAVE_IGNORED_TABLE;
+}
+
+/*
+ This function converts an engine's error to a server error.
+
+ If the thread does not have an error already reported, it tries to
+ define it by calling the engine's method print_error. However, if a
+ mapping is not found, it uses the ER_UNKNOWN_ERROR and prints out a
+ warning message.
+*/
+int convert_handler_error(int error, THD* thd, TABLE *table)
+{
+ uint actual_error= (thd->is_error() ? thd->get_stmt_da()->sql_errno() :
+ 0);
+
+ if (actual_error == 0)
+ {
+ table->file->print_error(error, MYF(0));
+ actual_error= (thd->is_error() ? thd->get_stmt_da()->sql_errno() :
+ ER_UNKNOWN_ERROR);
+ if (actual_error == ER_UNKNOWN_ERROR)
+ if (global_system_variables.log_warnings)
+ sql_print_warning("Unknown error detected %d in handler", error);
+ }
+
+ return (actual_error);
+}
+
+inline bool concurrency_error_code(int error)
+{
+ switch (error)
+ {
+ case ER_LOCK_WAIT_TIMEOUT:
+ case ER_LOCK_DEADLOCK:
+ case ER_XA_RBDEADLOCK:
+ return TRUE;
+ default:
+ return (FALSE);
+ }
+}
+
+inline bool unexpected_error_code(int unexpected_error)
+{
+ switch (unexpected_error)
+ {
+ case ER_NET_READ_ERROR:
+ case ER_NET_ERROR_ON_WRITE:
+ case ER_QUERY_INTERRUPTED:
+ case ER_STATEMENT_TIMEOUT:
+ case ER_CONNECTION_KILLED:
+ case ER_SERVER_SHUTDOWN:
+ case ER_NEW_ABORTING_CONNECTION:
+ return(TRUE);
+ default:
+ return(FALSE);
+ }
+}
+
+/*
+ pretty_print_str()
+*/
+
+static void
+pretty_print_str(String *packet, const char *str, int len)
+{
+ const char *end= str + len;
+ packet->append(STRING_WITH_LEN("'"));
+ while (str < end)
+ {
+ char c;
+ switch ((c=*str++)) {
+ case '\n': packet->append(STRING_WITH_LEN("\\n")); break;
+ case '\r': packet->append(STRING_WITH_LEN("\\r")); break;
+ case '\\': packet->append(STRING_WITH_LEN("\\\\")); break;
+ case '\b': packet->append(STRING_WITH_LEN("\\b")); break;
+ case '\t': packet->append(STRING_WITH_LEN("\\t")); break;
+ case '\'': packet->append(STRING_WITH_LEN("\\'")); break;
+ case 0 : packet->append(STRING_WITH_LEN("\\0")); break;
+ default:
+ packet->append(&c, 1);
+ break;
+ }
+ }
+ packet->append(STRING_WITH_LEN("'"));
+}
+#endif /* HAVE_REPLICATION */
+
+
+#if defined(HAVE_REPLICATION)
+
+/**
+ Create a prefix for the temporary files that is to be used for
+ load data file name for this master
+
+ @param name Store prefix of name here
+ @param connection_name Connection name
+
+ @return pointer to end of name
+
+ @description
+ We assume that FN_REFLEN is big enough to hold
+ MAX_CONNECTION_NAME * MAX_FILENAME_MBWIDTH characters + 2 numbers +
+ a short extension.
+
+ The resulting file name has the following parts, each separated with a '-'
+ - PREFIX_SQL_LOAD (SQL_LOAD-)
+ - If a connection name is given (multi-master setup):
+ - Add an extra '-' to mark that this is a multi-master file
+ - connection name in lower case, converted to safe file characters.
+ (see create_logfile_name_with_suffix()).
+ - server_id
+ - A last '-' (after server_id).
+*/
+
+static char *load_data_tmp_prefix(char *name,
+ LEX_CSTRING *connection_name)
+{
+ name= strmov(name, PREFIX_SQL_LOAD);
+ if (connection_name->length)
+ {
+ uint buf_length;
+ uint errors;
+ /* Add marker that this is a multi-master-file */
+ *name++='-';
+ /* Convert connection_name to a safe filename */
+ buf_length= strconvert(system_charset_info, connection_name->str, FN_REFLEN,
+ &my_charset_filename, name, FN_REFLEN, &errors);
+ name+= buf_length;
+ *name++= '-';
+ }
+ name= int10_to_str(global_system_variables.server_id, name, 10);
+ *name++ = '-';
+ *name= '\0'; // For testing prefixes
+ return name;
+}
+
+
+/**
+ Creates a temporary name for LOAD DATA INFILE
+
+ @param buf Store new filename here
+ @param file_id File_id (part of file name)
+ @param event_server_id Event_id (part of file name)
+ @param ext Extension for file name
+
+ @return
+ Pointer to start of extension
+*/
+
+static char *slave_load_file_stem(char *buf, uint file_id,
+ int event_server_id, const char *ext,
+ LEX_CSTRING *connection_name)
+{
+ char *res;
+ res= buf+ unpack_dirname(buf, slave_load_tmpdir);
+ to_unix_path(buf);
+ buf= load_data_tmp_prefix(res, connection_name);
+ buf= int10_to_str(event_server_id, buf, 10);
+ *buf++ = '-';
+ res= int10_to_str(file_id, buf, 10);
+ strmov(res, ext); // Add extension last
+ return res; // Pointer to extension
+}
+#endif
+
+
+#if defined(HAVE_REPLICATION)
+
+/**
+ Delete all temporary files used for SQL_LOAD.
+*/
+
+static void cleanup_load_tmpdir(LEX_CSTRING *connection_name)
+{
+ MY_DIR *dirp;
+ FILEINFO *file;
+ uint i;
+ char dir[FN_REFLEN], fname[FN_REFLEN];
+ char prefbuf[31 + MAX_CONNECTION_NAME* MAX_FILENAME_MBWIDTH + 1];
+ DBUG_ENTER("cleanup_load_tmpdir");
+
+ unpack_dirname(dir, slave_load_tmpdir);
+ if (!(dirp=my_dir(dir, MYF(MY_WME))))
+ return;
+
+ /*
+ When we are deleting temporary files, we should only remove
+ the files associated with the server id of our server.
+ We don't use event_server_id here because since we've disabled
+ direct binlogging of Create_file/Append_file/Exec_load events
+ we cannot meet Start_log event in the middle of events from one
+ LOAD DATA.
+ */
+
+ load_data_tmp_prefix(prefbuf, connection_name);
+ DBUG_PRINT("enter", ("dir: '%s' prefix: '%s'", dir, prefbuf));
+
+ for (i=0 ; i < (uint)dirp->number_of_files; i++)
+ {
+ file=dirp->dir_entry+i;
+ if (is_prefix(file->name, prefbuf))
+ {
+ fn_format(fname,file->name,slave_load_tmpdir,"",MY_UNPACK_FILENAME);
+ mysql_file_delete(key_file_misc, fname, MYF(0));
+ }
+ }
+
+ my_dirend(dirp);
+ DBUG_VOID_RETURN;
+}
+#endif
+
+
+/**
+ Append a version of the 'str' string suitable for use in a query to
+ the 'to' string. To generate a correct escaping, the character set
+ information in 'csinfo' is used.
+*/
+
+int append_query_string(CHARSET_INFO *csinfo, String *to,
+ const char *str, size_t len, bool no_backslash)
+{
+ char *beg, *ptr;
+ uint32 const orig_len= to->length();
+ if (to->reserve(orig_len + len * 2 + 4))
+ return 1;
+
+ beg= (char*) to->ptr() + to->length();
+ ptr= beg;
+ if (csinfo->escape_with_backslash_is_dangerous)
+ ptr= str_to_hex(ptr, str, len);
+ else
+ {
+ *ptr++= '\'';
+ if (!no_backslash)
+ {
+ ptr+= escape_string_for_mysql(csinfo, ptr, 0, str, len);
+ }
+ else
+ {
+ const char *frm_str= str;
+
+ for (; frm_str < (str + len); frm_str++)
+ {
+ /* Using '' way to represent "'" */
+ if (*frm_str == '\'')
+ *ptr++= *frm_str;
+
+ *ptr++= *frm_str;
+ }
+ }
+
+ *ptr++= '\'';
+ }
+ to->length((uint32)(orig_len + ptr - beg));
+ return 0;
+}
+
+
+/**************************************************************************
+ Log_event methods (= the parent class of all events)
+**************************************************************************/
+
+Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
+ :log_pos(0), temp_buf(0), exec_time(0), thd(thd_arg),
+ checksum_alg(BINLOG_CHECKSUM_ALG_UNDEF)
+{
+ server_id= thd->variables.server_id;
+ when= thd->start_time;
+ when_sec_part=thd->start_time_sec_part;
+
+ if (using_trans)
+ cache_type= Log_event::EVENT_TRANSACTIONAL_CACHE;
+ else
+ cache_type= Log_event::EVENT_STMT_CACHE;
+ flags= flags_arg |
+ (thd->variables.option_bits & OPTION_SKIP_REPLICATION ?
+ LOG_EVENT_SKIP_REPLICATION_F : 0);
+}
+
+/**
+ This minimal constructor is for when you are not even sure that there
+ is a valid THD. For example in the server when we are shutting down or
+ flushing logs after receiving a SIGHUP (then we must write a Rotate to
+ the binlog but we have no THD, so we need this minimal constructor).
+*/
+
+Log_event::Log_event()
+ :temp_buf(0), exec_time(0), flags(0), cache_type(EVENT_INVALID_CACHE),
+ thd(0), checksum_alg(BINLOG_CHECKSUM_ALG_UNDEF)
+{
+ server_id= global_system_variables.server_id;
+ /*
+ We can't call my_time() here as this would cause a call before
+ my_init() is called
+ */
+ when= 0;
+ when_sec_part=0;
+ log_pos= 0;
+}
+
+
+
+#ifdef HAVE_REPLICATION
+
+int Log_event::do_update_pos(rpl_group_info *rgi)
+{
+ Relay_log_info *rli= rgi->rli;
+ DBUG_ENTER("Log_event::do_update_pos");
+
+ DBUG_ASSERT(!rli->belongs_to_client());
+ /*
+ rli is null when (as far as I (Guilhem) know) the caller is
+ Load_log_event::do_apply_event *and* that one is called from
+ Execute_load_log_event::do_apply_event. In this case, we don't
+ do anything here ; Execute_load_log_event::do_apply_event will
+ call Log_event::do_apply_event again later with the proper rli.
+ Strictly speaking, if we were sure that rli is null only in the
+ case discussed above, 'if (rli)' is useless here. But as we are
+ not 100% sure, keep it for now.
+
+ Matz: I don't think we will need this check with this refactoring.
+ */
+ if (rli)
+ {
+ /*
+ In parallel execution, delay position update for the events that are
+ not part of event groups (format description, rotate, and such) until
+ the actual event execution reaches that point.
+ */
+ if (!rgi->is_parallel_exec || is_group_event(get_type_code()))
+ rli->stmt_done(log_pos, thd, rgi);
+ }
+ DBUG_RETURN(0); // Cannot fail currently
+}
+
+
+Log_event::enum_skip_reason
+Log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ Relay_log_info *rli= rgi->rli;
+ DBUG_PRINT("info", ("ev->server_id: %lu, ::server_id: %lu,"
+ " rli->replicate_same_server_id: %d,"
+ " rli->slave_skip_counter: %llu",
+ (ulong) server_id,
+ (ulong) global_system_variables.server_id,
+ rli->replicate_same_server_id,
+ rli->slave_skip_counter));
+ if ((server_id == global_system_variables.server_id &&
+ !rli->replicate_same_server_id) ||
+ (rli->slave_skip_counter == 1 && rli->is_in_group()) ||
+ (flags & LOG_EVENT_SKIP_REPLICATION_F &&
+ opt_replicate_events_marked_for_skip != RPL_SKIP_REPLICATE))
+ return EVENT_SKIP_IGNORE;
+ if (rli->slave_skip_counter > 0)
+ return EVENT_SKIP_COUNT;
+ return EVENT_SKIP_NOT;
+}
+
+
+/*
+ Log_event::pack_info()
+*/
+
+void Log_event::pack_info(Protocol *protocol)
+{
+ protocol->store("", &my_charset_bin);
+}
+
+
+/**
+ Only called by SHOW BINLOG EVENTS
+*/
+int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos)
+{
+ const char *p= strrchr(log_name, FN_LIBCHAR);
+ const char *event_type;
+ if (p)
+ log_name = p + 1;
+
+ protocol->prepare_for_resend();
+ protocol->store(log_name, &my_charset_bin);
+ protocol->store((ulonglong) pos);
+ event_type = get_type_str();
+ protocol->store(event_type, strlen(event_type), &my_charset_bin);
+ protocol->store((uint32) server_id);
+ protocol->store((ulonglong) log_pos);
+ pack_info(protocol);
+ return protocol->write();
+}
+#endif /* HAVE_REPLICATION */
+
+
+/**
+ init_show_field_list() prepares the column names and types for the
+ output of SHOW BINLOG EVENTS; it is used only by SHOW BINLOG
+ EVENTS.
+*/
+
+void Log_event::init_show_field_list(THD *thd, List<Item>* field_list)
+{
+ MEM_ROOT *mem_root= thd->mem_root;
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Log_name", 20),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Pos",
+ MY_INT64_NUM_DECIMAL_DIGITS,
+ MYSQL_TYPE_LONGLONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Event_type", 20),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Server_id", 10,
+ MYSQL_TYPE_LONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "End_log_pos",
+ MY_INT64_NUM_DECIMAL_DIGITS,
+ MYSQL_TYPE_LONGLONG),
+ mem_root);
+ field_list->push_back(new (mem_root) Item_empty_string(thd, "Info", 20),
+ mem_root);
+}
+
+/**
+ A decider of whether to trigger checksum computation or not.
+ To be invoked in Log_event::write() stack.
+ The decision is positive
+
+ S,M) if it's been marked for checksumming with @c checksum_alg
+
+ M) otherwise, if @@global.binlog_checksum is not NONE and the event is
+ directly written to the binlog file.
+ The to-be-cached event decides at @c write_cache() time.
+
+ Otherwise the decision is negative.
+
+ @note A side effect of the method is altering Log_event::checksum_alg
+ it the latter was undefined at calling.
+
+ @return true (positive) or false (negative)
+*/
+my_bool Log_event::need_checksum()
+{
+ DBUG_ENTER("Log_event::need_checksum");
+ my_bool ret;
+ /*
+ few callers of Log_event::write
+ (incl FD::write, FD constructing code on the slave side, Rotate relay log
+ and Stop event)
+ provides their checksum alg preference through Log_event::checksum_alg.
+ */
+ if (checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF)
+ ret= checksum_alg != BINLOG_CHECKSUM_ALG_OFF;
+ else
+ {
+ ret= binlog_checksum_options && cache_type == Log_event::EVENT_NO_CACHE;
+ checksum_alg= ret ? (enum_binlog_checksum_alg)binlog_checksum_options
+ : BINLOG_CHECKSUM_ALG_OFF;
+ }
+ /*
+ FD calls the methods before data_written has been calculated.
+ The following invariant claims if the current is not the first
+ call (and therefore data_written is not zero) then `ret' must be
+ TRUE. It may not be null because FD is always checksummed.
+ */
+
+ DBUG_ASSERT(get_type_code() != FORMAT_DESCRIPTION_EVENT || ret ||
+ data_written == 0);
+
+ DBUG_ASSERT(!ret ||
+ ((checksum_alg == binlog_checksum_options ||
+ /*
+ Stop event closes the relay-log and its checksum alg
+ preference is set by the caller can be different
+ from the server's binlog_checksum_options.
+ */
+ get_type_code() == STOP_EVENT ||
+ /*
+ Rotate:s can be checksummed regardless of the server's
+ binlog_checksum_options. That applies to both
+ the local RL's Rotate and the master's Rotate
+ which IO thread instantiates via queue_binlog_ver_3_event.
+ */
+ get_type_code() == ROTATE_EVENT ||
+ get_type_code() == START_ENCRYPTION_EVENT ||
+ /* FD is always checksummed */
+ get_type_code() == FORMAT_DESCRIPTION_EVENT) &&
+ checksum_alg != BINLOG_CHECKSUM_ALG_OFF));
+
+ DBUG_ASSERT(checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF);
+
+ DBUG_ASSERT(((get_type_code() != ROTATE_EVENT &&
+ get_type_code() != STOP_EVENT) ||
+ get_type_code() != FORMAT_DESCRIPTION_EVENT) ||
+ cache_type == Log_event::EVENT_NO_CACHE);
+
+ DBUG_RETURN(ret);
+}
+
+int Log_event_writer::write_internal(const uchar *pos, size_t len)
+{
+ if (my_b_safe_write(file, pos, len))
+ return 1;
+ bytes_written+= len;
+ return 0;
+}
+
+/*
+ as soon as encryption produces the first output block, write event_len
+ where it should be in a valid event header
+*/
+int Log_event_writer::maybe_write_event_len(uchar *pos, size_t len)
+{
+ if (len && event_len)
+ {
+ DBUG_ASSERT(len >= EVENT_LEN_OFFSET);
+ if (write_internal(pos + EVENT_LEN_OFFSET - 4, 4))
+ return 1;
+ int4store(pos + EVENT_LEN_OFFSET - 4, event_len);
+ event_len= 0;
+ }
+ return 0;
+}
+
+int Log_event_writer::encrypt_and_write(const uchar *pos, size_t len)
+{
+ uchar *dst= 0;
+ size_t dstsize= 0;
+
+ if (ctx)
+ {
+ dstsize= encryption_encrypted_length((uint)len, ENCRYPTION_KEY_SYSTEM_DATA,
+ crypto->key_version);
+ if (!(dst= (uchar*)my_safe_alloca(dstsize)))
+ return 1;
+
+ uint dstlen;
+ if (len == 0)
+ dstlen= 0;
+ else if (encryption_ctx_update(ctx, pos, (uint)len, dst, &dstlen))
+ goto err;
+
+ if (maybe_write_event_len(dst, dstlen))
+ return 1;
+ pos= dst;
+ len= dstlen;
+ }
+ if (write_internal(pos, len))
+ goto err;
+
+ my_safe_afree(dst, dstsize);
+ return 0;
+err:
+ my_safe_afree(dst, dstsize);
+ return 1;
+}
+
+int Log_event_writer::write_header(uchar *pos, size_t len)
+{
+ DBUG_ENTER("Log_event_writer::write_header");
+ /*
+ recording checksum of FD event computed with dropped
+ possibly active LOG_EVENT_BINLOG_IN_USE_F flag.
+ Similar step at verication: the active flag is dropped before
+ checksum computing.
+ */
+ if (checksum_len)
+ {
+ uchar save=pos[FLAGS_OFFSET];
+ pos[FLAGS_OFFSET]&= ~LOG_EVENT_BINLOG_IN_USE_F;
+ crc= my_checksum(0, pos, len);
+ pos[FLAGS_OFFSET]= save;
+ }
+
+ if (ctx)
+ {
+ uchar iv[BINLOG_IV_LENGTH];
+ crypto->set_iv(iv, (uint32)my_b_safe_tell(file));
+ if (encryption_ctx_init(ctx, crypto->key, crypto->key_length,
+ iv, sizeof(iv), ENCRYPTION_FLAG_ENCRYPT | ENCRYPTION_FLAG_NOPAD,
+ ENCRYPTION_KEY_SYSTEM_DATA, crypto->key_version))
+ DBUG_RETURN(1);
+
+ DBUG_ASSERT(len >= LOG_EVENT_HEADER_LEN);
+ event_len= uint4korr(pos + EVENT_LEN_OFFSET);
+ DBUG_ASSERT(event_len >= len);
+ memcpy(pos + EVENT_LEN_OFFSET, pos, 4);
+ pos+= 4;
+ len-= 4;
+ }
+ DBUG_RETURN(encrypt_and_write(pos, len));
+}
+
+int Log_event_writer::write_data(const uchar *pos, size_t len)
+{
+ DBUG_ENTER("Log_event_writer::write_data");
+ if (checksum_len)
+ crc= my_checksum(crc, pos, len);
+
+ DBUG_RETURN(encrypt_and_write(pos, len));
+}
+
+int Log_event_writer::write_footer()
+{
+ DBUG_ENTER("Log_event_writer::write_footer");
+ if (checksum_len)
+ {
+ uchar checksum_buf[BINLOG_CHECKSUM_LEN];
+ int4store(checksum_buf, crc);
+ if (encrypt_and_write(checksum_buf, BINLOG_CHECKSUM_LEN))
+ DBUG_RETURN(ER_ERROR_ON_WRITE);
+ }
+ if (ctx)
+ {
+ uint dstlen;
+ uchar dst[MY_AES_BLOCK_SIZE*2];
+ if (encryption_ctx_finish(ctx, dst, &dstlen))
+ DBUG_RETURN(1);
+ if (maybe_write_event_len(dst, dstlen) || write_internal(dst, dstlen))
+ DBUG_RETURN(ER_ERROR_ON_WRITE);
+ }
+ DBUG_RETURN(0);
+}
+
+/*
+ Log_event::write_header()
+*/
+
+bool Log_event::write_header(size_t event_data_length)
+{
+ uchar header[LOG_EVENT_HEADER_LEN];
+ ulong now;
+ DBUG_ENTER("Log_event::write_header");
+ DBUG_PRINT("enter", ("filepos: %lld length: %zu type: %d",
+ (longlong) writer->pos(), event_data_length,
+ (int) get_type_code()));
+
+ writer->checksum_len= need_checksum() ? BINLOG_CHECKSUM_LEN : 0;
+
+ /* Store number of bytes that will be written by this event */
+ data_written= event_data_length + sizeof(header) + writer->checksum_len;
+
+ /*
+ log_pos != 0 if this is relay-log event. In this case we should not
+ change the position
+ */
+
+ if (is_artificial_event())
+ {
+ /*
+ Artificial events are automatically generated and do not exist
+ in master's binary log, so log_pos should be set to 0.
+ */
+ log_pos= 0;
+ }
+ else if (!log_pos)
+ {
+ /*
+ Calculate the position of where the next event will start
+ (end of this event, that is).
+ */
+
+ log_pos= writer->pos() + data_written;
+
+ DBUG_EXECUTE_IF("dbug_master_binlog_over_2GB", log_pos += (1ULL <<31););
+ }
+
+ now= get_time(); // Query start time
+
+ /*
+ Header will be of size LOG_EVENT_HEADER_LEN for all events, except for
+ FORMAT_DESCRIPTION_EVENT and ROTATE_EVENT, where it will be
+ LOG_EVENT_MINIMAL_HEADER_LEN (remember these 2 have a frozen header,
+ because we read them before knowing the format).
+ */
+
+ int4store(header, now); // timestamp
+ header[EVENT_TYPE_OFFSET]= get_type_code();
+ int4store(header+ SERVER_ID_OFFSET, server_id);
+ int4store(header+ EVENT_LEN_OFFSET, data_written);
+ int4store(header+ LOG_POS_OFFSET, log_pos);
+ int2store(header + FLAGS_OFFSET, flags);
+
+ bool ret= writer->write_header(header, sizeof(header));
+ DBUG_RETURN(ret);
+}
+
+
+
+#if defined(HAVE_REPLICATION)
+inline Log_event::enum_skip_reason
+Log_event::continue_group(rpl_group_info *rgi)
+{
+ if (rgi->rli->slave_skip_counter == 1)
+ return Log_event::EVENT_SKIP_IGNORE;
+ return Log_event::do_shall_skip(rgi);
+}
+#endif
+
+/**************************************************************************
+ Query_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+
+/**
+ This (which is used only for SHOW BINLOG EVENTS) could be updated to
+ print SET @@session_var=. But this is not urgent, as SHOW BINLOG EVENTS is
+ only an information, it does not produce suitable queries to replay (for
+ example it does not print LOAD DATA INFILE).
+ @todo
+ show the catalog ??
+*/
+
+void Query_log_event::pack_info(Protocol *protocol)
+{
+ // TODO: show the catalog ??
+ char buf_mem[1024];
+ String buf(buf_mem, sizeof(buf_mem), system_charset_info);
+ buf.real_alloc(9 + db_len + q_len);
+ if (!(flags & LOG_EVENT_SUPPRESS_USE_F)
+ && db && db_len)
+ {
+ buf.append(STRING_WITH_LEN("use "));
+ append_identifier(protocol->thd, &buf, db, db_len);
+ buf.append(STRING_WITH_LEN("; "));
+ }
+ if (query && q_len)
+ buf.append(query, q_len);
+ protocol->store(&buf);
+}
+#endif
+
+
+/**
+ Utility function for the next method (Query_log_event::write()) .
+*/
+static void store_str_with_code_and_len(uchar **dst, const char *src,
+ uint len, uint code)
+{
+ /*
+ only 1 byte to store the length of catalog, so it should not
+ surpass 255
+ */
+ DBUG_ASSERT(len <= 255);
+ DBUG_ASSERT(src);
+ *((*dst)++)= (uchar) code;
+ *((*dst)++)= (uchar) len;
+ bmove(*dst, src, len);
+ (*dst)+= len;
+}
+
+
+/**
+ Query_log_event::write().
+
+ @note
+ In this event we have to modify the header to have the correct
+ EVENT_LEN_OFFSET as we don't yet know how many status variables we
+ will print!
+*/
+
+bool Query_log_event::write()
+{
+ uchar buf[QUERY_HEADER_LEN + MAX_SIZE_LOG_EVENT_STATUS];
+ uchar *start, *start_of_status;
+ ulong event_length;
+
+ if (!query)
+ return 1; // Something wrong with event
+
+ /*
+ We want to store the thread id:
+ (- as an information for the user when he reads the binlog)
+ - if the query uses temporary table: for the slave SQL thread to know to
+ which master connection the temp table belongs.
+ Now imagine we (write()) are called by the slave SQL thread (we are
+ logging a query executed by this thread; the slave runs with
+ --log-slave-updates). Then this query will be logged with
+ thread_id=the_thread_id_of_the_SQL_thread. Imagine that 2 temp tables of
+ the same name were created simultaneously on the master (in the master
+ binlog you have
+ CREATE TEMPORARY TABLE t; (thread 1)
+ CREATE TEMPORARY TABLE t; (thread 2)
+ ...)
+ then in the slave's binlog there will be
+ CREATE TEMPORARY TABLE t; (thread_id_of_the_slave_SQL_thread)
+ CREATE TEMPORARY TABLE t; (thread_id_of_the_slave_SQL_thread)
+ which is bad (same thread id!).
+
+ To avoid this, we log the thread's thread id EXCEPT for the SQL
+ slave thread for which we log the original (master's) thread id.
+ Now this moves the bug: what happens if the thread id on the
+ master was 10 and when the slave replicates the query, a
+ connection number 10 is opened by a normal client on the slave,
+ and updates a temp table of the same name? We get a problem
+ again. To avoid this, in the handling of temp tables (sql_base.cc)
+ we use thread_id AND server_id. TODO when this is merged into
+ 4.1: in 4.1, slave_proxy_id has been renamed to pseudo_thread_id
+ and is a session variable: that's to make mysqlbinlog work with
+ temp tables. We probably need to introduce
+
+ SET PSEUDO_SERVER_ID
+ for mysqlbinlog in 4.1. mysqlbinlog would print:
+ SET PSEUDO_SERVER_ID=
+ SET PSEUDO_THREAD_ID=
+ for each query using temp tables.
+ */
+ int4store(buf + Q_THREAD_ID_OFFSET, slave_proxy_id);
+ int4store(buf + Q_EXEC_TIME_OFFSET, exec_time);
+ buf[Q_DB_LEN_OFFSET] = (char) db_len;
+ int2store(buf + Q_ERR_CODE_OFFSET, error_code);
+
+ /*
+ You MUST always write status vars in increasing order of code. This
+ guarantees that a slightly older slave will be able to parse those he
+ knows.
+ */
+ start_of_status= start= buf+QUERY_HEADER_LEN;
+ if (flags2_inited)
+ {
+ *start++= Q_FLAGS2_CODE;
+ int4store(start, flags2);
+ start+= 4;
+ }
+ if (sql_mode_inited)
+ {
+ *start++= Q_SQL_MODE_CODE;
+ int8store(start, (ulonglong)sql_mode);
+ start+= 8;
+ }
+ if (catalog_len) // i.e. this var is inited (false for 4.0 events)
+ {
+ store_str_with_code_and_len(&start,
+ catalog, catalog_len, Q_CATALOG_NZ_CODE);
+ /*
+ In 5.0.x where x<4 masters we used to store the end zero here. This was
+ a waste of one byte so we don't do it in x>=4 masters. We change code to
+ Q_CATALOG_NZ_CODE, because re-using the old code would make x<4 slaves
+ of this x>=4 master segfault (expecting a zero when there is
+ none). Remaining compatibility problems are: the older slave will not
+ find the catalog; but it is will not crash, and it's not an issue
+ that it does not find the catalog as catalogs were not used in these
+ older MySQL versions (we store it in binlog and read it from relay log
+ but do nothing useful with it). What is an issue is that the older slave
+ will stop processing the Q_* blocks (and jumps to the db/query) as soon
+ as it sees unknown Q_CATALOG_NZ_CODE; so it will not be able to read
+ Q_AUTO_INCREMENT*, Q_CHARSET and so replication will fail silently in
+ various ways. Documented that you should not mix alpha/beta versions if
+ they are not exactly the same version, with example of 5.0.3->5.0.2 and
+ 5.0.4->5.0.3. If replication is from older to new, the new will
+ recognize Q_CATALOG_CODE and have no problem.
+ */
+ }
+ if (auto_increment_increment != 1 || auto_increment_offset != 1)
+ {
+ *start++= Q_AUTO_INCREMENT;
+ int2store(start, auto_increment_increment);
+ int2store(start+2, auto_increment_offset);
+ start+= 4;
+ }
+ if (charset_inited)
+ {
+ *start++= Q_CHARSET_CODE;
+ memcpy(start, charset, 6);
+ start+= 6;
+ }
+ if (time_zone_len)
+ {
+ /* In the TZ sys table, column Name is of length 64 so this should be ok */
+ DBUG_ASSERT(time_zone_len <= MAX_TIME_ZONE_NAME_LENGTH);
+ store_str_with_code_and_len(&start,
+ time_zone_str, time_zone_len, Q_TIME_ZONE_CODE);
+ }
+ if (lc_time_names_number)
+ {
+ DBUG_ASSERT(lc_time_names_number <= 0xFFFF);
+ *start++= Q_LC_TIME_NAMES_CODE;
+ int2store(start, lc_time_names_number);
+ start+= 2;
+ }
+ if (charset_database_number)
+ {
+ DBUG_ASSERT(charset_database_number <= 0xFFFF);
+ *start++= Q_CHARSET_DATABASE_CODE;
+ int2store(start, charset_database_number);
+ start+= 2;
+ }
+ if (table_map_for_update)
+ {
+ *start++= Q_TABLE_MAP_FOR_UPDATE_CODE;
+ int8store(start, table_map_for_update);
+ start+= 8;
+ }
+ if (master_data_written != 0)
+ {
+ /*
+ Q_MASTER_DATA_WRITTEN_CODE only exists in relay logs where the master
+ has binlog_version<4 and the slave has binlog_version=4. See comment
+ for master_data_written in log_event.h for details.
+ */
+ *start++= Q_MASTER_DATA_WRITTEN_CODE;
+ int4store(start, master_data_written);
+ start+= 4;
+ }
+
+ if (thd && thd->need_binlog_invoker())
+ {
+ LEX_CSTRING user;
+ LEX_CSTRING host;
+ memset(&user, 0, sizeof(user));
+ memset(&host, 0, sizeof(host));
+
+ if (thd->slave_thread && thd->has_invoker())
+ {
+ /* user will be null, if master is older than this patch */
+ user= thd->get_invoker_user();
+ host= thd->get_invoker_host();
+ }
+ else
+ {
+ Security_context *ctx= thd->security_ctx;
+
+ if (thd->need_binlog_invoker() == THD::INVOKER_USER)
+ {
+ user.str= ctx->priv_user;
+ host.str= ctx->priv_host;
+ host.length= strlen(host.str);
+ }
+ else
+ {
+ user.str= ctx->priv_role;
+ host= empty_clex_str;
+ }
+ user.length= strlen(user.str);
+ }
+
+ if (user.length > 0)
+ {
+ *start++= Q_INVOKER;
+
+ /*
+ Store user length and user. The max length of use is 16, so 1 byte is
+ enough to store the user's length.
+ */
+ *start++= (uchar)user.length;
+ memcpy(start, user.str, user.length);
+ start+= user.length;
+
+ /*
+ Store host length and host. The max length of host is 60, so 1 byte is
+ enough to store the host's length.
+ */
+ *start++= (uchar)host.length;
+ memcpy(start, host.str, host.length);
+ start+= host.length;
+ }
+ }
+
+ if (thd && thd->query_start_sec_part_used)
+ {
+ *start++= Q_HRNOW;
+ get_time();
+ int3store(start, when_sec_part);
+ start+= 3;
+ }
+ /*
+ NOTE: When adding new status vars, please don't forget to update
+ the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update the function
+ code_name() in this file.
+
+ Here there could be code like
+ if (command-line-option-which-says-"log_this_variable" && inited)
+ {
+ *start++= Q_THIS_VARIABLE_CODE;
+ int4store(start, this_variable);
+ start+= 4;
+ }
+ */
+
+ /* Store length of status variables */
+ status_vars_len= (uint) (start-start_of_status);
+ DBUG_ASSERT(status_vars_len <= MAX_SIZE_LOG_EVENT_STATUS);
+ int2store(buf + Q_STATUS_VARS_LEN_OFFSET, status_vars_len);
+
+ /*
+ Calculate length of whole event
+ The "1" below is the \0 in the db's length
+ */
+ event_length= (uint) (start-buf) + get_post_header_size_for_derived() + db_len + 1 + q_len;
+
+ return write_header(event_length) ||
+ write_data(buf, QUERY_HEADER_LEN) ||
+ write_post_header_for_derived() ||
+ write_data(start_of_status, (uint) (start-start_of_status)) ||
+ write_data(safe_str(db), db_len + 1) ||
+ write_data(query, q_len) ||
+ write_footer();
+}
+
+bool Query_compressed_log_event::write()
+{
+ const char *query_tmp = query;
+ uint32 q_len_tmp = q_len;
+ uint32 alloc_size;
+ bool ret = true;
+ q_len = alloc_size = binlog_get_compress_len(q_len);
+ query = (char *)my_safe_alloca(alloc_size);
+ if(query && !binlog_buf_compress(query_tmp, (char *)query, q_len_tmp, &q_len))
+ {
+ ret = Query_log_event::write();
+ }
+ my_safe_afree((void *)query, alloc_size);
+ query = query_tmp;
+ q_len = q_len_tmp;
+ return ret;
+}
+
+/**
+ The simplest constructor that could possibly work. This is used for
+ creating static objects that have a special meaning and are invisible
+ to the log.
+*/
+Query_log_event::Query_log_event()
+ :Log_event(), data_buf(0)
+{
+ memset(&user, 0, sizeof(user));
+ memset(&host, 0, sizeof(host));
+}
+
+
+/*
+ SYNOPSIS
+ Query_log_event::Query_log_event()
+ thd_arg - thread handle
+ query_arg - array of char representing the query
+ query_length - size of the `query_arg' array
+ using_trans - there is a modified transactional table
+ direct - Don't cache statement
+ suppress_use - suppress the generation of 'USE' statements
+ errcode - the error code of the query
+
+ DESCRIPTION
+ Creates an event for binlogging
+ The value for `errcode' should be supplied by caller.
+*/
+Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, size_t query_length, bool using_trans,
+ bool direct, bool suppress_use, int errcode)
+
+ :Log_event(thd_arg,
+ (thd_arg->thread_specific_used ? LOG_EVENT_THREAD_SPECIFIC_F :
+ 0) |
+ (suppress_use ? LOG_EVENT_SUPPRESS_USE_F : 0),
+ using_trans),
+ data_buf(0), query(query_arg), catalog(thd_arg->catalog),
+ db(thd_arg->db.str), q_len((uint32) query_length),
+ thread_id(thd_arg->thread_id),
+ /* save the original thread id; we already know the server id */
+ slave_proxy_id((ulong)thd_arg->variables.pseudo_thread_id),
+ flags2_inited(1), sql_mode_inited(1), charset_inited(1),
+ sql_mode(thd_arg->variables.sql_mode),
+ auto_increment_increment(thd_arg->variables.auto_increment_increment),
+ auto_increment_offset(thd_arg->variables.auto_increment_offset),
+ lc_time_names_number(thd_arg->variables.lc_time_names->number),
+ charset_database_number(0),
+ table_map_for_update((ulonglong)thd_arg->table_map_for_update),
+ master_data_written(0)
+{
+ time_t end_time;
+
+#ifdef WITH_WSREP
+ /*
+ If Query_log_event will contain non trans keyword (not BEGIN, COMMIT,
+ SAVEPOINT or ROLLBACK) we disable PA for this transaction.
+ */
+ if (WSREP_ON && !is_trans_keyword())
+ thd->wsrep_PA_safe= false;
+#endif /* WITH_WSREP */
+
+ memset(&user, 0, sizeof(user));
+ memset(&host, 0, sizeof(host));
+
+ error_code= errcode;
+
+ end_time= my_time(0);
+ exec_time = (ulong) (end_time - thd_arg->start_time);
+ /**
+ @todo this means that if we have no catalog, then it is replicated
+ as an existing catalog of length zero. is that safe? /sven
+ */
+ catalog_len = (catalog) ? (uint32) strlen(catalog) : 0;
+ /* status_vars_len is set just before writing the event */
+ db_len = (db) ? (uint32) strlen(db) : 0;
+ if (thd_arg->variables.collation_database != thd_arg->db_charset)
+ charset_database_number= thd_arg->variables.collation_database->number;
+
+ /*
+ We only replicate over the bits of flags2 that we need: the rest
+ are masked out by "& OPTIONS_WRITTEN_TO_BINLOG".
+
+ We also force AUTOCOMMIT=1. Rationale (cf. BUG#29288): After
+ fixing BUG#26395, we always write BEGIN and COMMIT around all
+ transactions (even single statements in autocommit mode). This is
+ so that replication from non-transactional to transactional table
+ and error recovery from XA to non-XA table should work as
+ expected. The BEGIN/COMMIT are added in log.cc. However, there is
+ one exception: MyISAM bypasses log.cc and writes directly to the
+ binlog. So if autocommit is off, master has MyISAM, and slave has
+ a transactional engine, then the slave will just see one long
+ never-ending transaction. The only way to bypass explicit
+ BEGIN/COMMIT in the binlog is by using a non-transactional table.
+ So setting AUTOCOMMIT=1 will make this work as expected.
+
+ Note: explicitly replicate AUTOCOMMIT=1 from master. We do not
+ assume AUTOCOMMIT=1 on slave; the slave still reads the state of
+ the autocommit flag as written by the master to the binlog. This
+ behavior may change after WL#4162 has been implemented.
+ */
+ flags2= (uint32) (thd_arg->variables.option_bits &
+ (OPTIONS_WRITTEN_TO_BIN_LOG & ~OPTION_NOT_AUTOCOMMIT));
+ DBUG_ASSERT(thd_arg->variables.character_set_client->number < 256*256);
+ DBUG_ASSERT(thd_arg->variables.collation_connection->number < 256*256);
+ DBUG_ASSERT(thd_arg->variables.collation_server->number < 256*256);
+ DBUG_ASSERT(thd_arg->variables.character_set_client->mbminlen == 1);
+ int2store(charset, thd_arg->variables.character_set_client->number);
+ int2store(charset+2, thd_arg->variables.collation_connection->number);
+ int2store(charset+4, thd_arg->variables.collation_server->number);
+ if (thd_arg->time_zone_used)
+ {
+ /*
+ Note that our event becomes dependent on the Time_zone object
+ representing the time zone. Fortunately such objects are never deleted
+ or changed during mysqld's lifetime.
+ */
+ time_zone_len= thd_arg->variables.time_zone->get_name()->length();
+ time_zone_str= thd_arg->variables.time_zone->get_name()->ptr();
+ }
+ else
+ time_zone_len= 0;
+
+ LEX *lex= thd->lex;
+ /*
+ Defines that the statement will be written directly to the binary log
+ without being wrapped by a BEGIN...COMMIT. Otherwise, the statement
+ will be written to either the trx-cache or stmt-cache.
+
+ Note that a cache will not be used if the parameter direct is TRUE.
+ */
+ bool use_cache= FALSE;
+ /*
+ TRUE defines that the trx-cache must be used and by consequence the
+ use_cache is TRUE.
+
+ Note that a cache will not be used if the parameter direct is TRUE.
+ */
+ bool trx_cache= FALSE;
+ cache_type= Log_event::EVENT_INVALID_CACHE;
+
+ if (!direct)
+ {
+ switch (lex->sql_command)
+ {
+ case SQLCOM_DROP_TABLE:
+ case SQLCOM_DROP_SEQUENCE:
+ use_cache= (lex->tmp_table() && thd->in_multi_stmt_transaction_mode());
+ break;
+
+ case SQLCOM_CREATE_TABLE:
+ case SQLCOM_CREATE_SEQUENCE:
+ /*
+ If we are using CREATE ... SELECT or if we are a slave
+ executing BEGIN...COMMIT (generated by CREATE...SELECT) we
+ have to use the transactional cache to ensure we don't
+ calculate any checksum for the CREATE part.
+ */
+ trx_cache= (lex->first_select_lex()->item_list.elements &&
+ thd->is_current_stmt_binlog_format_row()) ||
+ (thd->variables.option_bits & OPTION_GTID_BEGIN);
+ use_cache= (lex->tmp_table() &&
+ thd->in_multi_stmt_transaction_mode()) || trx_cache;
+ break;
+ case SQLCOM_SET_OPTION:
+ if (lex->autocommit)
+ use_cache= trx_cache= FALSE;
+ else
+ use_cache= TRUE;
+ break;
+ case SQLCOM_RELEASE_SAVEPOINT:
+ case SQLCOM_ROLLBACK_TO_SAVEPOINT:
+ case SQLCOM_SAVEPOINT:
+ case SQLCOM_XA_END:
+ use_cache= trx_cache= TRUE;
+ break;
+ default:
+ use_cache= sqlcom_can_generate_row_events(thd);
+ break;
+ }
+ }
+
+ if (!use_cache || direct)
+ {
+ cache_type= Log_event::EVENT_NO_CACHE;
+ }
+ else if (using_trans || trx_cache || stmt_has_updated_trans_table(thd) ||
+ thd->lex->is_mixed_stmt_unsafe(thd->in_multi_stmt_transaction_mode(),
+ thd->variables.binlog_direct_non_trans_update,
+ trans_has_updated_trans_table(thd),
+ thd->tx_isolation))
+ cache_type= Log_event::EVENT_TRANSACTIONAL_CACHE;
+ else
+ cache_type= Log_event::EVENT_STMT_CACHE;
+ DBUG_ASSERT(cache_type != Log_event::EVENT_INVALID_CACHE);
+ DBUG_PRINT("info",("Query_log_event has flags2: %lu sql_mode: %llu cache_tye: %d",
+ (ulong) flags2, sql_mode, cache_type));
+}
+
+Query_compressed_log_event::Query_compressed_log_event(THD* thd_arg, const char* query_arg,
+ ulong query_length, bool using_trans,
+ bool direct, bool suppress_use, int errcode)
+ :Query_log_event(thd_arg, query_arg, query_length, using_trans, direct,
+ suppress_use, errcode),
+ query_buf(0)
+{
+
+}
+
+
+#if defined(HAVE_REPLICATION)
+
+int Query_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ return do_apply_event(rgi, query, q_len);
+}
+
+/**
+ Compare if two errors should be regarded as equal.
+ This is to handle the case when you can get slightly different errors
+ on master and slave for the same thing.
+ @param
+ expected_error Error we got on master
+ actual_error Error we got on slave
+
+ @return
+ 1 Errors are equal
+ 0 Errors are different
+*/
+
+bool test_if_equal_repl_errors(int expected_error, int actual_error)
+{
+ if (expected_error == actual_error)
+ return 1;
+ switch (expected_error) {
+ case ER_DUP_ENTRY:
+ case ER_DUP_ENTRY_WITH_KEY_NAME:
+ case ER_DUP_KEY:
+ case ER_AUTOINC_READ_FAILED:
+ return (actual_error == ER_DUP_ENTRY ||
+ actual_error == ER_DUP_ENTRY_WITH_KEY_NAME ||
+ actual_error == ER_DUP_KEY ||
+ actual_error == ER_AUTOINC_READ_FAILED ||
+ actual_error == HA_ERR_AUTOINC_ERANGE);
+ case ER_UNKNOWN_TABLE:
+ return actual_error == ER_IT_IS_A_VIEW;
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+/**
+ @todo
+ Compare the values of "affected rows" around here. Something
+ like:
+ @code
+ if ((uint32) affected_in_event != (uint32) affected_on_slave)
+ {
+ sql_print_error("Slave: did not get the expected number of affected \
+ rows running query from master - expected %d, got %d (this numbers \
+ should have matched modulo 4294967296).", 0, ...);
+ thd->query_error = 1;
+ }
+ @endcode
+ We may also want an option to tell the slave to ignore "affected"
+ mismatch. This mismatch could be implemented with a new ER_ code, and
+ to ignore it you would use --slave-skip-errors...
+*/
+int Query_log_event::do_apply_event(rpl_group_info *rgi,
+ const char *query_arg, uint32 q_len_arg)
+{
+ int expected_error,actual_error= 0;
+ Schema_specification_st db_options;
+ uint64 sub_id= 0;
+ void *hton= NULL;
+ rpl_gtid gtid;
+ Relay_log_info const *rli= rgi->rli;
+ Rpl_filter *rpl_filter= rli->mi->rpl_filter;
+ bool current_stmt_is_commit;
+ DBUG_ENTER("Query_log_event::do_apply_event");
+
+ /*
+ Colleagues: please never free(thd->catalog) in MySQL. This would
+ lead to bugs as here thd->catalog is a part of an alloced block,
+ not an entire alloced block (see
+ Query_log_event::do_apply_event()). Same for thd->db. Thank
+ you.
+ */
+ thd->catalog= catalog_len ? (char *) catalog : (char *)"";
+
+ size_t valid_len= Well_formed_prefix(system_charset_info,
+ db, db_len, NAME_LEN).length();
+
+ if (valid_len != db_len)
+ {
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR),
+ "Invalid database name in Query event.");
+ thd->is_slave_error= true;
+ goto end;
+ }
+
+ set_thd_db(thd, rpl_filter, db, db_len);
+
+ /*
+ Setting the character set and collation of the current database thd->db.
+ */
+ load_db_opt_by_name(thd, thd->db.str, &db_options);
+ if (db_options.default_table_charset)
+ thd->db_charset= db_options.default_table_charset;
+ thd->variables.auto_increment_increment= auto_increment_increment;
+ thd->variables.auto_increment_offset= auto_increment_offset;
+
+ DBUG_PRINT("info", ("log_pos: %lu", (ulong) log_pos));
+
+ thd->clear_error(1);
+ current_stmt_is_commit= is_commit();
+
+ DBUG_ASSERT(!current_stmt_is_commit || !rgi->tables_to_lock);
+ rgi->slave_close_thread_tables(thd);
+
+ /*
+ Note: We do not need to execute reset_one_shot_variables() if this
+ db_ok() test fails.
+ Reason: The db stored in binlog events is the same for SET and for
+ its companion query. If the SET is ignored because of
+ db_ok(), the companion query will also be ignored, and if
+ the companion query is ignored in the db_ok() test of
+ ::do_apply_event(), then the companion SET also have so
+ we don't need to reset_one_shot_variables().
+ */
+ if (is_trans_keyword() || rpl_filter->db_ok(thd->db.str))
+ {
+ thd->set_time(when, when_sec_part);
+ thd->set_query_and_id((char*)query_arg, q_len_arg,
+ thd->charset(), next_query_id());
+ thd->variables.pseudo_thread_id= thread_id; // for temp tables
+ DBUG_PRINT("query",("%s", thd->query()));
+
+ if (unlikely(!(expected_error= error_code)) ||
+ ignored_error_code(expected_error) ||
+ !unexpected_error_code(expected_error))
+ {
+ thd->slave_expected_error= expected_error;
+ if (flags2_inited)
+ /*
+ all bits of thd->variables.option_bits which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG
+ must take their value from flags2.
+ */
+ thd->variables.option_bits= flags2|(thd->variables.option_bits & ~OPTIONS_WRITTEN_TO_BIN_LOG);
+ /*
+ else, we are in a 3.23/4.0 binlog; we previously received a
+ Rotate_log_event which reset thd->variables.option_bits and sql_mode etc, so
+ nothing to do.
+ */
+ /*
+ We do not replicate MODE_NO_DIR_IN_CREATE. That is, if the master is a
+ slave which runs with SQL_MODE=MODE_NO_DIR_IN_CREATE, this should not
+ force us to ignore the dir too. Imagine you are a ring of machines, and
+ one has a disk problem so that you temporarily need
+ MODE_NO_DIR_IN_CREATE on this machine; you don't want it to propagate
+ elsewhere (you don't want all slaves to start ignoring the dirs).
+ */
+ if (sql_mode_inited)
+ thd->variables.sql_mode=
+ (sql_mode_t) ((thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) |
+ (sql_mode & ~(sql_mode_t) MODE_NO_DIR_IN_CREATE));
+ if (charset_inited)
+ {
+ rpl_sql_thread_info *sql_info= thd->system_thread_info.rpl_sql_info;
+ if (sql_info->cached_charset_compare(charset))
+ {
+ /* Verify that we support the charsets found in the event. */
+ if (!(thd->variables.character_set_client=
+ get_charset(uint2korr(charset), MYF(MY_WME))) ||
+ !(thd->variables.collation_connection=
+ get_charset(uint2korr(charset+2), MYF(MY_WME))) ||
+ !(thd->variables.collation_server=
+ get_charset(uint2korr(charset+4), MYF(MY_WME))))
+ {
+ /*
+ We updated the thd->variables with nonsensical values (0). Let's
+ set them to something safe (i.e. which avoids crash), and we'll
+ stop with EE_UNKNOWN_CHARSET in compare_errors (unless set to
+ ignore this error).
+ */
+ set_slave_thread_default_charset(thd, rgi);
+ goto compare_errors;
+ }
+ thd->update_charset(); // for the charset change to take effect
+ /*
+ Reset thd->query_string.cs to the newly set value.
+ Note, there is a small flaw here. For a very short time frame
+ if the new charset is different from the old charset and
+ if another thread executes "SHOW PROCESSLIST" after
+ the above thd->set_query_and_id() and before this thd->set_query(),
+ and if the current query has some non-ASCII characters,
+ the another thread may see some '?' marks in the PROCESSLIST
+ result. This should be acceptable now. This is a reminder
+ to fix this if any refactoring happens here sometime.
+ */
+ thd->set_query((char*) query_arg, q_len_arg, thd->charset());
+ }
+ }
+ if (time_zone_len)
+ {
+ String tmp(time_zone_str, time_zone_len, &my_charset_bin);
+ if (!(thd->variables.time_zone= my_tz_find(thd, &tmp)))
+ {
+ my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), tmp.c_ptr());
+ thd->variables.time_zone= global_system_variables.time_zone;
+ goto compare_errors;
+ }
+ }
+ if (lc_time_names_number)
+ {
+ if (!(thd->variables.lc_time_names=
+ my_locale_by_number(lc_time_names_number)))
+ {
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "Unknown locale: '%d'", MYF(0), lc_time_names_number);
+ thd->variables.lc_time_names= &my_locale_en_US;
+ goto compare_errors;
+ }
+ }
+ else
+ thd->variables.lc_time_names= &my_locale_en_US;
+ if (charset_database_number)
+ {
+ CHARSET_INFO *cs;
+ if (!(cs= get_charset(charset_database_number, MYF(0))))
+ {
+ char buf[20];
+ int10_to_str((int) charset_database_number, buf, -10);
+ my_error(ER_UNKNOWN_COLLATION, MYF(0), buf);
+ goto compare_errors;
+ }
+ thd->variables.collation_database= cs;
+ }
+ else
+ thd->variables.collation_database= thd->db_charset;
+
+ {
+ const CHARSET_INFO *cs= thd->charset();
+ /*
+ We cannot ask for parsing a statement using a character set
+ without state_maps (parser internal data).
+ */
+ if (!cs->state_map)
+ {
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR),
+ "character_set cannot be parsed");
+ thd->is_slave_error= true;
+ goto end;
+ }
+ }
+
+ /*
+ Record any GTID in the same transaction, so slave state is
+ transactionally consistent.
+ */
+ if (current_stmt_is_commit)
+ {
+ thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
+ if (rgi->gtid_pending)
+ {
+ sub_id= rgi->gtid_sub_id;
+ rgi->gtid_pending= false;
+
+ gtid= rgi->current_gtid;
+ if (unlikely(rpl_global_gtid_slave_state->record_gtid(thd, &gtid,
+ sub_id,
+ true, false,
+ &hton)))
+ {
+ int errcode= thd->get_stmt_da()->sql_errno();
+ if (!is_parallel_retry_error(rgi, errcode))
+ rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE,
+ rgi->gtid_info(),
+ "Error during COMMIT: failed to update GTID state in "
+ "%s.%s: %d: %s",
+ "mysql", rpl_gtid_slave_state_table_name.str,
+ errcode,
+ thd->get_stmt_da()->message());
+ sub_id= 0;
+ thd->is_slave_error= 1;
+ goto end;
+ }
+ }
+ }
+
+ thd->table_map_for_update= (table_map)table_map_for_update;
+ thd->set_invoker(&user, &host);
+ /*
+ Flag if we need to rollback the statement transaction on
+ slave if it by chance succeeds.
+ If we expected a non-zero error code and get nothing and,
+ it is a concurrency issue or ignorable issue, effects
+ of the statement should be rolled back.
+ */
+ if (unlikely(expected_error) &&
+ (ignored_error_code(expected_error) ||
+ concurrency_error_code(expected_error)))
+ {
+ thd->variables.option_bits|= OPTION_MASTER_SQL_ERROR;
+ thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
+ }
+ /* Execute the query (note that we bypass dispatch_command()) */
+ Parser_state parser_state;
+ if (!parser_state.init(thd, thd->query(), thd->query_length()))
+ {
+ DBUG_ASSERT(thd->m_digest == NULL);
+ thd->m_digest= & thd->m_digest_state;
+ DBUG_ASSERT(thd->m_statement_psi == NULL);
+ thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state,
+ stmt_info_rpl.m_key,
+ thd->db.str, thd->db.length,
+ thd->charset(), NULL);
+ THD_STAGE_INFO(thd, stage_starting);
+ MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(), thd->query_length());
+ if (thd->m_digest != NULL)
+ thd->m_digest->reset(thd->m_token_array, max_digest_length);
+
+ if (thd->slave_thread)
+ {
+ /*
+ To be compatible with previous releases, the slave thread uses the global
+ log_slow_disabled_statements value, wich can be changed dynamically, so we
+ have to set the sql_log_slow respectively.
+ */
+ thd->variables.sql_log_slow= !MY_TEST(global_system_variables.log_slow_disabled_statements & LOG_SLOW_DISABLE_SLAVE);
+ }
+
+ mysql_parse(thd, thd->query(), thd->query_length(), &parser_state,
+ FALSE, FALSE);
+ /* Finalize server status flags after executing a statement. */
+ thd->update_server_status();
+ log_slow_statement(thd);
+ thd->lex->restore_set_statement_var();
+ }
+
+ thd->variables.option_bits&= ~OPTION_MASTER_SQL_ERROR;
+ }
+ else
+ {
+ /*
+ The query got a really bad error on the master (thread killed etc),
+ which could be inconsistent. Parse it to test the table names: if the
+ replicate-*-do|ignore-table rules say "this query must be ignored" then
+ we exit gracefully; otherwise we warn about the bad error and tell DBA
+ to check/fix it.
+ */
+ if (mysql_test_parse_for_slave(thd, thd->query(), thd->query_length()))
+ thd->clear_error(1);
+ else
+ {
+ rli->report(ERROR_LEVEL, expected_error, rgi->gtid_info(),
+ "\
+Query partially completed on the master (error on master: %d) \
+and was aborted. There is a chance that your master is inconsistent at this \
+point. If you are sure that your master is ok, run this query manually on the \
+slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; \
+START SLAVE; . Query: '%s'", expected_error, thd->query());
+ thd->is_slave_error= 1;
+ }
+ goto end;
+ }
+
+ /* If the query was not ignored, it is printed to the general log */
+ if (likely(!thd->is_error()) ||
+ thd->get_stmt_da()->sql_errno() != ER_SLAVE_IGNORED_TABLE)
+ general_log_write(thd, COM_QUERY, thd->query(), thd->query_length());
+ else
+ {
+ /*
+ Bug#54201: If we skip an INSERT query that uses auto_increment, then we
+ should reset any @@INSERT_ID set by an Intvar_log_event associated with
+ the query; otherwise the @@INSERT_ID will linger until the next INSERT
+ that uses auto_increment and may affect extra triggers on the slave etc.
+
+ We reset INSERT_ID unconditionally; it is probably cheaper than
+ checking if it is necessary.
+ */
+ thd->auto_inc_intervals_forced.empty();
+ }
+
+compare_errors:
+ /*
+ In the slave thread, we may sometimes execute some DROP / * 40005
+ TEMPORARY * / TABLE that come from parts of binlogs (likely if we
+ use RESET SLAVE or CHANGE MASTER TO), while the temporary table
+ has already been dropped. To ignore such irrelevant "table does
+ not exist errors", we silently clear the error if TEMPORARY was used.
+ */
+ if ((thd->lex->sql_command == SQLCOM_DROP_TABLE ||
+ thd->lex->sql_command == SQLCOM_DROP_SEQUENCE) &&
+ thd->lex->tmp_table() &&
+ thd->is_error() && thd->get_stmt_da()->sql_errno() == ER_BAD_TABLE_ERROR &&
+ !expected_error)
+ thd->get_stmt_da()->reset_diagnostics_area();
+ /*
+ If we expected a non-zero error code, and we don't get the same error
+ code, and it should be ignored or is related to a concurrency issue.
+ */
+ actual_error= thd->is_error() ? thd->get_stmt_da()->sql_errno() : 0;
+ DBUG_PRINT("info",("expected_error: %d sql_errno: %d",
+ expected_error, actual_error));
+
+ if ((unlikely(expected_error) &&
+ !test_if_equal_repl_errors(expected_error, actual_error) &&
+ !concurrency_error_code(expected_error)) &&
+ !ignored_error_code(actual_error) &&
+ !ignored_error_code(expected_error))
+ {
+ rli->report(ERROR_LEVEL, 0, rgi->gtid_info(),
+ "Query caused different errors on master and slave. "
+ "Error on master: message (format)='%s' error code=%d ; "
+ "Error on slave: actual message='%s', error code=%d. "
+ "Default database: '%s'. Query: '%s'",
+ ER_THD(thd, expected_error),
+ expected_error,
+ actual_error ? thd->get_stmt_da()->message() : "no error",
+ actual_error,
+ print_slave_db_safe(db), query_arg);
+ thd->is_slave_error= 1;
+ }
+ /*
+ If we get the same error code as expected and it is not a concurrency
+ issue, or should be ignored.
+ */
+ else if ((test_if_equal_repl_errors(expected_error, actual_error) &&
+ !concurrency_error_code(expected_error)) ||
+ ignored_error_code(actual_error))
+ {
+ DBUG_PRINT("info",("error ignored"));
+ thd->clear_error(1);
+ if (actual_error == ER_QUERY_INTERRUPTED ||
+ actual_error == ER_CONNECTION_KILLED)
+ thd->reset_killed();
+ }
+ /*
+ Other cases: mostly we expected no error and get one.
+ */
+ else if (unlikely(thd->is_slave_error || thd->is_fatal_error))
+ {
+ if (!is_parallel_retry_error(rgi, actual_error))
+ rli->report(ERROR_LEVEL, actual_error, rgi->gtid_info(),
+ "Error '%s' on query. Default database: '%s'. Query: '%s'",
+ (actual_error ? thd->get_stmt_da()->message() :
+ "unexpected success or fatal error"),
+ thd->get_db(), query_arg);
+ thd->is_slave_error= 1;
+#ifdef WITH_WSREP
+ if (wsrep_thd_is_toi(thd) && wsrep_must_ignore_error(thd))
+ {
+ thd->clear_error(1);
+ thd->killed= NOT_KILLED;
+ thd->wsrep_has_ignored_error= true;
+ }
+#endif /* WITH_WSREP */
+ }
+
+ /*
+ TODO: compare the values of "affected rows" around here. Something
+ like:
+ if ((uint32) affected_in_event != (uint32) affected_on_slave)
+ {
+ sql_print_error("Slave: did not get the expected number of affected \
+ rows running query from master - expected %d, got %d (this numbers \
+ should have matched modulo 4294967296).", 0, ...);
+ thd->is_slave_error = 1;
+ }
+ We may also want an option to tell the slave to ignore "affected"
+ mismatch. This mismatch could be implemented with a new ER_ code, and
+ to ignore it you would use --slave-skip-errors...
+
+ To do the comparison we need to know the value of "affected" which the
+ above mysql_parse() computed. And we need to know the value of
+ "affected" in the master's binlog. Both will be implemented later. The
+ important thing is that we now have the format ready to log the values
+ of "affected" in the binlog. So we can release 5.0.0 before effectively
+ logging "affected" and effectively comparing it.
+ */
+ } /* End of if (db_ok(... */
+
+ {
+ /**
+ The following failure injecion works in cooperation with tests
+ setting @@global.debug= 'd,stop_slave_middle_group'.
+ The sql thread receives the killed status and will proceed
+ to shutdown trying to finish incomplete events group.
+ */
+ DBUG_EXECUTE_IF("stop_slave_middle_group",
+ if (!current_stmt_is_commit && is_begin() == 0)
+ {
+ if (thd->transaction.all.modified_non_trans_table)
+ const_cast<Relay_log_info*>(rli)->abort_slave= 1;
+ };);
+ }
+
+end:
+ if (unlikely(sub_id && !thd->is_slave_error))
+ rpl_global_gtid_slave_state->update_state_hash(sub_id, &gtid, hton, rgi);
+
+ /*
+ Probably we have set thd->query, thd->db, thd->catalog to point to places
+ in the data_buf of this event. Now the event is going to be deleted
+ probably, so data_buf will be freed, so the thd->... listed above will be
+ pointers to freed memory.
+ So we must set them to 0, so that those bad pointers values are not later
+ used. Note that "cleanup" queries like automatic DROP TEMPORARY TABLE
+ don't suffer from these assignments to 0 as DROP TEMPORARY
+ TABLE uses the db.table syntax.
+ */
+ thd->catalog= 0;
+ thd->set_db(&null_clex_str); /* will free the current database */
+ thd->reset_query();
+ DBUG_PRINT("info", ("end: query= 0"));
+
+ /* Mark the statement completed. */
+ MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
+ thd->m_statement_psi= NULL;
+ thd->m_digest= NULL;
+
+ /*
+ As a disk space optimization, future masters will not log an event for
+ LAST_INSERT_ID() if that function returned 0 (and thus they will be able
+ to replace the THD::stmt_depends_on_first_successful_insert_id_in_prev_stmt
+ variable by (THD->first_successful_insert_id_in_prev_stmt > 0) ; with the
+ resetting below we are ready to support that.
+ */
+ thd->first_successful_insert_id_in_prev_stmt_for_binlog= 0;
+ thd->first_successful_insert_id_in_prev_stmt= 0;
+ thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
+ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
+ DBUG_RETURN(thd->is_slave_error);
+}
+
+Log_event::enum_skip_reason
+Query_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ Relay_log_info *rli= rgi->rli;
+ DBUG_ENTER("Query_log_event::do_shall_skip");
+ DBUG_PRINT("debug", ("query: '%s' q_len: %d", query, q_len));
+ DBUG_ASSERT(query && q_len > 0);
+ DBUG_ASSERT(thd == rgi->thd);
+
+ /*
+ An event skipped due to @@skip_replication must not be counted towards the
+ number of events to be skipped due to @@sql_slave_skip_counter.
+ */
+ if (flags & LOG_EVENT_SKIP_REPLICATION_F &&
+ opt_replicate_events_marked_for_skip != RPL_SKIP_REPLICATE)
+ DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE);
+
+ if (rli->slave_skip_counter > 0)
+ {
+ if (is_begin())
+ {
+ thd->variables.option_bits|= OPTION_BEGIN | OPTION_GTID_BEGIN;
+ DBUG_RETURN(Log_event::continue_group(rgi));
+ }
+
+ if (is_commit() || is_rollback())
+ {
+ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN);
+ DBUG_RETURN(Log_event::EVENT_SKIP_COUNT);
+ }
+ }
+#ifdef WITH_WSREP
+ else if (WSREP_ON && wsrep_mysql_replication_bundle && opt_slave_domain_parallel_threads == 0 &&
+ thd->wsrep_mysql_replicated > 0 &&
+ (is_begin() || is_commit()))
+ {
+ if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle)
+ {
+ WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated);
+ DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE);
+ }
+ else
+ {
+ thd->wsrep_mysql_replicated = 0;
+ }
+ }
+#endif
+ DBUG_RETURN(Log_event::do_shall_skip(rgi));
+}
+
+
+bool
+Query_log_event::peek_is_commit_rollback(const char *event_start,
+ size_t event_len,
+ enum enum_binlog_checksum_alg checksum_alg)
+{
+ if (checksum_alg == BINLOG_CHECKSUM_ALG_CRC32)
+ {
+ if (event_len > BINLOG_CHECKSUM_LEN)
+ event_len-= BINLOG_CHECKSUM_LEN;
+ else
+ event_len= 0;
+ }
+ else
+ DBUG_ASSERT(checksum_alg == BINLOG_CHECKSUM_ALG_UNDEF ||
+ checksum_alg == BINLOG_CHECKSUM_ALG_OFF);
+
+ if (event_len < LOG_EVENT_HEADER_LEN + QUERY_HEADER_LEN || event_len < 9)
+ return false;
+ return !memcmp(event_start + (event_len-7), "\0COMMIT", 7) ||
+ !memcmp(event_start + (event_len-9), "\0ROLLBACK", 9);
+}
+
+#endif
+
+
+/**************************************************************************
+ Start_log_event_v3 methods
+**************************************************************************/
+
+Start_log_event_v3::Start_log_event_v3()
+ :Log_event(), created(0), binlog_version(BINLOG_VERSION),
+ dont_set_created(0)
+{
+ memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
+}
+
+
+#if defined(HAVE_REPLICATION)
+void Start_log_event_v3::pack_info(Protocol *protocol)
+{
+ char buf[12 + ST_SERVER_VER_LEN + 14 + 22], *pos;
+ pos= strmov(buf, "Server ver: ");
+ pos= strmov(pos, server_version);
+ pos= strmov(pos, ", Binlog ver: ");
+ pos= int10_to_str(binlog_version, pos, 10);
+ protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
+}
+#endif
+
+
+bool Start_log_event_v3::write()
+{
+ char buff[START_V3_HEADER_LEN];
+ int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
+ memcpy(buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
+ if (!dont_set_created)
+ created= get_time(); // this sets when and when_sec_part as a side effect
+ int4store(buff + ST_CREATED_OFFSET,created);
+ return write_header(sizeof(buff)) ||
+ write_data(buff, sizeof(buff)) ||
+ write_footer();
+}
+
+
+#if defined(HAVE_REPLICATION)
+
+/**
+ Start_log_event_v3::do_apply_event() .
+ The master started
+
+ IMPLEMENTATION
+ - To handle the case where the master died without having time to write
+ DROP TEMPORARY TABLE, DO RELEASE_LOCK (prepared statements' deletion is
+ TODO), we clean up all temporary tables that we got, if we are sure we
+ can (see below).
+
+ @todo
+ - Remove all active user locks.
+ Guilhem 2003-06: this is true but not urgent: the worst it can cause is
+ the use of a bit of memory for a user lock which will not be used
+ anymore. If the user lock is later used, the old one will be released. In
+ other words, no deadlock problem.
+*/
+
+int Start_log_event_v3::do_apply_event(rpl_group_info *rgi)
+{
+ DBUG_ENTER("Start_log_event_v3::do_apply_event");
+ int error= 0;
+ Relay_log_info *rli= rgi->rli;
+
+ switch (binlog_version)
+ {
+ case 3:
+ case 4:
+ /*
+ This can either be 4.x (then a Start_log_event_v3 is only at master
+ startup so we are sure the master has restarted and cleared his temp
+ tables; the event always has 'created'>0) or 5.0 (then we have to test
+ 'created').
+ */
+ if (created)
+ {
+ rli->close_temporary_tables();
+
+ /*
+ The following is only false if we get here with a BINLOG statement
+ */
+ if (rli->mi)
+ cleanup_load_tmpdir(&rli->mi->cmp_connection_name);
+ }
+ break;
+
+ /*
+ Now the older formats; in that case load_tmpdir is cleaned up by the I/O
+ thread.
+ */
+ case 1:
+ if (strncmp(rli->relay_log.description_event_for_exec->server_version,
+ "3.23.57",7) >= 0 && created)
+ {
+ /*
+ Can distinguish, based on the value of 'created': this event was
+ generated at master startup.
+ */
+ rli->close_temporary_tables();
+ }
+ /*
+ Otherwise, can't distinguish a Start_log_event generated at
+ master startup and one generated by master FLUSH LOGS, so cannot
+ be sure temp tables have to be dropped. So do nothing.
+ */
+ break;
+ default:
+ /*
+ This case is not expected. It can be either an event corruption or an
+ unsupported binary log version.
+ */
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR),
+ "Binlog version not supported");
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(error);
+}
+#endif /* defined(HAVE_REPLICATION) */
+
+/***************************************************************************
+ Format_description_log_event methods
+****************************************************************************/
+
+bool Format_description_log_event::write()
+{
+ bool ret;
+ bool no_checksum;
+ /*
+ We don't call Start_log_event_v3::write() because this would make 2
+ my_b_safe_write().
+ */
+ uchar buff[START_V3_HEADER_LEN+1];
+ size_t rec_size= sizeof(buff) + BINLOG_CHECKSUM_ALG_DESC_LEN +
+ number_of_event_types;
+ int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
+ memcpy((char*) buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
+ if (!dont_set_created)
+ created= get_time();
+ int4store(buff + ST_CREATED_OFFSET,created);
+ buff[ST_COMMON_HEADER_LEN_OFFSET]= common_header_len;
+ /*
+ if checksum is requested
+ record the checksum-algorithm descriptor next to
+ post_header_len vector which will be followed by the checksum value.
+ Master is supposed to trigger checksum computing by binlog_checksum_options,
+ slave does it via marking the event according to
+ FD_queue checksum_alg value.
+ */
+ compile_time_assert(BINLOG_CHECKSUM_ALG_DESC_LEN == 1);
+#ifdef DBUG_ASSERT_EXISTS
+ data_written= 0; // to prepare for need_checksum assert
+#endif
+ uint8 checksum_byte= (uint8)
+ (need_checksum() ? checksum_alg : BINLOG_CHECKSUM_ALG_OFF);
+ /*
+ FD of checksum-aware server is always checksum-equipped, (V) is in,
+ regardless of @@global.binlog_checksum policy.
+ Thereby a combination of (A) == 0, (V) != 0 means
+ it's the checksum-aware server's FD event that heads checksum-free binlog
+ file.
+ Here 0 stands for checksumming OFF to evaluate (V) as 0 is that case.
+ A combination of (A) != 0, (V) != 0 denotes FD of the checksum-aware server
+ heading the checksummed binlog.
+ (A), (V) presence in FD of the checksum-aware server makes the event
+ 1 + 4 bytes bigger comparing to the former FD.
+ */
+
+ if ((no_checksum= (checksum_alg == BINLOG_CHECKSUM_ALG_OFF)))
+ {
+ checksum_alg= BINLOG_CHECKSUM_ALG_CRC32; // Forcing (V) room to fill anyway
+ }
+ ret= write_header(rec_size) ||
+ write_data(buff, sizeof(buff)) ||
+ write_data(post_header_len, number_of_event_types) ||
+ write_data(&checksum_byte, sizeof(checksum_byte)) ||
+ write_footer();
+ if (no_checksum)
+ checksum_alg= BINLOG_CHECKSUM_ALG_OFF;
+ return ret;
+}
+
+#if defined(HAVE_REPLICATION)
+int Format_description_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ int ret= 0;
+ Relay_log_info *rli= rgi->rli;
+ DBUG_ENTER("Format_description_log_event::do_apply_event");
+
+ /*
+ As a transaction NEVER spans on 2 or more binlogs:
+ if we have an active transaction at this point, the master died
+ while writing the transaction to the binary log, i.e. while
+ flushing the binlog cache to the binlog. XA guarantees that master has
+ rolled back. So we roll back.
+ Note: this event could be sent by the master to inform us of the
+ format of its binlog; in other words maybe it is not at its
+ original place when it comes to us; we'll know this by checking
+ log_pos ("artificial" events have log_pos == 0).
+ */
+ if (!is_artificial_event() && created && thd->transaction.all.ha_list)
+ {
+ /* This is not an error (XA is safe), just an information */
+ rli->report(INFORMATION_LEVEL, 0, NULL,
+ "Rolling back unfinished transaction (no COMMIT "
+ "or ROLLBACK in relay log). A probable cause is that "
+ "the master died while writing the transaction to "
+ "its binary log, thus rolled back too.");
+ rgi->cleanup_context(thd, 1);
+ }
+
+ /*
+ If this event comes from ourselves, there is no cleaning task to
+ perform, we don't call Start_log_event_v3::do_apply_event()
+ (this was just to update the log's description event).
+ */
+ if (server_id != (uint32) global_system_variables.server_id)
+ {
+ /*
+ If the event was not requested by the slave i.e. the master sent
+ it while the slave asked for a position >4, the event will make
+ rli->group_master_log_pos advance. Say that the slave asked for
+ position 1000, and the Format_desc event's end is 96. Then in
+ the beginning of replication rli->group_master_log_pos will be
+ 0, then 96, then jump to first really asked event (which is
+ >96). So this is ok.
+ */
+ ret= Start_log_event_v3::do_apply_event(rgi);
+ }
+
+ if (!ret)
+ {
+ /* Save the information describing this binlog */
+ copy_crypto_data(rli->relay_log.description_event_for_exec);
+ delete rli->relay_log.description_event_for_exec;
+ rli->relay_log.description_event_for_exec= this;
+ }
+
+ DBUG_RETURN(ret);
+}
+
+int Format_description_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ if (server_id == (uint32) global_system_variables.server_id)
+ {
+ /*
+ We only increase the relay log position if we are skipping
+ events and do not touch any group_* variables, nor flush the
+ relay log info. If there is a crash, we will have to re-skip
+ the events again, but that is a minor issue.
+
+ If we do not skip stepping the group log position (and the
+ server id was changed when restarting the server), it might well
+ be that we start executing at a position that is invalid, e.g.,
+ at a Rows_log_event or a Query_log_event preceeded by a
+ Intvar_log_event instead of starting at a Table_map_log_event or
+ the Intvar_log_event respectively.
+ */
+ rgi->inc_event_relay_log_pos();
+ return 0;
+ }
+ else
+ {
+ return Log_event::do_update_pos(rgi);
+ }
+}
+
+Log_event::enum_skip_reason
+Format_description_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ return Log_event::EVENT_SKIP_NOT;
+}
+
+#endif
+
+
+#if defined(HAVE_REPLICATION)
+int Start_encryption_log_event::do_apply_event(rpl_group_info* rgi)
+{
+ return rgi->rli->relay_log.description_event_for_exec->start_decryption(this);
+}
+
+int Start_encryption_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ /*
+ master never sends Start_encryption_log_event, any SELE that a slave
+ might see was created locally in MYSQL_BIN_LOG::open() on the slave
+ */
+ rgi->inc_event_relay_log_pos();
+ return 0;
+}
+
+#endif
+
+
+/**************************************************************************
+ Load_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+bool Load_log_event::print_query(THD *thd, bool need_db, const char *cs,
+ String *buf, my_off_t *fn_start,
+ my_off_t *fn_end, const char *qualify_db)
+{
+ if (need_db && db && db_len)
+ {
+ buf->append(STRING_WITH_LEN("use "));
+ append_identifier(thd, buf, db, db_len);
+ buf->append(STRING_WITH_LEN("; "));
+ }
+
+ buf->append(STRING_WITH_LEN("LOAD DATA "));
+
+ if (is_concurrent)
+ buf->append(STRING_WITH_LEN("CONCURRENT "));
+
+ if (fn_start)
+ *fn_start= buf->length();
+
+ if (check_fname_outside_temp_buf())
+ buf->append(STRING_WITH_LEN("LOCAL "));
+ buf->append(STRING_WITH_LEN("INFILE '"));
+ buf->append_for_single_quote(fname, fname_len);
+ buf->append(STRING_WITH_LEN("' "));
+
+ if (sql_ex.opt_flags & REPLACE_FLAG)
+ buf->append(STRING_WITH_LEN("REPLACE "));
+ else if (sql_ex.opt_flags & IGNORE_FLAG)
+ buf->append(STRING_WITH_LEN("IGNORE "));
+
+ buf->append(STRING_WITH_LEN("INTO"));
+
+ if (fn_end)
+ *fn_end= buf->length();
+
+ buf->append(STRING_WITH_LEN(" TABLE "));
+ if (qualify_db)
+ {
+ append_identifier(thd, buf, qualify_db, strlen(qualify_db));
+ buf->append(STRING_WITH_LEN("."));
+ }
+ append_identifier(thd, buf, table_name, table_name_len);
+
+ if (cs != NULL)
+ {
+ buf->append(STRING_WITH_LEN(" CHARACTER SET "));
+ buf->append(cs, strlen(cs));
+ }
+
+ /* We have to create all optional fields as the default is not empty */
+ buf->append(STRING_WITH_LEN(" FIELDS TERMINATED BY "));
+ pretty_print_str(buf, sql_ex.field_term, sql_ex.field_term_len);
+ if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG)
+ buf->append(STRING_WITH_LEN(" OPTIONALLY "));
+ buf->append(STRING_WITH_LEN(" ENCLOSED BY "));
+ pretty_print_str(buf, sql_ex.enclosed, sql_ex.enclosed_len);
+
+ buf->append(STRING_WITH_LEN(" ESCAPED BY "));
+ pretty_print_str(buf, sql_ex.escaped, sql_ex.escaped_len);
+
+ buf->append(STRING_WITH_LEN(" LINES TERMINATED BY "));
+ pretty_print_str(buf, sql_ex.line_term, sql_ex.line_term_len);
+ if (sql_ex.line_start_len)
+ {
+ buf->append(STRING_WITH_LEN(" STARTING BY "));
+ pretty_print_str(buf, sql_ex.line_start, sql_ex.line_start_len);
+ }
+
+ if ((long) skip_lines > 0)
+ {
+ buf->append(STRING_WITH_LEN(" IGNORE "));
+ buf->append_ulonglong(skip_lines);
+ buf->append(STRING_WITH_LEN(" LINES "));
+ }
+
+ if (num_fields)
+ {
+ uint i;
+ const char *field= fields;
+ buf->append(STRING_WITH_LEN(" ("));
+ for (i = 0; i < num_fields; i++)
+ {
+ if (i)
+ {
+ /*
+ Yes, the space and comma is reversed here. But this is mostly dead
+ code, at most used when reading really old binlogs from old servers,
+ so better just leave it as is...
+ */
+ buf->append(STRING_WITH_LEN(" ,"));
+ }
+ append_identifier(thd, buf, field, field_lens[i]);
+ field+= field_lens[i] + 1;
+ }
+ buf->append(STRING_WITH_LEN(")"));
+ }
+ return 0;
+}
+
+
+void Load_log_event::pack_info(Protocol *protocol)
+{
+ char query_buffer[1024];
+ String query_str(query_buffer, sizeof(query_buffer), system_charset_info);
+
+ query_str.length(0);
+ print_query(protocol->thd, TRUE, NULL, &query_str, 0, 0, NULL);
+ protocol->store(query_str.ptr(), query_str.length(), &my_charset_bin);
+}
+#endif /* defined(HAVE_REPLICATION) */
+
+
+bool Load_log_event::write_data_header()
+{
+ char buf[LOAD_HEADER_LEN];
+ int4store(buf + L_THREAD_ID_OFFSET, slave_proxy_id);
+ int4store(buf + L_EXEC_TIME_OFFSET, exec_time);
+ int4store(buf + L_SKIP_LINES_OFFSET, skip_lines);
+ buf[L_TBL_LEN_OFFSET] = (char)table_name_len;
+ buf[L_DB_LEN_OFFSET] = (char)db_len;
+ int4store(buf + L_NUM_FIELDS_OFFSET, num_fields);
+ return write_data(buf, LOAD_HEADER_LEN) != 0;
+}
+
+
+bool Load_log_event::write_data_body()
+{
+ if (sql_ex.write_data(writer))
+ return 1;
+ if (num_fields && fields && field_lens)
+ {
+ if (write_data(field_lens, num_fields) ||
+ write_data(fields, field_block_len))
+ return 1;
+ }
+ return (write_data(table_name, table_name_len + 1) ||
+ write_data(db, db_len + 1) ||
+ write_data(fname, fname_len));
+}
+
+
+Load_log_event::Load_log_event(THD *thd_arg, const sql_exchange *ex,
+ const char *db_arg, const char *table_name_arg,
+ List<Item> &fields_arg,
+ bool is_concurrent_arg,
+ enum enum_duplicates handle_dup,
+ bool ignore, bool using_trans)
+ :Log_event(thd_arg,
+ thd_arg->thread_specific_used ? LOG_EVENT_THREAD_SPECIFIC_F : 0,
+ using_trans),
+ thread_id(thd_arg->thread_id),
+ slave_proxy_id((ulong)thd_arg->variables.pseudo_thread_id),
+ num_fields(0),fields(0),
+ field_lens(0),field_block_len(0),
+ table_name(table_name_arg ? table_name_arg : ""),
+ db(db_arg), fname(ex->file_name), local_fname(FALSE),
+ is_concurrent(is_concurrent_arg)
+{
+ time_t end_time;
+ time(&end_time);
+ exec_time = (ulong) (end_time - thd_arg->start_time);
+ /* db can never be a zero pointer in 4.0 */
+ db_len = (uint32) strlen(db);
+ table_name_len = (uint32) strlen(table_name);
+ fname_len = (fname) ? (uint) strlen(fname) : 0;
+ sql_ex.field_term = ex->field_term->ptr();
+ sql_ex.field_term_len = (uint8) ex->field_term->length();
+ sql_ex.enclosed = ex->enclosed->ptr();
+ sql_ex.enclosed_len = (uint8) ex->enclosed->length();
+ sql_ex.line_term = ex->line_term->ptr();
+ sql_ex.line_term_len = (uint8) ex->line_term->length();
+ sql_ex.line_start = ex->line_start->ptr();
+ sql_ex.line_start_len = (uint8) ex->line_start->length();
+ sql_ex.escaped = ex->escaped->ptr();
+ sql_ex.escaped_len = (uint8) ex->escaped->length();
+ sql_ex.opt_flags = 0;
+ sql_ex.cached_new_format = -1;
+
+ if (ex->dumpfile)
+ sql_ex.opt_flags|= DUMPFILE_FLAG;
+ if (ex->opt_enclosed)
+ sql_ex.opt_flags|= OPT_ENCLOSED_FLAG;
+
+ sql_ex.empty_flags= 0;
+
+ switch (handle_dup) {
+ case DUP_REPLACE:
+ sql_ex.opt_flags|= REPLACE_FLAG;
+ break;
+ case DUP_UPDATE: // Impossible here
+ case DUP_ERROR:
+ break;
+ }
+ if (ignore)
+ sql_ex.opt_flags|= IGNORE_FLAG;
+
+ if (!ex->field_term->length())
+ sql_ex.empty_flags |= FIELD_TERM_EMPTY;
+ if (!ex->enclosed->length())
+ sql_ex.empty_flags |= ENCLOSED_EMPTY;
+ if (!ex->line_term->length())
+ sql_ex.empty_flags |= LINE_TERM_EMPTY;
+ if (!ex->line_start->length())
+ sql_ex.empty_flags |= LINE_START_EMPTY;
+ if (!ex->escaped->length())
+ sql_ex.empty_flags |= ESCAPED_EMPTY;
+
+ skip_lines = ex->skip_lines;
+
+ List_iterator<Item> li(fields_arg);
+ field_lens_buf.length(0);
+ fields_buf.length(0);
+ Item* item;
+ while ((item = li++))
+ {
+ num_fields++;
+ uchar len= (uchar) item->name.length;
+ field_block_len += len + 1;
+ fields_buf.append(item->name.str, len + 1);
+ field_lens_buf.append((char*)&len, 1);
+ }
+
+ field_lens = (const uchar*)field_lens_buf.ptr();
+ fields = fields_buf.ptr();
+}
+
+
+/**
+ Load_log_event::set_fields()
+
+ @note
+ This function can not use the member variable
+ for the database, since LOAD DATA INFILE on the slave
+ can be for a different database than the current one.
+ This is the reason for the affected_db argument to this method.
+*/
+
+void Load_log_event::set_fields(const char* affected_db,
+ List<Item> &field_list,
+ Name_resolution_context *context)
+{
+ uint i;
+ const char* field = fields;
+ for (i= 0; i < num_fields; i++)
+ {
+ LEX_CSTRING field_name= {field, field_lens[i] };
+ field_list.push_back(new (thd->mem_root)
+ Item_field(thd, context,
+ Lex_cstring_strlen(affected_db),
+ Lex_cstring_strlen(table_name),
+ field_name),
+ thd->mem_root);
+ field+= field_lens[i] + 1;
+ }
+}
+
+
+#if defined(HAVE_REPLICATION)
+/**
+ Does the data loading job when executing a LOAD DATA on the slave.
+
+ @param net
+ @param rli
+ @param use_rli_only_for_errors If set to 1, rli is provided to
+ Load_log_event::exec_event only for this
+ function to have RPL_LOG_NAME and
+ rli->last_slave_error, both being used by
+ error reports. rli's position advancing
+ is skipped (done by the caller which is
+ Execute_load_log_event::exec_event).
+ If set to 0, rli is provided for full use,
+ i.e. for error reports and position
+ advancing.
+
+ @todo
+ fix this; this can be done by testing rules in
+ Create_file_log_event::exec_event() and then discarding Append_block and
+ al.
+ @todo
+ this is a bug - this needs to be moved to the I/O thread
+
+ @retval
+ 0 Success
+ @retval
+ 1 Failure
+*/
+
+int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi,
+ bool use_rli_only_for_errors)
+{
+ Relay_log_info const *rli= rgi->rli;
+ Rpl_filter *rpl_filter= rli->mi->rpl_filter;
+ DBUG_ENTER("Load_log_event::do_apply_event");
+
+ 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 */
+ DBUG_ASSERT(!rgi->m_table_map.count());
+ /*
+ Usually lex_start() is called by mysql_parse(), but we need it here
+ as the present method does not call mysql_parse().
+ */
+ lex_start(thd);
+ thd->lex->local_file= local_fname;
+ thd->reset_for_next_command(0); // Errors are cleared above
+
+ /*
+ We test replicate_*_db rules. Note that we have already prepared
+ the file to load, even if we are going to ignore and delete it
+ now. So it is possible that we did a lot of disk writes for
+ nothing. In other words, a big LOAD DATA INFILE on the master will
+ still consume a lot of space on the slave (space in the relay log
+ + space of temp files: twice the space of the file to load...)
+ even if it will finally be ignored. TODO: fix this; this can be
+ done by testing rules in Create_file_log_event::do_apply_event()
+ and then discarding Append_block and al. Another way is do the
+ filtering in the I/O thread (more efficient: no disk writes at
+ all).
+
+
+ Note: We do not need to execute reset_one_shot_variables() if this
+ db_ok() test fails.
+ Reason: The db stored in binlog events is the same for SET and for
+ its companion query. If the SET is ignored because of
+ db_ok(), the companion query will also be ignored, and if
+ the companion query is ignored in the db_ok() test of
+ ::do_apply_event(), then the companion SET also have so
+ we don't need to reset_one_shot_variables().
+ */
+ if (rpl_filter->db_ok(thd->db.str))
+ {
+ thd->set_time(when, when_sec_part);
+ thd->set_query_id(next_query_id());
+ thd->get_stmt_da()->opt_clear_warning_info(thd->query_id);
+
+ 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;
+
+ // the table will be opened in mysql_load
+ if (rpl_filter->is_on() && !rpl_filter->tables_ok(thd->db.str, &tables))
+ {
+ // TODO: this is a bug - this needs to be moved to the I/O thread
+ if (net)
+ skip_load_data_infile(net);
+ }
+ else
+ {
+ enum enum_duplicates handle_dup;
+ bool ignore= 0;
+ char query_buffer[1024];
+ String query_str(query_buffer, sizeof(query_buffer), system_charset_info);
+ char *load_data_query;
+
+ query_str.length(0);
+ /*
+ Forge LOAD DATA INFILE query which will be used in SHOW PROCESS LIST
+ and written to slave's binlog if binlogging is on.
+ */
+ print_query(thd, FALSE, NULL, &query_str, NULL, NULL, NULL);
+ if (!(load_data_query= (char *)thd->strmake(query_str.ptr(),
+ query_str.length())))
+ {
+ /*
+ This will set thd->fatal_error in case of OOM. So we surely will notice
+ that something is wrong.
+ */
+ goto error;
+ }
+
+ thd->set_query(load_data_query, (uint) (query_str.length()));
+
+ if (sql_ex.opt_flags & REPLACE_FLAG)
+ handle_dup= DUP_REPLACE;
+ else if (sql_ex.opt_flags & IGNORE_FLAG)
+ {
+ ignore= 1;
+ handle_dup= DUP_ERROR;
+ }
+ else
+ {
+ /*
+ When replication is running fine, if it was DUP_ERROR on the
+ master then we could choose IGNORE here, because if DUP_ERROR
+ suceeded on master, and data is identical on the master and slave,
+ then there should be no uniqueness errors on slave, so IGNORE is
+ the same as DUP_ERROR. But in the unlikely case of uniqueness errors
+ (because the data on the master and slave happen to be different
+ (user error or bug), we want LOAD DATA to print an error message on
+ the slave to discover the problem.
+
+ If reading from net (a 3.23 master), mysql_load() will change this
+ to IGNORE.
+ */
+ handle_dup= DUP_ERROR;
+ }
+ /*
+ We need to set thd->lex->sql_command and thd->lex->duplicates
+ since InnoDB tests these variables to decide if this is a LOAD
+ DATA ... REPLACE INTO ... statement even though mysql_parse()
+ is not called. This is not needed in 5.0 since there the LOAD
+ DATA ... statement is replicated using mysql_parse(), which
+ sets the thd->lex fields correctly.
+ */
+ thd->lex->sql_command= SQLCOM_LOAD;
+ thd->lex->duplicates= handle_dup;
+
+ sql_exchange ex((char*)fname, sql_ex.opt_flags & DUMPFILE_FLAG);
+ String field_term(sql_ex.field_term,sql_ex.field_term_len,log_cs);
+ String enclosed(sql_ex.enclosed,sql_ex.enclosed_len,log_cs);
+ String line_term(sql_ex.line_term,sql_ex.line_term_len,log_cs);
+ String line_start(sql_ex.line_start,sql_ex.line_start_len,log_cs);
+ String escaped(sql_ex.escaped,sql_ex.escaped_len, log_cs);
+ ex.field_term= &field_term;
+ ex.enclosed= &enclosed;
+ ex.line_term= &line_term;
+ ex.line_start= &line_start;
+ ex.escaped= &escaped;
+
+ ex.opt_enclosed = (sql_ex.opt_flags & OPT_ENCLOSED_FLAG);
+ if (sql_ex.empty_flags & FIELD_TERM_EMPTY)
+ ex.field_term->length(0);
+
+ ex.skip_lines = skip_lines;
+ List<Item> field_list;
+ thd->lex->first_select_lex()->context.resolve_in_table_list_only(&tables);
+ set_fields(tables.db.str,
+ field_list, &thd->lex->first_select_lex()->context);
+ thd->variables.pseudo_thread_id= thread_id;
+ if (net)
+ {
+ // mysql_load will use thd->net to read the file
+ thd->net.vio = net->vio;
+ // Make sure the client does not get confused about the packet sequence
+ thd->net.pkt_nr = net->pkt_nr;
+ }
+ /*
+ It is safe to use tmp_list twice because we are not going to
+ update it inside mysql_load().
+ */
+ List<Item> tmp_list;
+ if (thd->open_temporary_tables(&tables) ||
+ mysql_load(thd, &ex, &tables, field_list, tmp_list, tmp_list,
+ handle_dup, ignore, net != 0))
+ thd->is_slave_error= 1;
+ if (thd->cuted_fields)
+ {
+ /* log_pos is the position of the LOAD event in the master log */
+ sql_print_warning("Slave: load data infile on table '%s' at "
+ "log position %llu in log '%s' produced %ld "
+ "warning(s). Default database: '%s'",
+ (char*) table_name, log_pos, RPL_LOG_NAME,
+ (ulong) thd->cuted_fields,
+ thd->get_db());
+ }
+ if (net)
+ net->pkt_nr= thd->net.pkt_nr;
+ }
+ }
+ else
+ {
+ /*
+ We will just ask the master to send us /dev/null if we do not
+ want to load the data.
+ TODO: this a bug - needs to be done in I/O thread
+ */
+ if (net)
+ skip_load_data_infile(net);
+ }
+
+error:
+ thd->net.vio = 0;
+ const char *remember_db= thd->get_db();
+ thd->catalog= 0;
+ thd->set_db(&null_clex_str); /* will free the current database */
+ thd->reset_query();
+ thd->get_stmt_da()->set_overwrite_status(true);
+ thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
+ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN);
+ thd->get_stmt_da()->set_overwrite_status(false);
+ close_thread_tables(thd);
+ /*
+ - If transaction rollback was requested due to deadlock
+ perform it and release metadata locks.
+ - If inside a multi-statement transaction,
+ defer the release of metadata locks until the current
+ transaction is either committed or rolled back. This prevents
+ other statements from modifying the table for the entire
+ duration of this transaction. This provides commit ordering
+ and guarantees serializability across multiple transactions.
+ - If in autocommit mode, or outside a transactional context,
+ automatically release metadata locks of the current statement.
+ */
+ if (thd->transaction_rollback_request)
+ {
+ trans_rollback_implicit(thd);
+ thd->mdl_context.release_transactional_locks();
+ }
+ else if (! thd->in_multi_stmt_transaction_mode())
+ thd->mdl_context.release_transactional_locks();
+ else
+ thd->mdl_context.release_statement_locks();
+
+ DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error",
+ thd->is_slave_error= 0; thd->is_fatal_error= 1;);
+
+ if (unlikely(thd->is_slave_error))
+ {
+ /* this err/sql_errno code is copy-paste from net_send_error() */
+ const char *err;
+ int sql_errno;
+ if (thd->is_error())
+ {
+ err= thd->get_stmt_da()->message();
+ sql_errno= thd->get_stmt_da()->sql_errno();
+ }
+ else
+ {
+ sql_errno=ER_UNKNOWN_ERROR;
+ err= ER_THD(thd, sql_errno);
+ }
+ rli->report(ERROR_LEVEL, sql_errno, rgi->gtid_info(), "\
+Error '%s' running LOAD DATA INFILE on table '%s'. Default database: '%s'",
+ err, (char*)table_name, remember_db);
+ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
+ DBUG_RETURN(1);
+ }
+ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
+
+ if (unlikely(thd->is_fatal_error))
+ {
+ char buf[256];
+ my_snprintf(buf, sizeof(buf),
+ "Running LOAD DATA INFILE on table '%-.64s'."
+ " Default database: '%-.64s'",
+ (char*)table_name,
+ remember_db);
+
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, rgi->gtid_info(),
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR), buf);
+ DBUG_RETURN(1);
+ }
+
+ DBUG_RETURN( use_rli_only_for_errors ? 0 : Log_event::do_apply_event(rgi) );
+}
+#endif
+
+
+/**************************************************************************
+ Rotate_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+void Rotate_log_event::pack_info(Protocol *protocol)
+{
+ StringBuffer<256> tmp(log_cs);
+ tmp.length(0);
+ tmp.append(new_log_ident, ident_len);
+ tmp.append(STRING_WITH_LEN(";pos="));
+ tmp.append_ulonglong(pos);
+ protocol->store(tmp.ptr(), tmp.length(), &my_charset_bin);
+}
+#endif
+
+
+Rotate_log_event::Rotate_log_event(const char* new_log_ident_arg,
+ uint ident_len_arg, ulonglong pos_arg,
+ uint flags_arg)
+ :Log_event(), new_log_ident(new_log_ident_arg),
+ pos(pos_arg),ident_len(ident_len_arg ? ident_len_arg :
+ (uint) strlen(new_log_ident_arg)), flags(flags_arg)
+{
+ DBUG_ENTER("Rotate_log_event::Rotate_log_event(...,flags)");
+ DBUG_PRINT("enter",("new_log_ident: %s pos: %llu flags: %lu", new_log_ident_arg,
+ pos_arg, (ulong) flags));
+ cache_type= EVENT_NO_CACHE;
+ if (flags & DUP_NAME)
+ new_log_ident= my_strndup(PSI_INSTRUMENT_ME, new_log_ident_arg, ident_len, MYF(MY_WME));
+ if (flags & RELAY_LOG)
+ set_relay_log_event();
+ DBUG_VOID_RETURN;
+}
+
+
+bool Rotate_log_event::write()
+{
+ char buf[ROTATE_HEADER_LEN];
+ int8store(buf + R_POS_OFFSET, pos);
+ return (write_header(ROTATE_HEADER_LEN + ident_len) ||
+ write_data(buf, ROTATE_HEADER_LEN) ||
+ write_data(new_log_ident, (uint) ident_len) ||
+ write_footer());
+}
+
+
+#if defined(HAVE_REPLICATION)
+
+/*
+ Got a rotate log event from the master.
+
+ This is mainly used so that we can later figure out the logname and
+ position for the master.
+
+ We can't rotate the slave's BINlog as this will cause infinitive rotations
+ in a A -> B -> A setup.
+ The NOTES below is a wrong comment which will disappear when 4.1 is merged.
+
+ This must only be called from the Slave SQL thread, since it calls
+ Relay_log_info::flush().
+
+ @retval
+ 0 ok
+ 1 error
+*/
+int Rotate_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ int error= 0;
+ Relay_log_info *rli= rgi->rli;
+ DBUG_ENTER("Rotate_log_event::do_update_pos");
+
+ DBUG_PRINT("info", ("server_id=%lu; ::server_id=%lu",
+ (ulong) this->server_id, (ulong) global_system_variables.server_id));
+ DBUG_PRINT("info", ("new_log_ident: %s", this->new_log_ident));
+ DBUG_PRINT("info", ("pos: %llu", this->pos));
+
+ /*
+ If we are in a transaction or in a group: the only normal case is
+ when the I/O thread was copying a big transaction, then it was
+ stopped and restarted: we have this in the relay log:
+
+ BEGIN
+ ...
+ ROTATE (a fake one)
+ ...
+ COMMIT or ROLLBACK
+
+ In that case, we don't want to touch the coordinates which
+ correspond to the beginning of the transaction. Starting from
+ 5.0.0, there also are some rotates from the slave itself, in the
+ relay log, which shall not change the group positions.
+
+ In parallel replication, rotate event is executed out-of-band with normal
+ events, so we cannot update group_master_log_name or _pos here, it will
+ be updated with the next normal event instead.
+ */
+ if ((server_id != global_system_variables.server_id ||
+ rli->replicate_same_server_id) &&
+ !is_relay_log_event() &&
+ !rli->is_in_group() &&
+ !rgi->is_parallel_exec)
+ {
+ mysql_mutex_lock(&rli->data_lock);
+ DBUG_PRINT("info", ("old group_master_log_name: '%s' "
+ "old group_master_log_pos: %lu",
+ rli->group_master_log_name,
+ (ulong) rli->group_master_log_pos));
+ memcpy(rli->group_master_log_name, new_log_ident, ident_len+1);
+ rli->notify_group_master_log_name_update();
+ rli->inc_group_relay_log_pos(pos, rgi, TRUE /* skip_lock */);
+ DBUG_PRINT("info", ("new group_master_log_name: '%s' "
+ "new group_master_log_pos: %lu",
+ rli->group_master_log_name,
+ (ulong) rli->group_master_log_pos));
+ mysql_mutex_unlock(&rli->data_lock);
+ rpl_global_gtid_slave_state->record_and_update_gtid(thd, rgi);
+ error= rli->flush();
+
+ /*
+ Reset thd->variables.option_bits and sql_mode etc, because this could
+ be the signal of a master's downgrade from 5.0 to 4.0.
+ However, no need to reset description_event_for_exec: indeed, if the next
+ master is 5.0 (even 5.0.1) we will soon get a Format_desc; if the next
+ master is 4.0 then the events are in the slave's format (conversion).
+ */
+ set_slave_thread_options(thd);
+ set_slave_thread_default_charset(thd, rgi);
+ thd->variables.sql_mode= global_system_variables.sql_mode;
+ thd->variables.auto_increment_increment=
+ thd->variables.auto_increment_offset= 1;
+ }
+ else
+ rgi->inc_event_relay_log_pos();
+
+ DBUG_RETURN(error);
+}
+
+
+Log_event::enum_skip_reason
+Rotate_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ enum_skip_reason reason= Log_event::do_shall_skip(rgi);
+
+ switch (reason) {
+ case Log_event::EVENT_SKIP_NOT:
+ case Log_event::EVENT_SKIP_COUNT:
+ return Log_event::EVENT_SKIP_NOT;
+
+ case Log_event::EVENT_SKIP_IGNORE:
+ return Log_event::EVENT_SKIP_IGNORE;
+ }
+ DBUG_ASSERT(0);
+ return Log_event::EVENT_SKIP_NOT; // To keep compiler happy
+}
+
+#endif
+
+
+/**************************************************************************
+ Binlog_checkpoint_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+void Binlog_checkpoint_log_event::pack_info(Protocol *protocol)
+{
+ protocol->store(binlog_file_name, binlog_file_len, &my_charset_bin);
+}
+
+
+Log_event::enum_skip_reason
+Binlog_checkpoint_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ enum_skip_reason reason= Log_event::do_shall_skip(rgi);
+ if (reason == EVENT_SKIP_COUNT)
+ reason= EVENT_SKIP_NOT;
+ return reason;
+}
+#endif
+
+
+Binlog_checkpoint_log_event::Binlog_checkpoint_log_event(
+ const char *binlog_file_name_arg,
+ uint binlog_file_len_arg)
+ :Log_event(),
+ binlog_file_name(my_strndup(PSI_INSTRUMENT_ME, binlog_file_name_arg, binlog_file_len_arg,
+ MYF(MY_WME))),
+ binlog_file_len(binlog_file_len_arg)
+{
+ cache_type= EVENT_NO_CACHE;
+}
+
+
+bool Binlog_checkpoint_log_event::write()
+{
+ uchar buf[BINLOG_CHECKPOINT_HEADER_LEN];
+ int4store(buf, binlog_file_len);
+ return write_header(BINLOG_CHECKPOINT_HEADER_LEN + binlog_file_len) ||
+ write_data(buf, BINLOG_CHECKPOINT_HEADER_LEN) ||
+ write_data(binlog_file_name, binlog_file_len) ||
+ write_footer();
+}
+
+
+/**************************************************************************
+ Global transaction ID stuff
+**************************************************************************/
+
+Gtid_log_event::Gtid_log_event(THD *thd_arg, uint64 seq_no_arg,
+ uint32 domain_id_arg, bool standalone,
+ uint16 flags_arg, bool is_transactional,
+ uint64 commit_id_arg)
+ : Log_event(thd_arg, flags_arg, is_transactional),
+ seq_no(seq_no_arg), commit_id(commit_id_arg), domain_id(domain_id_arg),
+ flags2((standalone ? FL_STANDALONE : 0) | (commit_id_arg ? FL_GROUP_COMMIT_ID : 0))
+{
+ cache_type= Log_event::EVENT_NO_CACHE;
+ bool is_tmp_table= thd_arg->lex->stmt_accessed_temp_table();
+ if (thd_arg->transaction.stmt.trans_did_wait() ||
+ thd_arg->transaction.all.trans_did_wait())
+ flags2|= FL_WAITED;
+ if (thd_arg->transaction.stmt.trans_did_ddl() ||
+ thd_arg->transaction.stmt.has_created_dropped_temp_table() ||
+ thd_arg->transaction.all.trans_did_ddl() ||
+ thd_arg->transaction.all.has_created_dropped_temp_table())
+ flags2|= FL_DDL;
+ else if (is_transactional && !is_tmp_table)
+ flags2|= FL_TRANSACTIONAL;
+ if (!(thd_arg->variables.option_bits & OPTION_RPL_SKIP_PARALLEL))
+ flags2|= FL_ALLOW_PARALLEL;
+ /* Preserve any DDL or WAITED flag in the slave's binlog. */
+ if (thd_arg->rgi_slave)
+ flags2|= (thd_arg->rgi_slave->gtid_ev_flags2 & (FL_DDL|FL_WAITED));
+
+ XID_STATE &xid_state= thd->transaction.xid_state;
+ if (is_transactional && xid_state.is_explicit_XA() &&
+ (thd->lex->sql_command == SQLCOM_XA_PREPARE ||
+ xid_state.get_state_code() == XA_PREPARED))
+ {
+ DBUG_ASSERT(thd->lex->xa_opt != XA_ONE_PHASE);
+
+ flags2|= thd->lex->sql_command == SQLCOM_XA_PREPARE ?
+ FL_PREPARED_XA : FL_COMPLETED_XA;
+ xid.set(xid_state.get_xid());
+ }
+}
+
+
+/*
+ Used to record GTID while sending binlog to slave, without having to
+ fully contruct every Gtid_log_event() needlessly.
+*/
+bool
+Gtid_log_event::peek(const char *event_start, size_t event_len,
+ enum enum_binlog_checksum_alg checksum_alg,
+ uint32 *domain_id, uint32 *server_id, uint64 *seq_no,
+ uchar *flags2, const Format_description_log_event *fdev)
+{
+ const char *p;
+
+ if (checksum_alg == BINLOG_CHECKSUM_ALG_CRC32)
+ {
+ if (event_len > BINLOG_CHECKSUM_LEN)
+ event_len-= BINLOG_CHECKSUM_LEN;
+ else
+ event_len= 0;
+ }
+ else
+ DBUG_ASSERT(checksum_alg == BINLOG_CHECKSUM_ALG_UNDEF ||
+ checksum_alg == BINLOG_CHECKSUM_ALG_OFF);
+
+ if (event_len < (uint32)fdev->common_header_len + GTID_HEADER_LEN)
+ return true;
+ *server_id= uint4korr(event_start + SERVER_ID_OFFSET);
+ p= event_start + fdev->common_header_len;
+ *seq_no= uint8korr(p);
+ p+= 8;
+ *domain_id= uint4korr(p);
+ p+= 4;
+ *flags2= (uchar)*p;
+ return false;
+}
+
+
+bool
+Gtid_log_event::write()
+{
+ uchar buf[GTID_HEADER_LEN+2+sizeof(XID)];
+ size_t write_len;
+
+ int8store(buf, seq_no);
+ int4store(buf+8, domain_id);
+ buf[12]= flags2;
+ if (flags2 & FL_GROUP_COMMIT_ID)
+ {
+ int8store(buf+13, commit_id);
+ write_len= GTID_HEADER_LEN + 2;
+ }
+ else
+ write_len= 13;
+
+ if (flags2 & (FL_PREPARED_XA | FL_COMPLETED_XA))
+ {
+ int4store(&buf[write_len], xid.formatID);
+ buf[write_len +4]= (uchar) xid.gtrid_length;
+ buf[write_len +4+1]= (uchar) xid.bqual_length;
+ write_len+= 6;
+ long data_length= xid.bqual_length + xid.gtrid_length;
+ memcpy(buf+write_len, xid.data, data_length);
+ write_len+= data_length;
+ }
+
+ if (write_len < GTID_HEADER_LEN)
+ {
+ bzero(buf+write_len, GTID_HEADER_LEN-write_len);
+ write_len= GTID_HEADER_LEN;
+ }
+ return write_header(write_len) ||
+ write_data(buf, write_len) ||
+ write_footer();
+}
+
+
+/*
+ Replace a GTID event with either a BEGIN event, dummy event, or nothing, as
+ appropriate to work with old slave that does not know global transaction id.
+
+ The need_dummy_event argument is an IN/OUT argument. It is passed as TRUE
+ if slave has capability lower than MARIA_SLAVE_CAPABILITY_TOLERATE_HOLES.
+ It is returned TRUE if we return a BEGIN (or dummy) event to be sent to the
+ slave, FALSE if event should be skipped completely.
+*/
+int
+Gtid_log_event::make_compatible_event(String *packet, bool *need_dummy_event,
+ ulong ev_offset,
+ enum enum_binlog_checksum_alg checksum_alg)
+{
+ uchar flags2;
+ if (packet->length() - ev_offset < LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN)
+ return 1;
+ flags2= (*packet)[ev_offset + LOG_EVENT_HEADER_LEN + 12];
+ if (flags2 & FL_STANDALONE)
+ {
+ if (*need_dummy_event)
+ return Query_log_event::dummy_event(packet, ev_offset, checksum_alg);
+ return 0;
+ }
+
+ *need_dummy_event= true;
+ return Query_log_event::begin_event(packet, ev_offset, checksum_alg);
+}
+
+
+#ifdef HAVE_REPLICATION
+void
+Gtid_log_event::pack_info(Protocol *protocol)
+{
+ char buf[6+5+10+1+10+1+20+1+4+20+1+ ser_buf_size+5 /* sprintf */];
+ char *p;
+ p = strmov(buf, (flags2 & FL_STANDALONE ? "GTID " :
+ flags2 & FL_PREPARED_XA ? "XA START " : "BEGIN GTID "));
+ if (flags2 & FL_PREPARED_XA)
+ {
+ p+= sprintf(p, "%s GTID ", xid.serialize());
+ }
+ p= longlong10_to_str(domain_id, p, 10);
+ *p++= '-';
+ p= longlong10_to_str(server_id, p, 10);
+ *p++= '-';
+ p= longlong10_to_str(seq_no, p, 10);
+ if (flags2 & FL_GROUP_COMMIT_ID)
+ {
+ p= strmov(p, " cid=");
+ p= longlong10_to_str(commit_id, p, 10);
+ }
+
+ protocol->store(buf, p-buf, &my_charset_bin);
+}
+
+static char gtid_begin_string[] = "BEGIN";
+
+int
+Gtid_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ ulonglong bits= thd->variables.option_bits;
+ thd->variables.server_id= this->server_id;
+ thd->variables.gtid_domain_id= this->domain_id;
+ thd->variables.gtid_seq_no= this->seq_no;
+ rgi->gtid_ev_flags2= flags2;
+ thd->reset_for_next_command();
+
+ if (opt_gtid_strict_mode && opt_bin_log && opt_log_slave_updates)
+ {
+ if (mysql_bin_log.check_strict_gtid_sequence(this->domain_id,
+ this->server_id, this->seq_no))
+ return 1;
+ }
+
+ DBUG_ASSERT((bits & OPTION_GTID_BEGIN) == 0);
+
+ Master_info *mi=rgi->rli->mi;
+ switch (flags2 & (FL_DDL | FL_TRANSACTIONAL))
+ {
+ case FL_TRANSACTIONAL:
+ mi->total_trans_groups++;
+ break;
+ case FL_DDL:
+ mi->total_ddl_groups++;
+ break;
+ default:
+ mi->total_non_trans_groups++;
+ }
+
+ if (flags2 & FL_STANDALONE)
+ return 0;
+
+ /* Execute this like a BEGIN query event. */
+ bits|= OPTION_GTID_BEGIN;
+ if (flags2 & FL_ALLOW_PARALLEL)
+ bits&= ~(ulonglong)OPTION_RPL_SKIP_PARALLEL;
+ else
+ bits|= (ulonglong)OPTION_RPL_SKIP_PARALLEL;
+ thd->variables.option_bits= bits;
+ DBUG_PRINT("info", ("Set OPTION_GTID_BEGIN"));
+ thd->is_slave_error= 0;
+
+ char buf_xa[sizeof("XA START") + 1 + ser_buf_size];
+ if (flags2 & FL_PREPARED_XA)
+ {
+ const char fmt[]= "XA START %s";
+
+ thd->lex->xid= &xid;
+ thd->lex->xa_opt= XA_NONE;
+ sprintf(buf_xa, fmt, xid.serialize());
+ thd->set_query_and_id(buf_xa, static_cast<uint32>(strlen(buf_xa)),
+ &my_charset_bin, next_query_id());
+ thd->lex->sql_command= SQLCOM_XA_START;
+ if (trans_xa_start(thd))
+ {
+ DBUG_PRINT("error", ("trans_xa_start() failed"));
+ thd->is_slave_error= 1;
+ }
+ }
+ else
+ {
+ thd->set_query_and_id(gtid_begin_string, sizeof(gtid_begin_string)-1,
+ &my_charset_bin, next_query_id());
+ thd->lex->sql_command= SQLCOM_BEGIN;
+ if (trans_begin(thd, 0))
+ {
+ DBUG_PRINT("error", ("trans_begin() failed"));
+ thd->is_slave_error= 1;
+ }
+ }
+ status_var_increment(thd->status_var.com_stat[thd->lex->sql_command]);
+ thd->update_stats();
+
+ if (likely(!thd->is_slave_error))
+ general_log_write(thd, COM_QUERY, thd->query(), thd->query_length());
+
+ thd->reset_query();
+ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
+ return thd->is_slave_error;
+}
+
+
+int
+Gtid_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ rgi->inc_event_relay_log_pos();
+ return 0;
+}
+
+
+Log_event::enum_skip_reason
+Gtid_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ Relay_log_info *rli= rgi->rli;
+ /*
+ An event skipped due to @@skip_replication must not be counted towards the
+ number of events to be skipped due to @@sql_slave_skip_counter.
+ */
+ if (flags & LOG_EVENT_SKIP_REPLICATION_F &&
+ opt_replicate_events_marked_for_skip != RPL_SKIP_REPLICATE)
+ return Log_event::EVENT_SKIP_IGNORE;
+
+ if (rli->slave_skip_counter > 0)
+ {
+ if (!(flags2 & FL_STANDALONE))
+ {
+ thd->variables.option_bits|= OPTION_BEGIN;
+ DBUG_ASSERT(rgi->rli->get_flag(Relay_log_info::IN_TRANSACTION));
+ }
+ return Log_event::continue_group(rgi);
+ }
+ return Log_event::do_shall_skip(rgi);
+}
+
+
+#endif /* HAVE_REPLICATION */
+
+
+
+Gtid_list_log_event::Gtid_list_log_event(rpl_binlog_state *gtid_set,
+ uint32 gl_flags_)
+ : count(gtid_set->count()), gl_flags(gl_flags_), list(0), sub_id_list(0)
+{
+ cache_type= EVENT_NO_CACHE;
+ /* Failure to allocate memory will be caught by is_valid() returning false. */
+ if (count < (1<<28) &&
+ (list = (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME,
+ count * sizeof(*list) + (count == 0), MYF(MY_WME))))
+ gtid_set->get_gtid_list(list, count);
+}
+
+
+Gtid_list_log_event::Gtid_list_log_event(slave_connection_state *gtid_set,
+ uint32 gl_flags_)
+ : count(gtid_set->count()), gl_flags(gl_flags_), list(0), sub_id_list(0)
+{
+ cache_type= EVENT_NO_CACHE;
+ /* Failure to allocate memory will be caught by is_valid() returning false. */
+ if (count < (1<<28) &&
+ (list = (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME,
+ count * sizeof(*list) + (count == 0), MYF(MY_WME))))
+ {
+ gtid_set->get_gtid_list(list, count);
+#if defined(HAVE_REPLICATION)
+ if (gl_flags & FLAG_IGN_GTIDS)
+ {
+ uint32 i;
+
+ if (!(sub_id_list= (uint64 *)my_malloc(PSI_INSTRUMENT_ME,
+ count * sizeof(uint64), MYF(MY_WME))))
+ {
+ my_free(list);
+ list= NULL;
+ return;
+ }
+ for (i= 0; i < count; ++i)
+ {
+ if (!(sub_id_list[i]=
+ rpl_global_gtid_slave_state->next_sub_id(list[i].domain_id)))
+ {
+ my_free(list);
+ my_free(sub_id_list);
+ list= NULL;
+ sub_id_list= NULL;
+ return;
+ }
+ }
+ }
+#endif
+ }
+}
+
+
+#if defined(HAVE_REPLICATION)
+bool
+Gtid_list_log_event::to_packet(String *packet)
+{
+ uint32 i;
+ uchar *p;
+ uint32 needed_length;
+
+ DBUG_ASSERT(count < 1<<28);
+
+ needed_length= packet->length() + get_data_size();
+ if (packet->reserve(needed_length))
+ return true;
+ p= (uchar *)packet->ptr() + packet->length();;
+ packet->length(needed_length);
+ int4store(p, (count & ((1<<28)-1)) | gl_flags);
+ p += 4;
+ /* Initialise the padding for empty Gtid_list. */
+ if (count == 0)
+ int2store(p, 0);
+ for (i= 0; i < count; ++i)
+ {
+ int4store(p, list[i].domain_id);
+ int4store(p+4, list[i].server_id);
+ int8store(p+8, list[i].seq_no);
+ p += 16;
+ }
+
+ return false;
+}
+
+
+bool
+Gtid_list_log_event::write()
+{
+ char buf[128];
+ String packet(buf, sizeof(buf), system_charset_info);
+
+ packet.length(0);
+ if (to_packet(&packet))
+ return true;
+ return write_header(get_data_size()) ||
+ write_data(packet.ptr(), packet.length()) ||
+ write_footer();
+}
+
+
+int
+Gtid_list_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ Relay_log_info *rli= const_cast<Relay_log_info*>(rgi->rli);
+ int ret;
+ if (gl_flags & FLAG_IGN_GTIDS)
+ {
+ void *hton= NULL;
+ uint32 i;
+
+ for (i= 0; i < count; ++i)
+ {
+ if ((ret= rpl_global_gtid_slave_state->record_gtid(thd, &list[i],
+ sub_id_list[i],
+ false, false, &hton)))
+ return ret;
+ rpl_global_gtid_slave_state->update_state_hash(sub_id_list[i], &list[i],
+ hton, NULL);
+ }
+ }
+ ret= Log_event::do_apply_event(rgi);
+ if (rli->until_condition == Relay_log_info::UNTIL_GTID &&
+ (gl_flags & FLAG_UNTIL_REACHED))
+ {
+ char str_buf[128];
+ String str(str_buf, sizeof(str_buf), system_charset_info);
+ rli->until_gtid_pos.to_string(&str);
+ sql_print_information("Slave SQL thread stops because it reached its"
+ " UNTIL master_gtid_pos %s", str.c_ptr_safe());
+ rli->abort_slave= true;
+ rli->stop_for_until= true;
+ }
+ free_root(thd->mem_root, MYF(MY_KEEP_PREALLOC));
+ return ret;
+}
+
+
+Log_event::enum_skip_reason
+Gtid_list_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ enum_skip_reason reason= Log_event::do_shall_skip(rgi);
+ if (reason == EVENT_SKIP_COUNT)
+ reason= EVENT_SKIP_NOT;
+ return reason;
+}
+
+
+void
+Gtid_list_log_event::pack_info(Protocol *protocol)
+{
+ char buf_mem[1024];
+ String buf(buf_mem, sizeof(buf_mem), system_charset_info);
+ uint32 i;
+ bool first;
+
+ buf.length(0);
+ buf.append(STRING_WITH_LEN("["));
+ first= true;
+ for (i= 0; i < count; ++i)
+ rpl_slave_state_tostring_helper(&buf, &list[i], &first);
+ buf.append(STRING_WITH_LEN("]"));
+
+ protocol->store(&buf);
+}
+#endif /* HAVE_REPLICATION */
+
+
+
+/**************************************************************************
+ Intvar_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+void Intvar_log_event::pack_info(Protocol *protocol)
+{
+ char buf[256], *pos;
+ pos= strmake(buf, get_var_type_name(), sizeof(buf)-23);
+ *pos++= '=';
+ pos= longlong10_to_str(val, pos, -10);
+ protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
+}
+#endif
+
+
+bool Intvar_log_event::write()
+{
+ uchar buf[9];
+ buf[I_TYPE_OFFSET]= (uchar) type;
+ int8store(buf + I_VAL_OFFSET, val);
+ return write_header(sizeof(buf)) ||
+ write_data(buf, sizeof(buf)) ||
+ write_footer();
+}
+
+
+#if defined(HAVE_REPLICATION)
+
+/*
+ Intvar_log_event::do_apply_event()
+*/
+
+int Intvar_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ DBUG_ENTER("Intvar_log_event::do_apply_event");
+ if (rgi->deferred_events_collecting)
+ {
+ DBUG_PRINT("info",("deferring event"));
+ DBUG_RETURN(rgi->deferred_events->add(this));
+ }
+
+ switch (type) {
+ case LAST_INSERT_ID_EVENT:
+ thd->first_successful_insert_id_in_prev_stmt= val;
+ DBUG_PRINT("info",("last_insert_id_event: %ld", (long) val));
+ break;
+ case INSERT_ID_EVENT:
+ thd->force_one_auto_inc_interval(val);
+ break;
+ }
+ DBUG_RETURN(0);
+}
+
+int Intvar_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ rgi->inc_event_relay_log_pos();
+ return 0;
+}
+
+
+Log_event::enum_skip_reason
+Intvar_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ /*
+ It is a common error to set the slave skip counter to 1 instead of
+ 2 when recovering from an insert which used a auto increment,
+ rand, or user var. Therefore, if the slave skip counter is 1, we
+ just say that this event should be skipped by ignoring it, meaning
+ that we do not change the value of the slave skip counter since it
+ will be decreased by the following insert event.
+ */
+ return continue_group(rgi);
+}
+
+#endif
+
+
+/**************************************************************************
+ Rand_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+void Rand_log_event::pack_info(Protocol *protocol)
+{
+ char buf1[256], *pos;
+ pos= strmov(buf1,"rand_seed1=");
+ pos= int10_to_str((long) seed1, pos, 10);
+ pos= strmov(pos, ",rand_seed2=");
+ pos= int10_to_str((long) seed2, pos, 10);
+ protocol->store(buf1, (uint) (pos-buf1), &my_charset_bin);
+}
+#endif
+
+
+bool Rand_log_event::write()
+{
+ uchar buf[16];
+ int8store(buf + RAND_SEED1_OFFSET, seed1);
+ int8store(buf + RAND_SEED2_OFFSET, seed2);
+ return write_header(sizeof(buf)) ||
+ write_data(buf, sizeof(buf)) ||
+ write_footer();
+}
+
+
+#if defined(HAVE_REPLICATION)
+int Rand_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ if (rgi->deferred_events_collecting)
+ return rgi->deferred_events->add(this);
+
+ thd->rand.seed1= (ulong) seed1;
+ thd->rand.seed2= (ulong) seed2;
+ return 0;
+}
+
+int Rand_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ rgi->inc_event_relay_log_pos();
+ return 0;
+}
+
+
+Log_event::enum_skip_reason
+Rand_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ /*
+ It is a common error to set the slave skip counter to 1 instead of
+ 2 when recovering from an insert which used a auto increment,
+ rand, or user var. Therefore, if the slave skip counter is 1, we
+ just say that this event should be skipped by ignoring it, meaning
+ that we do not change the value of the slave skip counter since it
+ will be decreased by the following insert event.
+ */
+ return continue_group(rgi);
+}
+
+/**
+ Exec deferred Int-, Rand- and User- var events prefixing
+ a Query-log-event event.
+
+ @param thd THD handle
+
+ @return false on success, true if a failure in an event applying occurred.
+*/
+bool slave_execute_deferred_events(THD *thd)
+{
+ bool res= false;
+ rpl_group_info *rgi= thd->rgi_slave;
+
+ DBUG_ASSERT(rgi && (!rgi->deferred_events_collecting || rgi->deferred_events));
+
+ if (!rgi->deferred_events_collecting || rgi->deferred_events->is_empty())
+ return res;
+
+ res= rgi->deferred_events->execute(rgi);
+ rgi->deferred_events->rewind();
+
+ return res;
+}
+
+#endif /* HAVE_REPLICATION */
+
+
+/**************************************************************************
+ Xid_apply_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+
+int Xid_apply_log_event::do_record_gtid(THD *thd, rpl_group_info *rgi,
+ bool in_trans, void **out_hton)
+{
+ int err= 0;
+ Relay_log_info const *rli= rgi->rli;
+
+ rgi->gtid_pending= false;
+ err= rpl_global_gtid_slave_state->record_gtid(thd, &rgi->current_gtid,
+ rgi->gtid_sub_id,
+ in_trans, false, out_hton);
+
+ if (unlikely(err))
+ {
+ int ec= thd->get_stmt_da()->sql_errno();
+ /*
+ Do not report an error if this is really a kill due to a deadlock.
+ In this case, the transaction will be re-tried instead.
+ */
+ if (!is_parallel_retry_error(rgi, ec))
+ rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE, rgi->gtid_info(),
+ "Error during XID COMMIT: failed to update GTID state in "
+ "%s.%s: %d: %s",
+ "mysql", rpl_gtid_slave_state_table_name.str, ec,
+ thd->get_stmt_da()->message());
+ thd->is_slave_error= 1;
+ }
+
+ return err;
+}
+
+int Xid_apply_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ bool res;
+ int err;
+ uint64 sub_id= 0;
+ void *hton= NULL;
+ rpl_gtid gtid;
+
+ /*
+ An instance of this class such as XID_EVENT works like a COMMIT
+ statement. It updates mysql.gtid_slave_pos with the GTID of the
+ current transaction.
+ Therefore, it acts much like a normal SQL statement, so we need to do
+ THD::reset_for_next_command() as if starting a new statement.
+
+ XA_PREPARE_LOG_EVENT also updates the gtid table *but* the update gets
+ committed as separate "autocommit" transaction.
+ */
+ thd->reset_for_next_command();
+ /*
+ Record any GTID in the same transaction, so slave state is transactionally
+ consistent.
+ */
+#ifdef WITH_WSREP
+ thd->wsrep_affected_rows= 0;
+#endif
+
+ if (rgi->gtid_pending)
+ {
+ sub_id= rgi->gtid_sub_id;
+ gtid= rgi->current_gtid;
+
+ if (!thd->transaction.xid_state.is_explicit_XA())
+ {
+ if ((err= do_record_gtid(thd, rgi, true /* in_trans */, &hton)))
+ return err;
+
+ DBUG_EXECUTE_IF("gtid_fail_after_record_gtid",
+ {
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0),
+ HA_ERR_WRONG_COMMAND);
+ thd->is_slave_error= 1;
+ return 1;
+ });
+ }
+ }
+
+ general_log_print(thd, COM_QUERY, get_query());
+ thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
+ res= do_commit();
+ if (!res && rgi->gtid_pending)
+ {
+ DBUG_ASSERT(!thd->transaction.xid_state.is_explicit_XA());
+
+ if ((err= do_record_gtid(thd, rgi, false, &hton)))
+ return err;
+ }
+
+#ifdef WITH_WSREP
+ if (WSREP(thd)) mysql_mutex_lock(&thd->LOCK_thd_data);
+ if ((!res || (WSREP(thd) && thd->wsrep_trx().state() == wsrep::transaction::s_must_replay )) && sub_id)
+#else
+ if (likely(!res) && sub_id)
+#endif /* WITH_WSREP */
+ rpl_global_gtid_slave_state->update_state_hash(sub_id, &gtid, hton, rgi);
+#ifdef WITH_WSREP
+ if (WSREP(thd)) mysql_mutex_unlock(&thd->LOCK_thd_data);
+#endif /* WITH_WSREP */
+ /*
+ Increment the global status commit count variable
+ */
+ enum enum_sql_command cmd= !thd->transaction.xid_state.is_explicit_XA() ?
+ SQLCOM_COMMIT : SQLCOM_XA_PREPARE;
+ status_var_increment(thd->status_var.com_stat[cmd]);
+
+ return res;
+}
+
+Log_event::enum_skip_reason
+Xid_apply_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ DBUG_ENTER("Xid_apply_log_event::do_shall_skip");
+ if (rgi->rli->slave_skip_counter > 0)
+ {
+ DBUG_ASSERT(!rgi->rli->get_flag(Relay_log_info::IN_TRANSACTION));
+ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN);
+ DBUG_RETURN(Log_event::EVENT_SKIP_COUNT);
+ }
+#ifdef WITH_WSREP
+ else if (wsrep_mysql_replication_bundle && WSREP_ON &&
+ opt_slave_domain_parallel_threads == 0)
+ {
+ if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle)
+ {
+ WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated);
+ DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE);
+ }
+ else
+ {
+ thd->wsrep_mysql_replicated = 0;
+ }
+ }
+#endif
+ DBUG_RETURN(Log_event::do_shall_skip(rgi));
+}
+#endif /* HAVE_REPLICATION */
+
+/**************************************************************************
+ Xid_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+void Xid_log_event::pack_info(Protocol *protocol)
+{
+ char buf[128], *pos;
+ pos= strmov(buf, "COMMIT /* xid=");
+ pos= longlong10_to_str(xid, pos, 10);
+ pos= strmov(pos, " */");
+ protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
+}
+
+
+int Xid_log_event::do_commit()
+{
+ bool res;
+ res= trans_commit(thd); /* Automatically rolls back on error. */
+ thd->mdl_context.release_transactional_locks();
+ return res;
+}
+#endif
+
+
+bool Xid_log_event::write()
+{
+ DBUG_EXECUTE_IF("do_not_write_xid", return 0;);
+ return write_header(sizeof(xid)) ||
+ write_data((uchar*)&xid, sizeof(xid)) ||
+ write_footer();
+}
+
+/**************************************************************************
+ XA_prepare_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+void XA_prepare_log_event::pack_info(Protocol *protocol)
+{
+ char query[sizeof("XA COMMIT ONE PHASE") + 1 + ser_buf_size];
+
+ sprintf(query,
+ (one_phase ? "XA COMMIT %s ONE PHASE" : "XA PREPARE %s"),
+ m_xid.serialize());
+
+ protocol->store(query, strlen(query), &my_charset_bin);
+}
+
+
+int XA_prepare_log_event::do_commit()
+{
+ int res;
+ xid_t xid;
+ xid.set(m_xid.formatID,
+ m_xid.data, m_xid.gtrid_length,
+ m_xid.data + m_xid.gtrid_length, m_xid.bqual_length);
+
+ thd->lex->xid= &xid;
+ if (!one_phase)
+ {
+ if ((res= thd->wait_for_prior_commit()))
+ return res;
+
+ thd->lex->sql_command= SQLCOM_XA_PREPARE;
+ res= trans_xa_prepare(thd);
+ }
+ else
+ {
+ res= trans_xa_commit(thd);
+ thd->mdl_context.release_transactional_locks();
+ }
+
+ return res;
+}
+#endif // HAVE_REPLICATION
+
+
+bool XA_prepare_log_event::write()
+{
+ uchar data[1 + 4 + 4 + 4]= {one_phase,};
+ uint8 one_phase_byte= one_phase;
+
+ int4store(data+1, static_cast<XID*>(xid)->formatID);
+ int4store(data+(1+4), static_cast<XID*>(xid)->gtrid_length);
+ int4store(data+(1+4+4), static_cast<XID*>(xid)->bqual_length);
+
+ DBUG_ASSERT(xid_subheader_no_data == sizeof(data) - 1);
+
+ return write_header(sizeof(one_phase_byte) + xid_subheader_no_data +
+ static_cast<XID*>(xid)->gtrid_length +
+ static_cast<XID*>(xid)->bqual_length) ||
+ write_data(data, sizeof(data)) ||
+ write_data((uchar*) static_cast<XID*>(xid)->data,
+ static_cast<XID*>(xid)->gtrid_length +
+ static_cast<XID*>(xid)->bqual_length) ||
+ write_footer();
+}
+
+
+/**************************************************************************
+ User_var_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+static bool
+user_var_append_name_part(THD *thd, String *buf,
+ const char *name, size_t name_len)
+{
+ return buf->append("@") ||
+ append_identifier(thd, buf, name, name_len) ||
+ buf->append("=");
+}
+
+void User_var_log_event::pack_info(Protocol* protocol)
+{
+ if (is_null)
+ {
+ char buf_mem[FN_REFLEN+7];
+ String buf(buf_mem, sizeof(buf_mem), system_charset_info);
+ buf.length(0);
+ if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
+ buf.append("NULL"))
+ return;
+ protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
+ }
+ else
+ {
+ switch (type) {
+ case REAL_RESULT:
+ {
+ double real_val;
+ char buf2[MY_GCVT_MAX_FIELD_WIDTH+1];
+ char buf_mem[FN_REFLEN + MY_GCVT_MAX_FIELD_WIDTH + 1];
+ String buf(buf_mem, sizeof(buf_mem), system_charset_info);
+ float8get(real_val, val);
+ buf.length(0);
+ if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
+ buf.append(buf2, my_gcvt(real_val, MY_GCVT_ARG_DOUBLE,
+ MY_GCVT_MAX_FIELD_WIDTH, buf2, NULL)))
+ return;
+ protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
+ break;
+ }
+ case INT_RESULT:
+ {
+ char buf2[22];
+ char buf_mem[FN_REFLEN + 22];
+ String buf(buf_mem, sizeof(buf_mem), system_charset_info);
+ buf.length(0);
+ if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
+ buf.append(buf2,
+ longlong10_to_str(uint8korr(val), buf2,
+ ((flags & User_var_log_event::UNSIGNED_F) ? 10 : -10))-buf2))
+ return;
+ protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
+ break;
+ }
+ case DECIMAL_RESULT:
+ {
+ char buf_mem[FN_REFLEN + DECIMAL_MAX_STR_LENGTH];
+ String buf(buf_mem, sizeof(buf_mem), system_charset_info);
+ char buf2[DECIMAL_MAX_STR_LENGTH+1];
+ String str(buf2, sizeof(buf2), &my_charset_bin);
+ buf.length(0);
+ my_decimal((const uchar *) (val + 2), val[0], val[1]).to_string(&str);
+ if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
+ buf.append(buf2))
+ return;
+ protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
+ break;
+ }
+ case STRING_RESULT:
+ {
+ /* 15 is for 'COLLATE' and other chars */
+ char buf_mem[FN_REFLEN + 512 + 1 + 2*MY_CS_NAME_SIZE+15];
+ String buf(buf_mem, sizeof(buf_mem), system_charset_info);
+ CHARSET_INFO *cs;
+ buf.length(0);
+ if (!(cs= get_charset(charset_number, MYF(0))))
+ {
+ if (buf.append("???"))
+ return;
+ }
+ else
+ {
+ size_t old_len;
+ char *beg, *end;
+ if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
+ buf.append("_") ||
+ buf.append(cs->csname) ||
+ buf.append(" "))
+ return;
+ old_len= buf.length();
+ if (buf.reserve(old_len + val_len * 2 + 3 + sizeof(" COLLATE ") +
+ MY_CS_NAME_SIZE))
+ return;
+ beg= const_cast<char *>(buf.ptr()) + old_len;
+ end= str_to_hex(beg, val, val_len);
+ buf.length(old_len + (end - beg));
+ if (buf.append(" COLLATE ") ||
+ buf.append(cs->name))
+ return;
+ }
+ protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
+ break;
+ }
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ return;
+ }
+ }
+}
+#endif // HAVE_REPLICATION
+
+
+bool User_var_log_event::write()
+{
+ char buf[UV_NAME_LEN_SIZE];
+ char buf1[UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
+ UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE];
+ uchar buf2[MY_MAX(8, DECIMAL_MAX_FIELD_SIZE + 2)], *pos= buf2;
+ uint unsigned_len= 0;
+ uint buf1_length;
+ size_t event_length;
+
+ int4store(buf, name_len);
+
+ if ((buf1[0]= is_null))
+ {
+ buf1_length= 1;
+ val_len= 0; // Length of 'pos'
+ }
+ else
+ {
+ buf1[1]= type;
+ int4store(buf1 + 2, charset_number);
+
+ switch (type) {
+ case REAL_RESULT:
+ float8store(buf2, *(double*) val);
+ break;
+ case INT_RESULT:
+ int8store(buf2, *(longlong*) val);
+ unsigned_len= 1;
+ break;
+ case DECIMAL_RESULT:
+ {
+ my_decimal *dec= (my_decimal *)val;
+ dec->fix_buffer_pointer();
+ buf2[0]= (char)(dec->intg + dec->frac);
+ buf2[1]= (char)dec->frac;
+ decimal2bin((decimal_t*)val, buf2+2, buf2[0], buf2[1]);
+ val_len= decimal_bin_size(buf2[0], buf2[1]) + 2;
+ break;
+ }
+ case STRING_RESULT:
+ pos= (uchar*) val;
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ return 0;
+ }
+ int4store(buf1 + 2 + UV_CHARSET_NUMBER_SIZE, val_len);
+ buf1_length= 10;
+ }
+
+ /* Length of the whole event */
+ event_length= sizeof(buf)+ name_len + buf1_length + val_len + unsigned_len;
+
+ return write_header(event_length) ||
+ write_data(buf, sizeof(buf)) ||
+ write_data(name, name_len) ||
+ write_data(buf1, buf1_length) ||
+ write_data(pos, val_len) ||
+ write_data(&flags, unsigned_len) ||
+ write_footer();
+}
+
+
+#if defined(HAVE_REPLICATION)
+int User_var_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ Item *it= 0;
+ CHARSET_INFO *charset;
+ DBUG_ENTER("User_var_log_event::do_apply_event");
+ query_id_t sav_query_id= 0; /* memorize orig id when deferred applying */
+
+ if (rgi->deferred_events_collecting)
+ {
+ set_deferred(current_thd->query_id);
+ DBUG_RETURN(rgi->deferred_events->add(this));
+ }
+ else if (is_deferred())
+ {
+ sav_query_id= current_thd->query_id;
+ current_thd->query_id= query_id; /* recreating original time context */
+ }
+
+ if (!(charset= get_charset(charset_number, MYF(MY_WME))))
+ {
+ rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR),
+ "Invalid character set for User var event");
+ DBUG_RETURN(1);
+ }
+ LEX_CSTRING user_var_name;
+ user_var_name.str= name;
+ user_var_name.length= name_len;
+ double real_val;
+ longlong int_val;
+
+ if (is_null)
+ {
+ it= new (thd->mem_root) Item_null(thd);
+ }
+ else
+ {
+ switch (type) {
+ case REAL_RESULT:
+ if (val_len != 8)
+ {
+ rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR),
+ "Invalid variable length at User var event");
+ return 1;
+ }
+ float8get(real_val, val);
+ it= new (thd->mem_root) Item_float(thd, real_val, 0);
+ val= (char*) &real_val; // Pointer to value in native format
+ val_len= 8;
+ break;
+ case INT_RESULT:
+ if (val_len != 8)
+ {
+ rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR),
+ "Invalid variable length at User var event");
+ return 1;
+ }
+ int_val= (longlong) uint8korr(val);
+ it= new (thd->mem_root) Item_int(thd, int_val);
+ val= (char*) &int_val; // Pointer to value in native format
+ val_len= 8;
+ break;
+ case DECIMAL_RESULT:
+ {
+ if (val_len < 3)
+ {
+ rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR),
+ "Invalid variable length at User var event");
+ return 1;
+ }
+ Item_decimal *dec= new (thd->mem_root) Item_decimal(thd, (uchar*) val+2, val[0], val[1]);
+ it= dec;
+ val= (char *)dec->val_decimal(NULL);
+ val_len= sizeof(my_decimal);
+ break;
+ }
+ case STRING_RESULT:
+ it= new (thd->mem_root) Item_string(thd, val, (uint)val_len, charset);
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ DBUG_RETURN(0);
+ }
+ }
+
+ Item_func_set_user_var *e= new (thd->mem_root) Item_func_set_user_var(thd, &user_var_name, it);
+ /*
+ Item_func_set_user_var can't substitute something else on its place =>
+ 0 can be passed as last argument (reference on item)
+
+ Fix_fields() can fail, in which case a call of update_hash() might
+ crash the server, so if fix fields fails, we just return with an
+ error.
+ */
+ if (e->fix_fields(thd, 0))
+ DBUG_RETURN(1);
+
+ /*
+ A variable can just be considered as a table with
+ a single record and with a single column. Thus, like
+ a column value, it could always have IMPLICIT derivation.
+ */
+ e->update_hash((void*) val, val_len, type, charset,
+ (flags & User_var_log_event::UNSIGNED_F));
+ if (!is_deferred())
+ free_root(thd->mem_root, 0);
+ else
+ current_thd->query_id= sav_query_id; /* restore current query's context */
+
+ DBUG_RETURN(0);
+}
+
+int User_var_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ rgi->inc_event_relay_log_pos();
+ return 0;
+}
+
+Log_event::enum_skip_reason
+User_var_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ /*
+ It is a common error to set the slave skip counter to 1 instead
+ of 2 when recovering from an insert which used a auto increment,
+ rand, or user var. Therefore, if the slave skip counter is 1, we
+ just say that this event should be skipped by ignoring it, meaning
+ that we do not change the value of the slave skip counter since it
+ will be decreased by the following insert event.
+ */
+ return continue_group(rgi);
+}
+#endif // HAVE_REPLICATION
+
+
+#ifdef HAVE_REPLICATION
+
+/**************************************************************************
+ Stop_log_event methods
+**************************************************************************/
+
+/*
+ The master stopped. We used to clean up all temporary tables but
+ this is useless as, as the master has shut down properly, it has
+ written all DROP TEMPORARY TABLE (prepared statements' deletion is
+ TODO only when we binlog prep stmts). We used to clean up
+ slave_load_tmpdir, but this is useless as it has been cleared at the
+ end of LOAD DATA INFILE. So we have nothing to do here. The place
+ were we must do this cleaning is in
+ Start_log_event_v3::do_apply_event(), not here. Because if we come
+ here, the master was sane.
+
+ This must only be called from the Slave SQL thread, since it calls
+ Relay_log_info::flush().
+*/
+
+int Stop_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ int error= 0;
+ Relay_log_info *rli= rgi->rli;
+ DBUG_ENTER("Stop_log_event::do_update_pos");
+ /*
+ We do not want to update master_log pos because we get a rotate event
+ before stop, so by now group_master_log_name is set to the next log.
+ If we updated it, we will have incorrect master coordinates and this
+ could give false triggers in MASTER_POS_WAIT() that we have reached
+ the target position when in fact we have not.
+ */
+ if (rli->get_flag(Relay_log_info::IN_TRANSACTION))
+ rgi->inc_event_relay_log_pos();
+ else if (!rgi->is_parallel_exec)
+ {
+ rpl_global_gtid_slave_state->record_and_update_gtid(thd, rgi);
+ rli->inc_group_relay_log_pos(0, rgi);
+ if (rli->flush())
+ error= 1;
+ }
+ DBUG_RETURN(error);
+}
+
+#endif /* HAVE_REPLICATION */
+
+
+/**************************************************************************
+ Create_file_log_event methods
+**************************************************************************/
+
+Create_file_log_event::
+Create_file_log_event(THD* thd_arg, sql_exchange* ex,
+ const char* db_arg, const char* table_name_arg,
+ List<Item>& fields_arg,
+ bool is_concurrent_arg,
+ enum enum_duplicates handle_dup,
+ bool ignore,
+ uchar* block_arg, uint block_len_arg, bool using_trans)
+ :Load_log_event(thd_arg, ex, db_arg, table_name_arg, fields_arg,
+ is_concurrent_arg,
+ handle_dup, ignore, using_trans),
+ fake_base(0), block(block_arg), event_buf(0), block_len(block_len_arg),
+ file_id(thd_arg->file_id = mysql_bin_log.next_file_id())
+{
+ DBUG_ENTER("Create_file_log_event");
+ sql_ex.force_new_format();
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Create_file_log_event::write_data_body()
+*/
+
+bool Create_file_log_event::write_data_body()
+{
+ bool res;
+ if ((res= Load_log_event::write_data_body()) || fake_base)
+ return res;
+ return write_data("", 1) ||
+ write_data(block, block_len);
+}
+
+
+/*
+ Create_file_log_event::write_data_header()
+*/
+
+bool Create_file_log_event::write_data_header()
+{
+ bool res;
+ uchar buf[CREATE_FILE_HEADER_LEN];
+ if ((res= Load_log_event::write_data_header()) || fake_base)
+ return res;
+ int4store(buf + CF_FILE_ID_OFFSET, file_id);
+ return write_data(buf, CREATE_FILE_HEADER_LEN) != 0;
+}
+
+
+/*
+ Create_file_log_event::write_base()
+*/
+
+bool Create_file_log_event::write_base()
+{
+ bool res;
+ fake_base= 1; // pretend we are Load event
+ res= write();
+ fake_base= 0;
+ return res;
+}
+
+
+#if defined(HAVE_REPLICATION)
+void Create_file_log_event::pack_info(Protocol *protocol)
+{
+ char buf[SAFE_NAME_LEN*2 + 30 + 21*2], *pos;
+ pos= strmov(buf, "db=");
+ memcpy(pos, db, db_len);
+ pos= strmov(pos + db_len, ";table=");
+ memcpy(pos, table_name, table_name_len);
+ pos= strmov(pos + table_name_len, ";file_id=");
+ pos= int10_to_str((long) file_id, pos, 10);
+ pos= strmov(pos, ";block_len=");
+ pos= int10_to_str((long) block_len, pos, 10);
+ protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
+}
+#endif /* defined(HAVE_REPLICATION) */
+
+
+/**
+ Create_file_log_event::do_apply_event()
+ Constructor for Create_file_log_event to intantiate an event
+ from the relay log on the slave.
+
+ @retval
+ 0 Success
+ @retval
+ 1 Failure
+*/
+
+#if defined(HAVE_REPLICATION)
+int Create_file_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ char fname_buf[FN_REFLEN];
+ char *ext;
+ int fd = -1;
+ IO_CACHE file;
+ Log_event_writer lew(&file, 0);
+ int error = 1;
+ Relay_log_info const *rli= rgi->rli;
+
+ THD_STAGE_INFO(thd, stage_making_temp_file_create_before_load_data);
+ bzero((char*)&file, sizeof(file));
+ ext= slave_load_file_stem(fname_buf, file_id, server_id, ".info",
+ &rli->mi->connection_name);
+ /* old copy may exist already */
+ mysql_file_delete(key_file_log_event_info, fname_buf, MYF(0));
+ if ((fd= mysql_file_create(key_file_log_event_info,
+ fname_buf, CREATE_MODE,
+ O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
+ MYF(MY_WME))) < 0 ||
+ init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0,
+ MYF(MY_WME|MY_NABP)))
+ {
+ rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
+ "Error in Create_file event: could not open file '%s'",
+ fname_buf);
+ goto err;
+ }
+
+ // a trick to avoid allocating another buffer
+ fname= fname_buf;
+ fname_len= (uint) (strmov(ext, ".data") - fname);
+ writer= &lew;
+ if (write_base())
+ {
+ strmov(ext, ".info"); // to have it right in the error message
+ rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
+ "Error in Create_file event: could not write to file '%s'",
+ fname_buf);
+ goto err;
+ }
+ end_io_cache(&file);
+ mysql_file_close(fd, MYF(0));
+
+ // fname_buf now already has .data, not .info, because we did our trick
+ /* old copy may exist already */
+ mysql_file_delete(key_file_log_event_data, fname_buf, MYF(0));
+ if ((fd= mysql_file_create(key_file_log_event_data,
+ fname_buf, CREATE_MODE,
+ O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
+ MYF(MY_WME))) < 0)
+ {
+ rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
+ "Error in Create_file event: could not open file '%s'",
+ fname_buf);
+ goto err;
+ }
+ if (mysql_file_write(fd, (uchar*) block, block_len, MYF(MY_WME+MY_NABP)))
+ {
+ rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
+ "Error in Create_file event: write to '%s' failed",
+ fname_buf);
+ goto err;
+ }
+ error=0; // Everything is ok
+
+err:
+ if (unlikely(error))
+ end_io_cache(&file);
+ if (likely(fd >= 0))
+ mysql_file_close(fd, MYF(0));
+ return error != 0;
+}
+#endif /* defined(HAVE_REPLICATION) */
+
+
+/**************************************************************************
+ Append_block_log_event methods
+**************************************************************************/
+
+Append_block_log_event::Append_block_log_event(THD *thd_arg,
+ const char *db_arg,
+ uchar *block_arg,
+ uint block_len_arg,
+ bool using_trans)
+ :Log_event(thd_arg,0, using_trans), block(block_arg),
+ block_len(block_len_arg), file_id(thd_arg->file_id), db(db_arg)
+{
+}
+
+
+bool Append_block_log_event::write()
+{
+ uchar buf[APPEND_BLOCK_HEADER_LEN];
+ int4store(buf + AB_FILE_ID_OFFSET, file_id);
+ return write_header(APPEND_BLOCK_HEADER_LEN + block_len) ||
+ write_data(buf, APPEND_BLOCK_HEADER_LEN) ||
+ write_data(block, block_len) ||
+ write_footer();
+}
+
+
+#if defined(HAVE_REPLICATION)
+void Append_block_log_event::pack_info(Protocol *protocol)
+{
+ char buf[256];
+ uint length;
+ length= (uint) sprintf(buf, ";file_id=%u;block_len=%u", file_id, block_len);
+ protocol->store(buf, length, &my_charset_bin);
+}
+
+
+/*
+ Append_block_log_event::get_create_or_append()
+*/
+
+int Append_block_log_event::get_create_or_append() const
+{
+ return 0; /* append to the file, fail if not exists */
+}
+
+/*
+ Append_block_log_event::do_apply_event()
+*/
+
+int Append_block_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ char fname[FN_REFLEN];
+ int fd;
+ int error = 1;
+ Relay_log_info const *rli= rgi->rli;
+ DBUG_ENTER("Append_block_log_event::do_apply_event");
+
+ THD_STAGE_INFO(thd, stage_making_temp_file_append_before_load_data);
+ slave_load_file_stem(fname, file_id, server_id, ".data",
+ &rli->mi->cmp_connection_name);
+ if (get_create_or_append())
+ {
+ /*
+ Usually lex_start() is called by mysql_parse(), but we need it here
+ as the present method does not call mysql_parse().
+ */
+ lex_start(thd);
+ thd->reset_for_next_command();
+ /* old copy may exist already */
+ mysql_file_delete(key_file_log_event_data, fname, MYF(0));
+ if ((fd= mysql_file_create(key_file_log_event_data,
+ fname, CREATE_MODE,
+ O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
+ MYF(MY_WME))) < 0)
+ {
+ rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
+ "Error in %s event: could not create file '%s'",
+ get_type_str(), fname);
+ goto err;
+ }
+ }
+ else if ((fd= mysql_file_open(key_file_log_event_data,
+ fname,
+ O_WRONLY | O_APPEND | O_BINARY | O_NOFOLLOW,
+ MYF(MY_WME))) < 0)
+ {
+ rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
+ "Error in %s event: could not open file '%s'",
+ get_type_str(), fname);
+ goto err;
+ }
+
+ DBUG_EXECUTE_IF("remove_slave_load_file_before_write",
+ {
+ my_delete(fname, MYF(0));
+ });
+
+ if (mysql_file_write(fd, (uchar*) block, block_len, MYF(MY_WME+MY_NABP)))
+ {
+ rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
+ "Error in %s event: write to '%s' failed",
+ get_type_str(), fname);
+ goto err;
+ }
+ error=0;
+
+err:
+ if (fd >= 0)
+ mysql_file_close(fd, MYF(0));
+ DBUG_RETURN(error);
+}
+#endif // HAVE_REPLICATION
+
+
+/**************************************************************************
+ Delete_file_log_event methods
+**************************************************************************/
+
+Delete_file_log_event::Delete_file_log_event(THD *thd_arg, const char* db_arg,
+ bool using_trans)
+ :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id), db(db_arg)
+{
+}
+
+
+bool Delete_file_log_event::write()
+{
+ uchar buf[DELETE_FILE_HEADER_LEN];
+ int4store(buf + DF_FILE_ID_OFFSET, file_id);
+ return write_header(sizeof(buf)) ||
+ write_data(buf, sizeof(buf)) ||
+ write_footer();
+}
+
+
+#if defined(HAVE_REPLICATION)
+void Delete_file_log_event::pack_info(Protocol *protocol)
+{
+ char buf[64];
+ uint length;
+ length= (uint) sprintf(buf, ";file_id=%u", (uint) file_id);
+ protocol->store(buf, (int32) length, &my_charset_bin);
+}
+#endif
+
+
+#if defined(HAVE_REPLICATION)
+int Delete_file_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ char fname[FN_REFLEN+10];
+ Relay_log_info const *rli= rgi->rli;
+ char *ext= slave_load_file_stem(fname, file_id, server_id, ".data",
+ &rli->mi->cmp_connection_name);
+ mysql_file_delete(key_file_log_event_data, fname, MYF(MY_WME));
+ strmov(ext, ".info");
+ mysql_file_delete(key_file_log_event_info, fname, MYF(MY_WME));
+ return 0;
+}
+#endif /* defined(HAVE_REPLICATION) */
+
+
+/**************************************************************************
+ Execute_load_log_event methods
+**************************************************************************/
+
+Execute_load_log_event::Execute_load_log_event(THD *thd_arg,
+ const char* db_arg,
+ bool using_trans)
+ :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id), db(db_arg)
+{
+}
+
+
+bool Execute_load_log_event::write()
+{
+ uchar buf[EXEC_LOAD_HEADER_LEN];
+ int4store(buf + EL_FILE_ID_OFFSET, file_id);
+ return write_header(sizeof(buf)) ||
+ write_data(buf, sizeof(buf)) ||
+ write_footer();
+}
+
+
+#if defined(HAVE_REPLICATION)
+void Execute_load_log_event::pack_info(Protocol *protocol)
+{
+ char buf[64];
+ uint length;
+ length= (uint) sprintf(buf, ";file_id=%u", (uint) file_id);
+ protocol->store(buf, (int32) length, &my_charset_bin);
+}
+
+
+/*
+ Execute_load_log_event::do_apply_event()
+*/
+
+int Execute_load_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ char fname[FN_REFLEN+10];
+ char *ext;
+ int fd;
+ int error= 1;
+ IO_CACHE file;
+ Load_log_event *lev= 0;
+ Relay_log_info const *rli= rgi->rli;
+
+ ext= slave_load_file_stem(fname, file_id, server_id, ".info",
+ &rli->mi->cmp_connection_name);
+ if ((fd= mysql_file_open(key_file_log_event_info,
+ fname, O_RDONLY | O_BINARY | O_NOFOLLOW,
+ MYF(MY_WME))) < 0 ||
+ init_io_cache(&file, fd, IO_SIZE, READ_CACHE, (my_off_t)0, 0,
+ MYF(MY_WME|MY_NABP)))
+ {
+ rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
+ "Error in Exec_load event: could not open file '%s'",
+ fname);
+ goto err;
+ }
+ if (!(lev= (Load_log_event*)
+ Log_event::read_log_event(&file,
+ rli->relay_log.description_event_for_exec,
+ opt_slave_sql_verify_checksum)) ||
+ lev->get_type_code() != NEW_LOAD_EVENT)
+ {
+ rli->report(ERROR_LEVEL, 0, rgi->gtid_info(), "Error in Exec_load event: "
+ "file '%s' appears corrupted", fname);
+ goto err;
+ }
+ lev->thd = thd;
+ /*
+ lev->do_apply_event should use rli only for errors i.e. should
+ not advance rli's position.
+
+ lev->do_apply_event is the place where the table is loaded (it
+ calls mysql_load()).
+ */
+
+ if (lev->do_apply_event(0,rgi,1))
+ {
+ /*
+ We want to indicate the name of the file that could not be loaded
+ (SQL_LOADxxx).
+ But as we are here we are sure the error is in rli->last_slave_error and
+ rli->last_slave_errno (example of error: duplicate entry for key), so we
+ don't want to overwrite it with the filename.
+ What we want instead is add the filename to the current error message.
+ */
+ char *tmp= my_strdup(PSI_INSTRUMENT_ME, rli->last_error().message, MYF(MY_WME));
+ if (tmp)
+ {
+ rli->report(ERROR_LEVEL, rli->last_error().number, rgi->gtid_info(),
+ "%s. Failed executing load from '%s'", tmp, fname);
+ my_free(tmp);
+ }
+ goto err;
+ }
+ /*
+ We have an open file descriptor to the .info file; we need to close it
+ or Windows will refuse to delete the file in mysql_file_delete().
+ */
+ if (fd >= 0)
+ {
+ mysql_file_close(fd, MYF(0));
+ end_io_cache(&file);
+ fd= -1;
+ }
+ mysql_file_delete(key_file_log_event_info, fname, MYF(MY_WME));
+ memcpy(ext, ".data", 6);
+ mysql_file_delete(key_file_log_event_data, fname, MYF(MY_WME));
+ error = 0;
+
+err:
+ delete lev;
+ if (fd >= 0)
+ {
+ mysql_file_close(fd, MYF(0));
+ end_io_cache(&file);
+ }
+ return error;
+}
+
+#endif /* defined(HAVE_REPLICATION) */
+
+/**************************************************************************
+ Begin_load_query_log_event methods
+**************************************************************************/
+
+Begin_load_query_log_event::
+Begin_load_query_log_event(THD* thd_arg, const char* db_arg, uchar* block_arg,
+ uint block_len_arg, bool using_trans)
+ :Append_block_log_event(thd_arg, db_arg, block_arg, block_len_arg,
+ using_trans)
+{
+ file_id= thd_arg->file_id= mysql_bin_log.next_file_id();
+}
+
+
+#if defined( HAVE_REPLICATION)
+int Begin_load_query_log_event::get_create_or_append() const
+{
+ return 1; /* create the file */
+}
+
+
+Log_event::enum_skip_reason
+Begin_load_query_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ /*
+ If the slave skip counter is 1, then we should not start executing
+ on the next event.
+ */
+ return continue_group(rgi);
+}
+#endif /* defined( HAVE_REPLICATION) */
+
+
+/**************************************************************************
+ Execute_load_query_log_event methods
+**************************************************************************/
+
+Execute_load_query_log_event::
+Execute_load_query_log_event(THD *thd_arg, const char* query_arg,
+ ulong query_length_arg, uint fn_pos_start_arg,
+ uint fn_pos_end_arg,
+ enum_load_dup_handling dup_handling_arg,
+ bool using_trans, bool direct, bool suppress_use,
+ int errcode):
+ Query_log_event(thd_arg, query_arg, query_length_arg, using_trans, direct,
+ suppress_use, errcode),
+ file_id(thd_arg->file_id), fn_pos_start(fn_pos_start_arg),
+ fn_pos_end(fn_pos_end_arg), dup_handling(dup_handling_arg)
+{
+}
+
+
+bool
+Execute_load_query_log_event::write_post_header_for_derived()
+{
+ uchar buf[EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN];
+ int4store(buf, file_id);
+ int4store(buf + 4, fn_pos_start);
+ int4store(buf + 4 + 4, fn_pos_end);
+ *(buf + 4 + 4 + 4)= (uchar) dup_handling;
+ return write_data(buf, EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN);
+}
+
+
+#if defined(HAVE_REPLICATION)
+void Execute_load_query_log_event::pack_info(Protocol *protocol)
+{
+ char buf_mem[1024];
+ String buf(buf_mem, sizeof(buf_mem), system_charset_info);
+ buf.real_alloc(9 + db_len + q_len + 10 + 21);
+ if (db && db_len)
+ {
+ if (buf.append(STRING_WITH_LEN("use ")) ||
+ append_identifier(protocol->thd, &buf, db, db_len) ||
+ buf.append(STRING_WITH_LEN("; ")))
+ return;
+ }
+ if (query && q_len && buf.append(query, q_len))
+ return;
+ if (buf.append(" ;file_id=") ||
+ buf.append_ulonglong(file_id))
+ return;
+ protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
+}
+
+
+int
+Execute_load_query_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ char *p;
+ char *buf;
+ char *fname;
+ char *fname_end;
+ int error;
+ Relay_log_info const *rli= rgi->rli;
+
+ buf= (char*) my_malloc(PSI_INSTRUMENT_ME, q_len + 1 -
+ (fn_pos_end - fn_pos_start) + (FN_REFLEN + 10) + 10 + 8 + 5, MYF(MY_WME));
+
+ DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error", my_free(buf); buf= NULL;);
+
+ /* Replace filename and LOCAL keyword in query before executing it */
+ if (buf == NULL)
+ {
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, rgi->gtid_info(),
+ ER_THD(rgi->thd, ER_SLAVE_FATAL_ERROR), "Not enough memory");
+ return 1;
+ }
+
+ p= buf;
+ memcpy(p, query, fn_pos_start);
+ p+= fn_pos_start;
+ fname= (p= strmake(p, STRING_WITH_LEN(" INFILE \'")));
+ p= slave_load_file_stem(p, file_id, server_id, ".data",
+ &rli->mi->cmp_connection_name);
+ fname_end= p= strend(p); // Safer than p=p+5
+ *(p++)='\'';
+ switch (dup_handling) {
+ case LOAD_DUP_IGNORE:
+ p= strmake(p, STRING_WITH_LEN(" IGNORE"));
+ break;
+ case LOAD_DUP_REPLACE:
+ p= strmake(p, STRING_WITH_LEN(" REPLACE"));
+ break;
+ default:
+ /* Ordinary load data */
+ break;
+ }
+ p= strmake(p, STRING_WITH_LEN(" INTO "));
+ p= strmake(p, query+fn_pos_end, q_len-fn_pos_end);
+
+ error= Query_log_event::do_apply_event(rgi, buf, (uint32)(p-buf));
+
+ /* Forging file name for deletion in same buffer */
+ *fname_end= 0;
+
+ /*
+ If there was an error the slave is going to stop, leave the
+ file so that we can re-execute this event at START SLAVE.
+ */
+ if (unlikely(!error))
+ mysql_file_delete(key_file_log_event_data, fname, MYF(MY_WME));
+
+ my_free(buf);
+ return error;
+}
+#endif // HAVE_REPLICATION
+
+
+/**************************************************************************
+ sql_ex_info methods
+**************************************************************************/
+
+static bool write_str(Log_event_writer *writer, const char *str, uint length)
+{
+ uchar tmp[1];
+ tmp[0]= (uchar) length;
+ return (writer->write_data(tmp, sizeof(tmp)) ||
+ writer->write_data((uchar*) str, length));
+}
+
+bool sql_ex_info::write_data(Log_event_writer *writer)
+{
+ if (new_format())
+ {
+ return write_str(writer, field_term, field_term_len) ||
+ write_str(writer, enclosed, enclosed_len) ||
+ write_str(writer, line_term, line_term_len) ||
+ write_str(writer, line_start, line_start_len) ||
+ write_str(writer, escaped, escaped_len) ||
+ writer->write_data((uchar*) &opt_flags, 1);
+ }
+ else
+ {
+ uchar old_ex[7];
+ old_ex[0]= *field_term;
+ old_ex[1]= *enclosed;
+ old_ex[2]= *line_term;
+ old_ex[3]= *line_start;
+ old_ex[4]= *escaped;
+ old_ex[5]= opt_flags;
+ old_ex[6]= empty_flags;
+ return writer->write_data(old_ex, sizeof(old_ex));
+ }
+}
+
+
+
+/**************************************************************************
+ Rows_log_event member functions
+**************************************************************************/
+
+Rows_log_event::Rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid,
+ MY_BITMAP const *cols, bool is_transactional,
+ Log_event_type event_type)
+ : Log_event(thd_arg, 0, is_transactional),
+ m_row_count(0),
+ m_table(tbl_arg),
+ m_table_id(tid),
+ m_width(tbl_arg ? tbl_arg->s->fields : 1),
+ m_rows_buf(0), m_rows_cur(0), m_rows_end(0), m_flags(0),
+ m_type(event_type), m_extra_row_data(0)
+#ifdef HAVE_REPLICATION
+ , m_curr_row(NULL), m_curr_row_end(NULL),
+ m_key(NULL), m_key_info(NULL), m_key_nr(0),
+ master_had_triggers(0)
+#endif
+{
+ /*
+ We allow a special form of dummy event when the table, and cols
+ are null and the table id is ~0UL. This is a temporary
+ solution, to be able to terminate a started statement in the
+ binary log: the extraneous events will be removed in the future.
+ */
+ DBUG_ASSERT((tbl_arg && tbl_arg->s && tid != ~0UL) ||
+ (!tbl_arg && !cols && tid == ~0UL));
+
+ if (thd_arg->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS)
+ set_flags(NO_FOREIGN_KEY_CHECKS_F);
+ if (thd_arg->variables.option_bits & OPTION_RELAXED_UNIQUE_CHECKS)
+ set_flags(RELAXED_UNIQUE_CHECKS_F);
+ if (thd_arg->variables.option_bits & OPTION_NO_CHECK_CONSTRAINT_CHECKS)
+ set_flags(NO_CHECK_CONSTRAINT_CHECKS_F);
+ /* if my_bitmap_init fails, caught in is_valid() */
+ if (likely(!my_bitmap_init(&m_cols,
+ m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
+ m_width,
+ false)))
+ {
+ /* Cols can be zero if this is a dummy binrows event */
+ if (likely(cols != NULL))
+ {
+ memcpy(m_cols.bitmap, cols->bitmap, no_bytes_in_map(cols));
+ create_last_word_mask(&m_cols);
+ }
+ }
+ else
+ {
+ // Needed because my_bitmap_init() does not set it to null on failure
+ m_cols.bitmap= 0;
+ }
+}
+
+
+int Rows_log_event::do_add_row_data(uchar *row_data, size_t length)
+{
+ /*
+ When the table has a primary key, we would probably want, by default, to
+ log only the primary key value instead of the entire "before image". This
+ would save binlog space. TODO
+ */
+ DBUG_ENTER("Rows_log_event::do_add_row_data");
+ DBUG_PRINT("enter", ("row_data:%p length: %lu", row_data,
+ (ulong) length));
+
+ /*
+ If length is zero, there is nothing to write, so we just
+ return. Note that this is not an optimization, since calling
+ realloc() with size 0 means free().
+ */
+ if (length == 0)
+ {
+ m_row_count++;
+ DBUG_RETURN(0);
+ }
+
+ /*
+ Don't print debug messages when running valgrind since they can
+ trigger false warnings.
+ */
+#ifndef HAVE_valgrind
+ DBUG_DUMP("row_data", row_data, MY_MIN(length, 32));
+#endif
+
+ DBUG_ASSERT(m_rows_buf <= m_rows_cur);
+ DBUG_ASSERT(!m_rows_buf || (m_rows_end && m_rows_buf < m_rows_end));
+ DBUG_ASSERT(m_rows_cur <= m_rows_end);
+
+ /* The cast will always work since m_rows_cur <= m_rows_end */
+ if (static_cast<size_t>(m_rows_end - m_rows_cur) <= length)
+ {
+ size_t const block_size= 1024;
+ size_t cur_size= m_rows_cur - m_rows_buf;
+ DBUG_EXECUTE_IF("simulate_too_big_row_case1",
+ cur_size= UINT_MAX32 - (block_size * 10);
+ length= UINT_MAX32 - (block_size * 10););
+ DBUG_EXECUTE_IF("simulate_too_big_row_case2",
+ cur_size= UINT_MAX32 - (block_size * 10);
+ length= block_size * 10;);
+ DBUG_EXECUTE_IF("simulate_too_big_row_case3",
+ cur_size= block_size * 10;
+ length= UINT_MAX32 - (block_size * 10););
+ DBUG_EXECUTE_IF("simulate_too_big_row_case4",
+ cur_size= UINT_MAX32 - (block_size * 10);
+ length= (block_size * 10) - block_size + 1;);
+ size_t remaining_space= UINT_MAX32 - cur_size;
+ /* Check that the new data fits within remaining space and we can add
+ block_size without wrapping.
+ */
+ if (cur_size > UINT_MAX32 || length > remaining_space ||
+ ((length + block_size) > remaining_space))
+ {
+ sql_print_error("The row data is greater than 4GB, which is too big to "
+ "write to the binary log.");
+ DBUG_RETURN(ER_BINLOG_ROW_LOGGING_FAILED);
+ }
+ size_t const new_alloc=
+ block_size * ((cur_size + length + block_size - 1) / block_size);
+
+ uchar* const new_buf= (uchar*)my_realloc(PSI_INSTRUMENT_ME, m_rows_buf,
+ new_alloc, MYF(MY_ALLOW_ZERO_PTR|MY_WME));
+ if (unlikely(!new_buf))
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+
+ /* If the memory moved, we need to move the pointers */
+ if (new_buf != m_rows_buf)
+ {
+ m_rows_buf= new_buf;
+ m_rows_cur= m_rows_buf + cur_size;
+ }
+
+ /*
+ The end pointer should always be changed to point to the end of
+ the allocated memory.
+ */
+ m_rows_end= m_rows_buf + new_alloc;
+ }
+
+ DBUG_ASSERT(m_rows_cur + length <= m_rows_end);
+ memcpy(m_rows_cur, row_data, length);
+ m_rows_cur+= length;
+ m_row_count++;
+ DBUG_RETURN(0);
+}
+
+
+#if defined(HAVE_REPLICATION)
+
+/**
+ Restores empty table list as it was before trigger processing.
+
+ @note We have a lot of ASSERTS that check the lists when we close tables.
+ There was the same problem with MERGE MYISAM tables and so here we try to
+ go the same way.
+*/
+static void restore_empty_query_table_list(LEX *lex)
+{
+ if (lex->first_not_own_table())
+ (*lex->first_not_own_table()->prev_global)= NULL;
+ lex->query_tables= NULL;
+ lex->query_tables_last= &lex->query_tables;
+}
+
+
+int Rows_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ Relay_log_info const *rli= rgi->rli;
+ TABLE* table;
+ DBUG_ENTER("Rows_log_event::do_apply_event(Relay_log_info*)");
+ int error= 0;
+ /*
+ If m_table_id == ~0ULL, then we have a dummy event that does not
+ contain any data. In that case, we just remove all tables in the
+ tables_to_lock list, close the thread tables, and return with
+ success.
+ */
+ if (m_table_id == ~0ULL)
+ {
+ /*
+ This one is supposed to be set: just an extra check so that
+ nothing strange has happened.
+ */
+ DBUG_ASSERT(get_flags(STMT_END_F));
+
+ rgi->slave_close_thread_tables(thd);
+ thd->clear_error();
+ DBUG_RETURN(0);
+ }
+
+ /*
+ 'thd' has been set by exec_relay_log_event(), just before calling
+ do_apply_event(). We still check here to prevent future coding
+ errors.
+ */
+ DBUG_ASSERT(rgi->thd == thd);
+
+ /*
+ If there is no locks taken, this is the first binrow event seen
+ after the table map events. We should then lock all the tables
+ used in the transaction and proceed with execution of the actual
+ event.
+ */
+ if (!thd->lock)
+ {
+ /*
+ Lock_tables() reads the contents of thd->lex, so they must be
+ initialized.
+
+ We also call the THD::reset_for_next_command(), since this
+ is the logical start of the next "statement". Note that this
+ call might reset the value of current_stmt_binlog_format, so
+ we need to do any changes to that value after this function.
+ */
+ delete_explain_query(thd->lex);
+ lex_start(thd);
+ thd->reset_for_next_command();
+ /*
+ The current statement is just about to begin and
+ has not yet modified anything. Note, all.modified is reset
+ by THD::reset_for_next_command().
+ */
+ thd->transaction.stmt.modified_non_trans_table= FALSE;
+ thd->transaction.stmt.m_unsafe_rollback_flags&= ~THD_TRANS::DID_WAIT;
+ /*
+ This is a row injection, so we flag the "statement" as
+ such. Note that this code is called both when the slave does row
+ injections and when the BINLOG statement is used to do row
+ injections.
+ */
+ thd->lex->set_stmt_row_injection();
+
+ /*
+ There are a few flags that are replicated with each row event.
+ Make sure to set/clear them before executing the main body of
+ the event.
+ */
+ if (get_flags(NO_FOREIGN_KEY_CHECKS_F))
+ thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS;
+ else
+ thd->variables.option_bits&= ~OPTION_NO_FOREIGN_KEY_CHECKS;
+
+ if (get_flags(RELAXED_UNIQUE_CHECKS_F))
+ thd->variables.option_bits|= OPTION_RELAXED_UNIQUE_CHECKS;
+ else
+ thd->variables.option_bits&= ~OPTION_RELAXED_UNIQUE_CHECKS;
+
+ if (get_flags(NO_CHECK_CONSTRAINT_CHECKS_F))
+ thd->variables.option_bits|= OPTION_NO_CHECK_CONSTRAINT_CHECKS;
+ else
+ thd->variables.option_bits&= ~OPTION_NO_CHECK_CONSTRAINT_CHECKS;
+
+ /* A small test to verify that objects have consistent types */
+ DBUG_ASSERT(sizeof(thd->variables.option_bits) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
+
+ DBUG_EXECUTE_IF("rows_log_event_before_open_table",
+ {
+ const char action[] = "now SIGNAL before_open_table WAIT_FOR go_ahead_sql";
+ DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(action)));
+ };);
+
+ if (slave_run_triggers_for_rbr)
+ {
+ LEX *lex= thd->lex;
+ uint8 new_trg_event_map= get_trg_event_map();
+
+ /*
+ Trigger's procedures work with global table list. So we have to add
+ rgi->tables_to_lock content there to get trigger's in the list.
+
+ Then restore_empty_query_table_list() restore the list as it was
+ */
+ DBUG_ASSERT(lex->query_tables == NULL);
+ if ((lex->query_tables= rgi->tables_to_lock))
+ rgi->tables_to_lock->prev_global= &lex->query_tables;
+
+ for (TABLE_LIST *tables= rgi->tables_to_lock; tables;
+ tables= tables->next_global)
+ {
+ tables->trg_event_map= new_trg_event_map;
+ lex->query_tables_last= &tables->next_global;
+ }
+ }
+ if (unlikely(open_and_lock_tables(thd, rgi->tables_to_lock, FALSE, 0)))
+ {
+#ifdef WITH_WSREP
+ if (WSREP(thd))
+ {
+ WSREP_WARN("BF applier failed to open_and_lock_tables: %u, fatal: %d "
+ "wsrep = (exec_mode: %d conflict_state: %d seqno: %lld)",
+ thd->get_stmt_da()->sql_errno(),
+ thd->is_fatal_error,
+ thd->wsrep_cs().mode(),
+ thd->wsrep_trx().state(),
+ (long long) wsrep_thd_trx_seqno(thd));
+ }
+#endif /* WITH_WSREP */
+ if (thd->is_error() &&
+ !is_parallel_retry_error(rgi, error= thd->get_stmt_da()->sql_errno()))
+ {
+ /*
+ Error reporting borrowed from Query_log_event with many excessive
+ simplifications.
+ We should not honour --slave-skip-errors at this point as we are
+ having severe errors which should not be skipped.
+ */
+ rli->report(ERROR_LEVEL, error, rgi->gtid_info(),
+ "Error executing row event: '%s'",
+ (error ? thd->get_stmt_da()->message() :
+ "unexpected success or fatal error"));
+ thd->is_slave_error= 1;
+ }
+ /* remove trigger's tables */
+ goto err;
+ }
+
+ /*
+ When the open and locking succeeded, we check all tables to
+ ensure that they still have the correct type.
+ */
+
+ {
+ DBUG_PRINT("debug", ("Checking compability of tables to lock - tables_to_lock: %p",
+ rgi->tables_to_lock));
+
+ /**
+ When using RBR and MyISAM MERGE tables the base tables that make
+ up the MERGE table can be appended to the list of tables to lock.
+
+ Thus, we just check compatibility for those that tables that have
+ a correspondent table map event (ie, those that are actually going
+ to be accessed while applying the event). That's why the loop stops
+ at rli->tables_to_lock_count .
+
+ NOTE: The base tables are added here are removed when
+ close_thread_tables is called.
+ */
+ TABLE_LIST *table_list_ptr= rgi->tables_to_lock;
+ for (uint i=0 ; table_list_ptr && (i < rgi->tables_to_lock_count);
+ table_list_ptr= table_list_ptr->next_global, i++)
+ {
+ /*
+ Below if condition takes care of skipping base tables that
+ make up the MERGE table (which are added by open_tables()
+ call). They are added next to the merge table in the list.
+ For eg: If RPL_TABLE_LIST is t3->t1->t2 (where t1 and t2
+ are base tables for merge table 't3'), open_tables will modify
+ the list by adding t1 and t2 again immediately after t3 in the
+ list (*not at the end of the list*). New table_to_lock list will
+ look like t3->t1'->t2'->t1->t2 (where t1' and t2' are TABLE_LIST
+ objects added by open_tables() call). There is no flag(or logic) in
+ open_tables() that can skip adding these base tables to the list.
+ So the logic here should take care of skipping them.
+
+ tables_to_lock_count logic will take care of skipping base tables
+ that are added at the end of the list.
+ For eg: If RPL_TABLE_LIST is t1->t2->t3, open_tables will modify
+ the list into t1->t2->t3->t1'->t2'. t1' and t2' will be skipped
+ because tables_to_lock_count logic in this for loop.
+ */
+ if (table_list_ptr->parent_l)
+ continue;
+ /*
+ We can use a down cast here since we know that every table added
+ to the tables_to_lock is a RPL_TABLE_LIST (or child table which is
+ skipped above).
+ */
+ RPL_TABLE_LIST *ptr= static_cast<RPL_TABLE_LIST*>(table_list_ptr);
+ DBUG_ASSERT(ptr->m_tabledef_valid);
+ TABLE *conv_table;
+ if (!ptr->m_tabledef.compatible_with(thd, rgi, ptr->table, &conv_table))
+ {
+ DBUG_PRINT("debug", ("Table: %s.%s is not compatible with master",
+ ptr->table->s->db.str,
+ ptr->table->s->table_name.str));
+ /*
+ We should not honour --slave-skip-errors at this point as we are
+ having severe errors which should not be skiped.
+ */
+ thd->is_slave_error= 1;
+ /* remove trigger's tables */
+ error= ERR_BAD_TABLE_DEF;
+ goto err;
+ }
+ DBUG_PRINT("debug", ("Table: %s.%s is compatible with master"
+ " - conv_table: %p",
+ ptr->table->s->db.str,
+ ptr->table->s->table_name.str, conv_table));
+ ptr->m_conv_table= conv_table;
+ }
+ }
+
+ /*
+ ... and then we add all the tables to the table map and but keep
+ them in the tables to lock list.
+
+ We also invalidate the query cache for all the tables, since
+ they will now be changed.
+
+ TODO [/Matz]: Maybe the query cache should not be invalidated
+ here? It might be that a table is not changed, even though it
+ was locked for the statement. We do know that each
+ Rows_log_event contain at least one row, so after processing one
+ Rows_log_event, we can invalidate the query cache for the
+ associated table.
+ */
+ TABLE_LIST *ptr= rgi->tables_to_lock;
+ for (uint i=0 ; ptr && (i < rgi->tables_to_lock_count); ptr= ptr->next_global, i++)
+ {
+ /*
+ Please see comment in above 'for' loop to know the reason
+ for this if condition
+ */
+ if (ptr->parent_l)
+ continue;
+ rgi->m_table_map.set_table(ptr->table_id, ptr->table);
+ /*
+ Following is passing flag about triggers on the server. The problem was
+ to pass it between table map event and row event. I do it via extended
+ TABLE_LIST (RPL_TABLE_LIST) but row event uses only TABLE so I need to
+ find somehow the corresponding TABLE_LIST.
+ */
+ if (m_table_id == ptr->table_id)
+ {
+ ptr->table->master_had_triggers=
+ ((RPL_TABLE_LIST*)ptr)->master_had_triggers;
+ }
+ }
+
+#ifdef HAVE_QUERY_CACHE
+#ifdef WITH_WSREP
+ /*
+ Moved invalidation right before the call to rows_event_stmt_cleanup(),
+ to avoid query cache being polluted with stale entries,
+ */
+ if (! (WSREP(thd) && wsrep_thd_is_applying(thd)))
+ {
+#endif /* WITH_WSREP */
+ query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock);
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
+#endif
+ }
+
+ table= m_table= rgi->m_table_map.get_table(m_table_id);
+
+ DBUG_PRINT("debug", ("m_table:%p, m_table_id: %llu%s",
+ m_table, m_table_id,
+ table && master_had_triggers ?
+ " (master had triggers)" : ""));
+ if (table)
+ {
+ master_had_triggers= table->master_had_triggers;
+ bool transactional_table= table->file->has_transactions();
+ /*
+ table == NULL means that this table should not be replicated
+ (this was set up by Table_map_log_event::do_apply_event()
+ which tested replicate-* rules).
+ */
+
+ /*
+ It's not needed to set_time() but
+ 1) it continues the property that "Time" in SHOW PROCESSLIST shows how
+ much slave is behind
+ 2) it will be needed when we allow replication from a table with no
+ TIMESTAMP column to a table with one.
+ So we call set_time(), like in SBR. Presently it changes nothing.
+ */
+ thd->set_time(when, when_sec_part);
+
+ if (m_width == table->s->fields && bitmap_is_set_all(&m_cols))
+ set_flags(COMPLETE_ROWS_F);
+
+ /*
+ Set tables write and read sets.
+
+ Read_set contains all slave columns (in case we are going to fetch
+ a complete record from slave)
+
+ Write_set equals the m_cols bitmap sent from master but it can be
+ longer if slave has extra columns.
+ */
+
+ DBUG_PRINT_BITSET("debug", "Setting table's read_set from: %s", &m_cols);
+
+ bitmap_set_all(table->read_set);
+ if (get_general_type_code() == DELETE_ROWS_EVENT ||
+ get_general_type_code() == UPDATE_ROWS_EVENT)
+ bitmap_intersect(table->read_set,&m_cols);
+
+ bitmap_set_all(table->write_set);
+ table->rpl_write_set= table->write_set;
+
+ /* WRITE ROWS EVENTS store the bitmap in m_cols instead of m_cols_ai */
+ MY_BITMAP *after_image= ((get_general_type_code() == UPDATE_ROWS_EVENT) ?
+ &m_cols_ai : &m_cols);
+ bitmap_intersect(table->write_set, after_image);
+
+ this->slave_exec_mode= slave_exec_mode_options; // fix the mode
+
+ // Do event specific preparations
+ error= do_before_row_operations(rli);
+
+ /*
+ Bug#56662 Assertion failed: next_insert_id == 0, file handler.cc
+ Don't allow generation of auto_increment value when processing
+ rows event by setting 'MODE_NO_AUTO_VALUE_ON_ZERO'. The exception
+ to this rule happens when the auto_inc column exists on some
+ extra columns on the slave. In that case, do not force
+ MODE_NO_AUTO_VALUE_ON_ZERO.
+ */
+ sql_mode_t saved_sql_mode= thd->variables.sql_mode;
+ if (!is_auto_inc_in_extra_columns())
+ thd->variables.sql_mode= MODE_NO_AUTO_VALUE_ON_ZERO;
+
+ // row processing loop
+
+ /*
+ set the initial time of this ROWS statement if it was not done
+ before in some other ROWS event.
+ */
+ rgi->set_row_stmt_start_timestamp();
+
+ THD_STAGE_INFO(thd, stage_executing);
+ do
+ {
+ /* in_use can have been set to NULL in close_tables_for_reopen */
+ THD* old_thd= table->in_use;
+ if (!table->in_use)
+ table->in_use= thd;
+
+ error= do_exec_row(rgi);
+
+ if (unlikely(error))
+ DBUG_PRINT("info", ("error: %s", HA_ERR(error)));
+ DBUG_ASSERT(error != HA_ERR_RECORD_DELETED);
+
+ table->in_use = old_thd;
+
+ if (unlikely(error))
+ {
+ int actual_error= convert_handler_error(error, thd, table);
+ bool idempotent_error= (idempotent_error_code(error) &&
+ (slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT));
+ bool ignored_error= (idempotent_error == 0 ?
+ ignored_error_code(actual_error) : 0);
+
+#ifdef WITH_WSREP
+ if (WSREP(thd) && wsrep_ignored_error_code(this, actual_error))
+ {
+ idempotent_error= true;
+ thd->wsrep_has_ignored_error= true;
+ }
+#endif /* WITH_WSREP */
+ if (idempotent_error || ignored_error)
+ {
+ if (global_system_variables.log_warnings)
+ slave_rows_error_report(WARNING_LEVEL, error, rgi, thd, table,
+ get_type_str(),
+ RPL_LOG_NAME, log_pos);
+ thd->clear_error(1);
+ error= 0;
+ if (idempotent_error == 0)
+ break;
+ }
+ }
+
+ /*
+ If m_curr_row_end was not set during event execution (e.g., because
+ of errors) we can't proceed to the next row. If the error is transient
+ (i.e., error==0 at this point) we must call unpack_current_row() to set
+ m_curr_row_end.
+ */
+
+ DBUG_PRINT("info", ("curr_row: %p; curr_row_end: %p; rows_end:%p",
+ m_curr_row, m_curr_row_end, m_rows_end));
+
+ if (!m_curr_row_end && likely(!error))
+ error= unpack_current_row(rgi);
+
+ m_curr_row= m_curr_row_end;
+
+ if (likely(error == 0) && !transactional_table)
+ thd->transaction.all.modified_non_trans_table=
+ thd->transaction.stmt.modified_non_trans_table= TRUE;
+ } // row processing loop
+ while (error == 0 && (m_curr_row != m_rows_end));
+
+ /*
+ Restore the sql_mode after the rows event is processed.
+ */
+ thd->variables.sql_mode= saved_sql_mode;
+
+ {/**
+ The following failure injecion works in cooperation with tests
+ setting @@global.debug= 'd,stop_slave_middle_group'.
+ The sql thread receives the killed status and will proceed
+ to shutdown trying to finish incomplete events group.
+ */
+ DBUG_EXECUTE_IF("stop_slave_middle_group",
+ if (thd->transaction.all.modified_non_trans_table)
+ const_cast<Relay_log_info*>(rli)->abort_slave= 1;);
+ }
+
+ if (unlikely(error= do_after_row_operations(rli, error)) &&
+ ignored_error_code(convert_handler_error(error, thd, table)))
+ {
+
+ if (global_system_variables.log_warnings)
+ slave_rows_error_report(WARNING_LEVEL, error, rgi, thd, table,
+ get_type_str(),
+ RPL_LOG_NAME, log_pos);
+ thd->clear_error(1);
+ error= 0;
+ }
+ } // if (table)
+
+
+ if (unlikely(error))
+ {
+ slave_rows_error_report(ERROR_LEVEL, error, rgi, thd, table,
+ get_type_str(),
+ RPL_LOG_NAME, log_pos);
+ /*
+ @todo We should probably not call
+ reset_current_stmt_binlog_format_row() from here.
+
+ Note: this applies to log_event_old.cc too.
+ /Sven
+ */
+ thd->reset_current_stmt_binlog_format_row();
+ thd->is_slave_error= 1;
+ /* remove trigger's tables */
+ goto err;
+ }
+
+ /* remove trigger's tables */
+ if (slave_run_triggers_for_rbr)
+ restore_empty_query_table_list(thd->lex);
+
+#if defined(WITH_WSREP) && defined(HAVE_QUERY_CACHE)
+ if (WSREP(thd) && wsrep_thd_is_applying(thd))
+ {
+ query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock);
+ }
+#endif /* WITH_WSREP && HAVE_QUERY_CACHE */
+
+ if (unlikely(get_flags(STMT_END_F) &&
+ (error= rows_event_stmt_cleanup(rgi, thd))))
+ slave_rows_error_report(ERROR_LEVEL,
+ thd->is_error() ? 0 : error,
+ rgi, thd, table,
+ get_type_str(),
+ RPL_LOG_NAME, log_pos);
+ DBUG_RETURN(error);
+
+err:
+ if (slave_run_triggers_for_rbr)
+ restore_empty_query_table_list(thd->lex);
+ rgi->slave_close_thread_tables(thd);
+ DBUG_RETURN(error);
+}
+
+Log_event::enum_skip_reason
+Rows_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ /*
+ If the slave skip counter is 1 and this event does not end a
+ statement, then we should not start executing on the next event.
+ Otherwise, we defer the decision to the normal skipping logic.
+ */
+ if (rgi->rli->slave_skip_counter == 1 && !get_flags(STMT_END_F))
+ return Log_event::EVENT_SKIP_IGNORE;
+ else
+ return Log_event::do_shall_skip(rgi);
+}
+
+/**
+ The function is called at Rows_log_event statement commit time,
+ normally from Rows_log_event::do_update_pos() and possibly from
+ Query_log_event::do_apply_event() of the COMMIT.
+ The function commits the last statement for engines, binlog and
+ releases resources have been allocated for the statement.
+
+ @retval 0 Ok.
+ @retval non-zero Error at the commit.
+ */
+
+static int rows_event_stmt_cleanup(rpl_group_info *rgi, THD * thd)
+{
+ int error;
+ DBUG_ENTER("rows_event_stmt_cleanup");
+
+ {
+ /*
+ This is the end of a statement or transaction, so close (and
+ unlock) the tables we opened when processing the
+ Table_map_log_event starting the statement.
+
+ OBSERVER. This will clear *all* mappings, not only those that
+ are open for the table. There is not good handle for on-close
+ actions for tables.
+
+ NOTE. Even if we have no table ('table' == 0) we still need to be
+ here, so that we increase the group relay log position. If we didn't, we
+ could have a group relay log position which lags behind "forever"
+ (assume the last master's transaction is ignored by the slave because of
+ replicate-ignore rules).
+ */
+ error= thd->binlog_flush_pending_rows_event(TRUE);
+
+ /*
+ If this event is not in a transaction, the call below will, if some
+ transactional storage engines are involved, commit the statement into
+ them and flush the pending event to binlog.
+ If this event is in a transaction, the call will do nothing, but a
+ Xid_log_event will come next which will, if some transactional engines
+ are involved, commit the transaction and flush the pending event to the
+ binlog.
+ If there was a deadlock the transaction should have been rolled back
+ already. So there should be no need to rollback the transaction.
+ */
+ DBUG_ASSERT(! thd->transaction_rollback_request);
+ error|= (int)(error ? trans_rollback_stmt(thd) : trans_commit_stmt(thd));
+
+ /*
+ Now what if this is not a transactional engine? we still need to
+ flush the pending event to the binlog; we did it with
+ thd->binlog_flush_pending_rows_event(). Note that we imitate
+ what is done for real queries: a call to
+ ha_autocommit_or_rollback() (sometimes only if involves a
+ transactional engine), and a call to be sure to have the pending
+ event flushed.
+ */
+
+ /*
+ @todo We should probably not call
+ reset_current_stmt_binlog_format_row() from here.
+
+ Note: this applies to log_event_old.cc too
+
+ Btw, the previous comment about transactional engines does not
+ seem related to anything that happens here.
+ /Sven
+ */
+ thd->reset_current_stmt_binlog_format_row();
+
+ /*
+ Reset modified_non_trans_table that we have set in
+ rows_log_event::do_apply_event()
+ */
+ if (!thd->in_multi_stmt_transaction_mode())
+ {
+ thd->transaction.all.modified_non_trans_table= 0;
+ thd->transaction.all.m_unsafe_rollback_flags&= ~THD_TRANS::DID_WAIT;
+ }
+
+ rgi->cleanup_context(thd, 0);
+ }
+ DBUG_RETURN(error);
+}
+
+/**
+ The method either increments the relay log position or
+ commits the current statement and increments the master group
+ possition if the event is STMT_END_F flagged and
+ the statement corresponds to the autocommit query (i.e replicated
+ without wrapping in BEGIN/COMMIT)
+
+ @retval 0 Success
+ @retval non-zero Error in the statement commit
+ */
+int
+Rows_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ Relay_log_info *rli= rgi->rli;
+ int error= 0;
+ DBUG_ENTER("Rows_log_event::do_update_pos");
+
+ DBUG_PRINT("info", ("flags: %s",
+ get_flags(STMT_END_F) ? "STMT_END_F " : ""));
+
+ if (get_flags(STMT_END_F))
+ {
+ /*
+ Indicate that a statement is finished.
+ Step the group log position if we are not in a transaction,
+ otherwise increase the event log position.
+ */
+ error= rli->stmt_done(log_pos, thd, rgi);
+ /*
+ Clear any errors in thd->net.last_err*. It is not known if this is
+ needed or not. It is believed that any errors that may exist in
+ thd->net.last_err* are allowed. Examples of errors are "key not
+ found", which is produced in the test case rpl_row_conflicts.test
+ */
+ thd->clear_error();
+ }
+ else
+ {
+ rgi->inc_event_relay_log_pos();
+ }
+
+ DBUG_RETURN(error);
+}
+
+#endif /* defined(HAVE_REPLICATION) */
+
+
+bool Rows_log_event::write_data_header()
+{
+ uchar buf[ROWS_HEADER_LEN_V2]; // No need to init the buffer
+ DBUG_ASSERT(m_table_id != ~0ULL);
+ DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master",
+ {
+ int4store(buf + 0, m_table_id);
+ int2store(buf + 4, m_flags);
+ return (write_data(buf, 6));
+ });
+ int6store(buf + RW_MAPID_OFFSET, m_table_id);
+ int2store(buf + RW_FLAGS_OFFSET, m_flags);
+ return write_data(buf, ROWS_HEADER_LEN);
+}
+
+bool Rows_log_event::write_data_body()
+{
+ /*
+ Note that this should be the number of *bits*, not the number of
+ bytes.
+ */
+ uchar sbuf[MAX_INT_WIDTH];
+ my_ptrdiff_t const data_size= m_rows_cur - m_rows_buf;
+ bool res= false;
+ uchar *const sbuf_end= net_store_length(sbuf, (size_t) m_width);
+ DBUG_ASSERT(static_cast<size_t>(sbuf_end - sbuf) <= sizeof(sbuf));
+
+ DBUG_DUMP("m_width", sbuf, (size_t) (sbuf_end - sbuf));
+ res= res || write_data(sbuf, (size_t) (sbuf_end - sbuf));
+
+ DBUG_DUMP("m_cols", (uchar*) m_cols.bitmap, no_bytes_in_map(&m_cols));
+ res= res || write_data((uchar*)m_cols.bitmap, no_bytes_in_map(&m_cols));
+ /*
+ TODO[refactor write]: Remove the "down cast" here (and elsewhere).
+ */
+ if (get_general_type_code() == UPDATE_ROWS_EVENT)
+ {
+ DBUG_DUMP("m_cols_ai", (uchar*) m_cols_ai.bitmap,
+ no_bytes_in_map(&m_cols_ai));
+ res= res || write_data((uchar*)m_cols_ai.bitmap,
+ no_bytes_in_map(&m_cols_ai));
+ }
+ DBUG_DUMP("rows", m_rows_buf, data_size);
+ res= res || write_data(m_rows_buf, (size_t) data_size);
+
+ return res;
+
+}
+
+bool Rows_log_event::write_compressed()
+{
+ uchar *m_rows_buf_tmp = m_rows_buf;
+ uchar *m_rows_cur_tmp = m_rows_cur;
+ bool ret = true;
+ uint32 comlen, alloc_size;
+ comlen= alloc_size= binlog_get_compress_len((uint32)(m_rows_cur_tmp - m_rows_buf_tmp));
+ m_rows_buf = (uchar *)my_safe_alloca(alloc_size);
+ if(m_rows_buf &&
+ !binlog_buf_compress((const char *)m_rows_buf_tmp, (char *)m_rows_buf,
+ (uint32)(m_rows_cur_tmp - m_rows_buf_tmp), &comlen))
+ {
+ m_rows_cur= comlen + m_rows_buf;
+ ret= Log_event::write();
+ }
+ my_safe_afree(m_rows_buf, alloc_size);
+ m_rows_buf= m_rows_buf_tmp;
+ m_rows_cur= m_rows_cur_tmp;
+ return ret;
+}
+
+
+#if defined(HAVE_REPLICATION)
+void Rows_log_event::pack_info(Protocol *protocol)
+{
+ char buf[256];
+ char const *const flagstr=
+ get_flags(STMT_END_F) ? " flags: STMT_END_F" : "";
+ size_t bytes= my_snprintf(buf, sizeof(buf),
+ "table_id: %llu%s", m_table_id, flagstr);
+ protocol->store(buf, bytes, &my_charset_bin);
+}
+#endif
+
+
+/**************************************************************************
+ Annotate_rows_log_event member functions
+**************************************************************************/
+
+Annotate_rows_log_event::Annotate_rows_log_event(THD *thd,
+ bool using_trans,
+ bool direct)
+ : Log_event(thd, 0, using_trans),
+ m_save_thd_query_txt(0),
+ m_save_thd_query_len(0),
+ m_saved_thd_query(false),
+ m_used_query_txt(0)
+{
+ m_query_txt= thd->query();
+ m_query_len= thd->query_length();
+ if (direct)
+ cache_type= Log_event::EVENT_NO_CACHE;
+}
+
+
+bool Annotate_rows_log_event::write_data_header()
+{
+ return 0;
+}
+
+
+bool Annotate_rows_log_event::write_data_body()
+{
+ return write_data(m_query_txt, m_query_len);
+}
+
+
+#if defined(HAVE_REPLICATION)
+void Annotate_rows_log_event::pack_info(Protocol* protocol)
+{
+ if (m_query_txt && m_query_len)
+ protocol->store(m_query_txt, m_query_len, &my_charset_bin);
+}
+#endif
+
+
+#if defined(HAVE_REPLICATION)
+int Annotate_rows_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ rgi->free_annotate_event();
+ m_save_thd_query_txt= thd->query();
+ m_save_thd_query_len= thd->query_length();
+ m_saved_thd_query= true;
+ m_used_query_txt= 1;
+ thd->set_query(m_query_txt, m_query_len);
+ return 0;
+}
+#endif
+
+
+#if defined(HAVE_REPLICATION)
+int Annotate_rows_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ rgi->inc_event_relay_log_pos();
+ return 0;
+}
+#endif
+
+
+#if defined(HAVE_REPLICATION)
+Log_event::enum_skip_reason
+Annotate_rows_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ return continue_group(rgi);
+}
+#endif
+
+/**************************************************************************
+ Table_map_log_event member functions and support functions
+**************************************************************************/
+
+/**
+ Save the field metadata based on the real_type of the field.
+ The metadata saved depends on the type of the field. Some fields
+ store a single byte for pack_length() while others store two bytes
+ for field_length (max length).
+
+ @retval 0 Ok.
+
+ @todo
+ We may want to consider changing the encoding of the information.
+ Currently, the code attempts to minimize the number of bytes written to
+ the tablemap. There are at least two other alternatives; 1) using
+ net_store_length() to store the data allowing it to choose the number of
+ bytes that are appropriate thereby making the code much easier to
+ maintain (only 1 place to change the encoding), or 2) use a fixed number
+ of bytes for each field. The problem with option 1 is that net_store_length()
+ will use one byte if the value < 251, but 3 bytes if it is > 250. Thus,
+ for fields like CHAR which can be no larger than 255 characters, the method
+ will use 3 bytes when the value is > 250. Further, every value that is
+ encoded using 2 parts (e.g., pack_length, field_length) will be numerically
+ > 250 therefore will use 3 bytes for eah value. The problem with option 2
+ is less wasteful for space but does waste 1 byte for every field that does
+ not encode 2 parts.
+*/
+int Table_map_log_event::save_field_metadata()
+{
+ DBUG_ENTER("Table_map_log_event::save_field_metadata");
+ int index= 0;
+ Binlog_type_info *info;
+ for (unsigned int i= 0 ; i < m_table->s->fields ; i++)
+ {
+ DBUG_PRINT("debug", ("field_type: %d", m_coltype[i]));
+ info= binlog_type_info_array + i;
+ int2store(&m_field_metadata[index], info->m_metadata);
+ index+= info->m_metadata_size;
+ DBUG_EXECUTE_IF("inject_invalid_blob_size",
+ {
+ if (m_coltype[i] == MYSQL_TYPE_BLOB)
+ m_field_metadata[index-1] = 5;
+ });
+ }
+ DBUG_RETURN(index);
+}
+
+
+/*
+ Constructor used to build an event for writing to the binary log.
+ Mats says tbl->s lives longer than this event so it's ok to copy pointers
+ (tbl->s->db etc) and not pointer content.
+ */
+Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid,
+ bool is_transactional)
+ : Log_event(thd, 0, is_transactional),
+ m_table(tbl),
+ m_dbnam(tbl->s->db.str),
+ m_dblen(m_dbnam ? tbl->s->db.length : 0),
+ m_tblnam(tbl->s->table_name.str),
+ m_tbllen(tbl->s->table_name.length),
+ m_colcnt(tbl->s->fields),
+ m_memory(NULL),
+ m_table_id(tid),
+ m_flags(TM_BIT_LEN_EXACT_F),
+ m_data_size(0),
+ m_field_metadata(0),
+ m_field_metadata_size(0),
+ m_null_bits(0),
+ m_meta_memory(NULL),
+ m_optional_metadata_len(0),
+ m_optional_metadata(NULL)
+{
+ uchar cbuf[MAX_INT_WIDTH];
+ uchar *cbuf_end;
+ DBUG_ENTER("Table_map_log_event::Table_map_log_event(TABLE)");
+ DBUG_ASSERT(m_table_id != ~0ULL);
+ /*
+ In TABLE_SHARE, "db" and "table_name" are 0-terminated (see this comment in
+ table.cc / alloc_table_share():
+ Use the fact the key is db/0/table_name/0
+ As we rely on this let's assert it.
+ */
+ DBUG_ASSERT((tbl->s->db.str == 0) ||
+ (tbl->s->db.str[tbl->s->db.length] == 0));
+ DBUG_ASSERT(tbl->s->table_name.str[tbl->s->table_name.length] == 0);
+
+#ifdef MYSQL_SERVER
+ binlog_type_info_array= (Binlog_type_info *)thd->alloc(m_table->s->fields *
+ sizeof(Binlog_type_info));
+ for (uint i= 0; i < m_table->s->fields; i++)
+ binlog_type_info_array[i]= m_table->field[i]->binlog_type_info();
+#endif
+
+
+ m_data_size= TABLE_MAP_HEADER_LEN;
+ DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master", m_data_size= 6;);
+ m_data_size+= m_dblen + 2; // Include length and terminating \0
+ m_data_size+= m_tbllen + 2; // Include length and terminating \0
+ cbuf_end= net_store_length(cbuf, (size_t) m_colcnt);
+ DBUG_ASSERT(static_cast<size_t>(cbuf_end - cbuf) <= sizeof(cbuf));
+ m_data_size+= (cbuf_end - cbuf) + m_colcnt; // COLCNT and column types
+
+ if (tbl->triggers)
+ m_flags|= TM_BIT_HAS_TRIGGERS_F;
+
+ /* If malloc fails, caught in is_valid() */
+ if ((m_memory= (uchar*) my_malloc(PSI_INSTRUMENT_ME, m_colcnt, MYF(MY_WME))))
+ {
+ m_coltype= reinterpret_cast<uchar*>(m_memory);
+ for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
+ m_coltype[i]= binlog_type_info_array[i].m_type_code;
+ DBUG_EXECUTE_IF("inject_invalid_column_type", m_coltype[1]= 230;);
+ }
+
+ /*
+ Calculate a bitmap for the results of maybe_null() for all columns.
+ The bitmap is used to determine when there is a column from the master
+ that is not on the slave and is null and thus not in the row data during
+ replication.
+ */
+ uint num_null_bytes= (m_table->s->fields + 7) / 8;
+ m_data_size+= num_null_bytes;
+ m_meta_memory= (uchar *)my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME),
+ &m_null_bits, num_null_bytes,
+ &m_field_metadata, (m_colcnt * 2),
+ NULL);
+
+ bzero(m_field_metadata, (m_colcnt * 2));
+
+ /*
+ Create an array for the field metadata and store it.
+ */
+ m_field_metadata_size= save_field_metadata();
+ DBUG_ASSERT(m_field_metadata_size <= (m_colcnt * 2));
+
+ /*
+ Now set the size of the data to the size of the field metadata array
+ plus one or three bytes (see pack.c:net_store_length) for number of
+ elements in the field metadata array.
+ */
+ if (m_field_metadata_size < 251)
+ m_data_size+= m_field_metadata_size + 1;
+ else
+ m_data_size+= m_field_metadata_size + 3;
+
+ bzero(m_null_bits, num_null_bytes);
+ for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
+ if (m_table->field[i]->maybe_null())
+ m_null_bits[(i / 8)]+= 1 << (i % 8);
+
+ init_metadata_fields();
+ m_data_size+= m_metadata_buf.length();
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Return value is an error code, one of:
+
+ -1 Failure to open table [from open_tables()]
+ 0 Success
+ 1 No room for more tables [from set_table()]
+ 2 Out of memory [from set_table()]
+ 3 Wrong table definition
+ 4 Daisy-chaining RBR with SBR not possible
+ */
+
+#if defined(HAVE_REPLICATION)
+
+enum enum_tbl_map_status
+{
+ /* no duplicate identifier found */
+ OK_TO_PROCESS= 0,
+
+ /* this table map must be filtered out */
+ FILTERED_OUT= 1,
+
+ /* identifier mapping table with different properties */
+ SAME_ID_MAPPING_DIFFERENT_TABLE= 2,
+
+ /* a duplicate identifier was found mapping the same table */
+ SAME_ID_MAPPING_SAME_TABLE= 3
+};
+
+/*
+ Checks if this table map event should be processed or not. First
+ it checks the filtering rules, and then looks for duplicate identifiers
+ in the existing list of rli->tables_to_lock.
+
+ It checks that there hasn't been any corruption by verifying that there
+ are no duplicate entries with different properties.
+
+ In some cases, some binary logs could get corrupted, showing several
+ tables mapped to the same table_id, 0 (see: BUG#56226). Thus we do this
+ early sanity check for such cases and avoid that the server crashes
+ later.
+
+ In some corner cases, the master logs duplicate table map events, i.e.,
+ same id, same database name, same table name (see: BUG#37137). This is
+ different from the above as it's the same table that is mapped again
+ to the same identifier. Thus we cannot just check for same ids and
+ assume that the event is corrupted we need to check every property.
+
+ NOTE: in the event that BUG#37137 ever gets fixed, this extra check
+ will still be valid because we would need to support old binary
+ logs anyway.
+
+ @param rli The relay log info reference.
+ @param table_list A list element containing the table to check against.
+ @return OK_TO_PROCESS
+ if there was no identifier already in rli->tables_to_lock
+
+ FILTERED_OUT
+ if the event is filtered according to the filtering rules
+
+ SAME_ID_MAPPING_DIFFERENT_TABLE
+ if the same identifier already maps a different table in
+ rli->tables_to_lock
+
+ SAME_ID_MAPPING_SAME_TABLE
+ if the same identifier already maps the same table in
+ rli->tables_to_lock.
+*/
+static enum_tbl_map_status
+check_table_map(rpl_group_info *rgi, RPL_TABLE_LIST *table_list)
+{
+ DBUG_ENTER("check_table_map");
+ enum_tbl_map_status res= OK_TO_PROCESS;
+ Relay_log_info *rli= rgi->rli;
+ if ((rgi->thd->slave_thread /* filtering is for slave only */ ||
+ IF_WSREP((WSREP(rgi->thd) && rgi->thd->wsrep_applier), 0)) &&
+ (!rli->mi->rpl_filter->db_ok(table_list->db.str) ||
+ (rli->mi->rpl_filter->is_on() && !rli->mi->rpl_filter->tables_ok("", table_list))))
+ res= FILTERED_OUT;
+ else
+ {
+ RPL_TABLE_LIST *ptr= static_cast<RPL_TABLE_LIST*>(rgi->tables_to_lock);
+ for(uint i=0 ; ptr && (i< rgi->tables_to_lock_count);
+ ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_local), i++)
+ {
+ if (ptr->table_id == table_list->table_id)
+ {
+
+ if (cmp(&ptr->db, &table_list->db) ||
+ cmp(&ptr->alias, &table_list->table_name) ||
+ ptr->lock_type != TL_WRITE) // the ::do_apply_event always sets TL_WRITE
+ res= SAME_ID_MAPPING_DIFFERENT_TABLE;
+ else
+ res= SAME_ID_MAPPING_SAME_TABLE;
+
+ break;
+ }
+ }
+ }
+
+ DBUG_PRINT("debug", ("check of table map ended up with: %u", res));
+
+ DBUG_RETURN(res);
+}
+
+int Table_map_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ RPL_TABLE_LIST *table_list;
+ char *db_mem, *tname_mem, *ptr;
+ size_t dummy_len, db_mem_length, tname_mem_length;
+ void *memory;
+ Rpl_filter *filter;
+ Relay_log_info const *rli= rgi->rli;
+ DBUG_ENTER("Table_map_log_event::do_apply_event(Relay_log_info*)");
+
+ /* Step the query id to mark what columns that are actually used. */
+ thd->set_query_id(next_query_id());
+
+ if (!(memory= my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME),
+ &table_list, (uint) sizeof(RPL_TABLE_LIST),
+ &db_mem, (uint) NAME_LEN + 1,
+ &tname_mem, (uint) NAME_LEN + 1,
+ 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;
+
+ /* 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 };
+
+ table_list->init_one_table(&tmp_db_name, &tmp_tbl_name, 0, TL_WRITE);
+ table_list->table_id= DBUG_EVALUATE_IF("inject_tblmap_same_id_maps_diff_table", 0, m_table_id);
+ table_list->updating= 1;
+ table_list->required_type= TABLE_TYPE_NORMAL;
+
+ DBUG_PRINT("debug", ("table: %s is mapped to %llu",
+ table_list->table_name.str,
+ table_list->table_id));
+ table_list->master_had_triggers= ((m_flags & TM_BIT_HAS_TRIGGERS_F) ? 1 : 0);
+ DBUG_PRINT("debug", ("table->master_had_triggers=%d",
+ (int)table_list->master_had_triggers));
+
+ enum_tbl_map_status tblmap_status= check_table_map(rgi, table_list);
+ if (tblmap_status == OK_TO_PROCESS)
+ {
+ DBUG_ASSERT(thd->lex->query_tables != table_list);
+
+ /*
+ Use placement new to construct the table_def instance in the
+ memory allocated for it inside table_list.
+
+ The memory allocated by the table_def structure (i.e., not the
+ memory allocated *for* the table_def structure) is released
+ inside Relay_log_info::clear_tables_to_lock() by calling the
+ table_def destructor explicitly.
+ */
+ new (&table_list->m_tabledef)
+ table_def(m_coltype, m_colcnt,
+ m_field_metadata, m_field_metadata_size,
+ m_null_bits, m_flags);
+ table_list->m_tabledef_valid= TRUE;
+ table_list->m_conv_table= NULL;
+ table_list->open_type= OT_BASE_ONLY;
+
+ /*
+ We record in the slave's information that the table should be
+ locked by linking the table into the list of tables to lock.
+ */
+ table_list->next_global= table_list->next_local= rgi->tables_to_lock;
+ rgi->tables_to_lock= table_list;
+ rgi->tables_to_lock_count++;
+ /* 'memory' is freed in clear_tables_to_lock */
+ }
+ else // FILTERED_OUT, SAME_ID_MAPPING_*
+ {
+ /*
+ If mapped already but with different properties, we raise an
+ error.
+ If mapped already but with same properties we skip the event.
+ If filtered out we skip the event.
+
+ In all three cases, we need to free the memory previously
+ allocated.
+ */
+ if (tblmap_status == SAME_ID_MAPPING_DIFFERENT_TABLE)
+ {
+ /*
+ Something bad has happened. We need to stop the slave as strange things
+ could happen if we proceed: slave crash, wrong table being updated, ...
+ As a consequence we push an error in this case.
+ */
+
+ char buf[256];
+
+ my_snprintf(buf, sizeof(buf),
+ "Found table map event mapping table id %u which "
+ "was already mapped but with different settings.",
+ table_list->table_id);
+
+ if (thd->slave_thread)
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, rgi->gtid_info(),
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR), buf);
+ else
+ /*
+ For the cases in which a 'BINLOG' statement is set to
+ execute in a user session
+ */
+ my_error(ER_SLAVE_FATAL_ERROR, MYF(0), buf);
+ }
+
+ my_free(memory);
+ }
+
+ DBUG_RETURN(tblmap_status == SAME_ID_MAPPING_DIFFERENT_TABLE);
+}
+
+Log_event::enum_skip_reason
+Table_map_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ /*
+ If the slave skip counter is 1, then we should not start executing
+ on the next event.
+ */
+ return continue_group(rgi);
+}
+
+int Table_map_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ rgi->inc_event_relay_log_pos();
+ return 0;
+}
+
+#endif /* defined(HAVE_REPLICATION) */
+
+bool Table_map_log_event::write_data_header()
+{
+ DBUG_ASSERT(m_table_id != ~0ULL);
+ uchar buf[TABLE_MAP_HEADER_LEN];
+ DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master",
+ {
+ int4store(buf + 0, m_table_id);
+ int2store(buf + 4, m_flags);
+ return (write_data(buf, 6));
+ });
+ int6store(buf + TM_MAPID_OFFSET, m_table_id);
+ int2store(buf + TM_FLAGS_OFFSET, m_flags);
+ return write_data(buf, TABLE_MAP_HEADER_LEN);
+}
+
+bool Table_map_log_event::write_data_body()
+{
+ DBUG_ASSERT(m_dbnam != NULL);
+ DBUG_ASSERT(m_tblnam != NULL);
+ /* We use only one byte per length for storage in event: */
+ DBUG_ASSERT(m_dblen <= MY_MIN(NAME_LEN, 255));
+ DBUG_ASSERT(m_tbllen <= MY_MIN(NAME_LEN, 255));
+
+ uchar const dbuf[]= { (uchar) m_dblen };
+ uchar const tbuf[]= { (uchar) m_tbllen };
+
+ uchar cbuf[MAX_INT_WIDTH];
+ uchar *const cbuf_end= net_store_length(cbuf, (size_t) m_colcnt);
+ DBUG_ASSERT(static_cast<size_t>(cbuf_end - cbuf) <= sizeof(cbuf));
+
+ /*
+ Store the size of the field metadata.
+ */
+ uchar mbuf[MAX_INT_WIDTH];
+ uchar *const mbuf_end= net_store_length(mbuf, m_field_metadata_size);
+
+ return write_data(dbuf, sizeof(dbuf)) ||
+ write_data(m_dbnam, m_dblen+1) ||
+ write_data(tbuf, sizeof(tbuf)) ||
+ write_data(m_tblnam, m_tbllen+1) ||
+ write_data(cbuf, (size_t) (cbuf_end - cbuf)) ||
+ write_data(m_coltype, m_colcnt) ||
+ write_data(mbuf, (size_t) (mbuf_end - mbuf)) ||
+ write_data(m_field_metadata, m_field_metadata_size),
+ write_data(m_null_bits, (m_colcnt + 7) / 8) ||
+ write_data((const uchar*) m_metadata_buf.ptr(),
+ m_metadata_buf.length());
+ }
+
+/**
+ stores an integer into packed format.
+
+ @param[out] str_buf a buffer where the packed integer will be stored.
+ @param[in] length the integer will be packed.
+ */
+static inline
+void store_compressed_length(String &str_buf, ulonglong length)
+{
+ // Store Type and packed length
+ uchar buf[4];
+ uchar *buf_ptr = net_store_length(buf, length);
+
+ str_buf.append(reinterpret_cast<char *>(buf), buf_ptr-buf);
+}
+
+/**
+ Write data into str_buf with Type|Length|Value(TLV) format.
+
+ @param[out] str_buf a buffer where the field is stored.
+ @param[in] type type of the field
+ @param[in] length length of the field value
+ @param[in] value value of the field
+*/
+static inline
+bool write_tlv_field(String &str_buf,
+ enum Table_map_log_event::Optional_metadata_field_type
+ type, uint length, const uchar *value)
+{
+ /* type is stored in one byte, so it should never bigger than 255. */
+ DBUG_ASSERT(static_cast<int>(type) <= 255);
+ str_buf.append((char) type);
+ store_compressed_length(str_buf, length);
+ return str_buf.append(reinterpret_cast<const char *>(value), length);
+}
+
+/**
+ Write data into str_buf with Type|Length|Value(TLV) format.
+
+ @param[out] str_buf a buffer where the field is stored.
+ @param[in] type type of the field
+ @param[in] value value of the field
+*/
+static inline
+bool write_tlv_field(String &str_buf,
+ enum Table_map_log_event::Optional_metadata_field_type
+ type, const String &value)
+{
+ return write_tlv_field(str_buf, type, value.length(),
+ reinterpret_cast<const uchar *>(value.ptr()));
+}
+
+static inline bool is_character_field(Binlog_type_info *info_array, Field *field)
+{
+ Binlog_type_info *info= info_array + field->field_index;
+ if (!info->m_cs)
+ return 0;
+ if (info->m_set_typelib || info->m_enum_typelib)
+ return 0;
+ return 1;
+}
+
+static inline bool is_enum_or_set_field(Binlog_type_info *info_array, Field *field) {
+ Binlog_type_info *info= info_array + field->field_index;
+ if (info->m_set_typelib || info->m_enum_typelib)
+ return 1;
+ return 0;
+}
+
+
+void Table_map_log_event::init_metadata_fields()
+{
+ DBUG_ENTER("init_metadata_fields");
+ DBUG_EXECUTE_IF("simulate_no_optional_metadata", DBUG_VOID_RETURN;);
+
+ if (binlog_row_metadata == BINLOG_ROW_METADATA_NO_LOG)
+ DBUG_VOID_RETURN;
+ if (init_signedness_field() ||
+ init_charset_field(&is_character_field, DEFAULT_CHARSET,
+ COLUMN_CHARSET) ||
+ init_geometry_type_field())
+ {
+ m_metadata_buf.length(0);
+ DBUG_VOID_RETURN;
+ }
+
+ if (binlog_row_metadata == BINLOG_ROW_METADATA_FULL)
+ {
+ if (DBUG_EVALUATE_IF("dont_log_column_name", 0, init_column_name_field()) ||
+ init_charset_field(&is_enum_or_set_field, ENUM_AND_SET_DEFAULT_CHARSET,
+ ENUM_AND_SET_COLUMN_CHARSET) ||
+ init_set_str_value_field() ||
+ init_enum_str_value_field() ||
+ init_primary_key_field())
+ m_metadata_buf.length(0);
+ }
+ DBUG_VOID_RETURN;
+}
+
+bool Table_map_log_event::init_signedness_field()
+{
+ /* use it to store signed flags, each numeric column take a bit. */
+ StringBuffer<128> buf;
+ unsigned char flag= 0;
+ unsigned char mask= 0x80;
+ Binlog_type_info *info;
+
+ for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
+ {
+ info= binlog_type_info_array + i;
+ if (info->m_signedness != Binlog_type_info::SIGN_NOT_APPLICABLE)
+ {
+ if (info->m_signedness == Binlog_type_info::SIGN_UNSIGNED)
+ flag|= mask;
+ mask >>= 1;
+
+ // 8 fields are tested, store the result and clear the flag.
+ if (mask == 0)
+ {
+ buf.append(flag);
+ flag= 0;
+ mask= 0x80;
+ }
+ }
+ }
+
+ // Stores the signedness flags of last few columns
+ if (mask != 0x80)
+ buf.append(flag);
+
+ // The table has no numeric column, so don't log SIGNEDNESS field
+ if (buf.is_empty())
+ return false;
+
+ return write_tlv_field(m_metadata_buf, SIGNEDNESS, buf);
+}
+
+bool Table_map_log_event::init_charset_field(
+ bool (* include_type)(Binlog_type_info *, Field *),
+ Optional_metadata_field_type default_charset_type,
+ Optional_metadata_field_type column_charset_type)
+{
+ DBUG_EXECUTE_IF("simulate_init_charset_field_error", return true;);
+
+ std::map<uint, uint> collation_map;
+ // For counting characters columns
+ uint char_col_cnt= 0;
+
+ /* Find the collation number used by most fields */
+ for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
+ {
+ if ((*include_type)(binlog_type_info_array, m_table->field[i]))
+ {
+ collation_map[binlog_type_info_array[i].m_cs->number]++;
+ char_col_cnt++;
+ }
+ }
+
+ if (char_col_cnt == 0)
+ return false;
+
+ /* Find the most used collation */
+ uint most_used_collation= 0;
+ uint most_used_count= 0;
+ for (std::map<uint, uint>::iterator it= collation_map.begin();
+ it != collation_map.end(); it++)
+ {
+ if (it->second > most_used_count)
+ {
+ most_used_count= it->second;
+ most_used_collation= it->first;
+ }
+ }
+
+ /*
+ Comparing length of COLUMN_CHARSET field and COLUMN_CHARSET_WITH_DEFAULT
+ field to decide which field should be logged.
+
+ Length of COLUMN_CHARSET = character column count * collation id size.
+ Length of COLUMN_CHARSET_WITH_DEFAULT =
+ default collation_id size + count of columns not use default charset *
+ (column index size + collation id size)
+
+ Assume column index just uses 1 byte and collation number also uses 1 byte.
+ */
+ if (char_col_cnt * 1 < (1 + (char_col_cnt - most_used_count) * 2))
+ {
+ StringBuffer<512> buf;
+
+ /*
+ Stores character set information into COLUMN_CHARSET format,
+ character sets of all columns are stored one by one.
+ -----------------------------------------
+ | Charset number | .... |Charset number |
+ -----------------------------------------
+ */
+ for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
+ {
+ if (include_type(binlog_type_info_array, m_table->field[i]))
+ store_compressed_length(buf, binlog_type_info_array[i].m_cs->number);
+ }
+ return write_tlv_field(m_metadata_buf, column_charset_type, buf);
+ }
+ else
+ {
+ StringBuffer<512> buf;
+ uint char_column_index= 0;
+ uint default_collation= most_used_collation;
+
+ /*
+ Stores character set information into DEFAULT_CHARSET format,
+ First stores the default character set, and then stores the character
+ sets different to default character with their column index one by one.
+ --------------------------------------------------------
+ | Default Charset | Col Index | Charset number | ... |
+ --------------------------------------------------------
+ */
+
+ // Store the default collation number
+ store_compressed_length(buf, default_collation);
+
+ for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
+ {
+ if (include_type(binlog_type_info_array, m_table->field[i]))
+ {
+ CHARSET_INFO *cs= binlog_type_info_array[i].m_cs;
+ DBUG_ASSERT(cs);
+ if (cs->number != default_collation)
+ {
+ store_compressed_length(buf, char_column_index);
+ store_compressed_length(buf, cs->number);
+ }
+ char_column_index++;
+ }
+ }
+ return write_tlv_field(m_metadata_buf, default_charset_type, buf);
+ }
+}
+
+bool Table_map_log_event::init_column_name_field()
+{
+ StringBuffer<2048> buf;
+
+ for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
+ {
+ size_t len= m_table->field[i]->field_name.length;
+
+ store_compressed_length(buf, len);
+ buf.append(m_table->field[i]->field_name.str, len);
+ }
+ return write_tlv_field(m_metadata_buf, COLUMN_NAME, buf);
+}
+
+bool Table_map_log_event::init_set_str_value_field()
+{
+ StringBuffer<1024> buf;
+ TYPELIB *typelib;
+
+ /*
+ SET string values are stored in the same format:
+ ----------------------------------------------
+ | Value number | value1 len | value 1| .... | // first SET column
+ ----------------------------------------------
+ | Value number | value1 len | value 1| .... | // second SET column
+ ----------------------------------------------
+ */
+ for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
+ {
+ if ((typelib= binlog_type_info_array[i].m_set_typelib))
+ {
+ store_compressed_length(buf, typelib->count);
+ for (unsigned int i= 0; i < typelib->count; i++)
+ {
+ store_compressed_length(buf, typelib->type_lengths[i]);
+ buf.append(typelib->type_names[i], typelib->type_lengths[i]);
+ }
+ }
+ }
+ if (buf.length() > 0)
+ return write_tlv_field(m_metadata_buf, SET_STR_VALUE, buf);
+ return false;
+}
+
+bool Table_map_log_event::init_enum_str_value_field()
+{
+ StringBuffer<1024> buf;
+ TYPELIB *typelib;
+
+ /* ENUM is same to SET columns, see comment in init_set_str_value_field */
+ for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
+ {
+ if ((typelib= binlog_type_info_array[i].m_enum_typelib))
+ {
+ store_compressed_length(buf, typelib->count);
+ for (unsigned int i= 0; i < typelib->count; i++)
+ {
+ store_compressed_length(buf, typelib->type_lengths[i]);
+ buf.append(typelib->type_names[i], typelib->type_lengths[i]);
+ }
+ }
+ }
+
+ if (buf.length() > 0)
+ return write_tlv_field(m_metadata_buf, ENUM_STR_VALUE, buf);
+ return false;
+}
+
+bool Table_map_log_event::init_geometry_type_field()
+{
+ StringBuffer<256> buf;
+ uint geom_type;
+
+ /* Geometry type of geometry columns is stored one by one as packed length */
+ for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
+ {
+ if (binlog_type_info_array[i].m_type_code == MYSQL_TYPE_GEOMETRY)
+ {
+ geom_type= binlog_type_info_array[i].m_geom_type;
+ DBUG_EXECUTE_IF("inject_invalid_geometry_type", geom_type= 100;);
+ store_compressed_length(buf, geom_type);
+ }
+ }
+
+ if (buf.length() > 0)
+ return write_tlv_field(m_metadata_buf, GEOMETRY_TYPE, buf);
+ return false;
+}
+
+bool Table_map_log_event::init_primary_key_field()
+{
+ DBUG_EXECUTE_IF("simulate_init_primary_key_field_error", return true;);
+
+ if (unlikely(m_table->s->primary_key == MAX_KEY))
+ return false;
+
+ // If any key column uses prefix like KEY(c1(10)) */
+ bool has_prefix= false;
+ KEY *pk= m_table->key_info + m_table->s->primary_key;
+
+ DBUG_ASSERT(pk->user_defined_key_parts > 0);
+
+ /* Check if any key column uses prefix */
+ for (uint i= 0; i < pk->user_defined_key_parts; i++)
+ {
+ KEY_PART_INFO *key_part= pk->key_part+i;
+ if (key_part->length != m_table->field[key_part->fieldnr-1]->key_length())
+ {
+ has_prefix= true;
+ break;
+ }
+ }
+
+ StringBuffer<128> buf;
+
+ if (!has_prefix)
+ {
+ /* Index of PK columns are stored one by one. */
+ for (uint i= 0; i < pk->user_defined_key_parts; i++)
+ {
+ KEY_PART_INFO *key_part= pk->key_part+i;
+ store_compressed_length(buf, key_part->fieldnr-1);
+ }
+ return write_tlv_field(m_metadata_buf, SIMPLE_PRIMARY_KEY, buf);
+ }
+ else
+ {
+ /* Index of PK columns are stored with a prefix length one by one. */
+ for (uint i= 0; i < pk->user_defined_key_parts; i++)
+ {
+ KEY_PART_INFO *key_part= pk->key_part+i;
+ size_t prefix= 0;
+
+ store_compressed_length(buf, key_part->fieldnr-1);
+
+ // Store character length but not octet length
+ if (key_part->length != m_table->field[key_part->fieldnr-1]->key_length())
+ prefix= key_part->length / key_part->field->charset()->mbmaxlen;
+ store_compressed_length(buf, prefix);
+ }
+ return write_tlv_field(m_metadata_buf, PRIMARY_KEY_WITH_PREFIX, buf);
+ }
+}
+
+#if defined(HAVE_REPLICATION)
+/*
+ Print some useful information for the SHOW BINARY LOG information
+ field.
+ */
+
+void Table_map_log_event::pack_info(Protocol *protocol)
+{
+ char buf[256];
+ size_t bytes= my_snprintf(buf, sizeof(buf),
+ "table_id: %llu (%s.%s)",
+ m_table_id, m_dbnam, m_tblnam);
+ protocol->store(buf, bytes, &my_charset_bin);
+}
+#endif
+
+
+/**************************************************************************
+ Write_rows_log_event member functions
+**************************************************************************/
+
+/*
+ Constructor used to build an event for writing to the binary log.
+ */
+Write_rows_log_event::Write_rows_log_event(THD *thd_arg, TABLE *tbl_arg,
+ ulong tid_arg,
+ bool is_transactional)
+ :Rows_log_event(thd_arg, tbl_arg, tid_arg, tbl_arg->rpl_write_set,
+ is_transactional, WRITE_ROWS_EVENT_V1)
+{
+}
+
+Write_rows_compressed_log_event::Write_rows_compressed_log_event(
+ THD *thd_arg,
+ TABLE *tbl_arg,
+ ulong tid_arg,
+ bool is_transactional)
+ : Write_rows_log_event(thd_arg, tbl_arg, tid_arg, is_transactional)
+{
+ m_type = WRITE_ROWS_COMPRESSED_EVENT_V1;
+}
+
+bool Write_rows_compressed_log_event::write()
+{
+ return Rows_log_event::write_compressed();
+}
+
+
+#if defined(HAVE_REPLICATION)
+int
+Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability *const)
+{
+ int error= 0;
+
+ /*
+ Increment the global status insert count variable
+ */
+ if (get_flags(STMT_END_F))
+ status_var_increment(thd->status_var.com_stat[SQLCOM_INSERT]);
+
+ /**
+ todo: to introduce a property for the event (handler?) which forces
+ applying the event in the replace (idempotent) fashion.
+ */
+ if (slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT)
+ {
+ /*
+ We are using REPLACE semantics and not INSERT IGNORE semantics
+ when writing rows, that is: new rows replace old rows. We need to
+ inform the storage engine that it should use this behaviour.
+ */
+
+ /* Tell the storage engine that we are using REPLACE semantics. */
+ thd->lex->duplicates= DUP_REPLACE;
+
+ /*
+ Pretend we're executing a REPLACE command: this is needed for
+ InnoDB since it is not (properly) checking the lex->duplicates flag.
+ */
+ thd->lex->sql_command= SQLCOM_REPLACE;
+ /*
+ Do not raise the error flag in case of hitting to an unique attribute
+ */
+ m_table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
+ /*
+ The following is needed in case if we have AFTER DELETE triggers.
+ */
+ m_table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
+ m_table->file->extra(HA_EXTRA_IGNORE_NO_KEY);
+ }
+ if (m_table->triggers && do_invoke_trigger())
+ m_table->prepare_triggers_for_insert_stmt_or_event();
+
+ /* Honor next number column if present */
+ m_table->next_number_field= m_table->found_next_number_field;
+ /*
+ * Fixed Bug#45999, In RBR, Store engine of Slave auto-generates new
+ * sequence numbers for auto_increment fields if the values of them are 0.
+ * If generateing a sequence number is decided by the values of
+ * table->auto_increment_field_not_null and SQL_MODE(if includes
+ * MODE_NO_AUTO_VALUE_ON_ZERO) in update_auto_increment function.
+ * SQL_MODE of slave sql thread is always consistency with master's.
+ * In RBR, auto_increment fields never are NULL, except if the auto_inc
+ * column exists only on the slave side (i.e., in an extra column
+ * on the slave's table).
+ */
+ if (!is_auto_inc_in_extra_columns())
+ m_table->auto_increment_field_not_null= TRUE;
+ else
+ {
+ /*
+ Here we have checked that there is an extra field
+ on this server's table that has an auto_inc column.
+
+ Mark that the auto_increment field is null and mark
+ the read and write set bits.
+
+ (There can only be one AUTO_INC column, it is always
+ indexed and it cannot have a DEFAULT value).
+ */
+ m_table->auto_increment_field_not_null= FALSE;
+ m_table->mark_auto_increment_column();
+ }
+
+ return error;
+}
+
+int
+Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability *const,
+ int error)
+{
+ int local_error= 0;
+
+ /**
+ Clear the write_set bit for auto_inc field that only
+ existed on the destination table as an extra column.
+ */
+ if (is_auto_inc_in_extra_columns())
+ {
+ bitmap_clear_bit(m_table->rpl_write_set,
+ m_table->next_number_field->field_index);
+ bitmap_clear_bit(m_table->read_set,
+ m_table->next_number_field->field_index);
+
+ if (get_flags(STMT_END_F))
+ m_table->file->ha_release_auto_increment();
+ }
+ m_table->next_number_field=0;
+ m_table->auto_increment_field_not_null= FALSE;
+ if (slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT)
+ {
+ m_table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
+ m_table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
+ /*
+ resetting the extra with
+ table->file->extra(HA_EXTRA_NO_IGNORE_NO_KEY);
+ fires bug#27077
+ explanation: file->reset() performs this duty
+ ultimately. Still todo: fix
+ */
+ }
+ if (unlikely((local_error= m_table->file->ha_end_bulk_insert())))
+ {
+ m_table->file->print_error(local_error, MYF(0));
+ }
+ return error? error : local_error;
+}
+
+bool Rows_log_event::process_triggers(trg_event_type event,
+ trg_action_time_type time_type,
+ bool old_row_is_record1)
+{
+ bool result;
+ DBUG_ENTER("Rows_log_event::process_triggers");
+ m_table->triggers->mark_fields_used(event);
+ if (slave_run_triggers_for_rbr == SLAVE_RUN_TRIGGERS_FOR_RBR_YES)
+ {
+ tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */
+ result= m_table->triggers->process_triggers(thd, event,
+ time_type, old_row_is_record1);
+ reenable_binlog(thd);
+ }
+ else
+ result= m_table->triggers->process_triggers(thd, event,
+ time_type, old_row_is_record1);
+
+ DBUG_RETURN(result);
+}
+/*
+ Check if there are more UNIQUE keys after the given key.
+*/
+static int
+last_uniq_key(TABLE *table, uint keyno)
+{
+ while (++keyno < table->s->keys)
+ if (table->key_info[keyno].flags & HA_NOSAME)
+ return 0;
+ return 1;
+}
+
+/**
+ Check if an error is a duplicate key error.
+
+ This function is used to check if an error code is one of the
+ duplicate key error, i.e., and error code for which it is sensible
+ to do a <code>get_dup_key()</code> to retrieve the duplicate key.
+
+ @param errcode The error code to check.
+
+ @return <code>true</code> if the error code is such that
+ <code>get_dup_key()</code> will return true, <code>false</code>
+ otherwise.
+ */
+bool
+is_duplicate_key_error(int errcode)
+{
+ switch (errcode)
+ {
+ case HA_ERR_FOUND_DUPP_KEY:
+ case HA_ERR_FOUND_DUPP_UNIQUE:
+ return true;
+ }
+ return false;
+}
+
+/**
+ Write the current row into event's table.
+
+ The row is located in the row buffer, pointed by @c m_curr_row member.
+ Number of columns of the row is stored in @c m_width member (it can be
+ different from the number of columns in the table to which we insert).
+ Bitmap @c m_cols indicates which columns are present in the row. It is assumed
+ that event's table is already open and pointed by @c m_table.
+
+ If the same record already exists in the table it can be either overwritten
+ or an error is reported depending on the value of @c overwrite flag
+ (error reporting not yet implemented). Note that the matching record can be
+ different from the row we insert if we use primary keys to identify records in
+ the table.
+
+ The row to be inserted can contain values only for selected columns. The
+ missing columns are filled with default values using @c prepare_record()
+ function. If a matching record is found in the table and @c overwritte is
+ true, the missing columns are taken from it.
+
+ @param rli Relay log info (needed for row unpacking).
+ @param overwrite
+ Shall we overwrite if the row already exists or signal
+ error (currently ignored).
+
+ @returns Error code on failure, 0 on success.
+
+ This method, if successful, sets @c m_curr_row_end pointer to point at the
+ next row in the rows buffer. This is done when unpacking the row to be
+ inserted.
+
+ @note If a matching record is found, it is either updated using
+ @c ha_update_row() or first deleted and then new record written.
+*/
+
+int
+Rows_log_event::write_row(rpl_group_info *rgi,
+ const bool overwrite)
+{
+ DBUG_ENTER("write_row");
+ DBUG_ASSERT(m_table != NULL && thd != NULL);
+
+ TABLE *table= m_table; // pointer to event's table
+ int error;
+ int UNINIT_VAR(keynum);
+ const bool invoke_triggers= (m_table->triggers && do_invoke_trigger());
+ auto_afree_ptr<char> key(NULL);
+
+ prepare_record(table, m_width, true);
+
+ /* unpack row into table->record[0] */
+ if (unlikely((error= unpack_current_row(rgi))))
+ {
+ table->file->print_error(error, MYF(0));
+ DBUG_RETURN(error);
+ }
+
+ if (m_curr_row == m_rows_buf && !invoke_triggers)
+ {
+ /*
+ This table has no triggers so we can do bulk insert.
+
+ This is the first row to be inserted, we estimate the rows with
+ the size of the first row and use that value to initialize
+ storage engine for bulk insertion.
+ */
+ /* this is the first row to be inserted, we estimate the rows with
+ the size of the first row and use that value to initialize
+ storage engine for bulk insertion */
+ DBUG_ASSERT(!(m_curr_row > m_curr_row_end));
+ ha_rows estimated_rows= 0;
+ if (m_curr_row < m_curr_row_end)
+ estimated_rows= (m_rows_end - m_curr_row) / (m_curr_row_end - m_curr_row);
+ else if (m_curr_row == m_curr_row_end)
+ estimated_rows= 1;
+
+ table->file->ha_start_bulk_insert(estimated_rows);
+ }
+
+ /*
+ Explicitly set the auto_inc to null to make sure that
+ it gets an auto_generated value.
+ */
+ if (is_auto_inc_in_extra_columns())
+ m_table->next_number_field->set_null();
+
+ DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
+ DBUG_PRINT_BITSET("debug", "rpl_write_set: %s", table->rpl_write_set);
+ DBUG_PRINT_BITSET("debug", "read_set: %s", table->read_set);
+
+ if (invoke_triggers &&
+ unlikely(process_triggers(TRG_EVENT_INSERT, TRG_ACTION_BEFORE, TRUE)))
+ {
+ DBUG_RETURN(HA_ERR_GENERIC); // in case if error is not set yet
+ }
+
+ // Handle INSERT.
+ if (table->versioned(VERS_TIMESTAMP))
+ {
+ ulong sec_part;
+ bitmap_set_bit(table->read_set, table->vers_start_field()->field_index);
+ table->file->column_bitmaps_signal();
+ // Check whether a row came from unversioned table and fix vers fields.
+ if (table->vers_start_field()->get_timestamp(&sec_part) == 0 && sec_part == 0)
+ table->vers_update_fields();
+ }
+
+ /*
+ Try to write record. If a corresponding record already exists in the table,
+ we try to change it using ha_update_row() if possible. Otherwise we delete
+ it and repeat the whole process again.
+
+ TODO: Add safety measures against infinite looping.
+ */
+
+ if (table->s->sequence)
+ error= update_sequence();
+ else while (unlikely(error= table->file->ha_write_row(table->record[0])))
+ {
+ if (error == HA_ERR_LOCK_DEADLOCK ||
+ error == HA_ERR_LOCK_WAIT_TIMEOUT ||
+ (keynum= table->file->get_dup_key(error)) < 0 ||
+ !overwrite)
+ {
+ DBUG_PRINT("info",("get_dup_key returns %d)", keynum));
+ /*
+ Deadlock, waiting for lock or just an error from the handler
+ such as HA_ERR_FOUND_DUPP_KEY when overwrite is false.
+ Retrieval of the duplicate key number may fail
+ - either because the error was not "duplicate key" error
+ - or because the information which key is not available
+ */
+ table->file->print_error(error, MYF(0));
+ DBUG_RETURN(error);
+ }
+ /*
+ We need to retrieve the old row into record[1] to be able to
+ either update or delete the offending record. We either:
+
+ - use rnd_pos() with a row-id (available as dupp_row) to the
+ offending row, if that is possible (MyISAM and Blackhole), or else
+
+ - use index_read_idx() with the key that is duplicated, to
+ retrieve the offending row.
+ */
+ if (table->file->ha_table_flags() & HA_DUPLICATE_POS)
+ {
+ DBUG_PRINT("info",("Locating offending record using rnd_pos()"));
+
+ if ((error= table->file->ha_rnd_init_with_error(0)))
+ {
+ DBUG_RETURN(error);
+ }
+
+ error= table->file->ha_rnd_pos(table->record[1], table->file->dup_ref);
+ if (unlikely(error))
+ {
+ DBUG_PRINT("info",("rnd_pos() returns error %d",error));
+ table->file->print_error(error, MYF(0));
+ DBUG_RETURN(error);
+ }
+ table->file->ha_rnd_end();
+ }
+ else
+ {
+ DBUG_PRINT("info",("Locating offending record using index_read_idx()"));
+
+ if (table->file->extra(HA_EXTRA_FLUSH_CACHE))
+ {
+ DBUG_PRINT("info",("Error when setting HA_EXTRA_FLUSH_CACHE"));
+ DBUG_RETURN(my_errno);
+ }
+
+ if (key.get() == NULL)
+ {
+ key.assign(static_cast<char*>(my_alloca(table->s->max_unique_length)));
+ if (key.get() == NULL)
+ {
+ DBUG_PRINT("info",("Can't allocate key buffer"));
+ DBUG_RETURN(ENOMEM);
+ }
+ }
+
+ key_copy((uchar*)key.get(), table->record[0], table->key_info + keynum,
+ 0);
+ error= table->file->ha_index_read_idx_map(table->record[1], keynum,
+ (const uchar*)key.get(),
+ HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT);
+ if (unlikely(error))
+ {
+ DBUG_PRINT("info",("index_read_idx() returns %s", HA_ERR(error)));
+ table->file->print_error(error, MYF(0));
+ DBUG_RETURN(error);
+ }
+ }
+
+ /*
+ Now, record[1] should contain the offending row. That
+ will enable us to update it or, alternatively, delete it (so
+ that we can insert the new row afterwards).
+ */
+
+ /*
+ If row is incomplete we will use the record found to fill
+ missing columns.
+ */
+ if (!get_flags(COMPLETE_ROWS_F))
+ {
+ restore_record(table,record[1]);
+ error= unpack_current_row(rgi);
+ }
+
+ DBUG_PRINT("debug",("preparing for update: before and after image"));
+ DBUG_DUMP("record[1] (before)", table->record[1], table->s->reclength);
+ DBUG_DUMP("record[0] (after)", table->record[0], table->s->reclength);
+
+ /*
+ REPLACE is defined as either INSERT or DELETE + INSERT. If
+ possible, we can replace it with an UPDATE, but that will not
+ work on InnoDB if FOREIGN KEY checks are necessary.
+
+ I (Matz) am not sure of the reason for the last_uniq_key()
+ check as, but I'm guessing that it's something along the
+ following lines.
+
+ Suppose that we got the duplicate key to be a key that is not
+ the last unique key for the table and we perform an update:
+ then there might be another key for which the unique check will
+ fail, so we're better off just deleting the row and inserting
+ the correct row.
+
+ Additionally we don't use UPDATE if rbr triggers should be invoked -
+ when triggers are used we want a simple and predictable execution path.
+ */
+ if (last_uniq_key(table, keynum) && !invoke_triggers &&
+ !table->file->referenced_by_foreign_key())
+ {
+ DBUG_PRINT("info",("Updating row using ha_update_row()"));
+ error= table->file->ha_update_row(table->record[1],
+ table->record[0]);
+ switch (error) {
+
+ case HA_ERR_RECORD_IS_THE_SAME:
+ DBUG_PRINT("info",("ignoring HA_ERR_RECORD_IS_THE_SAME error from"
+ " ha_update_row()"));
+ error= 0;
+
+ case 0:
+ break;
+
+ default:
+ DBUG_PRINT("info",("ha_update_row() returns error %d",error));
+ table->file->print_error(error, MYF(0));
+ }
+
+ DBUG_RETURN(error);
+ }
+ else
+ {
+ DBUG_PRINT("info",("Deleting offending row and trying to write new one again"));
+ if (invoke_triggers &&
+ unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE,
+ TRUE)))
+ error= HA_ERR_GENERIC; // in case if error is not set yet
+ else
+ {
+ if (unlikely((error= table->file->ha_delete_row(table->record[1]))))
+ {
+ DBUG_PRINT("info",("ha_delete_row() returns error %d",error));
+ table->file->print_error(error, MYF(0));
+ DBUG_RETURN(error);
+ }
+ if (invoke_triggers &&
+ unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_AFTER,
+ TRUE)))
+ DBUG_RETURN(HA_ERR_GENERIC); // in case if error is not set yet
+ }
+ /* Will retry ha_write_row() with the offending row removed. */
+ }
+ }
+
+ if (invoke_triggers &&
+ unlikely(process_triggers(TRG_EVENT_INSERT, TRG_ACTION_AFTER, TRUE)))
+ error= HA_ERR_GENERIC; // in case if error is not set yet
+
+ DBUG_RETURN(error);
+}
+
+
+int Rows_log_event::update_sequence()
+{
+ TABLE *table= m_table; // pointer to event's table
+
+ if (!bitmap_is_set(table->rpl_write_set, MIN_VALUE_FIELD_NO))
+ {
+ /* This event come from a setval function executed on the master.
+ Update the sequence next_number and round, like we do with setval()
+ */
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
+ table->read_set);
+ longlong nextval= table->field[NEXT_FIELD_NO]->val_int();
+ longlong round= table->field[ROUND_FIELD_NO]->val_int();
+ dbug_tmp_restore_column_map(table->read_set, old_map);
+
+ return table->s->sequence->set_value(table, nextval, round, 0) > 0;
+ }
+
+ /*
+ Update all fields in table and update the active sequence, like with
+ ALTER SEQUENCE
+ */
+ return table->file->ha_write_row(table->record[0]);
+}
+
+
+#endif
+
+
+#if defined(HAVE_REPLICATION)
+
+int
+Write_rows_log_event::do_exec_row(rpl_group_info *rgi)
+{
+ DBUG_ASSERT(m_table != NULL);
+ const char *tmp= thd->get_proc_info();
+ const char *message= "Write_rows_log_event::write_row()";
+ int error;
+
+#ifdef WSREP_PROC_INFO
+ my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "Write_rows_log_event::write_row(%lld)",
+ (long long) wsrep_thd_trx_seqno(thd));
+ message= thd->wsrep_info;
+#endif /* WSREP_PROC_INFO */
+
+ thd_proc_info(thd, message);
+ error= write_row(rgi, slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT);
+ thd_proc_info(thd, tmp);
+
+ if (unlikely(error) && unlikely(!thd->is_error()))
+ {
+ DBUG_ASSERT(0);
+ my_error(ER_UNKNOWN_ERROR, MYF(0));
+ }
+
+ return error;
+}
+
+#endif /* defined(HAVE_REPLICATION) */
+
+
+#if defined(HAVE_REPLICATION)
+uint8 Write_rows_log_event::get_trg_event_map()
+{
+ return trg2bit(TRG_EVENT_INSERT) | trg2bit(TRG_EVENT_UPDATE) |
+ trg2bit(TRG_EVENT_DELETE);
+}
+#endif
+
+/**************************************************************************
+ Delete_rows_log_event member functions
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+/*
+ Compares table->record[0] and table->record[1]
+
+ Returns TRUE if different.
+*/
+static bool record_compare(TABLE *table)
+{
+ bool result= FALSE;
+ /**
+ Compare full record only if:
+ - there are no blob fields (otherwise we would also need
+ to compare blobs contents as well);
+ - there are no varchar fields (otherwise we would also need
+ to compare varchar contents as well);
+ - there are no null fields, otherwise NULLed fields
+ contents (i.e., the don't care bytes) may show arbitrary
+ values, depending on how each engine handles internally.
+ */
+ if ((table->s->blob_fields +
+ table->s->varchar_fields +
+ table->s->null_fields) == 0)
+ {
+ result= cmp_record(table,record[1]);
+ goto record_compare_exit;
+ }
+
+ /* Compare null bits */
+ if (memcmp(table->null_flags,
+ table->null_flags+table->s->rec_buff_length,
+ table->s->null_bytes))
+ {
+ result= TRUE; // Diff in NULL value
+ goto record_compare_exit;
+ }
+
+ /* Compare fields */
+ for (Field **ptr=table->field ; *ptr ; ptr++)
+ {
+ if (table->versioned() && (*ptr)->vers_sys_field())
+ {
+ continue;
+ }
+ /**
+ We only compare field contents that are not null.
+ NULL fields (i.e., their null bits) were compared
+ earlier.
+ */
+ if (!(*(ptr))->is_null())
+ {
+ if ((*ptr)->cmp_binary_offset(table->s->rec_buff_length))
+ {
+ result= TRUE;
+ goto record_compare_exit;
+ }
+ }
+ }
+
+record_compare_exit:
+ return result;
+}
+
+
+/**
+ Find the best key to use when locating the row in @c find_row().
+
+ A primary key is preferred if it exists; otherwise a unique index is
+ preferred. Else we pick the index with the smalles rec_per_key value.
+
+ If a suitable key is found, set @c m_key, @c m_key_nr and @c m_key_info
+ member fields appropriately.
+
+ @returns Error code on failure, 0 on success.
+*/
+int Rows_log_event::find_key()
+{
+ uint i, best_key_nr, last_part;
+ KEY *key, *UNINIT_VAR(best_key);
+ ulong UNINIT_VAR(best_rec_per_key), tmp;
+ DBUG_ENTER("Rows_log_event::find_key");
+ DBUG_ASSERT(m_table);
+
+ best_key_nr= MAX_KEY;
+
+ /*
+ Keys are sorted so that any primary key is first, followed by unique keys,
+ followed by any other. So we will automatically pick the primary key if
+ it exists.
+ */
+ for (i= 0, key= m_table->key_info; i < m_table->s->keys; i++, key++)
+ {
+ if (!m_table->s->keys_in_use.is_set(i))
+ continue;
+ /*
+ We cannot use a unique key with NULL-able columns to uniquely identify
+ a row (but we can still select it for range scan below if nothing better
+ is available).
+ */
+ if ((key->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
+ {
+ best_key_nr= i;
+ best_key= key;
+ break;
+ }
+ /*
+ We can only use a non-unique key if it allows range scans (ie. skip
+ FULLTEXT indexes and such).
+ */
+ last_part= key->user_defined_key_parts - 1;
+ DBUG_PRINT("info", ("Index %s rec_per_key[%u]= %lu",
+ key->name.str, last_part, key->rec_per_key[last_part]));
+ if (!(m_table->file->index_flags(i, last_part, 1) & HA_READ_NEXT))
+ continue;
+
+ tmp= key->rec_per_key[last_part];
+ if (best_key_nr == MAX_KEY || (tmp > 0 && tmp < best_rec_per_key))
+ {
+ best_key_nr= i;
+ best_key= key;
+ best_rec_per_key= tmp;
+ }
+ }
+
+ if (best_key_nr == MAX_KEY)
+ {
+ m_key_info= NULL;
+ DBUG_RETURN(0);
+ }
+
+ // Allocate buffer for key searches
+ m_key= (uchar *) my_malloc(PSI_INSTRUMENT_ME, best_key->key_length, MYF(MY_WME));
+ if (m_key == NULL)
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ m_key_info= best_key;
+ m_key_nr= best_key_nr;
+
+ DBUG_RETURN(0);;
+}
+
+
+/*
+ Check if we are already spending too much time on this statement.
+ if we are, warn user that it might be because table does not have
+ a PK, but only if the warning was not printed before for this STMT.
+
+ @param type The event type code.
+ @param table_name The name of the table that the slave is
+ operating.
+ @param is_index_scan States whether the slave is doing an index scan
+ or not.
+ @param rli The relay metadata info.
+*/
+static inline
+void issue_long_find_row_warning(Log_event_type type,
+ const char *table_name,
+ bool is_index_scan,
+ rpl_group_info *rgi)
+{
+ if ((global_system_variables.log_warnings > 1 &&
+ !rgi->is_long_find_row_note_printed()))
+ {
+ ulonglong now= microsecond_interval_timer();
+ ulonglong stmt_ts= rgi->get_row_stmt_start_timestamp();
+
+ DBUG_EXECUTE_IF("inject_long_find_row_note",
+ stmt_ts-=(LONG_FIND_ROW_THRESHOLD*2*HRTIME_RESOLUTION););
+
+ longlong delta= (now - stmt_ts)/HRTIME_RESOLUTION;
+
+ if (delta > LONG_FIND_ROW_THRESHOLD)
+ {
+ rgi->set_long_find_row_note_printed();
+ const char* evt_type= LOG_EVENT_IS_DELETE_ROW(type) ? " DELETE" : "n UPDATE";
+ const char* scan_type= is_index_scan ? "scanning an index" : "scanning the table";
+
+ sql_print_information("The slave is applying a ROW event on behalf of a%s statement "
+ "on table %s and is currently taking a considerable amount "
+ "of time (%lld seconds). This is due to the fact that it is %s "
+ "while looking up records to be processed. Consider adding a "
+ "primary key (or unique key) to the table to improve "
+ "performance.",
+ evt_type, table_name, (long) delta, scan_type);
+ }
+ }
+}
+
+
+/*
+ HA_ERR_KEY_NOT_FOUND is a fatal error normally, but it's an expected
+ error in speculate optimistic mode, so use something non-fatal instead
+*/
+static int row_not_found_error(rpl_group_info *rgi)
+{
+ return rgi->speculation != rpl_group_info::SPECULATE_OPTIMISTIC
+ ? HA_ERR_KEY_NOT_FOUND : HA_ERR_RECORD_CHANGED;
+}
+
+/**
+ Locate the current row in event's table.
+
+ The current row is pointed by @c m_curr_row. Member @c m_width tells
+ how many columns are there in the row (this can be differnet from
+ the number of columns in the table). It is assumed that event's
+ table is already open and pointed by @c m_table.
+
+ If a corresponding record is found in the table it is stored in
+ @c m_table->record[0]. Note that when record is located based on a primary
+ key, it is possible that the record found differs from the row being located.
+
+ If no key is specified or table does not have keys, a table scan is used to
+ find the row. In that case the row should be complete and contain values for
+ all columns. However, it can still be shorter than the table, i.e. the table
+ can contain extra columns not present in the row. It is also possible that
+ the table has fewer columns than the row being located.
+
+ @returns Error code on failure, 0 on success.
+
+ @post In case of success @c m_table->record[0] contains the record found.
+ Also, the internal "cursor" of the table is positioned at the record found.
+
+ @note If the engine allows random access of the records, a combination of
+ @c position() and @c rnd_pos() will be used.
+
+ Note that one MUST call ha_index_or_rnd_end() after this function if
+ it returns 0 as we must leave the row position in the handler intact
+ for any following update/delete command.
+*/
+
+int Rows_log_event::find_row(rpl_group_info *rgi)
+{
+ DBUG_ENTER("Rows_log_event::find_row");
+
+ DBUG_ASSERT(m_table && m_table->in_use != NULL);
+
+ TABLE *table= m_table;
+ int error= 0;
+ bool is_table_scan= false, is_index_scan= false;
+
+ /*
+ rpl_row_tabledefs.test specifies that
+ if the extra field on the slave does not have a default value
+ and this is okay with Delete or Update events.
+ Todo: fix wl3228 hld that requires defauls for all types of events
+ */
+
+ prepare_record(table, m_width, FALSE);
+ error= unpack_current_row(rgi);
+
+ m_vers_from_plain= false;
+ if (table->versioned())
+ {
+ Field *row_end= table->vers_end_field();
+ DBUG_ASSERT(table->read_set);
+ bitmap_set_bit(table->read_set, row_end->field_index);
+ // check whether master table is unversioned
+ if (row_end->val_int() == 0)
+ {
+ bitmap_set_bit(table->write_set, row_end->field_index);
+ // Plain source table may have a PRIMARY KEY. And row_end is always
+ // a part of PRIMARY KEY. Set it to max value for engine to find it in
+ // index. Needed for an UPDATE/DELETE cases.
+ table->vers_end_field()->set_max();
+ m_vers_from_plain= true;
+ }
+ table->file->column_bitmaps_signal();
+ }
+
+ DBUG_PRINT("info",("looking for the following record"));
+ DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
+
+ if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION) &&
+ table->s->primary_key < MAX_KEY)
+ {
+ /*
+ Use a more efficient method to fetch the record given by
+ table->record[0] if the engine allows it. We first compute a
+ row reference using the position() member function (it will be
+ stored in table->file->ref) and the use rnd_pos() to position
+ the "cursor" (i.e., record[0] in this case) at the correct row.
+
+ TODO: Add a check that the correct record has been fetched by
+ comparing with the original record. Take into account that the
+ record on the master and slave can be of different
+ length. Something along these lines should work:
+
+ ADD>>> store_record(table,record[1]);
+ int error= table->file->ha_rnd_pos(table->record[0],
+ table->file->ref);
+ ADD>>> DBUG_ASSERT(memcmp(table->record[1], table->record[0],
+ table->s->reclength) == 0);
+
+ */
+ int error;
+ DBUG_PRINT("info",("locating record using primary key (position)"));
+
+ error= table->file->ha_rnd_pos_by_record(table->record[0]);
+ if (unlikely(error))
+ {
+ DBUG_PRINT("info",("rnd_pos returns error %d",error));
+ if (error == HA_ERR_KEY_NOT_FOUND)
+ error= row_not_found_error(rgi);
+ table->file->print_error(error, MYF(0));
+ }
+ DBUG_RETURN(error);
+ }
+
+ // We can't use position() - try other methods.
+
+ /*
+ We need to retrieve all fields
+ TODO: Move this out from this function to main loop
+ */
+ table->use_all_columns();
+
+ /*
+ Save copy of the record in table->record[1]. It might be needed
+ later if linear search is used to find exact match.
+ */
+ store_record(table,record[1]);
+
+ if (m_key_info)
+ {
+ DBUG_PRINT("info",("locating record using key #%u [%s] (index_read)",
+ m_key_nr, m_key_info->name.str));
+ /* We use this to test that the correct key is used in test cases. */
+ DBUG_EXECUTE_IF("slave_crash_if_wrong_index",
+ if(0 != strcmp(m_key_info->name.str,"expected_key")) abort(););
+
+ /* The key is active: search the table using the index */
+ if (!table->file->inited &&
+ (error= table->file->ha_index_init(m_key_nr, FALSE)))
+ {
+ DBUG_PRINT("info",("ha_index_init returns error %d",error));
+ table->file->print_error(error, MYF(0));
+ goto end;
+ }
+
+ /* Fill key data for the row */
+
+ DBUG_ASSERT(m_key);
+ key_copy(m_key, table->record[0], m_key_info, 0);
+
+ /*
+ Don't print debug messages when running valgrind since they can
+ trigger false warnings.
+ */
+#ifndef HAVE_valgrind
+ DBUG_DUMP("key data", m_key, m_key_info->key_length);
+#endif
+
+ /*
+ We need to set the null bytes to ensure that the filler bit are
+ all set when returning. There are storage engines that just set
+ the necessary bits on the bytes and don't set the filler bits
+ correctly.
+ */
+ if (table->s->null_bytes > 0)
+ table->record[0][table->s->null_bytes - 1]|=
+ 256U - (1U << table->s->last_null_bit_pos);
+
+ if (unlikely((error= table->file->ha_index_read_map(table->record[0],
+ m_key,
+ HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))))
+ {
+ DBUG_PRINT("info",("no record matching the key found in the table"));
+ if (error == HA_ERR_KEY_NOT_FOUND)
+ error= row_not_found_error(rgi);
+ table->file->print_error(error, MYF(0));
+ table->file->ha_index_end();
+ goto end;
+ }
+
+ /*
+ Don't print debug messages when running valgrind since they can
+ trigger false warnings.
+ */
+#ifndef HAVE_valgrind
+ DBUG_PRINT("info",("found first matching record"));
+ DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
+#endif
+ /*
+ Below is a minor "optimization". If the key (i.e., key number
+ 0) has the HA_NOSAME flag set, we know that we have found the
+ correct record (since there can be no duplicates); otherwise, we
+ have to compare the record with the one found to see if it is
+ the correct one.
+
+ CAVEAT! This behaviour is essential for the replication of,
+ e.g., the mysql.proc table since the correct record *shall* be
+ found using the primary key *only*. There shall be no
+ comparison of non-PK columns to decide if the correct record is
+ found. I can see no scenario where it would be incorrect to
+ chose the row to change only using a PK or an UNNI.
+ */
+ if (table->key_info->flags & HA_NOSAME)
+ {
+ /* Unique does not have non nullable part */
+ if (!(table->key_info->flags & (HA_NULL_PART_KEY)))
+ {
+ error= 0;
+ goto end;
+ }
+ else
+ {
+ KEY *keyinfo= table->key_info;
+ /*
+ Unique has nullable part. We need to check if there is any
+ field in the BI image that is null and part of UNNI.
+ */
+ bool null_found= FALSE;
+ for (uint i=0; i < keyinfo->user_defined_key_parts && !null_found; i++)
+ {
+ uint fieldnr= keyinfo->key_part[i].fieldnr - 1;
+ Field **f= table->field+fieldnr;
+ null_found= (*f)->is_null();
+ }
+
+ if (!null_found)
+ {
+ error= 0;
+ goto end;
+ }
+
+ /* else fall through to index scan */
+ }
+ }
+
+ is_index_scan=true;
+
+ /*
+ In case key is not unique, we still have to iterate over records found
+ and find the one which is identical to the row given. A copy of the
+ record we are looking for is stored in record[1].
+ */
+ DBUG_PRINT("info",("non-unique index, scanning it to find matching record"));
+ /* We use this to test that the correct key is used in test cases. */
+ DBUG_EXECUTE_IF("slave_crash_if_index_scan", abort(););
+
+ while (record_compare(table))
+ {
+ while ((error= table->file->ha_index_next(table->record[0])))
+ {
+ DBUG_PRINT("info",("no record matching the given row found"));
+ table->file->print_error(error, MYF(0));
+ table->file->ha_index_end();
+ goto end;
+ }
+ }
+ }
+ else
+ {
+ DBUG_PRINT("info",("locating record using table scan (rnd_next)"));
+ /* We use this to test that the correct key is used in test cases. */
+ DBUG_EXECUTE_IF("slave_crash_if_table_scan", abort(););
+
+ /* We don't have a key: search the table using rnd_next() */
+ if (unlikely((error= table->file->ha_rnd_init_with_error(1))))
+ {
+ DBUG_PRINT("info",("error initializing table scan"
+ " (ha_rnd_init returns %d)",error));
+ goto end;
+ }
+
+ is_table_scan= true;
+
+ /* Continue until we find the right record or have made a full loop */
+ do
+ {
+ error= table->file->ha_rnd_next(table->record[0]);
+
+ if (unlikely(error))
+ DBUG_PRINT("info", ("error: %s", HA_ERR(error)));
+ switch (error) {
+
+ case 0:
+ DBUG_DUMP("record found", table->record[0], table->s->reclength);
+ break;
+
+ case HA_ERR_END_OF_FILE:
+ DBUG_PRINT("info", ("Record not found"));
+ table->file->ha_rnd_end();
+ goto end;
+
+ default:
+ DBUG_PRINT("info", ("Failed to get next record"
+ " (rnd_next returns %d)",error));
+ table->file->print_error(error, MYF(0));
+ table->file->ha_rnd_end();
+ goto end;
+ }
+ }
+ while (record_compare(table));
+
+ /*
+ Note: above record_compare will take into accout all record fields
+ which might be incorrect in case a partial row was given in the event
+ */
+
+ DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == 0);
+ }
+
+end:
+ if (is_table_scan || is_index_scan)
+ issue_long_find_row_warning(get_general_type_code(), m_table->alias.c_ptr(),
+ is_index_scan, rgi);
+ table->default_column_bitmaps();
+ DBUG_RETURN(error);
+}
+
+#endif
+
+/*
+ Constructor used to build an event for writing to the binary log.
+ */
+
+Delete_rows_log_event::Delete_rows_log_event(THD *thd_arg, TABLE *tbl_arg,
+ ulong tid, bool is_transactional)
+ : Rows_log_event(thd_arg, tbl_arg, tid, tbl_arg->read_set, is_transactional,
+ DELETE_ROWS_EVENT_V1)
+{
+}
+
+Delete_rows_compressed_log_event::Delete_rows_compressed_log_event(
+ THD *thd_arg, TABLE *tbl_arg,
+ ulong tid_arg,
+ bool is_transactional)
+ : Delete_rows_log_event(thd_arg, tbl_arg, tid_arg, is_transactional)
+{
+ m_type= DELETE_ROWS_COMPRESSED_EVENT_V1;
+}
+
+bool Delete_rows_compressed_log_event::write()
+{
+ return Rows_log_event::write_compressed();
+}
+
+
+#if defined(HAVE_REPLICATION)
+
+int
+Delete_rows_log_event::do_before_row_operations(const Slave_reporting_capability *const)
+{
+ /*
+ Increment the global status delete count variable
+ */
+ if (get_flags(STMT_END_F))
+ status_var_increment(thd->status_var.com_stat[SQLCOM_DELETE]);
+
+ if ((m_table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION) &&
+ m_table->s->primary_key < MAX_KEY)
+ {
+ /*
+ We don't need to allocate any memory for m_key since it is not used.
+ */
+ return 0;
+ }
+ if (do_invoke_trigger())
+ m_table->prepare_triggers_for_delete_stmt_or_event();
+
+ return find_key();
+}
+
+int
+Delete_rows_log_event::do_after_row_operations(const Slave_reporting_capability *const,
+ int error)
+{
+ m_table->file->ha_index_or_rnd_end();
+ my_free(m_key);
+ m_key= NULL;
+ m_key_info= NULL;
+
+ return error;
+}
+
+int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi)
+{
+ int error;
+ const char *tmp= thd->get_proc_info();
+ const char *message= "Delete_rows_log_event::find_row()";
+ const bool invoke_triggers= (m_table->triggers && do_invoke_trigger());
+ DBUG_ASSERT(m_table != NULL);
+
+#ifdef WSREP_PROC_INFO
+ my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "Delete_rows_log_event::find_row(%lld)",
+ (long long) wsrep_thd_trx_seqno(thd));
+ message= thd->wsrep_info;
+#endif /* WSREP_PROC_INFO */
+
+ thd_proc_info(thd, message);
+ if (likely(!(error= find_row(rgi))))
+ {
+ /*
+ Delete the record found, located in record[0]
+ */
+ message= "Delete_rows_log_event::ha_delete_row()";
+#ifdef WSREP_PROC_INFO
+ snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "Delete_rows_log_event::ha_delete_row(%lld)",
+ (long long) wsrep_thd_trx_seqno(thd));
+ message= thd->wsrep_info;
+#endif
+ thd_proc_info(thd, message);
+
+ if (invoke_triggers &&
+ unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE, FALSE)))
+ error= HA_ERR_GENERIC; // in case if error is not set yet
+ if (likely(!error))
+ {
+ m_table->mark_columns_per_binlog_row_image();
+ if (m_vers_from_plain && m_table->versioned(VERS_TIMESTAMP))
+ {
+ Field *end= m_table->vers_end_field();
+ bitmap_set_bit(m_table->write_set, end->field_index);
+ store_record(m_table, record[1]);
+ end->set_time();
+ error= m_table->file->ha_update_row(m_table->record[1],
+ m_table->record[0]);
+ }
+ else
+ {
+ error= m_table->file->ha_delete_row(m_table->record[0]);
+ }
+ m_table->default_column_bitmaps();
+ }
+ if (invoke_triggers && likely(!error) &&
+ unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_AFTER, FALSE)))
+ error= HA_ERR_GENERIC; // in case if error is not set yet
+ m_table->file->ha_index_or_rnd_end();
+ }
+ thd_proc_info(thd, tmp);
+ return error;
+}
+
+#endif /* defined(HAVE_REPLICATION) */
+
+#if defined(HAVE_REPLICATION)
+uint8 Delete_rows_log_event::get_trg_event_map()
+{
+ return trg2bit(TRG_EVENT_DELETE);
+}
+#endif
+
+/**************************************************************************
+ Update_rows_log_event member functions
+**************************************************************************/
+
+/*
+ Constructor used to build an event for writing to the binary log.
+ */
+Update_rows_log_event::Update_rows_log_event(THD *thd_arg, TABLE *tbl_arg,
+ ulong tid,
+ bool is_transactional)
+: Rows_log_event(thd_arg, tbl_arg, tid, tbl_arg->read_set, is_transactional,
+ UPDATE_ROWS_EVENT_V1)
+{
+ init(tbl_arg->rpl_write_set);
+}
+
+Update_rows_compressed_log_event::Update_rows_compressed_log_event(THD *thd_arg, TABLE *tbl_arg,
+ ulong tid,
+ bool is_transactional)
+: Update_rows_log_event(thd_arg, tbl_arg, tid, is_transactional)
+{
+ m_type = UPDATE_ROWS_COMPRESSED_EVENT_V1;
+}
+
+bool Update_rows_compressed_log_event::write()
+{
+ return Rows_log_event::write_compressed();
+}
+
+void Update_rows_log_event::init(MY_BITMAP const *cols)
+{
+ /* if my_bitmap_init fails, caught in is_valid() */
+ if (likely(!my_bitmap_init(&m_cols_ai,
+ m_width <= sizeof(m_bitbuf_ai)*8 ? m_bitbuf_ai : NULL,
+ m_width,
+ false)))
+ {
+ /* Cols can be zero if this is a dummy binrows event */
+ if (likely(cols != NULL))
+ {
+ memcpy(m_cols_ai.bitmap, cols->bitmap, no_bytes_in_map(cols));
+ create_last_word_mask(&m_cols_ai);
+ }
+ }
+}
+
+
+#if defined(HAVE_REPLICATION)
+
+int
+Update_rows_log_event::do_before_row_operations(const Slave_reporting_capability *const)
+{
+ /*
+ Increment the global status update count variable
+ */
+ if (get_flags(STMT_END_F))
+ status_var_increment(thd->status_var.com_stat[SQLCOM_UPDATE]);
+
+ int err;
+ if ((err= find_key()))
+ return err;
+
+ if (do_invoke_trigger())
+ m_table->prepare_triggers_for_update_stmt_or_event();
+
+ return 0;
+}
+
+int
+Update_rows_log_event::do_after_row_operations(const Slave_reporting_capability *const,
+ int error)
+{
+ /*error= ToDo:find out what this should really be, this triggers close_scan in nbd, returning error?*/
+ m_table->file->ha_index_or_rnd_end();
+ my_free(m_key); // Free for multi_malloc
+ m_key= NULL;
+ m_key_info= NULL;
+
+ return error;
+}
+
+int
+Update_rows_log_event::do_exec_row(rpl_group_info *rgi)
+{
+ const bool invoke_triggers= (m_table->triggers && do_invoke_trigger());
+ const char *tmp= thd->get_proc_info();
+ const char *message= "Update_rows_log_event::find_row()";
+ DBUG_ASSERT(m_table != NULL);
+
+#ifdef WSREP_PROC_INFO
+ my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "Update_rows_log_event::find_row(%lld)",
+ (long long) wsrep_thd_trx_seqno(thd));
+ message= thd->wsrep_info;
+#endif /* WSREP_PROC_INFO */
+
+ thd_proc_info(thd, message);
+ int error= find_row(rgi);
+ if (unlikely(error))
+ {
+ /*
+ We need to read the second image in the event of error to be
+ able to skip to the next pair of updates
+ */
+ if ((m_curr_row= m_curr_row_end))
+ unpack_current_row(rgi, &m_cols_ai);
+ thd_proc_info(thd, tmp);
+ return error;
+ }
+
+ /*
+ This is the situation after locating BI:
+
+ ===|=== before image ====|=== after image ===|===
+ ^ ^
+ m_curr_row m_curr_row_end
+
+ BI found in the table is stored in record[0]. We copy it to record[1]
+ and unpack AI to record[0].
+ */
+
+ store_record(m_table,record[1]);
+
+ m_curr_row= m_curr_row_end;
+ message= "Update_rows_log_event::unpack_current_row()";
+#ifdef WSREP_PROC_INFO
+ my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "Update_rows_log_event::unpack_current_row(%lld)",
+ (long long) wsrep_thd_trx_seqno(thd));
+ message= thd->wsrep_info;
+#endif /* WSREP_PROC_INFO */
+
+ /* this also updates m_curr_row_end */
+ thd_proc_info(thd, message);
+ if (unlikely((error= unpack_current_row(rgi, &m_cols_ai))))
+ goto err;
+
+ /*
+ Now we have the right row to update. The old row (the one we're
+ looking for) is in record[1] and the new row is in record[0].
+ */
+#ifndef HAVE_valgrind
+ /*
+ Don't print debug messages when running valgrind since they can
+ trigger false warnings.
+ */
+ DBUG_PRINT("info",("Updating row in table"));
+ DBUG_DUMP("old record", m_table->record[1], m_table->s->reclength);
+ DBUG_DUMP("new values", m_table->record[0], m_table->s->reclength);
+#endif
+
+ message= "Update_rows_log_event::ha_update_row()";
+#ifdef WSREP_PROC_INFO
+ my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "Update_rows_log_event::ha_update_row(%lld)",
+ (long long) wsrep_thd_trx_seqno(thd));
+ message= thd->wsrep_info;
+#endif /* WSREP_PROC_INFO */
+
+ thd_proc_info(thd, message);
+ if (invoke_triggers &&
+ unlikely(process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_BEFORE, TRUE)))
+ {
+ error= HA_ERR_GENERIC; // in case if error is not set yet
+ goto err;
+ }
+
+ // Temporary fix to find out why it fails [/Matz]
+ memcpy(m_table->read_set->bitmap, m_cols.bitmap, (m_table->read_set->n_bits + 7) / 8);
+ memcpy(m_table->write_set->bitmap, m_cols_ai.bitmap, (m_table->write_set->n_bits + 7) / 8);
+
+ m_table->mark_columns_per_binlog_row_image();
+ if (m_vers_from_plain && m_table->versioned(VERS_TIMESTAMP))
+ m_table->vers_update_fields();
+ error= m_table->file->ha_update_row(m_table->record[1], m_table->record[0]);
+ if (unlikely(error == HA_ERR_RECORD_IS_THE_SAME))
+ error= 0;
+ if (m_vers_from_plain && m_table->versioned(VERS_TIMESTAMP))
+ {
+ store_record(m_table, record[2]);
+ error= vers_insert_history_row(m_table);
+ restore_record(m_table, record[2]);
+ }
+ m_table->default_column_bitmaps();
+
+ if (invoke_triggers && likely(!error) &&
+ unlikely(process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE)))
+ error= HA_ERR_GENERIC; // in case if error is not set yet
+
+ thd_proc_info(thd, tmp);
+
+err:
+ m_table->file->ha_index_or_rnd_end();
+ return error;
+}
+
+#endif /* defined(HAVE_REPLICATION) */
+
+
+#if defined(HAVE_REPLICATION)
+uint8 Update_rows_log_event::get_trg_event_map()
+{
+ return trg2bit(TRG_EVENT_UPDATE);
+}
+#endif
+
+
+void Incident_log_event::pack_info(Protocol *protocol)
+{
+ char buf[256];
+ size_t bytes;
+ if (m_message.length > 0)
+ bytes= my_snprintf(buf, sizeof(buf), "#%d (%s)",
+ m_incident, description());
+ else
+ bytes= my_snprintf(buf, sizeof(buf), "#%d (%s): %s",
+ m_incident, description(), m_message.str);
+ protocol->store(buf, bytes, &my_charset_bin);
+}
+
+
+#if defined(WITH_WSREP)
+/*
+ read the first event from (*buf). The size of the (*buf) is (*buf_len).
+ At the end (*buf) is shitfed to point to the following event or NULL and
+ (*buf_len) will be changed to account just being read bytes of the 1st event.
+*/
+#define WSREP_MAX_ALLOWED_PACKET 1024*1024*1024 // current protocol max
+
+Log_event* wsrep_read_log_event(
+ char **arg_buf, size_t *arg_buf_len,
+ const Format_description_log_event *description_event)
+{
+ char *head= (*arg_buf);
+ uint data_len = uint4korr(head + EVENT_LEN_OFFSET);
+ char *buf= (*arg_buf);
+ const char *error= 0;
+ Log_event *res= 0;
+ DBUG_ENTER("wsrep_read_log_event");
+
+ if (data_len > WSREP_MAX_ALLOWED_PACKET)
+ {
+ error = "Event too big";
+ goto err;
+ }
+
+ res= Log_event::read_log_event(buf, data_len, &error, description_event, false);
+
+err:
+ if (!res)
+ {
+ DBUG_ASSERT(error != 0);
+ sql_print_error("Error in Log_event::read_log_event(): "
+ "'%s', data_len: %d, event_type: %d",
+ error,data_len,(uchar)head[EVENT_TYPE_OFFSET]);
+ }
+ (*arg_buf)+= data_len;
+ (*arg_buf_len)-= data_len;
+ DBUG_RETURN(res);
+}
+#endif
+
+
+#if defined(HAVE_REPLICATION)
+int
+Incident_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ Relay_log_info const *rli= rgi->rli;
+ DBUG_ENTER("Incident_log_event::do_apply_event");
+
+ if (ignored_error_code(ER_SLAVE_INCIDENT))
+ {
+ DBUG_PRINT("info", ("Ignoring Incident"));
+ DBUG_RETURN(0);
+ }
+
+ rli->report(ERROR_LEVEL, ER_SLAVE_INCIDENT, NULL,
+ ER_THD(rgi->thd, ER_SLAVE_INCIDENT),
+ description(),
+ m_message.length > 0 ? m_message.str : "<none>");
+ DBUG_RETURN(1);
+}
+#endif
+
+
+bool
+Incident_log_event::write_data_header()
+{
+ DBUG_ENTER("Incident_log_event::write_data_header");
+ DBUG_PRINT("enter", ("m_incident: %d", m_incident));
+ uchar buf[sizeof(int16)];
+ int2store(buf, (int16) m_incident);
+ DBUG_RETURN(write_data(buf, sizeof(buf)));
+}
+
+bool
+Incident_log_event::write_data_body()
+{
+ uchar tmp[1];
+ DBUG_ENTER("Incident_log_event::write_data_body");
+ tmp[0]= (uchar) m_message.length;
+ DBUG_RETURN(write_data(tmp, sizeof(tmp)) ||
+ write_data(m_message.str, m_message.length));
+}
+
+
+/* Pack info for its unrecognized ignorable event */
+void Ignorable_log_event::pack_info(Protocol *protocol)
+{
+ char buf[256];
+ size_t bytes;
+ bytes= my_snprintf(buf, sizeof(buf), "# Ignorable event type %d (%s)",
+ number, description);
+ protocol->store(buf, bytes, &my_charset_bin);
+}
+
+
+#if defined(HAVE_REPLICATION)
+Heartbeat_log_event::Heartbeat_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event)
+ :Log_event(buf, description_event)
+{
+ uint8 header_size= description_event->common_header_len;
+ ident_len = event_len - header_size;
+ set_if_smaller(ident_len,FN_REFLEN-1);
+ log_ident= buf + header_size;
+}
+#endif
+
+
+/**
+ Check if we should write event to the relay log
+
+ This is used to skip events that is only supported by MySQL
+
+ Return:
+ 0 ok
+ 1 Don't write event
+*/
+
+bool event_that_should_be_ignored(const char *buf)
+{
+ uint event_type= (uchar)buf[EVENT_TYPE_OFFSET];
+ if (event_type == GTID_LOG_EVENT ||
+ event_type == ANONYMOUS_GTID_LOG_EVENT ||
+ event_type == PREVIOUS_GTIDS_LOG_EVENT ||
+ event_type == TRANSACTION_CONTEXT_EVENT ||
+ event_type == VIEW_CHANGE_EVENT ||
+ (uint2korr(buf + FLAGS_OFFSET) & LOG_EVENT_IGNORABLE_F))
+ return 1;
+ return 0;
+}
diff --git a/sql/mdl.cc b/sql/mdl.cc
index 591127dc1d8..98a9d8f0d01 100644
--- a/sql/mdl.cc
+++ b/sql/mdl.cc
@@ -24,6 +24,12 @@
#include <mysql/plugin.h>
#include <mysql/service_thd_wait.h>
#include <mysql/psi/mysql_stage.h>
+#include <tpool.h>
+#include <pfs_metadata_provider.h>
+#include <mysql/psi/mysql_mdl.h>
+
+static PSI_memory_key key_memory_MDL_context_acquire_locks;
+
#ifdef HAVE_PSI_INTERFACE
static PSI_mutex_key key_MDL_wait_LOCK_wait_status;
@@ -48,6 +54,11 @@ static PSI_cond_info all_mdl_conds[]=
{ &key_MDL_wait_COND_wait_status, "MDL_context::COND_wait_status", 0}
};
+static PSI_memory_info all_mdl_memory[]=
+{
+ { &key_memory_MDL_context_acquire_locks, "MDL_context::acquire_locks", 0}
+};
+
/**
Initialise all the performance schema instrumentation points
used by the MDL subsystem.
@@ -65,6 +76,9 @@ static void init_mdl_psi_keys(void)
count= array_elements(all_mdl_conds);
mysql_cond_register("sql", all_mdl_conds, count);
+ count= array_elements(all_mdl_memory);
+ mysql_memory_register("sql", all_mdl_memory, count);
+
MDL_key::init_psi_keys();
}
#endif /* HAVE_PSI_INTERFACE */
@@ -953,16 +967,20 @@ bool MDL_context::fix_pins()
@param mdl_type The MDL lock type for the request.
*/
-void MDL_request::init(MDL_key::enum_mdl_namespace mdl_namespace,
+void MDL_request::init_with_source(MDL_key::enum_mdl_namespace mdl_namespace,
const char *db_arg,
const char *name_arg,
enum_mdl_type mdl_type_arg,
- enum_mdl_duration mdl_duration_arg)
+ enum_mdl_duration mdl_duration_arg,
+ const char *src_file,
+ uint src_line)
{
key.mdl_key_init(mdl_namespace, db_arg, name_arg);
type= mdl_type_arg;
duration= mdl_duration_arg;
ticket= NULL;
+ m_src_file= src_file;
+ m_src_line= src_line;
}
@@ -975,14 +993,18 @@ void MDL_request::init(MDL_key::enum_mdl_namespace mdl_namespace,
@param mdl_type_arg The MDL lock type for the request.
*/
-void MDL_request::init(const MDL_key *key_arg,
+void MDL_request::init_by_key_with_source(const MDL_key *key_arg,
enum_mdl_type mdl_type_arg,
- enum_mdl_duration mdl_duration_arg)
+ enum_mdl_duration mdl_duration_arg,
+ const char *src_file,
+ uint src_line)
{
key.mdl_key_init(key_arg);
type= mdl_type_arg;
duration= mdl_duration_arg;
ticket= NULL;
+ m_src_file= src_file;
+ m_src_line= src_line;
}
@@ -1011,6 +1033,9 @@ MDL_ticket *MDL_ticket::create(MDL_context *ctx_arg, enum_mdl_type type_arg
void MDL_ticket::destroy(MDL_ticket *ticket)
{
+ mysql_mdl_destroy(ticket->m_psi);
+ ticket->m_psi= NULL;
+
delete ticket;
}
@@ -1125,6 +1150,7 @@ MDL_wait::timed_wait(MDL_context_owner *owner, struct timespec *abs_timeout,
owner->ENTER_COND(&m_COND_wait_status, &m_LOCK_wait_status,
wait_state_name, & old_stage);
thd_wait_begin(NULL, THD_WAIT_META_DATA_LOCK);
+ tpool::tpool_wait_begin();
while (!m_wait_status && !owner->is_killed() &&
wait_result != ETIMEDOUT && wait_result != ETIME)
{
@@ -1147,6 +1173,7 @@ MDL_wait::timed_wait(MDL_context_owner *owner, struct timespec *abs_timeout,
wait_result= mysql_cond_timedwait(&m_COND_wait_status, &m_LOCK_wait_status,
abs_timeout);
}
+ tpool::tpool_wait_end();
thd_wait_end(NULL);
if (m_wait_status == EMPTY)
@@ -2095,6 +2122,15 @@ MDL_context::try_acquire_lock_impl(MDL_request *mdl_request,
return TRUE;
}
+ DBUG_ASSERT(ticket->m_psi == NULL);
+ ticket->m_psi= mysql_mdl_create(ticket,
+ &mdl_request->key,
+ mdl_request->type,
+ mdl_request->duration,
+ MDL_ticket::PENDING,
+ mdl_request->m_src_file,
+ mdl_request->m_src_line);
+
ticket->m_lock= lock;
if (lock->can_grant_lock(mdl_request->type, this, false))
@@ -2106,6 +2142,8 @@ MDL_context::try_acquire_lock_impl(MDL_request *mdl_request,
m_tickets[mdl_request->duration].push_front(ticket);
mdl_request->ticket= ticket;
+
+ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED);
}
else
*out_ticket= ticket;
@@ -2155,6 +2193,15 @@ MDL_context::clone_ticket(MDL_request *mdl_request)
)))
return TRUE;
+ DBUG_ASSERT(ticket->m_psi == NULL);
+ ticket->m_psi= mysql_mdl_create(ticket,
+ &mdl_request->key,
+ mdl_request->type,
+ mdl_request->duration,
+ MDL_ticket::PENDING,
+ mdl_request->m_src_file,
+ mdl_request->m_src_line);
+
/* clone() is not supposed to be used to get a stronger lock. */
DBUG_ASSERT(mdl_request->ticket->has_stronger_or_equal_type(ticket->m_type));
@@ -2167,6 +2214,8 @@ MDL_context::clone_ticket(MDL_request *mdl_request)
m_tickets[mdl_request->duration].push_front(ticket);
+ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED);
+
return FALSE;
}
@@ -2306,6 +2355,12 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout)
mysql_prlock_unlock(&lock->m_rwlock);
+ PSI_metadata_locker_state state __attribute__((unused));
+ PSI_metadata_locker *locker= NULL;
+
+ if (ticket->m_psi != NULL)
+ locker= PSI_CALL_start_metadata_wait(&state, ticket->m_psi, __FILE__, __LINE__);
+
will_wait_for(ticket);
/* There is a shared or exclusive lock on the object. */
@@ -2351,6 +2406,9 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout)
done_waiting_for();
+ if (locker != NULL)
+ PSI_CALL_end_metadata_wait(locker, 0);
+
if (wait_status != MDL_wait::GRANTED)
{
lock->remove_ticket(m_pins, &MDL_lock::m_waiting, ticket);
@@ -2386,6 +2444,8 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout)
mdl_request->ticket= ticket;
+ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED);
+
DBUG_RETURN(FALSE);
}
@@ -2431,8 +2491,8 @@ bool MDL_context::acquire_locks(MDL_request_list *mdl_requests,
DBUG_RETURN(FALSE);
/* Sort requests according to MDL_key. */
- if (! (sort_buf= (MDL_request **)my_malloc(req_count *
- sizeof(MDL_request*),
+ if (! (sort_buf= (MDL_request **)my_malloc(key_memory_MDL_context_acquire_locks,
+ req_count * sizeof(MDL_request*),
MYF(MY_WME))))
DBUG_RETURN(TRUE);
@@ -2517,8 +2577,8 @@ MDL_context::upgrade_shared_lock(MDL_ticket *mdl_ticket,
mdl_ticket->get_key()->mdl_namespace() != MDL_key::BACKUP)
DBUG_RETURN(FALSE);
- mdl_xlock_request.init(&mdl_ticket->m_lock->key, new_type,
- MDL_TRANSACTION);
+ MDL_REQUEST_INIT_BY_KEY(&mdl_xlock_request, &mdl_ticket->m_lock->key,
+ new_type, MDL_TRANSACTION);
if (acquire_lock(&mdl_xlock_request, lock_wait_timeout))
DBUG_RETURN(TRUE);
@@ -2958,7 +3018,8 @@ MDL_context::is_lock_owner(MDL_key::enum_mdl_namespace mdl_namespace,
MDL_request mdl_request;
enum_mdl_duration not_unused;
/* We don't care about exact duration of lock here. */
- mdl_request.init(mdl_namespace, db, name, mdl_type, MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&mdl_request, mdl_namespace, db, name, mdl_type,
+ MDL_TRANSACTION);
MDL_ticket *ticket= find_ticket(&mdl_request, &not_unused);
DBUG_ASSERT(ticket == NULL || ticket->m_lock);
diff --git a/sql/mdl.h b/sql/mdl.h
index b084670e5c6..4659238e9f2 100644
--- a/sql/mdl.h
+++ b/sql/mdl.h
@@ -353,7 +353,7 @@ enum enum_mdl_duration {
or "name".
*/
-class MDL_key
+struct MDL_key
{
public:
#ifdef HAVE_PSI_INTERFACE
@@ -535,18 +535,23 @@ public:
/** A lock is requested based on a fully qualified name and type. */
MDL_key key;
+ const char *m_src_file;
+ uint m_src_line;
+
public:
static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
{ return alloc_root(mem_root, size); }
static void operator delete(void *, MEM_ROOT *) {}
- void init(MDL_key::enum_mdl_namespace namespace_arg,
+ void init_with_source(MDL_key::enum_mdl_namespace namespace_arg,
const char *db_arg, const char *name_arg,
enum_mdl_type mdl_type_arg,
- enum_mdl_duration mdl_duration_arg);
- void init(const MDL_key *key_arg, enum_mdl_type mdl_type_arg,
- enum_mdl_duration mdl_duration_arg);
+ enum_mdl_duration mdl_duration_arg,
+ const char *src_file, uint src_line);
+ void init_by_key_with_source(const MDL_key *key_arg, enum_mdl_type mdl_type_arg,
+ enum_mdl_duration mdl_duration_arg,
+ const char *src_file, uint src_line);
/** Set type of lock request. Can be only applied to pending locks. */
inline void set_type(enum_mdl_type type_arg)
{
@@ -610,6 +615,12 @@ public:
typedef void (*mdl_cached_object_release_hook)(void *);
+#define MDL_REQUEST_INIT(R, P1, P2, P3, P4, P5) \
+ (*R).init_with_source(P1, P2, P3, P4, P5, __FILE__, __LINE__)
+
+#define MDL_REQUEST_INIT_BY_KEY(R, P1, P2, P3) \
+ (*R).init_by_key_with_source(P1, P2, P3, __FILE__, __LINE__)
+
/**
An abstract class for inspection of a connected
@@ -718,6 +729,11 @@ public:
/** Implement MDL_wait_for_subgraph interface. */
virtual bool accept_visitor(MDL_wait_for_graph_visitor *dvisitor);
virtual uint get_deadlock_weight() const;
+ /**
+ Status of lock request represented by the ticket as reflected in P_S.
+ */
+ enum enum_psi_status { PENDING = 0, GRANTED,
+ PRE_ACQUIRE_NOTIFY, POST_RELEASE_NOTIFY };
private:
friend class MDL_context;
@@ -731,9 +747,15 @@ private:
m_duration(duration_arg),
#endif
m_ctx(ctx_arg),
- m_lock(NULL)
+ m_lock(NULL),
+ m_psi(NULL)
{}
+ virtual ~MDL_ticket()
+ {
+ DBUG_ASSERT(m_psi == NULL);
+ }
+
static MDL_ticket *create(MDL_context *ctx_arg, enum_mdl_type type_arg
#ifndef DBUG_OFF
, enum_mdl_duration duration_arg
@@ -760,6 +782,8 @@ private:
*/
MDL_lock *m_lock;
+ PSI_metadata_lock *m_psi;
+
private:
MDL_ticket(const MDL_ticket &); /* not implemented */
MDL_ticket &operator=(const MDL_ticket &); /* not implemented */
diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc
index 601268ec2f6..0965ec0eb9f 100644
--- a/sql/multi_range_read.cc
+++ b/sql/multi_range_read.cc
@@ -1186,7 +1186,7 @@ int DsMrr_impl::setup_two_handlers()
scans.
Calling primary_file->index_end() will invoke dsmrr_close() for this object,
- which will delete secondary_file. We need to keep it, so put it away and dont
+ which will delete secondary_file. We need to keep it, so put it away and don't
let it be deleted:
*/
if (primary_file->inited == handler::INDEX)
diff --git a/sql/mysql_install_db.cc b/sql/mysql_install_db.cc
index 54bd46240bc..f8b94159a8f 100644
--- a/sql/mysql_install_db.cc
+++ b/sql/mysql_install_db.cc
@@ -96,10 +96,10 @@ static struct my_option my_long_options[]=
static my_bool
-get_one_option(int optid, const struct my_option *, char *)
+get_one_option(const struct my_option *opt, char *, const char *)
{
DBUG_ENTER("get_one_option");
- switch (optid) {
+ switch (opt->id) {
case '?':
printf("%s\n", USAGETEXT);
my_print_help(my_long_options);
diff --git a/sql/mysql_upgrade_service.cc b/sql/mysql_upgrade_service.cc
index a10b5bb5162..60fd8fc7efa 100644
--- a/sql/mysql_upgrade_service.cc
+++ b/sql/mysql_upgrade_service.cc
@@ -78,12 +78,10 @@ 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(const struct my_option *opt, char *, const char *)
{
DBUG_ENTER("get_one_option");
- switch (optid) {
+ switch (opt->id) {
case '?':
printf("%s\n", USAGETEXT);
my_print_help(my_long_options);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index c33dc566f04..387482ef6f0 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2008, 2019, MariaDB Corporation.
+ Copyright (c) 2008, 2020, 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
@@ -113,7 +113,7 @@
#include "sp_rcontext.h"
#include "sp_cache.h"
#include "sql_reload.h" // reload_acl_and_cache
-#include "pcre.h"
+#include "sp_head.h" // init_sp_psi_keys
#ifdef HAVE_POLL_H
#include <poll.h>
@@ -322,10 +322,6 @@ static PSI_rwlock_key key_rwlock_openssl;
#endif
#endif /* HAVE_PSI_INTERFACE */
-#ifdef HAVE_NPTL
-volatile sig_atomic_t ld_assume_kernel_is_set= 0;
-#endif
-
/**
Statement instrumentation key for replication.
*/
@@ -335,14 +331,12 @@ PSI_statement_info stmt_info_rpl;
/* the default log output is log tables */
static bool lower_case_table_names_used= 0;
-static bool max_long_data_size_used= false;
static bool volatile select_thread_in_use, signal_thread_in_use;
static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0;
static my_bool opt_short_log_format= 0, opt_silent_startup= 0;
bool my_disable_leak_check= false;
uint kill_cached_threads;
-static uint wake_thread;
ulong max_used_connections;
volatile ulong cached_thread_count= 0;
static char *mysqld_user, *mysqld_chroot;
@@ -424,6 +418,7 @@ my_bool use_temp_pool, relay_log_purge;
my_bool relay_log_recovery;
my_bool opt_sync_frm, opt_allow_suspicious_udfs;
my_bool opt_secure_auth= 0;
+my_bool opt_require_secure_transport= 0;
char* opt_secure_file_priv;
my_bool lower_case_file_system= 0;
my_bool opt_large_pages= 0;
@@ -446,6 +441,7 @@ my_bool opt_noacl;
my_bool sp_automatic_privileges= 1;
ulong opt_binlog_rows_event_max_size;
+ulong binlog_row_metadata;
my_bool opt_master_verify_checksum= 0;
my_bool opt_slave_sql_verify_checksum= 1;
const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS};
@@ -461,7 +457,7 @@ Atomic_counter<uint32_t> thread_count;
bool shutdown_wait_for_slaves;
int32 slave_open_temp_tables;
ulong thread_created;
-ulong back_log, connect_timeout, concurrency, server_id;
+ulong back_log, connect_timeout, server_id;
ulong what_to_log;
ulong slow_launch_time;
ulong open_files_limit, max_binlog_size;
@@ -507,12 +503,6 @@ long opt_secure_timestamp;
uint default_password_lifetime;
my_bool disconnect_on_expired_password;
-/*
- Maximum length of parameter value which can be set through
- mysql_send_long_data() call.
-*/
-ulong max_long_data_size;
-
bool max_user_connections_checking=0;
/**
Limit of the total number of prepared statements in the server.
@@ -544,7 +534,7 @@ ulong stored_program_cache_size= 0;
ulong opt_slave_parallel_threads= 0;
ulong opt_slave_domain_parallel_threads= 0;
-ulong opt_slave_parallel_mode= SLAVE_PARALLEL_CONSERVATIVE;
+ulong opt_slave_parallel_mode;
ulong opt_binlog_commit_wait_count= 0;
ulong opt_binlog_commit_wait_usec= 0;
ulong opt_slave_parallel_max_queued= 131072;
@@ -701,7 +691,7 @@ mysql_mutex_t
LOCK_crypt,
LOCK_global_system_variables,
LOCK_user_conn,
- LOCK_connection_count, LOCK_error_messages, LOCK_slave_background;
+ LOCK_error_messages, LOCK_slave_background;
mysql_mutex_t LOCK_stats, LOCK_global_user_client_stats,
LOCK_global_table_stats, LOCK_global_index_stats;
@@ -796,8 +786,8 @@ static struct my_option pfs_early_options[]=
{"performance_schema_consumer_events_statements_current", 0,
"Default startup value for the events_statements_current consumer.",
&pfs_param.m_consumer_events_statements_current_enabled,
- &pfs_param.m_consumer_events_statements_current_enabled, 0,
- GET_BOOL, OPT_ARG, TRUE, 0, 0, 0, 0, 0},
+ &pfs_param.m_consumer_events_statements_current_enabled, 0, GET_BOOL,
+ OPT_ARG, FALSE, 0, 0, 0, 0, 0},
{"performance_schema_consumer_events_statements_history", 0,
"Default startup value for the events_statements_history consumer.",
&pfs_param.m_consumer_events_statements_history_enabled,
@@ -808,6 +798,21 @@ static struct my_option pfs_early_options[]=
&pfs_param.m_consumer_events_statements_history_long_enabled,
&pfs_param.m_consumer_events_statements_history_long_enabled, 0,
GET_BOOL, OPT_ARG, FALSE, 0, 0, 0, 0, 0},
+ {"performance_schema_consumer_events_transactions_current", 0,
+ "Default startup value for the events_transactions_current consumer.",
+ &pfs_param.m_consumer_events_transactions_current_enabled,
+ &pfs_param.m_consumer_events_transactions_current_enabled, 0,
+ GET_BOOL, OPT_ARG, FALSE, 0, 0, 0, 0, 0},
+ {"performance_schema_consumer_events_transactions_history", 0,
+ "Default startup value for the events_transactions_history consumer.",
+ &pfs_param.m_consumer_events_transactions_history_enabled,
+ &pfs_param.m_consumer_events_transactions_history_enabled, 0,
+ GET_BOOL, OPT_ARG, FALSE, 0, 0, 0, 0, 0},
+ {"performance_schema_consumer_events_transactions_history_long", 0,
+ "Default startup value for the events_transactions_history_long consumer.",
+ &pfs_param.m_consumer_events_transactions_history_long_enabled,
+ &pfs_param.m_consumer_events_transactions_history_long_enabled, 0,
+ GET_BOOL, OPT_ARG, FALSE, 0, 0, 0, 0, 0},
{"performance_schema_consumer_events_waits_current", 0,
"Default startup value for the events_waits_current consumer.",
&pfs_param.m_consumer_events_waits_current_enabled,
@@ -845,6 +850,19 @@ static struct my_option pfs_early_options[]=
NO_ARG, 1, 0, 1, 0, 0, 0}
};
+PSI_file_key key_file_binlog, key_file_binlog_cache, key_file_binlog_index,
+ key_file_binlog_index_cache, key_file_casetest,
+ key_file_dbopt, key_file_des_key_file, key_file_ERRMSG, key_select_to_file,
+ key_file_fileparser, key_file_frm, key_file_global_ddl_log, key_file_load,
+ key_file_loadfile, key_file_log_event_data, key_file_log_event_info,
+ key_file_master_info, key_file_misc, key_file_partition_ddl_log,
+ key_file_pid, key_file_relay_log_info, key_file_send_file, key_file_tclog,
+ key_file_trg, key_file_trn, key_file_init;
+PSI_file_key key_file_query_log, key_file_slow_log;
+PSI_file_key key_file_relaylog, key_file_relaylog_index,
+ key_file_relaylog_cache, key_file_relaylog_index_cache;
+PSI_file_key key_file_binlog_state;
+
#ifdef HAVE_PSI_INTERFACE
#ifdef HAVE_MMAP
PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active, key_LOCK_pool,
@@ -859,7 +877,7 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
key_BINLOG_LOCK_binlog_background_thread,
key_LOCK_binlog_end_pos,
key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi,
- key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create,
+ key_LOCK_crypt, key_LOCK_delayed_create,
key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log,
key_LOCK_gdl, key_LOCK_global_system_variables,
key_LOCK_manager,
@@ -924,7 +942,6 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_delayed_insert_mutex, "Delayed_insert::mutex", 0},
{ &key_hash_filo_lock, "hash_filo::lock", 0},
{ &key_LOCK_active_mi, "LOCK_active_mi", PSI_FLAG_GLOBAL},
- { &key_LOCK_connection_count, "LOCK_connection_count", PSI_FLAG_GLOBAL},
{ &key_LOCK_thread_id, "LOCK_thread_id", PSI_FLAG_GLOBAL},
{ &key_LOCK_crypt, "LOCK_crypt", PSI_FLAG_GLOBAL},
{ &key_LOCK_delayed_create, "LOCK_delayed_create", PSI_FLAG_GLOBAL},
@@ -1118,17 +1135,6 @@ static PSI_thread_info all_server_threads[]=
PSI_file_key key_file_map;
#endif /* HAVE_MMAP */
-PSI_file_key key_file_binlog, key_file_binlog_index, key_file_casetest,
- key_file_dbopt, key_file_des_key_file, key_file_ERRMSG, key_select_to_file,
- key_file_fileparser, key_file_frm, key_file_global_ddl_log, key_file_load,
- key_file_loadfile, key_file_log_event_data, key_file_log_event_info,
- key_file_master_info, key_file_misc, key_file_partition,
- key_file_pid, key_file_relay_log_info, key_file_send_file, key_file_tclog,
- key_file_trg, key_file_trn, key_file_init;
-PSI_file_key key_file_query_log, key_file_slow_log;
-PSI_file_key key_file_relaylog, key_file_relaylog_index;
-PSI_file_key key_file_binlog_state;
-
#endif /* HAVE_PSI_INTERFACE */
#ifdef HAVE_PSI_STATEMENT_INTERFACE
@@ -1176,9 +1182,9 @@ void net_after_header_psi(struct st_net *net, void *user_data,
thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state,
stmt_info_new_packet.m_key,
thd->get_db(), thd->db.length,
- thd->charset());
+ thd->charset(), NULL);
- THD_STAGE_INFO(thd, stage_init);
+ THD_STAGE_INFO(thd, stage_starting);
}
/*
@@ -1304,7 +1310,7 @@ private:
void Buffered_logs::init()
{
- init_alloc_root(&m_root, "Buffered_logs", 1024, 0, MYF(0));
+ init_alloc_root(PSI_NOT_INSTRUMENTED, &m_root, 1024, 0, MYF(0));
}
void Buffered_logs::cleanup()
@@ -1467,10 +1473,10 @@ struct st_VioSSLFd *ssl_acceptor_fd;
#endif /* HAVE_OPENSSL */
/**
- Number of currently active user connections. The variable is protected by
- LOCK_connection_count.
+ Number of currently active user connections.
*/
-uint connection_count= 0, extra_connection_count= 0;
+Atomic_counter<uint> connection_count;
+static Atomic_counter<uint> extra_connection_count;
my_bool opt_gtid_strict_mode= FALSE;
@@ -1482,7 +1488,7 @@ static int mysql_init_variables(void);
static int get_options(int *argc_ptr, char ***argv_ptr);
static bool add_terminator(DYNAMIC_ARRAY *options);
static bool add_many_options(DYNAMIC_ARRAY *, my_option *, size_t);
-extern "C" my_bool mysqld_get_one_option(int, const struct my_option *, char *);
+extern "C" my_bool mysqld_get_one_option(const struct my_option *, char *, const char *);
static int init_thread_environment();
static char *get_relative_path(const char *path);
static int fix_paths(void);
@@ -1684,7 +1690,7 @@ void kill_mysql(THD *thd)
make_user_name(thd, user_host_buff);
- if ((user= my_strdup(user_host_buff, MYF(0))) &&
+ if ((user= my_strdup(PSI_NOT_INSTRUMENTED, user_host_buff, MYF(0))) &&
!shutdown_user.compare_exchange_strong(expected_shutdown_user,
user,
std::memory_order_relaxed,
@@ -2003,9 +2009,7 @@ static void clean_up(bool print_message)
sp_cache_end();
free_status_vars();
end_thr_alarm(1); /* Free allocated memory */
-#ifndef EMBEDDED_LIBRARY
end_thr_timer();
-#endif
my_free_open_file_info();
if (defaults_argv)
free_defaults(defaults_argv);
@@ -2100,7 +2104,6 @@ static void clean_up_mutexes()
mysql_mutex_destroy(&LOCK_delayed_create);
mysql_mutex_destroy(&LOCK_crypt);
mysql_mutex_destroy(&LOCK_user_conn);
- mysql_mutex_destroy(&LOCK_connection_count);
mysql_mutex_destroy(&LOCK_thread_id);
mysql_mutex_destroy(&LOCK_stats);
mysql_mutex_destroy(&LOCK_global_user_client_stats);
@@ -2592,20 +2595,6 @@ extern "C" sig_handler end_mysqld_signal(int sig __attribute__((unused)))
}
#endif /* EMBEDDED_LIBRARY */
-/*
- Decrease number of connections
-
- SYNOPSIS
- dec_connection_count()
-*/
-
-void dec_connection_count(scheduler_functions *scheduler)
-{
- mysql_mutex_lock(&LOCK_connection_count);
- (*scheduler->connection_count)--;
- mysql_mutex_unlock(&LOCK_connection_count);
-}
-
/*
Unlink thd from global list of available connections
@@ -2631,7 +2620,7 @@ void unlink_thd(THD *thd)
*/
if (!thd->wsrep_applier)
#endif /* WITH_WSREP */
- dec_connection_count(thd->scheduler);
+ --*thd->scheduler->connection_count;
thd->free_connection();
@@ -2656,134 +2645,57 @@ void unlink_thd(THD *thd)
*/
-static bool cache_thread(THD *thd)
+CONNECT *cache_thread(THD *thd)
{
struct timespec abstime;
+ CONNECT *connect;
+ bool flushed= false;
DBUG_ENTER("cache_thread");
DBUG_ASSERT(thd);
+ set_timespec(abstime, THREAD_CACHE_TIMEOUT);
+
+ /*
+ Delete the instrumentation for the job that just completed,
+ before parking this pthread in the cache (blocked on COND_thread_cache).
+ */
+ PSI_CALL_delete_current_thread();
+
+#ifndef DBUG_OFF
+ while (_db_is_pushed_())
+ _db_pop_();
+#endif
mysql_mutex_lock(&LOCK_thread_cache);
- if (cached_thread_count < thread_cache_size &&
- ! abort_loop && !kill_cached_threads)
+ if ((connect= thread_cache.get()))
+ cached_thread_count++;
+ else if (cached_thread_count < thread_cache_size && !kill_cached_threads)
{
/* Don't kill the thread, just put it in cache for reuse */
DBUG_PRINT("info", ("Adding thread to cache"));
cached_thread_count++;
-
- /*
- Delete the instrumentation for the job that just completed,
- before parking this pthread in the cache (blocked on COND_thread_cache).
- */
- PSI_CALL_delete_current_thread();
-
-#ifndef DBUG_OFF
- while (_db_is_pushed_())
- _db_pop_();
-#endif
-
- set_timespec(abstime, THREAD_CACHE_TIMEOUT);
- while (!abort_loop && ! wake_thread && ! kill_cached_threads)
+ for (;;)
{
int error= mysql_cond_timedwait(&COND_thread_cache, &LOCK_thread_cache,
&abstime);
- if (error == ETIMEDOUT || error == ETIME)
+ flushed= kill_cached_threads;
+ if ((connect= thread_cache.get()))
+ break;
+ else if (flushed || error == ETIMEDOUT || error == ETIME)
{
/*
If timeout, end thread.
- If a new thread is requested (wake_thread is set), we will handle
+ If a new thread is requested, we will handle
the call, even if we got a timeout (as we are already awake and free)
*/
+ cached_thread_count--;
break;
}
}
- cached_thread_count--;
- if (kill_cached_threads)
- mysql_cond_signal(&COND_flush_thread_cache);
- if (wake_thread)
- {
- CONNECT *connect;
-
- wake_thread--;
- connect= thread_cache.get();
- mysql_mutex_unlock(&LOCK_thread_cache);
-
- if (!(connect->create_thd(thd)))
- {
- /* Out of resources. Free thread to get more resources */
- connect->close_and_delete();
- DBUG_RETURN(0);
- }
- delete connect;
-
- /*
- We have to call store_globals to update mysys_var->id and lock_info
- with the new thread_id
- */
- thd->store_globals();
-
- /*
- Create new instrumentation for the new THD job,
- and attach it to this running pthread.
- */
- PSI_CALL_set_thread(PSI_CALL_new_thread(key_thread_one_connection,
- thd, thd->thread_id));
-
- /* reset abort flag for the thread */
- thd->mysys_var->abort= 0;
- thd->thr_create_utime= microsecond_interval_timer();
- thd->start_utime= thd->thr_create_utime;
-
- server_threads.insert(thd);
- DBUG_RETURN(1);
- }
}
mysql_mutex_unlock(&LOCK_thread_cache);
- DBUG_RETURN(0);
-}
-
-
-/*
- End thread for the current connection
-
- SYNOPSIS
- one_thread_per_connection_end()
- thd Thread handler. This may be null if we run out of resources.
- put_in_cache Store thread in cache, if there is room in it
- Normally this is true in all cases except when we got
- out of resources initializing the current thread
-
- NOTES
- If thread is cached, we will wait until thread is scheduled to be
- reused and then we will return.
- If thread is not cached, we end the thread.
-
- RETURN
- 0 Signal to handle_one_connection to reuse connection
-*/
-
-bool one_thread_per_connection_end(THD *thd, bool put_in_cache)
-{
- DBUG_ENTER("one_thread_per_connection_end");
-
- if (thd)
- {
- const bool wsrep_applier= IF_WSREP(thd->wsrep_applier, false);
-
- unlink_thd(thd);
- if (!wsrep_applier && put_in_cache && cache_thread(thd))
- DBUG_RETURN(0); // Thread is reused
- delete thd;
- }
-
- DBUG_PRINT("info", ("killing thread"));
- DBUG_LEAVE; // Must match DBUG_ENTER()
-#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
- ERR_remove_state(0);
-#endif
- my_thread_end();
-
- pthread_exit(0);
- return 0; // Avoid compiler warnings
+ if (flushed)
+ mysql_cond_signal(&COND_flush_thread_cache);
+ DBUG_RETURN(connect);
}
@@ -2974,75 +2886,6 @@ extern "C" char *my_demangle(const char *mangled_name, int *status)
#endif
-/*
- pthread_attr_setstacksize() without so much platform-dependency
-
- Return: The actual stack size if possible.
-*/
-
-#ifndef EMBEDDED_LIBRARY
-static size_t my_setstacksize(pthread_attr_t *attr, size_t stacksize)
-{
- size_t guard_size __attribute__((unused))= 0;
-
-#if defined(__ia64__) || defined(__ia64)
- /*
- On IA64, half of the requested stack size is used for "normal stack"
- and half for "register stack". The space measured by check_stack_overrun
- is the "normal stack", so double the request to make sure we have the
- caller-expected amount of normal stack.
-
- NOTE: there is no guarantee that the register stack can't grow faster
- than normal stack, so it's very unclear that we won't dump core due to
- stack overrun despite check_stack_overrun's efforts. Experimentation
- shows that in the execution_constants test, the register stack grows
- less than half as fast as normal stack, but perhaps other scenarios are
- less forgiving. If it turns out that more space is needed for the
- register stack, that could be forced (rather inefficiently) by using a
- multiplier higher than 2 here.
- */
- stacksize *= 2;
-#endif
-
- /*
- On many machines, the "guard space" is subtracted from the requested
- stack size, and that space is quite large on some platforms. So add
- it to our request, if we can find out what it is.
- */
-#ifdef HAVE_PTHREAD_ATTR_GETGUARDSIZE
- if (pthread_attr_getguardsize(attr, &guard_size))
- guard_size = 0; /* if can't find it out, treat as 0 */
-#endif
-
- pthread_attr_setstacksize(attr, stacksize + guard_size);
-
- /* Retrieve actual stack size if possible */
-#ifdef HAVE_PTHREAD_ATTR_GETSTACKSIZE
- {
- size_t real_stack_size= 0;
- /* We must ignore real_stack_size = 0 as Solaris 2.9 can return 0 here */
- if (pthread_attr_getstacksize(attr, &real_stack_size) == 0 &&
- real_stack_size > guard_size)
- {
- real_stack_size -= guard_size;
- if (real_stack_size < stacksize)
- {
- if (global_system_variables.log_warnings)
- sql_print_warning("Asked for %zu thread stack, but got %zu",
- stacksize, real_stack_size);
- stacksize= real_stack_size;
- }
- }
- }
-#endif /* !EMBEDDED_LIBRARY */
-
-#if defined(__ia64__) || defined(__ia64)
- stacksize /= 2;
-#endif
- return stacksize;
-}
-#endif
-
#ifdef DBUG_ASSERT_AS_PRINTF
extern "C" void
mariadb_dbug_assert_failed(const char *assert_expr, const char *file,
@@ -3082,7 +2925,7 @@ void init_signals(void)
sigemptyset(&sa.sa_mask);
sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL);
- my_init_stacktrace();
+ my_init_stacktrace(0);
#if defined(__amiga__)
sa.sa_handler=(void(*)())handle_fatal_signal;
#else
@@ -3124,8 +2967,7 @@ void init_signals(void)
sa.sa_flags = 0;
sa.sa_handler = print_signal_warning;
sigaction(SIGHUP, &sa, (struct sigaction*) 0);
- if (thd_lib_detected != THD_LIB_LT)
- sigaddset(&set,THR_SERVER_ALARM);
+ sigaddset(&set,THR_SERVER_ALARM);
if (test_flags & TEST_SIGINT)
{
/* Allow SIGINT to break mysqld. This is for debugging with --gdb */
@@ -3382,10 +3224,18 @@ extern "C" void *my_str_malloc_mysqld(size_t size);
void *my_str_malloc_mysqld(size_t size)
{
- return my_malloc(size, MYF(MY_FAE));
+ return my_malloc(key_memory_my_str_malloc, size, MYF(MY_FAE));
}
+#if 0
+extern "C" void *my_str_realloc_mysqld(void *ptr, size_t size);
+void *my_str_realloc_mysqld(void *ptr, size_t size)
+{
+ return my_realloc(key_memory_my_str_malloc, ptr, size, MYF(MY_FAE));
+}
+#endif
+
#include <mysqld_default_groups.h>
#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY)
@@ -3431,20 +3281,6 @@ static void init_libstrings()
#endif
}
-ulonglong my_pcre_frame_size;
-
-static void init_pcre()
-{
- pcre_malloc= pcre_stack_malloc= my_str_malloc_mysqld;
- pcre_free= pcre_stack_free= my_free;
- pcre_stack_guard= check_enough_stack_size_slow;
- /* See http://pcre.org/original/doc/html/pcrestack.html */
- my_pcre_frame_size= -pcre_exec(NULL, NULL, NULL, -999, -999, 0, NULL, 0);
- // pcre can underestimate its stack usage. Use a safe value, as in the manual
- set_if_bigger(my_pcre_frame_size, 500);
- my_pcre_frame_size += 16; // Again, safety margin, see the manual
-}
-
/**
Initialize one of the global date/time format variables.
@@ -3608,7 +3444,7 @@ SHOW_VAR com_status_vars[]= {
{"show_generic", STMT_STATUS(SQLCOM_SHOW_GENERIC)},
{"show_grants", STMT_STATUS(SQLCOM_SHOW_GRANTS)},
{"show_keys", STMT_STATUS(SQLCOM_SHOW_KEYS)},
- {"show_master_status", STMT_STATUS(SQLCOM_SHOW_MASTER_STAT)},
+ {"show_binlog_status", STMT_STATUS(SQLCOM_SHOW_BINLOG_STAT)},
{"show_open_tables", STMT_STATUS(SQLCOM_SHOW_OPEN_TABLES)},
{"show_package_status", STMT_STATUS(SQLCOM_SHOW_STATUS_PACKAGE)},
#ifndef DBUG_OFF
@@ -3822,10 +3658,8 @@ int json_unescape_json(const char *json_str, const char *json_end,
@returns Pointer to string containing the full file path, or NULL if
it was not possible to create the path.
*/
-static inline const char *
-rpl_make_log_name(const char *opt,
- const char *def,
- const char *ext)
+static const char *rpl_make_log_name(PSI_memory_key key, const char *opt,
+ const char *def, const char *ext)
{
DBUG_ENTER("rpl_make_log_name");
DBUG_PRINT("enter", ("opt: %s, def: %s, ext: %s", opt, def, ext));
@@ -3843,7 +3677,7 @@ rpl_make_log_name(const char *opt,
mysql_real_data_home_ptr= mysql_real_data_home;
if (fn_format(buff, base, mysql_real_data_home_ptr, ext, options))
- DBUG_RETURN(my_strdup(buff, MYF(MY_WME)));
+ DBUG_RETURN(my_strdup(key, buff, MYF(MY_WME)));
else
DBUG_RETURN(NULL);
}
@@ -3979,7 +3813,9 @@ static int init_common_variables()
key_BINLOG_COND_relay_log_updated,
key_BINLOG_COND_bin_log_updated,
key_file_binlog,
+ key_file_binlog_cache,
key_file_binlog_index,
+ key_file_binlog_index_cache,
key_BINLOG_COND_queue_busy,
key_LOCK_binlog_end_pos);
#endif
@@ -4309,7 +4145,6 @@ static int init_common_variables()
if (item_create_init())
return 1;
item_init();
- init_pcre();
/*
Process a comma-separated character set list and choose
the first available character set. This is mostly for
@@ -4528,8 +4363,6 @@ static int init_thread_environment()
&LOCK_error_messages, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_uuid_short_generator,
&LOCK_short_uuid_generator, MY_MUTEX_INIT_FAST);
- mysql_mutex_init(key_LOCK_connection_count,
- &LOCK_connection_count, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_thread_id,
&LOCK_thread_id, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_stats, &LOCK_stats, MY_MUTEX_INIT_FAST);
@@ -4716,6 +4549,21 @@ void ssl_acceptor_stats_update(int sslaccept_ret)
static void init_ssl()
{
+/*
+ Not need to check require_secure_transport on the Linux,
+ because it always has Unix domain sockets that are secure:
+*/
+#ifdef _WIN32
+ if (opt_require_secure_transport &&
+ !opt_use_ssl &&
+ !opt_enable_named_pipe &&
+ !opt_bootstrap)
+ {
+ sql_print_error("Server is started with --require-secure-transport=ON "
+ "but no secure transport (SSL or PIPE) are configured.");
+ unireg_abort(1);
+ }
+#endif
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
if (opt_use_ssl)
{
@@ -4916,13 +4764,11 @@ static int init_server_components()
init_thr_lock();
backup_init();
-#ifndef EMBEDDED_LIBRARY
if (init_thr_timer(thread_scheduler->max_threads + extra_max_connections))
{
fprintf(stderr, "Can't initialize timers\n");
unireg_abort(1);
}
-#endif
my_uuid_init((ulong) (my_rnd(&sql_rand))*12345,12345);
wt_init();
@@ -5156,10 +5002,12 @@ static int init_server_components()
}
log_bin_basename=
- rpl_make_log_name(opt_bin_logname, pidfile_name,
+ rpl_make_log_name(key_memory_MYSQL_BIN_LOG_basename,
+ opt_bin_logname, pidfile_name,
opt_bin_logname ? "" : "-bin");
log_bin_index=
- rpl_make_log_name(opt_binlog_index_name, log_bin_basename, ".index");
+ rpl_make_log_name(key_memory_MYSQL_BIN_LOG_index,
+ opt_binlog_index_name, log_bin_basename, ".index");
if (log_bin_basename == NULL || log_bin_index == NULL)
{
sql_print_error("Unable to create replication path names:"
@@ -5177,10 +5025,12 @@ static int init_server_components()
if (opt_relay_logname)
{
relay_log_basename=
- rpl_make_log_name(opt_relay_logname, pidfile_name,
+ rpl_make_log_name(key_memory_MYSQL_RELAY_LOG_basename,
+ opt_relay_logname, pidfile_name,
opt_relay_logname ? "" : "-relay-bin");
relay_log_index=
- rpl_make_log_name(opt_relaylog_index_name, relay_log_basename, ".index");
+ rpl_make_log_name(key_memory_MYSQL_RELAY_LOG_index,
+ opt_relaylog_index_name, relay_log_basename, ".index");
if (relay_log_basename == NULL || relay_log_index == NULL)
{
sql_print_error("Unable to create replication path names:"
@@ -5235,8 +5085,20 @@ static int init_server_components()
if (remaining_argc > 1)
{
int ho_error;
- struct my_option no_opts[]=
+ struct my_option removed_opts[]=
{
+ /* All options in this list are accepted by the server for backwards
+ compatibility, but do not have any effect otherwise, they behave
+ as if supplied with --loose. Whenever a deprecated option is removed
+ it should be appended here. */
+ {"multi-range-count", OPT_DEPRECATED_OPTION, "",
+ 0, 0, 0, GET_NO_ARG, OPT_ARG, 0, 0, 0, 0, 0, 0},
+ {"skip-bdb", OPT_DEPRECATED_OPTION, "",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"thread-concurrency", OPT_DEPRECATED_OPTION, "",
+ 0, 0, 0, GET_NO_ARG, OPT_ARG, 0, 0, 0, 0, 0, 0},
+ {"timed-mutexes", OPT_DEPRECATED_OPTION, "",
+ 0, 0, 0, GET_NO_ARG, OPT_ARG, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
/*
@@ -5245,7 +5107,7 @@ static int init_server_components()
*/
my_getopt_skip_unknown= 0;
- if ((ho_error= handle_options(&remaining_argc, &remaining_argv, no_opts,
+ if ((ho_error= handle_options(&remaining_argc, &remaining_argv, removed_opts,
mysqld_get_one_option)))
unireg_abort(ho_error);
/* Add back the program name handle_options removes */
@@ -5378,7 +5240,7 @@ static int init_server_components()
int error;
mysql_mutex_t *log_lock= mysql_bin_log.get_log_lock();
mysql_mutex_lock(log_lock);
- error= mysql_bin_log.open(opt_bin_logname, LOG_BIN, 0, 0,
+ error= mysql_bin_log.open(opt_bin_logname, 0, 0,
WRITE_CACHE, max_binlog_size, 0, TRUE);
mysql_mutex_unlock(log_lock);
if (unlikely(error))
@@ -5470,13 +5332,13 @@ static void test_lc_time_sz()
for (const char **month= (*loc)->month_names->type_names; *month; month++)
{
set_if_bigger(max_month_len,
- my_numchars_mb(&my_charset_utf8_general_ci,
+ my_numchars_mb(&my_charset_utf8mb3_general_ci,
*month, *month + strlen(*month)));
}
for (const char **day= (*loc)->day_names->type_names; *day; day++)
{
set_if_bigger(max_day_len,
- my_numchars_mb(&my_charset_utf8_general_ci,
+ my_numchars_mb(&my_charset_utf8mb3_general_ci,
*day, *day + strlen(*day)));
}
if ((*loc)->max_month_name_length != max_month_len ||
@@ -5514,10 +5376,10 @@ int mysqld_main(int argc, char **argv)
if (init_early_variables())
exit(1);
-#ifdef HAVE_NPTL
- ld_assume_kernel_is_set= (getenv("LD_ASSUME_KERNEL") != 0);
-#endif
#ifndef _WIN32
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+ pre_initialize_performance_schema();
+#endif /*WITH_PERFSCHEMA_STORAGE_ENGINE */
// For windows, my_init() is called from the win specific mysqld_main
if (my_init()) // init my_sys library & pthreads
{
@@ -5528,16 +5390,15 @@ int mysqld_main(int argc, char **argv)
orig_argc= argc;
orig_argv= argv;
- my_getopt_use_args_separator= TRUE;
+ my_defaults_mark_files= TRUE;
load_defaults_or_exit(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv);
- my_getopt_use_args_separator= FALSE;
defaults_argc= argc;
defaults_argv= argv;
remaining_argc= argc;
remaining_argv= argv;
/* Must be initialized early for comparison of options name */
- system_charset_info= &my_charset_utf8_general_ci;
+ system_charset_info= &my_charset_utf8mb3_general_ci;
sys_var_init();
@@ -5618,6 +5479,7 @@ int mysqld_main(int argc, char **argv)
init_server_psi_keys();
/* Instrument the main thread */
PSI_thread *psi= PSI_CALL_new_thread(key_thread_main, NULL, 0);
+ PSI_CALL_set_thread_os_id(psi);
PSI_CALL_set_thread(psi);
/*
@@ -5680,7 +5542,13 @@ int mysqld_main(int argc, char **argv)
new_thread_stack_size= my_setstacksize(&connection_attrib,
(size_t)my_thread_stack_size);
if (new_thread_stack_size != my_thread_stack_size)
+ {
+ if ((new_thread_stack_size < my_thread_stack_size) &&
+ global_system_variables.log_warnings)
+ sql_print_warning("Asked for %llu thread stack, but got %llu",
+ my_thread_stack_size, new_thread_stack_size);
SYSVAR_AUTOSIZE(my_thread_stack_size, new_thread_stack_size);
+ }
(void) thr_setconcurrency(concurrency); // 10 by default
@@ -5792,6 +5660,7 @@ int mysqld_main(int argc, char **argv)
if (Events::init((THD*) 0, opt_noacl || opt_bootstrap))
unireg_abort(1);
+#ifdef WITH_WSREP
if (WSREP_ON)
{
if (opt_bootstrap)
@@ -5803,14 +5672,15 @@ int mysqld_main(int argc, char **argv)
wsrep_init_globals();
if (!wsrep_before_SE())
{
- wsrep_init_startup (false);
+ wsrep_init_startup(false);
}
-
+ wsrep_new_cluster= false;
WSREP_DEBUG("Startup creating %ld applier threads running %lu",
wsrep_slave_threads - 1, wsrep_running_applier_threads);
wsrep_create_appliers(wsrep_slave_threads - 1);
}
}
+#endif /* WITH_WSREP */
if (opt_bootstrap)
{
@@ -5889,7 +5759,7 @@ int mysqld_main(int argc, char **argv)
mysql_cond_broadcast(&COND_server_started);
mysql_mutex_unlock(&LOCK_server_started);
- MYSQL_SET_STAGE(0 ,__FILE__, __LINE__);
+ (void)MYSQL_SET_STAGE(0 ,__FILE__, __LINE__);
/* Memory used when everything is setup */
start_memory_used= global_status_var.global_memory_used;
@@ -5918,10 +5788,12 @@ int mysqld_main(int argc, char **argv)
{
wsrep_shutdown_replication();
}
+ /* Release threads if they are waiting in WSREP_SYNC_WAIT_UPTO_GTID */
+ wsrep_gtid_server.signal_waiters(0, true);
#endif
close_connections();
-
+ ha_pre_shutdown();
clean_up(1);
sd_notify(0, "STATUS=MariaDB server is down");
@@ -6070,7 +5942,11 @@ int mysqld_main(int argc, char **argv)
"MySQLShutdown"), 10);
/* Must be initialized early for comparison of service name */
- system_charset_info= &my_charset_utf8_general_ci;
+ system_charset_info= &my_charset_utf8mb3_general_ci;
+
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+ pre_initialize_performance_schema();
+#endif /*WITH_PERFSCHEMA_STORAGE_ENGINE */
if (my_init())
{
@@ -6201,8 +6077,7 @@ void inc_thread_created(void)
void handle_connection_in_main_thread(CONNECT *connect)
{
- thread_cache_size= 0; // Safety
- do_handle_one_connection(connect);
+ do_handle_one_connection(connect, false);
}
@@ -6212,37 +6087,32 @@ void handle_connection_in_main_thread(CONNECT *connect)
void create_thread_to_handle_connection(CONNECT *connect)
{
- char error_message_buff[MYSQL_ERRMSG_SIZE];
- int error;
DBUG_ENTER("create_thread_to_handle_connection");
- /* Check if we can get thread from the cache */
- if (cached_thread_count > wake_thread)
+ mysql_mutex_lock(&LOCK_thread_cache);
+ if (cached_thread_count)
{
- mysql_mutex_lock(&LOCK_thread_cache);
- /* Recheck condition when we have the lock */
- if (cached_thread_count > wake_thread)
- {
- /* Get thread from cache */
- thread_cache.push_back(connect);
- wake_thread++;
- mysql_cond_signal(&COND_thread_cache);
- mysql_mutex_unlock(&LOCK_thread_cache);
- DBUG_PRINT("info",("Thread created"));
- DBUG_VOID_RETURN;
- }
+ /* Get thread from cache */
+ thread_cache.push_back(connect);
+ cached_thread_count--;
mysql_mutex_unlock(&LOCK_thread_cache);
+ mysql_cond_signal(&COND_thread_cache);
+ DBUG_PRINT("info",("Thread created"));
+ DBUG_VOID_RETURN;
}
+ mysql_mutex_unlock(&LOCK_thread_cache);
/* Create new thread to handle connection */
inc_thread_created();
DBUG_PRINT("info",(("creating thread %lu"), (ulong) connect->thread_id));
connect->prior_thr_create_utime= microsecond_interval_timer();
- if ((error= mysql_thread_create(key_thread_one_connection,
- &connect->real_id, &connection_attrib,
- handle_one_connection, (void*) connect)))
+ pthread_t tmp;
+ if (auto error= mysql_thread_create(key_thread_one_connection,
+ &tmp, &connection_attrib,
+ handle_one_connection, (void*) connect))
{
+ char error_message_buff[MYSQL_ERRMSG_SIZE];
/* purecov: begin inspected */
DBUG_PRINT("error", ("Can't create thread to handle request (error %d)",
error));
@@ -6279,29 +6149,17 @@ void create_new_thread(CONNECT *connect)
Don't allow too many connections. We roughly check here that we allow
only (max_connections + 1) connections.
*/
-
- mysql_mutex_lock(&LOCK_connection_count);
-
- if (*connect->scheduler->connection_count >=
- *connect->scheduler->max_connections + 1|| abort_loop)
+ if ((*connect->scheduler->connection_count)++ >=
+ *connect->scheduler->max_connections + 1)
{
DBUG_PRINT("error",("Too many connections"));
-
- mysql_mutex_unlock(&LOCK_connection_count);
- statistic_increment(denied_connections, &LOCK_status);
- statistic_increment(connection_errors_max_connection, &LOCK_status);
- connect->close_with_error(0, NullS, abort_loop ? ER_SERVER_SHUTDOWN : ER_CON_COUNT_ERROR);
+ connect->close_with_error(0, NullS, ER_CON_COUNT_ERROR);
DBUG_VOID_RETURN;
}
- ++*connect->scheduler->connection_count;
-
- if (connection_count + extra_connection_count > max_used_connections)
- max_used_connections= connection_count + extra_connection_count;
-
- mysql_mutex_unlock(&LOCK_connection_count);
-
- connect->thread_count_incremented= 1;
+ uint sum= connection_count + extra_connection_count;
+ if (sum > max_used_connections)
+ max_used_connections= sum;
/*
The initialization of thread_id is done in create_embedded_thd() for
@@ -6322,13 +6180,6 @@ void create_new_thread(CONNECT *connect)
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) ||
@@ -6374,53 +6225,46 @@ void handle_accepted_socket(MYSQL_SOCKET new_sock, MYSQL_SOCKET sock)
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)
+ if (auto connect= new CONNECT(new_sock,
+ mysql_socket_getfd(sock) ==
+ mysql_socket_getfd(unix_sock) ?
+ VIO_TYPE_SOCKET : VIO_TYPE_TCPIP,
+ mysql_socket_getfd(sock) ==
+ mysql_socket_getfd(extra_ip_sock) ?
+ extra_thread_scheduler : thread_scheduler))
+ create_new_thread(connect);
+ else
{
/* 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))
+#ifndef _WIN32
+static void set_non_blocking_if_supported(MYSQL_SOCKET sock)
+{
+#if !defined(NO_FCNTL_NONBLOCK)
+ if (!(test_flags & TEST_BLOCKING))
{
- connect->extra_port= 1;
- connect->scheduler= extra_thread_scheduler;
+ int flags= fcntl(mysql_socket_getfd(sock), F_GETFL, 0);
+#if defined(O_NONBLOCK)
+ fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NONBLOCK);
+#elif defined(O_NDELAY)
+ fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NDELAY);
+#endif
}
- create_new_thread(connect);
+#endif
}
-#ifndef _WIN32
+
void handle_connections_sockets()
{
MYSQL_SOCKET sock= mysql_socket_invalid();
- MYSQL_SOCKET new_sock= mysql_socket_invalid();
uint error_count=0;
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;
+ int retval;
#ifdef HAVE_POLL
int socket_count= 0;
struct pollfd fds[3]; // for ip_sock, unix_sock and extra_ip_sock
@@ -6442,16 +6286,16 @@ void handle_connections_sockets()
if (mysql_socket_getfd(base_ip_sock) != INVALID_SOCKET)
{
setup_fds(base_ip_sock);
- ip_flags = fcntl(mysql_socket_getfd(base_ip_sock), F_GETFL, 0);
+ set_non_blocking_if_supported(base_ip_sock);
}
if (mysql_socket_getfd(extra_ip_sock) != INVALID_SOCKET)
{
setup_fds(extra_ip_sock);
- extra_ip_flags = fcntl(mysql_socket_getfd(extra_ip_sock), F_GETFL, 0);
+ set_non_blocking_if_supported(extra_ip_sock);
}
#ifdef HAVE_SYS_UN_H
setup_fds(unix_sock);
- socket_flags=fcntl(mysql_socket_getfd(unix_sock), F_GETFL, 0);
+ set_non_blocking_if_supported(unix_sock);
#endif
sd_notify(0, "READY=1\n"
@@ -6493,79 +6337,44 @@ void handle_connections_sockets()
if (fds[i].revents & POLLIN)
{
sock= pfs_fds[i];
- flags= fcntl(mysql_socket_getfd(sock), F_GETFL, 0);
break;
}
}
#else // HAVE_POLL
if (FD_ISSET(mysql_socket_getfd(base_ip_sock),&readFDs))
- {
sock= base_ip_sock;
- flags= ip_flags;
- }
else
if (FD_ISSET(mysql_socket_getfd(extra_ip_sock),&readFDs))
- {
sock= extra_ip_sock;
- flags= extra_ip_flags;
- }
else
- {
sock = unix_sock;
- flags= socket_flags;
- }
#endif // HAVE_POLL
-#if !defined(NO_FCNTL_NONBLOCK)
- if (!(test_flags & TEST_BLOCKING))
- {
-#if defined(O_NONBLOCK)
- fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NONBLOCK);
-#elif defined(O_NDELAY)
- fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NDELAY);
-#endif
- }
-#endif /* NO_FCNTL_NONBLOCK */
for (uint retry=0; retry < MAX_ACCEPT_RETRY; retry++)
{
size_socket length= sizeof(struct sockaddr_storage);
+ MYSQL_SOCKET new_sock;
+
new_sock= mysql_socket_accept(key_socket_client_connection, sock,
(struct sockaddr *)(&cAddr),
&length);
- if (mysql_socket_getfd(new_sock) != INVALID_SOCKET ||
- (socket_errno != SOCKET_EINTR && socket_errno != SOCKET_EAGAIN))
- break;
-#if !defined(NO_FCNTL_NONBLOCK)
- if (!(test_flags & TEST_BLOCKING))
+ if (mysql_socket_getfd(new_sock) != INVALID_SOCKET)
+ handle_accepted_socket(new_sock, sock);
+ else if (socket_errno != SOCKET_EINTR && socket_errno != SOCKET_EAGAIN)
{
- if (retry == MAX_ACCEPT_RETRY - 1)
- {
- // Try without O_NONBLOCK
- fcntl(mysql_socket_getfd(sock), F_SETFL, flags);
- }
+ /*
+ accept(2) failed on the listening port.
+ There is not much details to report about the client,
+ increment the server global status variable.
+ */
+ statistic_increment(connection_errors_accept, &LOCK_status);
+ if ((error_count++ & 255) == 0) // This can happen often
+ sql_perror("Error in accept");
+ if (socket_errno == SOCKET_ENFILE || socket_errno == SOCKET_EMFILE)
+ sleep(1); // Give other threads some time
+ break;
}
-#endif
- }
-
- if (mysql_socket_getfd(new_sock) == INVALID_SOCKET)
- {
- /*
- accept(2) failed on the listening port, after many retries.
- There is not much details to report about the client,
- increment the server global status variable.
- */
- statistic_increment(connection_errors_accept, &LOCK_status);
- if ((error_count++ & 255) == 0) // This can happen often
- sql_perror("Error in accept");
- if (socket_errno == SOCKET_ENFILE || socket_errno == SOCKET_EMFILE)
- sleep(1); // Give other threads some time
- continue;
}
-#if !defined(NO_FCNTL_NONBLOCK)
- if (!(test_flags & TEST_BLOCKING))
- fcntl(mysql_socket_getfd(sock), F_SETFL, flags);
-#endif
- handle_accepted_socket(new_sock, sock);
}
sd_notify(0, "STOPPING=1\n"
"STATUS=Shutdown in progress\n");
@@ -6598,12 +6407,12 @@ int handle_early_options()
int ho_error;
DYNAMIC_ARRAY all_early_options;
- my_getopt_register_get_addr(NULL);
/* Skip unknown options so that they may be processed later */
my_getopt_skip_unknown= TRUE;
/* prepare all_early_options array */
- my_init_dynamic_array(&all_early_options, sizeof(my_option), 100, 25, MYF(0));
+ my_init_dynamic_array(PSI_NOT_INSTRUMENTED, &all_early_options,
+ sizeof(my_option), 100, 25, MYF(0));
add_many_options(&all_early_options, pfs_early_options,
array_elements(pfs_early_options));
sys_var_add_options(&all_early_options, sys_var::PARSE_EARLY);
@@ -6637,6 +6446,10 @@ int handle_early_options()
{ option, OPT_MYSQL_COMPATIBILITY, \
0, 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0 }
+#define MARIADB_REMOVED_OPTION(option) \
+ { option, OPT_REMOVED_OPTION, \
+ 0, 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0 }
+
/**
System variables are automatically command-line options (few
@@ -6976,9 +6789,6 @@ struct my_option my_long_options[]=
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"silent-startup", OPT_SILENT, "Don't print [Note] to the error log during startup.",
&opt_silent_startup, &opt_silent_startup, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"skip-bdb", OPT_DEPRECATED_OPTION,
- "Deprecated option; Exist only for compatibility with old my.cnf files",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifndef DISABLE_GRANT_OPTIONS
{"skip-grant-tables", 0,
"Start without grant tables. This gives all users FULL ACCESS to all tables.",
@@ -7296,16 +7106,6 @@ static int show_table_definitions(THD *thd, SHOW_VAR *var, char *buff,
}
-static int show_flush_commands(THD *thd, SHOW_VAR *var, char *buff,
- enum enum_var_type scope)
-{
- var->type= SHOW_LONGLONG;
- var->value= buff;
- *((longlong *) buff)= (longlong)tdc_refresh_version();
- return 0;
-}
-
-
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
/*
@@ -7615,7 +7415,7 @@ static int debug_status_func(THD *thd, SHOW_VAR *var, char *buff,
#endif
#ifdef HAVE_POOL_OF_THREADS
-int show_threadpool_idle_threads(THD *thd, SHOW_VAR *var, char *buff,
+static int show_threadpool_idle_threads(THD *thd, SHOW_VAR *var, char *buff,
enum enum_var_type scope)
{
var->type= SHOW_INT;
@@ -7674,6 +7474,7 @@ SHOW_VAR status_vars[]= {
{"Feature_dynamic_columns", (char*) offsetof(STATUS_VAR, feature_dynamic_columns), SHOW_LONG_STATUS},
{"Feature_fulltext", (char*) offsetof(STATUS_VAR, feature_fulltext), SHOW_LONG_STATUS},
{"Feature_gis", (char*) offsetof(STATUS_VAR, feature_gis), SHOW_LONG_STATUS},
+ {"Feature_insert_returning", (char*)offsetof(STATUS_VAR, feature_insert_returning), SHOW_LONG_STATUS},
{"Feature_invisible_columns", (char*) offsetof(STATUS_VAR, feature_invisible_columns), SHOW_LONG_STATUS},
{"Feature_json", (char*) offsetof(STATUS_VAR, feature_json), SHOW_LONG_STATUS},
{"Feature_locale", (char*) offsetof(STATUS_VAR, feature_locale), SHOW_LONG_STATUS},
@@ -7684,7 +7485,6 @@ SHOW_VAR status_vars[]= {
{"Feature_trigger", (char*) offsetof(STATUS_VAR, feature_trigger), SHOW_LONG_STATUS},
{"Feature_window_functions", (char*) offsetof(STATUS_VAR, feature_window_functions), SHOW_LONG_STATUS},
{"Feature_xml", (char*) offsetof(STATUS_VAR, feature_xml), SHOW_LONG_STATUS},
- {"Flush_commands", (char*) &show_flush_commands, SHOW_SIMPLE_FUNC},
{"Handler_commit", (char*) offsetof(STATUS_VAR, ha_commit_count), SHOW_LONG_STATUS},
{"Handler_delete", (char*) offsetof(STATUS_VAR, ha_delete_count), SHOW_LONG_STATUS},
{"Handler_discover", (char*) offsetof(STATUS_VAR, ha_discover_count), SHOW_LONG_STATUS},
@@ -7931,7 +7731,7 @@ static int option_cmp(my_option *a, my_option *b)
static void print_help()
{
MEM_ROOT mem_root;
- init_alloc_root(&mem_root, "help", 4096, 4096, MYF(0));
+ init_alloc_root(PSI_NOT_INSTRUMENTED, &mem_root, 4096, 4096, MYF(0));
pop_dynamic(&all_options);
add_many_options(&all_options, pfs_early_options,
@@ -8038,8 +7838,8 @@ static int mysql_init_variables(void)
disable_log_notes= 0;
mqh_used= 0;
cleanup_done= 0;
- select_errors= dropping_tables= ha_open_options=0;
- thread_count= kill_cached_threads= wake_thread= 0;
+ test_flags= select_errors= dropping_tables= ha_open_options=0;
+ thread_count= kill_cached_threads= 0;
slave_open_temp_tables= 0;
cached_thread_count= 0;
opt_endinfo= using_udf_functions= 0;
@@ -8068,9 +7868,9 @@ static int mysql_init_variables(void)
key_map_full.set_all();
/* Character sets */
- system_charset_info= &my_charset_utf8_general_ci;
- files_charset_info= &my_charset_utf8_general_ci;
- national_charset_info= &my_charset_utf8_general_ci;
+ system_charset_info= &my_charset_utf8mb3_general_ci;
+ files_charset_info= &my_charset_utf8mb3_general_ci;
+ national_charset_info= &my_charset_utf8mb3_general_ci;
table_alias_charset= &my_charset_bin;
character_set_filesystem= &my_charset_bin;
@@ -8224,7 +8024,8 @@ static int mysql_init_variables(void)
}
my_bool
-mysqld_get_one_option(int optid, const struct my_option *opt, char *argument)
+mysqld_get_one_option(const struct my_option *opt, char *argument,
+ const char *filename)
{
if (opt->app_type)
{
@@ -8234,10 +8035,16 @@ mysqld_get_one_option(int optid, const struct my_option *opt, char *argument)
var->value_origin= sys_var::AUTO;
return 0;
}
- var->value_origin= sys_var::CONFIG;
+ if (*filename)
+ {
+ var->origin_filename= filename;
+ var->value_origin= sys_var::CONFIG;
+ }
+ else
+ var->value_origin= sys_var::COMMAND_LINE;
}
- switch(optid) {
+ switch(opt->id) {
case '#':
#ifndef DBUG_OFF
if (!argument)
@@ -8262,6 +8069,8 @@ mysqld_get_one_option(int optid, const struct my_option *opt, char *argument)
"for compatibility with old my.cnf files.",
opt->name);
break;
+ case OPT_REMOVED_OPTION:
+ break;
case OPT_MYSQL_COMPATIBILITY:
sql_print_warning("'%s' is MySQL 5.6 / 5.7 compatible option. Not used or "
"needed in MariaDB.", opt->name);
@@ -8562,9 +8371,6 @@ mysqld_get_one_option(int optid, const struct my_option *opt, char *argument)
case OPT_PLUGIN_LOAD_ADD:
opt_plugin_load_list_ptr->push_back(new i_string(argument));
break;
- case OPT_MAX_LONG_DATA_SIZE:
- max_long_data_size_used= true;
- break;
case OPT_PFS_INSTRUMENT:
{
#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
@@ -8776,13 +8582,12 @@ static int get_options(int *argc_ptr, char ***argv_ptr)
{
int ho_error;
- my_getopt_register_get_addr(mysql_getopt_value);
+ my_getopt_get_addr= mysql_getopt_value;
my_getopt_error_reporter= option_error_reporter;
/* prepare all_options array */
- my_init_dynamic_array(&all_options, sizeof(my_option),
- array_elements(my_long_options) +
- sys_var_elements(),
+ my_init_dynamic_array(PSI_INSTRUMENT_ME, &all_options, sizeof(my_option),
+ array_elements(my_long_options) + sys_var_elements(),
array_elements(my_long_options)/4, MYF(0));
add_many_options(&all_options, my_long_options, array_elements(my_long_options));
sys_var_add_options(&all_options, 0);
@@ -8980,14 +8785,6 @@ static int get_options(int *argc_ptr, char ***argv_ptr)
opt_readonly= read_only;
- /*
- If max_long_data_size is not specified explicitly use
- value of max_allowed_packet.
- */
- if (!max_long_data_size_used)
- SYSVAR_AUTOSIZE(max_long_data_size,
- global_system_variables.max_allowed_packet);
-
/* Remember if max_user_connections was 0 at startup */
max_user_connections_checking= global_system_variables.max_user_connections != 0;
@@ -9127,11 +8924,10 @@ bool is_secure_file_path(char *path)
}
else
{
- if (files_charset_info->coll->strnncoll(files_charset_info,
- (uchar *) buff2, strlen(buff2),
- (uchar *) opt_secure_file_priv,
- opt_secure_file_priv_len,
- TRUE))
+ if (files_charset_info->strnncoll(buff2, strlen(buff2),
+ opt_secure_file_priv,
+ opt_secure_file_priv_len,
+ TRUE))
return FALSE;
}
return TRUE;
@@ -9222,7 +9018,7 @@ static int fix_paths(void)
sql_print_warning("Failed to normalize the argument for --secure-file-priv.");
DBUG_RETURN(1);
}
- char *secure_file_real_path= (char *)my_malloc(FN_REFLEN, MYF(MY_FAE));
+ char *secure_file_real_path= (char *)my_malloc(PSI_INSTRUMENT_ME, FN_REFLEN, MYF(MY_FAE));
convert_dirname(secure_file_real_path, buff, NullS);
my_free(opt_secure_file_priv);
opt_secure_file_priv= secure_file_real_path;
@@ -9323,6 +9119,11 @@ void refresh_status(THD *thd)
{
mysql_mutex_lock(&LOCK_status);
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+ /* Reset aggregated status counters. */
+ reset_pfs_status_stats();
+#endif
+
/* Add thread's status variabes to global status */
add_to_status(&global_status_var, &thd->status_var);
@@ -9360,9 +9161,14 @@ static PSI_file_info all_server_files[]=
{ &key_file_map, "map", 0},
#endif /* HAVE_MMAP */
{ &key_file_binlog, "binlog", 0},
+ { &key_file_binlog_cache, "binlog_cache", 0},
{ &key_file_binlog_index, "binlog_index", 0},
+ { &key_file_binlog_index_cache, "binlog_index_cache", 0},
{ &key_file_relaylog, "relaylog", 0},
+ { &key_file_relaylog_cache, "relaylog_cache", 0},
{ &key_file_relaylog_index, "relaylog_index", 0},
+ { &key_file_relaylog_index_cache, "relaylog_index_cache", 0},
+ { &key_file_io_cache, "io_cache", 0},
{ &key_file_casetest, "casetest", 0},
{ &key_file_dbopt, "dbopt", 0},
{ &key_file_des_key_file, "des_key_file", 0},
@@ -9377,7 +9183,7 @@ static PSI_file_info all_server_files[]=
{ &key_file_log_event_info, "log_event_info", 0},
{ &key_file_master_info, "master_info", 0},
{ &key_file_misc, "misc", 0},
- { &key_file_partition, "partition", 0},
+ { &key_file_partition_ddl_log, "partition_ddl_log", 0},
{ &key_file_pid, "pid", 0},
{ &key_file_query_log, "query_log", 0},
{ &key_file_relay_log_info, "relay_log_info", 0},
@@ -9396,25 +9202,25 @@ PSI_stage_info stage_after_create= { 0, "After create", 0};
PSI_stage_info stage_after_opening_tables= { 0, "After opening tables", 0};
PSI_stage_info stage_after_table_lock= { 0, "After table lock", 0};
PSI_stage_info stage_allocating_local_table= { 0, "Allocating local table", 0};
-PSI_stage_info stage_alter_inplace_prepare= { 0, "Preparing for alter table", 0};
-PSI_stage_info stage_alter_inplace= { 0, "Altering table", 0};
+PSI_stage_info stage_alter_inplace_prepare= { 0, "preparing for alter table", 0};
+PSI_stage_info stage_alter_inplace= { 0, "altering table", 0};
PSI_stage_info stage_alter_inplace_commit= { 0, "Committing alter table to storage engine", 0};
PSI_stage_info stage_apply_event= { 0, "Apply log event", 0};
PSI_stage_info stage_changing_master= { 0, "Changing master", 0};
PSI_stage_info stage_checking_master_version= { 0, "Checking master version", 0};
-PSI_stage_info stage_checking_permissions= { 0, "Checking permissions", 0};
-PSI_stage_info stage_checking_privileges_on_cached_query= { 0, "Checking privileges on cached query", 0};
+PSI_stage_info stage_checking_permissions= { 0, "checking permissions", 0};
+PSI_stage_info stage_checking_privileges_on_cached_query= { 0, "checking privileges on cached query", 0};
PSI_stage_info stage_checking_query_cache_for_query= { 0, "Checking query cache for query", 0};
PSI_stage_info stage_cleaning_up= { 0, "Reset for next command", 0};
-PSI_stage_info stage_closing_tables= { 0, "Closing tables", 0};
+PSI_stage_info stage_closing_tables= { 0, "closing tables", 0};
PSI_stage_info stage_connecting_to_master= { 0, "Connecting to master", 0};
PSI_stage_info stage_converting_heap_to_myisam= { 0, "Converting HEAP to " TMP_ENGINE_NAME, 0};
PSI_stage_info stage_copying_to_group_table= { 0, "Copying to group table", 0};
PSI_stage_info stage_copying_to_tmp_table= { 0, "Copying to tmp table", 0};
-PSI_stage_info stage_copy_to_tmp_table= { 0, "Copy to tmp table", 0};
+PSI_stage_info stage_copy_to_tmp_table= { 0, "copy to tmp table", PSI_FLAG_STAGE_PROGRESS};
PSI_stage_info stage_creating_delayed_handler= { 0, "Creating delayed handler", 0};
PSI_stage_info stage_creating_sort_index= { 0, "Creating sort index", 0};
-PSI_stage_info stage_creating_table= { 0, "Creating table", 0};
+PSI_stage_info stage_creating_table= { 0, "creating table", 0};
PSI_stage_info stage_creating_tmp_table= { 0, "Creating tmp table", 0};
PSI_stage_info stage_deleting_from_main_table= { 0, "Deleting from main table", 0};
PSI_stage_info stage_deleting_from_reference_tables= { 0, "Deleting from reference tables", 0};
@@ -9432,17 +9238,17 @@ PSI_stage_info stage_freeing_items= { 0, "Freeing items", 0};
PSI_stage_info stage_fulltext_initialization= { 0, "Fulltext initialization", 0};
PSI_stage_info stage_got_handler_lock= { 0, "Got handler lock", 0};
PSI_stage_info stage_got_old_table= { 0, "Got old table", 0};
-PSI_stage_info stage_init= { 0, "Init", 0};
-PSI_stage_info stage_init_update= { 0, "Init for update", 0};
+PSI_stage_info stage_init= { 0, "init", 0};
+PSI_stage_info stage_init_update= { 0, "init for update", 0};
PSI_stage_info stage_insert= { 0, "Insert", 0};
PSI_stage_info stage_invalidating_query_cache_entries_table= { 0, "Invalidating query cache entries (table)", 0};
PSI_stage_info stage_invalidating_query_cache_entries_table_list= { 0, "Invalidating query cache entries (table list)", 0};
PSI_stage_info stage_killing_slave= { 0, "Killing slave", 0};
PSI_stage_info stage_logging_slow_query= { 0, "Logging slow query", 0};
-PSI_stage_info stage_making_temp_file_append_before_load_data= { 0, "Making temporary file (append) before replaying LOAD DATA INFILE.", 0};
-PSI_stage_info stage_making_temp_file_create_before_load_data= { 0, "Making temporary file (create) before replaying LOAD DATA INFILE.", 0};
+PSI_stage_info stage_making_temp_file_append_before_load_data= { 0, "Making temporary file (append) before replaying LOAD DATA INFILE", 0};
+PSI_stage_info stage_making_temp_file_create_before_load_data= { 0, "Making temporary file (create) before replaying LOAD DATA INFILE", 0};
PSI_stage_info stage_manage_keys= { 0, "Manage keys", 0};
-PSI_stage_info stage_master_has_sent_all_binlog_to_slave= { 0, "Master has sent all binlog to slave; waiting for binlog to be updated", 0};
+PSI_stage_info stage_master_has_sent_all_binlog_to_slave= { 0, "Master has sent all binlog to slave; waiting for more updates", 0};
PSI_stage_info stage_opening_tables= { 0, "Opening tables", 0};
PSI_stage_info stage_optimizing= { 0, "Optimizing", 0};
PSI_stage_info stage_preparing= { 0, "Preparing", 0};
@@ -9452,7 +9258,7 @@ PSI_stage_info stage_starting_cleanup= { 0, "Starting cleanup", 0};
PSI_stage_info stage_rollback= { 0, "Rollback", 0};
PSI_stage_info stage_rollback_implicit= { 0, "Rollback_implicit", 0};
PSI_stage_info stage_commit= { 0, "Commit", 0};
-PSI_stage_info stage_commit_implicit= { 0, "Commit_implicit", 0};
+PSI_stage_info stage_commit_implicit= { 0, "Commit implicit", 0};
PSI_stage_info stage_queueing_master_event_to_the_relay_log= { 0, "Queueing master event to the relay log", 0};
PSI_stage_info stage_reading_event_from_the_relay_log= { 0, "Reading event from the relay log", 0};
PSI_stage_info stage_recreating_table= { 0, "Recreating table", 0};
@@ -9467,9 +9273,9 @@ PSI_stage_info stage_searching_rows_for_update= { 0, "Searching rows for update"
PSI_stage_info stage_sending_binlog_event_to_slave= { 0, "Sending binlog event to slave", 0};
PSI_stage_info stage_sending_cached_result_to_client= { 0, "Sending cached result to client", 0};
PSI_stage_info stage_sending_data= { 0, "Sending data", 0};
-PSI_stage_info stage_setup= { 0, "Setup", 0};
+PSI_stage_info stage_setup= { 0, "setup", 0};
PSI_stage_info stage_show_explain= { 0, "Show explain", 0};
-PSI_stage_info stage_slave_has_read_all_relay_log= { 0, "Slave has read all relay log; waiting for the slave I/O thread to update it", 0};
+PSI_stage_info stage_slave_has_read_all_relay_log= { 0, "Slave has read all relay log; waiting for more updates", 0};
PSI_stage_info stage_sorting= { 0, "Sorting", 0};
PSI_stage_info stage_sorting_for_group= { 0, "Sorting for group", 0};
PSI_stage_info stage_sorting_for_order= { 0, "Sorting for order", 0};
@@ -9480,7 +9286,7 @@ PSI_stage_info stage_storing_result_in_query_cache= { 0, "Storing result in quer
PSI_stage_info stage_storing_row_into_queue= { 0, "Storing row into queue", 0};
PSI_stage_info stage_system_lock= { 0, "System lock", 0};
PSI_stage_info stage_unlocking_tables= { 0, "Unlocking tables", 0};
-PSI_stage_info stage_table_lock= { 0, "Table lock", 0};
+PSI_stage_info stage_table_lock= { 0, "table lock", 0};
PSI_stage_info stage_filling_schema_table= { 0, "Filling schema table", 0};
PSI_stage_info stage_update= { 0, "Update", 0};
PSI_stage_info stage_updating= { 0, "Updating", 0};
@@ -9510,14 +9316,13 @@ PSI_stage_info stage_waiting_for_query_cache_lock= { 0, "Waiting for query cache
PSI_stage_info stage_waiting_for_the_next_event_in_relay_log= { 0, "Waiting for the next event in relay log", 0};
PSI_stage_info stage_waiting_for_the_slave_thread_to_advance_position= { 0, "Waiting for the slave SQL thread to advance position", 0};
PSI_stage_info stage_waiting_to_finalize_termination= { 0, "Waiting to finalize termination", 0};
-PSI_stage_info stage_waiting_to_get_readlock= { 0, "Waiting to get readlock", 0};
PSI_stage_info stage_binlog_waiting_background_tasks= { 0, "Waiting for background binlog tasks", 0};
PSI_stage_info stage_binlog_write= { 0, "Writing to binlog", 0};
PSI_stage_info stage_binlog_processing_checkpoint_notify= { 0, "Processing binlog checkpoint notification", 0};
PSI_stage_info stage_binlog_stopping_background_thread= { 0, "Stopping binlog background thread", 0};
PSI_stage_info stage_waiting_for_work_from_sql_thread= { 0, "Waiting for work from SQL thread", 0};
PSI_stage_info stage_waiting_for_prior_transaction_to_commit= { 0, "Waiting for prior transaction to commit", 0};
-PSI_stage_info stage_waiting_for_prior_transaction_to_start_commit= { 0, "Waiting for prior transaction to start commit before starting next transaction", 0};
+PSI_stage_info stage_waiting_for_prior_transaction_to_start_commit= { 0, "Waiting for prior transaction to start commit", 0};
PSI_stage_info stage_waiting_for_room_in_worker_thread= { 0, "Waiting for room in worker thread event queue", 0};
PSI_stage_info stage_waiting_for_workers_idle= { 0, "Waiting for worker threads to be idle", 0};
PSI_stage_info stage_waiting_for_ftwrl= { 0, "Waiting due to global read lock", 0};
@@ -9525,10 +9330,92 @@ PSI_stage_info stage_waiting_for_ftwrl_threads_to_pause= { 0, "Waiting for worke
PSI_stage_info stage_waiting_for_rpl_thread_pool= { 0, "Waiting while replication worker thread pool is busy", 0};
PSI_stage_info stage_master_gtid_wait_primary= { 0, "Waiting in MASTER_GTID_WAIT() (primary waiter)", 0};
PSI_stage_info stage_master_gtid_wait= { 0, "Waiting in MASTER_GTID_WAIT()", 0};
-PSI_stage_info stage_gtid_wait_other_connection= { 0, "Waiting for other master connection to process GTID received on multiple master connections", 0};
+PSI_stage_info stage_gtid_wait_other_connection= { 0, "Waiting for other master connection to process the same GTID", 0};
PSI_stage_info stage_slave_background_process_request= { 0, "Processing requests", 0};
PSI_stage_info stage_slave_background_wait_request= { 0, "Waiting for requests", 0};
PSI_stage_info stage_waiting_for_deadlock_kill= { 0, "Waiting for parallel replication deadlock handling to complete", 0};
+PSI_stage_info stage_starting= { 0, "starting", 0};
+
+PSI_memory_key key_memory_DATE_TIME_FORMAT;
+PSI_memory_key key_memory_DDL_LOG_MEMORY_ENTRY;
+PSI_memory_key key_memory_Event_queue_element_for_exec_names;
+PSI_memory_key key_memory_Event_scheduler_scheduler_param;
+PSI_memory_key key_memory_Filesort_info_merge;
+PSI_memory_key key_memory_Filesort_info_record_pointers;
+PSI_memory_key key_memory_Gis_read_stream_err_msg;
+PSI_memory_key key_memory_JOIN_CACHE;
+PSI_memory_key key_memory_MPVIO_EXT_auth_info;
+PSI_memory_key key_memory_MYSQL_BIN_LOG_basename;
+PSI_memory_key key_memory_MYSQL_BIN_LOG_index;
+PSI_memory_key key_memory_MYSQL_LOCK;
+PSI_memory_key key_memory_MYSQL_LOG_name;
+PSI_memory_key key_memory_MYSQL_RELAY_LOG_basename;
+PSI_memory_key key_memory_MYSQL_RELAY_LOG_index;
+PSI_memory_key key_memory_NAMED_ILINK_name;
+PSI_memory_key key_memory_PROFILE;
+PSI_memory_key key_memory_QUICK_RANGE_SELECT_mrr_buf_desc;
+PSI_memory_key key_memory_Query_cache;
+PSI_memory_key key_memory_Relay_log_info_group_relay_log_name;
+PSI_memory_key key_memory_Row_data_memory_memory;
+PSI_memory_key key_memory_Rpl_info_file_buffer;
+PSI_memory_key key_memory_SLAVE_INFO;
+PSI_memory_key key_memory_ST_SCHEMA_TABLE;
+PSI_memory_key key_memory_Sort_param_tmp_buffer;
+PSI_memory_key key_memory_Sys_var_charptr_value;
+PSI_memory_key key_memory_TABLE;
+PSI_memory_key key_memory_TABLE_RULE_ENT;
+PSI_memory_key key_memory_TC_LOG_MMAP_pages;
+PSI_memory_key key_memory_THD_db;
+PSI_memory_key key_memory_THD_handler_tables_hash;
+PSI_memory_key key_memory_THD_variables;
+PSI_memory_key key_memory_Table_trigger_dispatcher;
+PSI_memory_key key_memory_Unique_merge_buffer;
+PSI_memory_key key_memory_Unique_sort_buffer;
+PSI_memory_key key_memory_User_level_lock;
+PSI_memory_key key_memory_XID;
+PSI_memory_key key_memory_acl_cache;
+PSI_memory_key key_memory_acl_mem;
+PSI_memory_key key_memory_acl_memex;
+PSI_memory_key key_memory_binlog_cache_mngr;
+PSI_memory_key key_memory_binlog_pos;
+PSI_memory_key key_memory_binlog_recover_exec;
+PSI_memory_key key_memory_binlog_statement_buffer;
+PSI_memory_key key_memory_binlog_ver_1_event;
+PSI_memory_key key_memory_bison_stack;
+PSI_memory_key key_memory_blob_mem_storage;
+PSI_memory_key key_memory_dboptions_hash;
+PSI_memory_key key_memory_errmsgs;
+PSI_memory_key key_memory_frm_string;
+PSI_memory_key key_memory_gdl;
+PSI_memory_key key_memory_global_system_variables;
+PSI_memory_key key_memory_handler_errmsgs;
+PSI_memory_key key_memory_handlerton;
+PSI_memory_key key_memory_hash_index_key_buffer;
+PSI_memory_key key_memory_host_cache_hostname;
+PSI_memory_key key_memory_ignored_db;
+PSI_memory_key key_memory_locked_table_list;
+PSI_memory_key key_memory_locked_thread_list;
+PSI_memory_key key_memory_my_str_malloc;
+PSI_memory_key key_memory_native_functions;
+PSI_memory_key key_memory_prepared_statement_main_mem_root;
+PSI_memory_key key_memory_prepared_statement_map;
+PSI_memory_key key_memory_queue_item;
+PSI_memory_key key_memory_quick_range_select_root;
+PSI_memory_key key_memory_rpl_filter;
+PSI_memory_key key_memory_sp_cache;
+PSI_memory_key key_memory_sp_head_call_root;
+PSI_memory_key key_memory_sp_head_execute_root;
+PSI_memory_key key_memory_sp_head_main_root;
+PSI_memory_key key_memory_table_mapping_root;
+PSI_memory_key key_memory_table_share;
+PSI_memory_key key_memory_table_triggers_list;
+PSI_memory_key key_memory_thd_main_mem_root;
+PSI_memory_key key_memory_thd_transactions;
+PSI_memory_key key_memory_user_conn;
+PSI_memory_key key_memory_user_var_entry;
+PSI_memory_key key_memory_user_var_entry_value;
+
+PSI_memory_key key_memory_String_value;
#ifdef HAVE_PSI_INTERFACE
@@ -9657,7 +9544,6 @@ PSI_stage_info *all_server_stages[]=
& stage_waiting_for_the_slave_thread_to_advance_position,
& stage_waiting_for_work_from_sql_thread,
& stage_waiting_to_finalize_termination,
- & stage_waiting_to_get_readlock,
& stage_master_gtid_wait_primary,
& stage_master_gtid_wait,
& stage_gtid_wait_other_connection,
@@ -9666,7 +9552,8 @@ PSI_stage_info *all_server_stages[]=
& stage_waiting_for_semi_sync_ack_from_slave,
& stage_waiting_for_semi_sync_slave,
& stage_reading_semi_sync_ack,
- & stage_waiting_for_deadlock_kill
+ & stage_waiting_for_deadlock_kill,
+ & stage_starting
};
PSI_socket_key key_socket_tcpip, key_socket_unix, key_socket_client_connection;
@@ -9678,6 +9565,145 @@ static PSI_socket_info all_server_sockets[]=
{ &key_socket_client_connection, "client_connection", 0}
};
+static PSI_memory_info all_server_memory[]=
+{
+ { &key_memory_locked_table_list, "Locked_tables_list::m_locked_tables_root", 0},
+ { &key_memory_locked_thread_list, "display_table_locks", PSI_FLAG_THREAD},
+ { &key_memory_thd_transactions, "THD::transactions::mem_root", PSI_FLAG_THREAD},
+// { &key_memory_delegate, "Delegate::memroot", 0},
+ { &key_memory_acl_mem, "sql_acl_mem", PSI_FLAG_GLOBAL},
+ { &key_memory_acl_memex, "sql_acl_memex", PSI_FLAG_GLOBAL},
+ { &key_memory_acl_cache, "acl_cache", PSI_FLAG_GLOBAL},
+ { &key_memory_thd_main_mem_root, "thd::main_mem_root", PSI_FLAG_THREAD},
+// { &key_memory_help, "help", 0},
+// { &key_memory_new_frm_mem, "new_frm_mem", 0},
+ { &key_memory_table_share, "TABLE_SHARE::mem_root", PSI_FLAG_GLOBAL}, /* table definition cache */
+ { &key_memory_gdl, "gdl", 0},
+ { &key_memory_table_triggers_list, "Table_triggers_list", 0},
+// { &key_memory_servers, "servers", 0},
+ { &key_memory_prepared_statement_map, "Prepared_statement_map", PSI_FLAG_THREAD},
+ { &key_memory_prepared_statement_main_mem_root, "Prepared_statement::main_mem_root", PSI_FLAG_THREAD},
+// { &key_memory_protocol_rset_root, "Protocol_local::m_rset_root", PSI_FLAG_THREAD},
+// { &key_memory_warning_info_warn_root, "Warning_info::m_warn_root", PSI_FLAG_THREAD},
+ { &key_memory_sp_cache, "THD::sp_cache", 0},
+ { &key_memory_sp_head_main_root, "sp_head::main_mem_root", 0},
+ { &key_memory_sp_head_execute_root, "sp_head::execute_mem_root", PSI_FLAG_THREAD},
+ { &key_memory_sp_head_call_root, "sp_head::call_mem_root", PSI_FLAG_THREAD},
+ { &key_memory_table_mapping_root, "table_mapping::m_mem_root", 0},
+ { &key_memory_quick_range_select_root, "QUICK_RANGE_SELECT::alloc", PSI_FLAG_THREAD},
+// { &key_memory_quick_index_merge_root, "QUICK_INDEX_MERGE_SELECT::alloc", PSI_FLAG_THREAD},
+// { &key_memory_quick_ror_intersect_select_root, "QUICK_ROR_INTERSECT_SELECT::alloc", PSI_FLAG_THREAD},
+// { &key_memory_quick_ror_union_select_root, "QUICK_ROR_UNION_SELECT::alloc", PSI_FLAG_THREAD},
+// { &key_memory_quick_group_min_max_select_root, "QUICK_GROUP_MIN_MAX_SELECT::alloc", PSI_FLAG_THREAD},
+// { &key_memory_test_quick_select_exec, "test_quick_select", PSI_FLAG_THREAD},
+// { &key_memory_prune_partitions_exec, "prune_partitions::exec", 0},
+ { &key_memory_binlog_recover_exec, "MYSQL_BIN_LOG::recover", 0},
+ { &key_memory_blob_mem_storage, "Blob_mem_storage::storage", 0},
+ { &key_memory_NAMED_ILINK_name, "NAMED_ILINK::name", 0},
+ { &key_memory_String_value, "String::value", 0},
+ { &key_memory_Sys_var_charptr_value, "Sys_var_charptr::value", 0},
+ { &key_memory_queue_item, "Queue::queue_item", 0},
+ { &key_memory_THD_db, "THD::db", 0},
+ { &key_memory_user_var_entry, "user_var_entry", 0},
+// { &key_memory_Slave_job_group_group_relay_log_name, "Slave_job_group::group_relay_log_name", 0},
+ { &key_memory_Relay_log_info_group_relay_log_name, "Relay_log_info::group_relay_log_name", 0},
+ { &key_memory_binlog_cache_mngr, "binlog_cache_mngr", 0},
+ { &key_memory_Row_data_memory_memory, "Row_data_memory::memory", 0},
+// { &key_memory_Gtid_set_to_string, "Gtid_set::to_string", 0},
+// { &key_memory_Gtid_state_to_string, "Gtid_state::to_string", 0},
+// { &key_memory_Owned_gtids_to_string, "Owned_gtids::to_string", 0},
+// { &key_memory_log_event, "Log_event", 0},
+// { &key_memory_Incident_log_event_message, "Incident_log_event::message", 0},
+// { &key_memory_Rows_query_log_event_rows_query, "Rows_query_log_event::rows_query", 0},
+ { &key_memory_Sort_param_tmp_buffer, "Sort_param::tmp_buffer", 0},
+ { &key_memory_Filesort_info_merge, "Filesort_info::merge", 0},
+ { &key_memory_Filesort_info_record_pointers, "Filesort_info::record_pointers", 0},
+// { &key_memory_Filesort_buffer_sort_keys, "Filesort_buffer::sort_keys", 0},
+ { &key_memory_handler_errmsgs, "handler::errmsgs", 0},
+ { &key_memory_handlerton, "handlerton", 0},
+ { &key_memory_XID, "XID", 0},
+ { &key_memory_host_cache_hostname, "host_cache::hostname", 0},
+ { &key_memory_user_var_entry_value, "user_var_entry::value", 0},
+ { &key_memory_User_level_lock, "User_level_lock", 0},
+ { &key_memory_MYSQL_LOG_name, "MYSQL_LOG::name", 0},
+ { &key_memory_TC_LOG_MMAP_pages, "TC_LOG_MMAP::pages", 0},
+// { &key_memory_my_bitmap_map, "my_bitmap_map", 0},
+ { &key_memory_QUICK_RANGE_SELECT_mrr_buf_desc, "QUICK_RANGE_SELECT::mrr_buf_desc", 0},
+ { &key_memory_Event_queue_element_for_exec_names, "Event_queue_element_for_exec::names", 0},
+ { &key_memory_my_str_malloc, "my_str_malloc", 0},
+ { &key_memory_MYSQL_BIN_LOG_basename, "MYSQL_BIN_LOG::basename", 0},
+ { &key_memory_MYSQL_BIN_LOG_index, "MYSQL_BIN_LOG::index", 0},
+ { &key_memory_MYSQL_RELAY_LOG_basename, "MYSQL_RELAY_LOG::basename", 0},
+ { &key_memory_MYSQL_RELAY_LOG_index, "MYSQL_RELAY_LOG::index", 0},
+ { &key_memory_rpl_filter, "rpl_filter memory", 0},
+ { &key_memory_errmsgs, "errmsgs", 0},
+ { &key_memory_Gis_read_stream_err_msg, "Gis_read_stream::err_msg", 0},
+// { &key_memory_Geometry_objects_data, "Geometry::ptr_and_wkb_data", 0},
+ { &key_memory_MYSQL_LOCK, "MYSQL_LOCK", 0},
+// { &key_memory_NET_buff, "NET::buff", 0},
+// { &key_memory_NET_compress_packet, "NET::compress_packet", 0},
+ { &key_memory_Event_scheduler_scheduler_param, "Event_scheduler::scheduler_param", 0},
+// { &key_memory_Gtid_set_Interval_chunk, "Gtid_set::Interval_chunk", 0},
+// { &key_memory_Owned_gtids_sidno_to_hash, "Owned_gtids::sidno_to_hash", 0},
+// { &key_memory_Sid_map_Node, "Sid_map::Node", 0},
+// { &key_memory_Gtid_state_group_commit_sidno, "Gtid_state::group_commit_sidno_locks", 0},
+// { &key_memory_Mutex_cond_array_Mutex_cond, "Mutex_cond_array::Mutex_cond", 0},
+ { &key_memory_TABLE_RULE_ENT, "TABLE_RULE_ENT", 0},
+// { &key_memory_Rpl_info_table, "Rpl_info_table", 0},
+ { &key_memory_Rpl_info_file_buffer, "Rpl_info_file::buffer", 0},
+// { &key_memory_db_worker_hash_entry, "db_worker_hash_entry", 0},
+// { &key_memory_rpl_slave_check_temp_dir, "rpl_slave::check_temp_dir", 0},
+// { &key_memory_rpl_slave_command_buffer, "rpl_slave::command_buffer", 0},
+ { &key_memory_binlog_ver_1_event, "binlog_ver_1_event", 0},
+ { &key_memory_SLAVE_INFO, "SLAVE_INFO", 0},
+ { &key_memory_binlog_pos, "binlog_pos", 0},
+// { &key_memory_HASH_ROW_ENTRY, "HASH_ROW_ENTRY", 0},
+ { &key_memory_binlog_statement_buffer, "binlog_statement_buffer", 0},
+// { &key_memory_partition_syntax_buffer, "partition_syntax_buffer", 0},
+// { &key_memory_READ_INFO, "READ_INFO", 0},
+ { &key_memory_JOIN_CACHE, "JOIN_CACHE", 0},
+// { &key_memory_TABLE_sort_io_cache, "TABLE::sort_io_cache", 0},
+// { &key_memory_frm, "frm", 0},
+ { &key_memory_Unique_sort_buffer, "Unique::sort_buffer", 0},
+ { &key_memory_Unique_merge_buffer, "Unique::merge_buffer", 0},
+ { &key_memory_TABLE, "TABLE", PSI_FLAG_GLOBAL}, /* Table cache */
+// { &key_memory_frm_extra_segment_buff, "frm::extra_segment_buff", 0},
+// { &key_memory_frm_form_pos, "frm::form_pos", 0},
+ { &key_memory_frm_string, "frm::string", 0},
+// { &key_memory_LOG_name, "LOG_name", 0},
+ { &key_memory_DATE_TIME_FORMAT, "DATE_TIME_FORMAT", 0},
+ { &key_memory_DDL_LOG_MEMORY_ENTRY, "DDL_LOG_MEMORY_ENTRY", 0},
+ { &key_memory_ST_SCHEMA_TABLE, "ST_SCHEMA_TABLE", 0},
+ { &key_memory_ignored_db, "ignored_db", 0},
+ { &key_memory_PROFILE, "PROFILE", 0},
+ { &key_memory_global_system_variables, "global_system_variables", 0},
+ { &key_memory_THD_variables, "THD::variables", 0},
+// { &key_memory_Security_context, "Security_context", 0},
+// { &key_memory_shared_memory_name, "Shared_memory_name", 0},
+ { &key_memory_bison_stack, "bison_stack", 0},
+ { &key_memory_THD_handler_tables_hash, "THD::handler_tables_hash", 0},
+ { &key_memory_hash_index_key_buffer, "hash_index_key_buffer", 0},
+ { &key_memory_dboptions_hash, "dboptions_hash", 0},
+ { &key_memory_user_conn, "user_conn", 0},
+// { &key_memory_LOG_POS_COORD, "LOG_POS_COORD", 0},
+// { &key_memory_XID_STATE, "XID_STATE", 0},
+ { &key_memory_MPVIO_EXT_auth_info, "MPVIO_EXT::auth_info", 0},
+// { &key_memory_opt_bin_logname, "opt_bin_logname", 0},
+ { &key_memory_Query_cache, "Query_cache", PSI_FLAG_GLOBAL},
+// { &key_memory_READ_RECORD_cache, "READ_RECORD_cache", 0},
+// { &key_memory_Quick_ranges, "Quick_ranges", 0},
+// { &key_memory_File_query_log_name, "File_query_log::name", 0},
+ { &key_memory_Table_trigger_dispatcher, "Table_trigger_dispatcher::m_mem_root", 0},
+// { &key_memory_thd_timer, "thd_timer", 0},
+// { &key_memory_THD_Session_tracker, "THD::Session_tracker", 0},
+// { &key_memory_THD_Session_sysvar_resource_manager, "THD::Session_sysvar_resource_manager", 0},
+// { &key_memory_show_slave_status_io_gtid_set, "show_slave_status_io_gtid_set", 0},
+// { &key_memory_write_set_extraction, "write_set_extraction", 0},
+// { &key_memory_get_all_tables, "get_all_tables", 0},
+// { &key_memory_fill_schema_schemata, "fill_schema_schemata", 0},
+ { &key_memory_native_functions, "native_functions", PSI_FLAG_GLOBAL},
+};
+
/**
Initialise all the performance schema instrumentation points
used by the server.
@@ -9708,11 +9734,16 @@ void init_server_psi_keys(void)
count= array_elements(all_server_sockets);
mysql_socket_register(category, all_server_sockets, count);
+ count= array_elements(all_server_memory);
+ mysql_memory_register(category, all_server_memory, count);
+
#ifdef HAVE_PSI_STATEMENT_INTERFACE
init_sql_statement_info();
count= array_elements(sql_statement_info);
mysql_statement_register(category, sql_statement_info, count);
+ init_sp_psi_keys();
+
category= "com";
init_com_statement_info();
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 44db6c6216b..018c8cdcaf5 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2006, 2016, Oracle and/or its affiliates.
- Copyright (c) 2010, 2019, MariaDB Corporation.
+ Copyright (c) 2010, 2020, 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
@@ -80,11 +80,10 @@ void close_connection(THD *thd, uint sql_errno= 0);
void handle_connection_in_main_thread(CONNECT *thd);
void create_thread_to_handle_connection(CONNECT *connect);
void unlink_thd(THD *thd);
-bool one_thread_per_connection_end(THD *thd, bool put_in_cache);
+CONNECT *cache_thread(THD *thd);
void flush_thread_cache();
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);
@@ -120,7 +119,7 @@ extern bool opt_ignore_builtin_innodb;
extern my_bool opt_character_set_client_handshake;
extern my_bool debug_assert_on_not_freed_memory;
extern bool volatile abort_loop;
-extern uint connection_count;
+extern Atomic_counter<uint> connection_count;
extern my_bool opt_safe_user_create;
extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap;
extern my_bool opt_slave_compressed_protocol, use_temp_pool;
@@ -135,6 +134,7 @@ extern my_bool read_only, opt_readonly;
extern MYSQL_PLUGIN_IMPORT my_bool lower_case_file_system;
extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs;
extern my_bool opt_secure_auth;
+extern my_bool opt_require_secure_transport;
extern const char *current_dbug_option;
extern char* opt_secure_file_priv;
extern char* opt_secure_backup_file_priv;
@@ -158,7 +158,6 @@ extern plugin_ref *opt_gtid_pos_auto_plugins;
extern bool opt_endinfo, using_udf_functions;
extern my_bool locked_in_memory;
extern bool opt_using_transactions;
-extern ulong max_long_data_size;
extern ulong current_pid;
extern ulong expire_logs_days;
extern my_bool relay_log_recovery;
@@ -247,6 +246,7 @@ extern ulonglong max_binlog_cache_size, max_binlog_stmt_cache_size;
extern ulong max_binlog_size;
extern ulong slave_max_allowed_packet;
extern ulong opt_binlog_rows_event_max_size;
+extern ulong binlog_row_metadata;
extern ulong thread_cache_size;
extern ulong stored_program_cache_size;
extern ulong opt_slave_parallel_threads;
@@ -306,7 +306,6 @@ extern my_bool disconnect_on_expired_password;
enum secure_timestamp { SECTIME_NO, SECTIME_SUPER, SECTIME_REPL, SECTIME_YES };
-#ifdef HAVE_PSI_INTERFACE
#ifdef HAVE_MMAP
extern PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active,
key_LOCK_pool, key_LOCK_pending_checkpoint;
@@ -320,7 +319,7 @@ extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
key_BINLOG_LOCK_binlog_background_thread,
key_LOCK_binlog_end_pos,
key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi,
- key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create,
+ key_LOCK_crypt, key_LOCK_delayed_create,
key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log,
key_LOCK_gdl, key_LOCK_global_system_variables,
key_LOCK_logger, key_LOCK_manager,
@@ -391,22 +390,153 @@ extern PSI_thread_key key_thread_delayed_insert,
key_thread_one_connection, key_thread_signal_hand,
key_thread_slave_background, key_rpl_parallel_thread;
-extern PSI_file_key key_file_binlog, key_file_binlog_index, key_file_casetest,
+extern PSI_file_key key_file_binlog, key_file_binlog_cache,
+ key_file_binlog_index, key_file_binlog_index_cache, key_file_casetest,
key_file_dbopt, key_file_des_key_file, key_file_ERRMSG, key_select_to_file,
key_file_fileparser, key_file_frm, key_file_global_ddl_log, key_file_load,
key_file_loadfile, key_file_log_event_data, key_file_log_event_info,
- key_file_master_info, key_file_misc, key_file_partition,
+ key_file_master_info, key_file_misc, key_file_partition_ddl_log,
key_file_pid, key_file_relay_log_info, key_file_send_file, key_file_tclog,
key_file_trg, key_file_trn, key_file_init;
extern PSI_file_key key_file_query_log, key_file_slow_log;
-extern PSI_file_key key_file_relaylog, key_file_relaylog_index;
+extern PSI_file_key key_file_relaylog, key_file_relaylog_index,
+ key_file_relaylog_cache, key_file_relaylog_index_cache;
extern PSI_socket_key key_socket_tcpip, key_socket_unix,
key_socket_client_connection;
extern PSI_file_key key_file_binlog_state;
+#ifdef HAVE_PSI_INTERFACE
void init_server_psi_keys();
#endif /* HAVE_PSI_INTERFACE */
+extern PSI_memory_key key_memory_locked_table_list;
+extern PSI_memory_key key_memory_locked_thread_list;
+extern PSI_memory_key key_memory_thd_transactions;
+extern PSI_memory_key key_memory_delegate;
+extern PSI_memory_key key_memory_acl_mem;
+extern PSI_memory_key key_memory_acl_memex;
+extern PSI_memory_key key_memory_acl_cache;
+extern PSI_memory_key key_memory_thd_main_mem_root;
+extern PSI_memory_key key_memory_help;
+extern PSI_memory_key key_memory_frm;
+extern PSI_memory_key key_memory_table_share;
+extern PSI_memory_key key_memory_gdl;
+extern PSI_memory_key key_memory_table_triggers_list;
+extern PSI_memory_key key_memory_prepared_statement_map;
+extern PSI_memory_key key_memory_prepared_statement_main_mem_root;
+extern PSI_memory_key key_memory_protocol_rset_root;
+extern PSI_memory_key key_memory_warning_info_warn_root;
+extern PSI_memory_key key_memory_sp_cache;
+extern PSI_memory_key key_memory_sp_head_main_root;
+extern PSI_memory_key key_memory_sp_head_execute_root;
+extern PSI_memory_key key_memory_sp_head_call_root;
+extern PSI_memory_key key_memory_table_mapping_root;
+extern PSI_memory_key key_memory_quick_range_select_root;
+extern PSI_memory_key key_memory_quick_index_merge_root;
+extern PSI_memory_key key_memory_quick_ror_intersect_select_root;
+extern PSI_memory_key key_memory_quick_ror_union_select_root;
+extern PSI_memory_key key_memory_quick_group_min_max_select_root;
+extern PSI_memory_key key_memory_test_quick_select_exec;
+extern PSI_memory_key key_memory_prune_partitions_exec;
+extern PSI_memory_key key_memory_binlog_recover_exec;
+extern PSI_memory_key key_memory_blob_mem_storage;
+
+extern PSI_memory_key key_memory_Sys_var_charptr_value;
+extern PSI_memory_key key_memory_THD_db;
+extern PSI_memory_key key_memory_user_var_entry;
+extern PSI_memory_key key_memory_user_var_entry_value;
+extern PSI_memory_key key_memory_Slave_job_group_group_relay_log_name;
+extern PSI_memory_key key_memory_Relay_log_info_group_relay_log_name;
+extern PSI_memory_key key_memory_binlog_cache_mngr;
+extern PSI_memory_key key_memory_Row_data_memory_memory;
+extern PSI_memory_key key_memory_errmsgs;
+extern PSI_memory_key key_memory_Event_queue_element_for_exec_names;
+extern PSI_memory_key key_memory_Event_scheduler_scheduler_param;
+extern PSI_memory_key key_memory_Gis_read_stream_err_msg;
+extern PSI_memory_key key_memory_Geometry_objects_data;
+extern PSI_memory_key key_memory_host_cache_hostname;
+extern PSI_memory_key key_memory_User_level_lock;
+extern PSI_memory_key key_memory_Filesort_info_record_pointers;
+extern PSI_memory_key key_memory_Sort_param_tmp_buffer;
+extern PSI_memory_key key_memory_Filesort_info_merge;
+extern PSI_memory_key key_memory_Filesort_buffer_sort_keys;
+extern PSI_memory_key key_memory_handler_errmsgs;
+extern PSI_memory_key key_memory_handlerton;
+extern PSI_memory_key key_memory_XID;
+extern PSI_memory_key key_memory_MYSQL_LOCK;
+extern PSI_memory_key key_memory_MYSQL_LOG_name;
+extern PSI_memory_key key_memory_TC_LOG_MMAP_pages;
+extern PSI_memory_key key_memory_my_str_malloc;
+extern PSI_memory_key key_memory_MYSQL_BIN_LOG_basename;
+extern PSI_memory_key key_memory_MYSQL_BIN_LOG_index;
+extern PSI_memory_key key_memory_MYSQL_RELAY_LOG_basename;
+extern PSI_memory_key key_memory_MYSQL_RELAY_LOG_index;
+extern PSI_memory_key key_memory_rpl_filter;
+extern PSI_memory_key key_memory_Security_context;
+extern PSI_memory_key key_memory_NET_buff;
+extern PSI_memory_key key_memory_NET_compress_packet;
+extern PSI_memory_key key_memory_my_bitmap_map;
+extern PSI_memory_key key_memory_QUICK_RANGE_SELECT_mrr_buf_desc;
+extern PSI_memory_key key_memory_TABLE_RULE_ENT;
+extern PSI_memory_key key_memory_Mutex_cond_array_Mutex_cond;
+extern PSI_memory_key key_memory_Owned_gtids_sidno_to_hash;
+extern PSI_memory_key key_memory_Sid_map_Node;
+extern PSI_memory_key key_memory_bison_stack;
+extern PSI_memory_key key_memory_TABLE_sort_io_cache;
+extern PSI_memory_key key_memory_DATE_TIME_FORMAT;
+extern PSI_memory_key key_memory_DDL_LOG_MEMORY_ENTRY;
+extern PSI_memory_key key_memory_ST_SCHEMA_TABLE;
+extern PSI_memory_key key_memory_ignored_db;
+extern PSI_memory_key key_memory_SLAVE_INFO;
+extern PSI_memory_key key_memory_log_event_old;
+extern PSI_memory_key key_memory_HASH_ROW_ENTRY;
+extern PSI_memory_key key_memory_table_def_memory;
+extern PSI_memory_key key_memory_MPVIO_EXT_auth_info;
+extern PSI_memory_key key_memory_LOG_POS_COORD;
+extern PSI_memory_key key_memory_XID_STATE;
+extern PSI_memory_key key_memory_Rpl_info_file_buffer;
+extern PSI_memory_key key_memory_Rpl_info_table;
+extern PSI_memory_key key_memory_binlog_pos;
+extern PSI_memory_key key_memory_db_worker_hash_entry;
+extern PSI_memory_key key_memory_rpl_slave_command_buffer;
+extern PSI_memory_key key_memory_binlog_ver_1_event;
+extern PSI_memory_key key_memory_rpl_slave_check_temp_dir;
+extern PSI_memory_key key_memory_TABLE;
+extern PSI_memory_key key_memory_binlog_statement_buffer;
+extern PSI_memory_key key_memory_user_conn;
+extern PSI_memory_key key_memory_dboptions_hash;
+extern PSI_memory_key key_memory_hash_index_key_buffer;
+extern PSI_memory_key key_memory_THD_handler_tables_hash;
+extern PSI_memory_key key_memory_JOIN_CACHE;
+extern PSI_memory_key key_memory_READ_INFO;
+extern PSI_memory_key key_memory_partition_syntax_buffer;
+extern PSI_memory_key key_memory_global_system_variables;
+extern PSI_memory_key key_memory_THD_variables;
+extern PSI_memory_key key_memory_PROFILE;
+extern PSI_memory_key key_memory_LOG_name;
+extern PSI_memory_key key_memory_string_iterator;
+extern PSI_memory_key key_memory_frm_extra_segment_buff;
+extern PSI_memory_key key_memory_frm_form_pos;
+extern PSI_memory_key key_memory_frm_string;
+extern PSI_memory_key key_memory_Unique_sort_buffer;
+extern PSI_memory_key key_memory_Unique_merge_buffer;
+extern PSI_memory_key key_memory_shared_memory_name;
+extern PSI_memory_key key_memory_opt_bin_logname;
+extern PSI_memory_key key_memory_Query_cache;
+extern PSI_memory_key key_memory_READ_RECORD_cache;
+extern PSI_memory_key key_memory_Quick_ranges;
+extern PSI_memory_key key_memory_File_query_log_name;
+extern PSI_memory_key key_memory_Table_trigger_dispatcher;
+extern PSI_memory_key key_memory_show_slave_status_io_gtid_set;
+extern PSI_memory_key key_memory_write_set_extraction;
+extern PSI_memory_key key_memory_thd_timer;
+extern PSI_memory_key key_memory_THD_Session_tracker;
+extern PSI_memory_key key_memory_THD_Session_sysvar_resource_manager;
+extern PSI_memory_key key_memory_get_all_tables;
+extern PSI_memory_key key_memory_fill_schema_schemata;
+extern PSI_memory_key key_memory_native_functions;
+extern PSI_memory_key key_memory_JSON;
+
/*
MAINTAINER: Please keep this list in order, to limit merge collisions.
Hint: grep PSI_stage_info | sort -u
@@ -526,7 +656,6 @@ extern PSI_stage_info stage_waiting_for_table_flush;
extern PSI_stage_info stage_waiting_for_the_next_event_in_relay_log;
extern PSI_stage_info stage_waiting_for_the_slave_thread_to_advance_position;
extern PSI_stage_info stage_waiting_to_finalize_termination;
-extern PSI_stage_info stage_waiting_to_get_readlock;
extern PSI_stage_info stage_binlog_waiting_background_tasks;
extern PSI_stage_info stage_binlog_write;
extern PSI_stage_info stage_binlog_processing_checkpoint_notify;
@@ -545,6 +674,7 @@ extern PSI_stage_info stage_gtid_wait_other_connection;
extern PSI_stage_info stage_slave_background_process_request;
extern PSI_stage_info stage_slave_background_wait_request;
extern PSI_stage_info stage_waiting_for_deadlock_kill;
+extern PSI_stage_info stage_starting;
#ifdef HAVE_PSI_STATEMENT_INTERFACE
/**
@@ -576,8 +706,6 @@ extern pthread_t signal_thread;
extern struct st_VioSSLFd * ssl_acceptor_fd;
#endif /* HAVE_OPENSSL */
-extern ulonglong my_pcre_frame_size;
-
/*
The following variables were under INNODB_COMPABILITY_HOOKS
*/
@@ -616,7 +744,7 @@ extern mysql_mutex_t
LOCK_error_log, LOCK_delayed_insert, LOCK_short_uuid_generator,
LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
LOCK_active_mi, LOCK_manager, LOCK_user_conn,
- LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_connection_count,
+ LOCK_prepared_stmt_count, LOCK_error_messages,
LOCK_slave_background;
extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_global_system_variables;
extern mysql_rwlock_t LOCK_all_status_vars;
@@ -635,6 +763,7 @@ extern mysql_cond_t COND_manager;
extern mysql_cond_t COND_slave_background;
extern Atomic_counter<uint32_t> thread_count;
+extern my_bool opt_use_ssl;
extern char *opt_ssl_ca, *opt_ssl_capath, *opt_ssl_cert, *opt_ssl_cipher,
*opt_ssl_key, *opt_ssl_crl, *opt_ssl_crlpath;
extern ulonglong tls_version;
@@ -658,6 +787,7 @@ enum options_mysqld
OPT_CONSOLE,
OPT_DEBUG_SYNC_TIMEOUT,
OPT_DEPRECATED_OPTION,
+ OPT_REMOVED_OPTION,
OPT_IGNORE_DB_DIRECTORY,
OPT_ISAM_LOG,
OPT_KEY_BUFFER_SIZE,
@@ -669,7 +799,6 @@ enum options_mysqld
OPT_LOG_BASENAME,
OPT_LOG_ERROR,
OPT_LOWER_CASE_TABLE_NAMES,
- OPT_MAX_LONG_DATA_SIZE,
OPT_PLUGIN_LOAD,
OPT_PLUGIN_LOAD_ADD,
OPT_PFS_INSTRUMENT,
@@ -792,8 +921,7 @@ extern "C" void unireg_clear(int exit_code);
inline void table_case_convert(char * name, uint length)
{
if (lower_case_table_names)
- files_charset_info->cset->casedn(files_charset_info,
- name, length, name, length);
+ files_charset_info->casedn(name, length, name, length);
}
extern void set_server_version(char *buf, size_t size);
@@ -811,7 +939,6 @@ inline int set_current_thd(THD *thd)
*/
extern handlerton *maria_hton;
-extern uint extra_connection_count;
extern uint64 global_gtid_counter;
extern my_bool opt_gtid_strict_mode;
extern my_bool opt_userstat_running, debug_assert_if_crashed_table;
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 4fecf8bffd0..55ae19237ac 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -47,6 +47,9 @@
#include "probes_mysql.h"
#include "proxy_protocol.h"
+PSI_memory_key key_memory_NET_buff;
+PSI_memory_key key_memory_NET_compress_packet;
+
#ifdef EMBEDDED_LIBRARY
#undef MYSQL_SERVER
#undef MYSQL_CLIENT
@@ -176,8 +179,9 @@ my_bool my_net_init(NET *net, Vio *vio, void *thd, uint my_flags)
my_bool net_allocate_new_packet(NET *net, void *thd, uint my_flags)
{
DBUG_ENTER("net_allocate_new_packet");
- if (!(net->buff=(uchar*) my_malloc((size_t) net->max_packet+
- NET_HEADER_SIZE + COMP_HEADER_SIZE +1,
+ if (!(net->buff=(uchar*) my_malloc(key_memory_NET_buff,
+ (size_t) net->max_packet +
+ NET_HEADER_SIZE + COMP_HEADER_SIZE + 1,
MYF(MY_WME | my_flags))))
DBUG_RETURN(1);
net->buff_end=net->buff+net->max_packet;
@@ -221,11 +225,11 @@ my_bool net_realloc(NET *net, size_t length)
my_real_read() may actually read 4 bytes depending on build flags and
platform.
*/
- if (!(buff= (uchar*) my_realloc((char*) net->buff, pkt_length +
+ if (!(buff= (uchar*) my_realloc(key_memory_NET_buff,
+ (char*) net->buff, pkt_length +
NET_HEADER_SIZE + COMP_HEADER_SIZE + 1,
- MYF(MY_WME |
- (net->thread_specific_malloc ?
- MY_THREAD_SPECIFIC : 0)))))
+ MYF(MY_WME | (net->thread_specific_malloc
+ ? MY_THREAD_SPECIFIC : 0)))))
{
/* @todo: 1 and 2 codes are identical. */
net->error= 1;
@@ -407,7 +411,6 @@ my_bool net_flush(NET *net)
my_bool my_net_write(NET *net, const uchar *packet, size_t len)
{
uchar buff[NET_HEADER_SIZE];
- int rc;
if (unlikely(!net->vio)) /* nowhere to write */
return 0;
@@ -444,7 +447,7 @@ my_bool my_net_write(NET *net, const uchar *packet, size_t len)
#ifndef DEBUG_DATA_PACKETS
DBUG_DUMP("packet_header", buff, NET_HEADER_SIZE);
#endif
- rc= MY_TEST(net_write_buff(net, packet, len));
+ my_bool rc= MY_TEST(net_write_buff(net, packet, len));
MYSQL_NET_WRITE_DONE(rc);
return rc;
}
@@ -485,7 +488,7 @@ net_write_command(NET *net,uchar command,
size_t length=len+1+head_len; /* 1 extra byte for command */
uchar buff[NET_HEADER_SIZE+1];
uint header_size=NET_HEADER_SIZE+1;
- int rc;
+ my_bool rc;
DBUG_ENTER("net_write_command");
DBUG_PRINT("enter",("length: %lu", (ulong) len));
@@ -636,11 +639,10 @@ net_real_write(NET *net,const uchar *packet, size_t len)
size_t complen;
uchar *b;
uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
- if (!(b= (uchar*) my_malloc(len + NET_HEADER_SIZE +
- COMP_HEADER_SIZE + 1,
- MYF(MY_WME |
- (net->thread_specific_malloc ?
- MY_THREAD_SPECIFIC : 0)))))
+ if (!(b= (uchar*) my_malloc(key_memory_NET_compress_packet,
+ len + NET_HEADER_SIZE + COMP_HEADER_SIZE + 1,
+ MYF(MY_WME | (net->thread_specific_malloc
+ ? MY_THREAD_SPECIFIC : 0)))))
{
net->error= 2;
net->last_errno= ER_OUT_OF_RESOURCES;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 0528dfcadc6..8ce89705127 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2008, 2019, MariaDB
+ Copyright (c) 2008, 2020, 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
@@ -405,7 +405,7 @@ bool get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
uchar *max_key,uint max_key_flag);
static bool eq_tree(SEL_ARG* a,SEL_ARG *b);
-static SEL_ARG null_element(SEL_ARG::IMPOSSIBLE);
+SEL_ARG null_element(SEL_ARG::IMPOSSIBLE);
static bool null_part_in_key(KEY_PART *key_part, const uchar *key,
uint length);
static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts);
@@ -1267,9 +1267,8 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
if (!no_alloc && !parent_alloc)
{
// Allocates everything through the internal memroot
- init_sql_alloc(&alloc, "QUICK_RANGE_SELECT",
- thd->variables.range_alloc_block_size, 0,
- MYF(MY_THREAD_SPECIFIC));
+ init_sql_alloc(key_memory_quick_range_select_root, &alloc,
+ thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC));
thd->mem_root= &alloc;
}
else
@@ -1277,7 +1276,7 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
file= head->file;
record= head->record[0];
- my_init_dynamic_array2(&ranges, sizeof(QUICK_RANGE*),
+ my_init_dynamic_array2(PSI_INSTRUMENT_ME, &ranges, sizeof(QUICK_RANGE*),
thd->alloc(sizeof(QUICK_RANGE*) * 16), 16, 16,
MYF(MY_THREAD_SPECIFIC));
@@ -1363,9 +1362,8 @@ QUICK_INDEX_SORT_SELECT::QUICK_INDEX_SORT_SELECT(THD *thd_param, TABLE *table)
DBUG_ENTER("QUICK_INDEX_SORT_SELECT::QUICK_INDEX_SORT_SELECT");
index= MAX_KEY;
head= table;
- init_sql_alloc(&alloc, "QUICK_INDEX_SORT_SELECT",
- thd->variables.range_alloc_block_size, 0,
- MYF(MY_THREAD_SPECIFIC));
+ init_sql_alloc(key_memory_quick_range_select_root, &alloc,
+ thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC));
DBUG_VOID_RETURN;
}
@@ -1435,9 +1433,8 @@ QUICK_ROR_INTERSECT_SELECT::QUICK_ROR_INTERSECT_SELECT(THD *thd_param,
head= table;
record= head->record[0];
if (!parent_alloc)
- init_sql_alloc(&alloc, "QUICK_ROR_INTERSECT_SELECT",
- thd->variables.range_alloc_block_size, 0,
- MYF(MY_THREAD_SPECIFIC));
+ init_sql_alloc(key_memory_quick_range_select_root, &alloc,
+ thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC));
else
bzero(&alloc, sizeof(MEM_ROOT));
last_rowid= (uchar*) alloc_root(parent_alloc? parent_alloc : &alloc,
@@ -1713,9 +1710,8 @@ QUICK_ROR_UNION_SELECT::QUICK_ROR_UNION_SELECT(THD *thd_param,
head= table;
rowid_length= table->file->ref_length;
record= head->record[0];
- init_sql_alloc(&alloc, "QUICK_ROR_UNION_SELECT",
- thd->variables.range_alloc_block_size, 0,
- MYF(MY_THREAD_SPECIFIC));
+ init_sql_alloc(key_memory_quick_range_select_root, &alloc,
+ thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC));
thd_param->mem_root= &alloc;
}
@@ -2651,6 +2647,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
{
uint idx;
double scan_time;
+ Item *notnull_cond= NULL;
DBUG_ENTER("SQL_SELECT::test_quick_select");
DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu",
(ulong) keys_to_use.to_ulonglong(), (ulong) prev_tables,
@@ -2665,6 +2662,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
if (keys_to_use.is_clear_all() || head->is_filled_at_execution())
DBUG_RETURN(0);
records= head->stat_records();
+ notnull_cond= head->notnull_cond;
if (!records)
records++; /* purecov: inspected */
@@ -2675,9 +2673,12 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
scan_time= (double) records / TIME_FOR_COMPARE + 1;
read_time= (double) head->file->scan_time() + scan_time + 1.1;
if (limit < records)
+ {
read_time= (double) records + scan_time + 1; // Force to use index
+ notnull_cond= NULL;
+ }
}
-
+
possible_keys.clear_all();
DBUG_PRINT("info",("Time to scan table: %g", read_time));
@@ -2699,6 +2700,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
uchar buff[STACK_BUFF_ALLOC];
MEM_ROOT alloc;
SEL_TREE *tree= NULL;
+ SEL_TREE *notnull_cond_tree= NULL;
KEY_PART *key_parts;
KEY *key_info;
PARAM param;
@@ -2726,9 +2728,8 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
param.possible_keys.clear_all();
thd->no_errors=1; // Don't warn about NULL
- init_sql_alloc(&alloc, "test_quick_select",
- thd->variables.range_alloc_block_size, 0,
- MYF(MY_THREAD_SPECIFIC));
+ init_sql_alloc(key_memory_quick_range_select_root, &alloc,
+ thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC));
if (!(param.key_parts=
(KEY_PART*) alloc_root(&alloc,
sizeof(KEY_PART) *
@@ -2835,12 +2836,18 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
TRP_GROUP_MIN_MAX *group_trp= NULL;
double best_read_time= read_time;
- if (cond)
+ if (notnull_cond)
+ notnull_cond_tree= notnull_cond->get_mm_tree(&param, &notnull_cond);
+
+ if (cond || notnull_cond_tree)
{
{
Json_writer_array trace_range_summary(thd,
"setup_range_conditions");
- tree= cond->get_mm_tree(&param, &cond);
+ if (cond)
+ tree= cond->get_mm_tree(&param, &cond);
+ if (notnull_cond_tree)
+ tree= tree_and(&param, tree, notnull_cond_tree);
}
if (tree)
{
@@ -3402,9 +3409,8 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
SEL_TREE *tree;
double rows;
- init_sql_alloc(&alloc, "calculate_cond_selectivity_for_table",
- thd->variables.range_alloc_block_size, 0,
- MYF(MY_THREAD_SPECIFIC));
+ init_sql_alloc(key_memory_quick_range_select_root, &alloc,
+ thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC));
param.thd= thd;
param.mem_root= &alloc;
param.old_root= thd->mem_root;
@@ -3834,9 +3840,8 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond)
my_bitmap_map *old_sets[2];
prune_param.part_info= part_info;
- init_sql_alloc(&alloc, "prune_partitions",
- thd->variables.range_alloc_block_size, 0,
- MYF(MY_THREAD_SPECIFIC));
+ init_sql_alloc(key_memory_quick_range_select_root, &alloc,
+ thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC));
range_par->mem_root= &alloc;
range_par->old_root= thd->mem_root;
@@ -5755,7 +5760,7 @@ bool prepare_search_best_index_intersect(PARAM *param,
{
idx_scan.add("chosen", true);
if (!*scan_ptr)
- idx_scan.add("cause", "first occurence of index prefix");
+ idx_scan.add("cause", "first occurrence of index prefix");
else
idx_scan.add("cause", "better cost for same idx prefix");
*scan_ptr= *index_scan;
@@ -8149,16 +8154,6 @@ SEL_TREE *Item_bool_func::get_full_func_mm_tree(RANGE_OPT_PARAM *param,
table_map ref_tables= 0;
table_map param_comp= ~(param->prev_tables | param->read_tables |
param->current_table);
-#ifdef HAVE_SPATIAL
- Field::geometry_type sav_geom_type;
- 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 */
- ((Field_geom*) field_item->field)->geom_type= Field::GEOM_GEOMETRY;
- }
-#endif /*HAVE_SPATIAL*/
for (uint i= 0; i < arg_count; i++)
{
@@ -8186,12 +8181,6 @@ SEL_TREE *Item_bool_func::get_full_func_mm_tree(RANGE_OPT_PARAM *param,
}
}
-#ifdef HAVE_SPATIAL
- if (geometry)
- {
- ((Field_geom*) field_item->field)->geom_type= sav_geom_type;
- }
-#endif /*HAVE_SPATIAL*/
DBUG_RETURN(ftree);
}
@@ -8627,13 +8616,12 @@ Item_func_like::get_mm_leaf(RANGE_OPT_PARAM *param,
size_t min_length, max_length;
field_length-= maybe_null;
- if (my_like_range(field->charset(),
- res->ptr(), res->length(),
- escape, wild_one, wild_many,
- field_length,
- (char*) min_str + offset,
- (char*) max_str + offset,
- &min_length, &max_length))
+ if (field->charset()->like_range(res->ptr(), res->length(),
+ escape, wild_one, wild_many,
+ field_length,
+ (char*) min_str + offset,
+ (char*) max_str + offset,
+ &min_length, &max_length))
DBUG_RETURN(0); // Can't optimize with LIKE
if (offset != maybe_null) // BLOB or VARCHAR
@@ -12120,7 +12108,8 @@ int QUICK_RANGE_SELECT::reset()
if (mrr_buf_size && !mrr_buf_desc)
{
buf_size= mrr_buf_size;
- while (buf_size && !my_multi_malloc(MYF(MY_WME),
+ while (buf_size && !my_multi_malloc(key_memory_QUICK_RANGE_SELECT_mrr_buf_desc,
+ MYF(MY_WME),
&mrr_buf_desc, sizeof(*mrr_buf_desc),
&mrange_buff, buf_size,
NullS))
@@ -14472,10 +14461,10 @@ QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg,
DBUG_ASSERT(!parent_alloc);
if (!parent_alloc)
{
- init_sql_alloc(&alloc, "QUICK_GROUP_MIN_MAX_SELECT",
- join->thd->variables.range_alloc_block_size, 0,
- MYF(MY_THREAD_SPECIFIC));
- join->thd->mem_root= &alloc;
+ THD *thd= join->thd;
+ init_sql_alloc(key_memory_quick_range_select_root, &alloc,
+ thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC));
+ thd->mem_root= &alloc;
}
else
bzero(&alloc, sizeof(MEM_ROOT)); // ensure that it's not used
@@ -14535,7 +14524,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::init()
if (min_max_arg_part)
{
- if (my_init_dynamic_array(&min_max_ranges, sizeof(QUICK_RANGE*), 16, 16,
+ if (my_init_dynamic_array(PSI_INSTRUMENT_ME, &min_max_ranges,
+ sizeof(QUICK_RANGE*), 16, 16,
MYF(MY_THREAD_SPECIFIC)))
return 1;
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 73def7bde92..a504e35bf45 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -598,6 +598,7 @@ public:
SEL_ARG *clone_tree(RANGE_OPT_PARAM *param);
};
+extern MYSQL_PLUGIN_IMPORT SEL_ARG null_element;
class SEL_ARG_IMPOSSIBLE: public SEL_ARG
{
diff --git a/sql/opt_split.cc b/sql/opt_split.cc
index 6f8248c315c..b27a0d757cb 100644
--- a/sql/opt_split.cc
+++ b/sql/opt_split.cc
@@ -341,7 +341,7 @@ bool JOIN::check_for_splittable_materialized()
return false;
ORDER *ord;
- Dynamic_array<SplM_field_ext_info> candidates;
+ Dynamic_array<SplM_field_ext_info> candidates(PSI_INSTRUMENT_MEM);
/*
Select from partition_list all candidates for splitting.
@@ -712,7 +712,7 @@ void JOIN::add_keyuses_for_splitting()
KEY_FIELD *added_key_field;
if (!spl_opt_info->added_key_fields.elements)
goto err;
- if (!(ext_keyuses_for_splitting= new Dynamic_array<KEYUSE_EXT>))
+ if (!(ext_keyuses_for_splitting= new Dynamic_array<KEYUSE_EXT>(PSI_INSTRUMENT_MEM)))
goto err;
while ((added_key_field= li++))
{
@@ -742,13 +742,11 @@ void JOIN::add_keyuses_for_splitting()
save_query_plan(save_qep);
if (!keyuse.buffer &&
- my_init_dynamic_array(&keyuse, sizeof(KEYUSE), 20, 64,
- MYF(MY_THREAD_SPECIFIC)))
+ my_init_dynamic_array(PSI_INSTRUMENT_ME, &keyuse, sizeof(KEYUSE),
+ 20, 64, MYF(MY_THREAD_SPECIFIC)))
goto err;
- if (allocate_dynamic(&keyuse,
- save_qep->keyuse.elements +
- added_keyuse_count))
+ if (allocate_dynamic(&keyuse, save_qep->keyuse.elements + added_keyuse_count))
goto err;
memcpy(keyuse.buffer,
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index dbb71264777..607d9a2d95a 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -2204,7 +2204,7 @@ int pull_out_semijoin_tables(JOIN *join)
/*
Don't do table pull-out for nested joins (if we get nested joins here, it
means these are outer joins. It is theoretically possible to do pull-out
- for some of the outer tables but we dont support this currently.
+ for some of the outer tables but we don't support this currently.
*/
bool have_join_nest_children= FALSE;
@@ -3967,6 +3967,39 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
/*
+ Return the number of tables at the top-level of the JOIN
+
+ SYNOPSIS
+ get_number_of_tables_at_top_level()
+ join The join with the picked join order
+
+ DESCRIPTION
+ The number of tables in the JOIN currently include all the inner tables of the
+ mergeable semi-joins. The function would make sure that we only count the semi-join
+ nest and not the inner tables of teh semi-join nest.
+*/
+
+uint get_number_of_tables_at_top_level(JOIN *join)
+{
+ uint j= 0, tables= 0;
+ while(j < join->table_count)
+ {
+ POSITION *cur_pos= &join->best_positions[j];
+ tables++;
+ if (cur_pos->sj_strategy == SJ_OPT_MATERIALIZE ||
+ cur_pos->sj_strategy == SJ_OPT_MATERIALIZE_SCAN)
+ {
+ SJ_MATERIALIZATION_INFO *sjm= cur_pos->table->emb_sj_nest->sj_mat_info;
+ j= j + sjm->tables;
+ }
+ else
+ j++;
+ }
+ return tables;
+}
+
+
+/*
Setup semi-join materialization strategy for one semi-join nest
SYNOPSIS
@@ -4441,8 +4474,8 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
using_unique_constraint= TRUE;
/* STEP 3: Allocate memory for temptable description */
- init_sql_alloc(&own_root, "SJ_TMP_TABLE",
- TABLE_ALLOC_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC));
+ init_sql_alloc(PSI_INSTRUMENT_ME, &own_root, TABLE_ALLOC_BLOCK_SIZE, 0,
+ MYF(MY_THREAD_SPECIFIC));
if (!multi_alloc_root(&own_root,
&table, sizeof(*table),
&share, sizeof(*share),
@@ -4521,7 +4554,7 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
}
uint reclength= field->pack_length();
- if (using_unique_constraint)
+ if (using_unique_constraint || thd->variables.tmp_memory_table_size == 0)
{
share->db_plugin= ha_lock_engine(0, TMP_ENGINE_HTON);
table->file= get_new_handler(share, &table->mem_root,
@@ -4596,15 +4629,7 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
/* Make entry for create table */
recinfo->length=length;
- if (field->flags & BLOB_FLAG)
- recinfo->type= FIELD_BLOB;
- else if (use_packed_rows &&
- field->real_type() == MYSQL_TYPE_STRING &&
- length >= MIN_STRING_LENGTH_TO_PACK_ROWS)
- recinfo->type=FIELD_SKIP_ENDSPACE;
- else
- recinfo->type=FIELD_NORMAL;
-
+ recinfo->type= field->tmp_engine_column_type(use_packed_rows);
field->set_table_name(&table->alias);
}
@@ -4614,7 +4639,7 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
share->max_rows= (ha_rows) (((share->db_type() == heap_hton) ?
MY_MIN(thd->variables.tmp_memory_table_size,
thd->variables.max_heap_table_size) :
- thd->variables.tmp_memory_table_size) /
+ thd->variables.tmp_disk_table_size) /
share->reclength);
set_if_bigger(share->max_rows,1); // For dummy start options
@@ -5721,12 +5746,6 @@ int select_value_catcher::send_data(List<Item> &items)
DBUG_ASSERT(!assigned);
DBUG_ASSERT(items.elements == n_elements);
- if (unit->offset_limit_cnt)
- { // Using limit offset,count
- unit->offset_limit_cnt--;
- DBUG_RETURN(0);
- }
-
Item *val_item;
List_iterator_fast<Item> li(items);
for (uint i= 0; (val_item= li++); i++)
@@ -6581,7 +6600,7 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
Set the limit of this JOIN object as well, because normally its being
set in the beginning of JOIN::optimize, which was already done.
*/
- select_limit= in_subs->unit->select_limit_cnt;
+ select_limit= in_subs->unit->lim.get_select_limit();
}
else if (in_subs->test_strategy(SUBS_IN_TO_EXISTS))
{
@@ -6885,8 +6904,7 @@ get_corresponding_item_for_in_subq_having(THD *thd, Item *in_item,
Item_ref *ref=
new (thd->mem_root) Item_ref(thd,
&subq_pred->unit->first_select()->context,
- NullS, NullS,
- &new_item->name);
+ new_item->name);
if (!ref)
DBUG_ASSERT(0);
return ref;
diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h
index d7978e9ef73..abd37f1e98e 100644
--- a/sql/opt_subselect.h
+++ b/sql/opt_subselect.h
@@ -324,6 +324,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join);
bool setup_sj_materialization_part1(JOIN_TAB *sjm_tab);
bool setup_sj_materialization_part2(JOIN_TAB *sjm_tab);
+uint get_number_of_tables_at_top_level(JOIN *join);
/*
diff --git a/sql/opt_trace.cc b/sql/opt_trace.cc
index afb188ceeb0..a8676eec411 100644
--- a/sql/opt_trace.cc
+++ b/sql/opt_trace.cc
@@ -17,7 +17,7 @@
#include "sql_class.h"
#include "sql_show.h"
#include "field.h"
-#include "table.h"
+#include "sql_i_s.h"
#include "opt_trace.h"
#include "sql_parse.h"
#include "set_var.h"
@@ -66,18 +66,21 @@ bool sets_var_optimizer_trace(enum enum_sql_command sql_command,
}
+namespace Show {
+
+
ST_FIELD_INFO optimizer_trace_info[]=
{
- /* name, length, type, value, maybe_null, old_name, open_method */
- {"QUERY", 65535, MYSQL_TYPE_STRING, 0, false, NULL, SKIP_OPEN_TABLE},
- {"TRACE", 65535, MYSQL_TYPE_STRING, 0, false, NULL, SKIP_OPEN_TABLE},
- {"MISSING_BYTES_BEYOND_MAX_MEM_SIZE", 20, MYSQL_TYPE_LONG, 0, false, NULL,
- SKIP_OPEN_TABLE},
- {"INSUFFICIENT_PRIVILEGES", 1, MYSQL_TYPE_TINY, 0, false, NULL,
- SKIP_OPEN_TABLE},
- {NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL, 0}
+ Column("QUERY", Longtext(65535), NOT_NULL),
+ Column("TRACE", Longtext(65535), NOT_NULL),
+ Column("MISSING_BYTES_BEYOND_MAX_MEM_SIZE", SLong(20), NOT_NULL),
+ Column("INSUFFICIENT_PRIVILEGES", STiny(1), NOT_NULL),
+ CEnd()
};
+} // namespace Show
+
+
/*
TODO: one-line needs to be implemented seperately
*/
@@ -258,7 +261,7 @@ void opt_trace_disable_if_no_tables_access(THD *thd, TABLE_LIST *tbl)
bool rc =
check_table_access(thd, SELECT_ACL, t, false, 1, true) || // (1)
- ((t->grant.privilege & SELECT_ACL) == 0); // (2)
+ ((t->grant.privilege & SELECT_ACL) == NO_ACL); // (2)
if (t->is_view())
{
/*
@@ -412,7 +415,7 @@ bool Opt_trace_context::is_enabled()
return false;
}
-Opt_trace_context::Opt_trace_context()
+Opt_trace_context::Opt_trace_context() : traces(PSI_INSTRUMENT_MEM)
{
current_trace= NULL;
max_mem_size= 0;
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index 66ec6a70b12..5e3c19850de 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -30,11 +30,11 @@
// NOT_A_PARTITION_ID
#include "partition_info.h"
#include "sql_parse.h"
-#include "sql_acl.h" // *_ACL
#include "sql_base.h" // fill_record
-#include "sql_statistics.h" // vers_stat_end
-#include "vers_utils.h"
#include "lock.h"
+#include "table.h"
+#include "sql_class.h"
+#include "vers_string.h"
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
@@ -196,49 +196,6 @@ bool partition_info::set_named_partition_bitmap(const char *part_name, size_t le
}
-
-/**
- Prune away partitions not mentioned in the PARTITION () clause,
- if used.
-
- @param table_list Table list pointing to table to prune.
-
- @return Operation status
- @retval false Success
- @retval true Failure
-*/
-bool partition_info::set_read_partitions(List<char> *partition_names)
-{
- DBUG_ENTER("partition_info::set_read_partitions");
- if (!partition_names || !partition_names->elements)
- {
- DBUG_RETURN(true);
- }
-
- uint num_names= partition_names->elements;
- List_iterator<char> partition_names_it(*partition_names);
- uint i= 0;
- /*
- TODO: When adding support for FK in partitioned tables, the referenced
- table must probably lock all partitions for read, and also write depending
- of ON DELETE/UPDATE.
- */
- bitmap_clear_all(&read_partitions);
-
- /* No check for duplicate names or overlapping partitions/subpartitions. */
-
- DBUG_PRINT("info", ("Searching through partition_name_hash"));
- do
- {
- char *part_name= partition_names_it++;
- if (add_named_partition(part_name, strlen(part_name)))
- DBUG_RETURN(true);
- } while (++i < num_names);
- DBUG_RETURN(false);
-}
-
-
-
/**
Prune away partitions not mentioned in the PARTITION () clause,
if used.
@@ -446,7 +403,15 @@ bool partition_info::set_up_default_partitions(THD *thd, handler *file,
bool result= TRUE;
DBUG_ENTER("partition_info::set_up_default_partitions");
- if (part_type != HASH_PARTITION)
+ if (part_type == VERSIONING_PARTITION)
+ {
+ if (use_default_num_partitions)
+ {
+ num_parts= 2;
+ use_default_num_partitions= false;
+ }
+ }
+ else if (part_type != HASH_PARTITION)
{
const char *error_string;
if (part_type == RANGE_PARTITION)
@@ -482,7 +447,17 @@ bool partition_info::set_up_default_partitions(THD *thd, handler *file,
{
part_elem->engine_type= default_engine_type;
part_elem->partition_name= default_name;
+ part_elem->id= i;
default_name+=MAX_PART_NAME_SIZE;
+ if (part_type == VERSIONING_PARTITION)
+ {
+ if (i < num_parts - 1) {
+ part_elem->type= partition_element::HISTORY;
+ } else {
+ part_elem->type= partition_element::CURRENT;
+ part_elem->partition_name= "pn";
+ }
+ }
}
else
goto end;
@@ -587,8 +562,9 @@ bool partition_info::set_up_defaults_for_partitioning(THD *thd, handler *file,
if (!default_partitions_setup)
{
default_partitions_setup= TRUE;
- if (use_default_partitions)
- DBUG_RETURN(set_up_default_partitions(thd, file, info, start_no));
+ if (use_default_partitions &&
+ set_up_default_partitions(thd, file, info, start_no))
+ DBUG_RETURN(TRUE);
if (is_sub_partitioned() &&
use_default_subpartitions)
DBUG_RETURN(set_up_default_subpartitions(thd, file, info));
@@ -756,7 +732,7 @@ char *partition_info::find_duplicate_name()
max_names= num_parts;
if (is_sub_partitioned())
max_names+= num_parts * num_subparts;
- if (my_hash_init(&partition_names, system_charset_info, max_names, 0, 0,
+ if (my_hash_init(PSI_INSTRUMENT_ME, &partition_names, system_charset_info, max_names, 0, 0,
(my_hash_get_key) get_part_name_from_elem, 0, HASH_UNIQUE))
{
DBUG_ASSERT(0);
@@ -830,6 +806,15 @@ bool partition_info::has_unique_name(partition_element *element)
DBUG_RETURN(TRUE);
}
+
+/**
+ @brief Switch history partition according limit or interval
+
+ @note
+ vers_info->limit Limit by number of partition records
+ vers_info->interval Limit by fixed time interval
+ vers_info->hist_part (out) Working history partition
+*/
void partition_info::vers_set_hist_part(THD *thd)
{
if (vers_info->limit)
@@ -848,11 +833,16 @@ void partition_info::vers_set_hist_part(THD *thd)
vers_info->hist_part= next;
records= next_records;
}
- if (records > vers_info->limit)
+ if (records >= vers_info->limit)
{
if (next == vers_info->now_part)
- goto warn;
- vers_info->hist_part= next;
+ {
+ my_error(WARN_VERS_PART_FULL, MYF(ME_WARNING|ME_ERROR_LOG),
+ table->s->db.str, table->s->table_name.str,
+ vers_info->hist_part->partition_name, "LIMIT");
+ }
+ else
+ vers_info->hist_part= next;
}
return;
}
@@ -873,56 +863,10 @@ void partition_info::vers_set_hist_part(THD *thd)
if (next->range_value > thd->query_start())
return;
}
- goto warn;
+ my_error(WARN_VERS_PART_FULL, MYF(ME_WARNING|ME_ERROR_LOG),
+ table->s->db.str, table->s->table_name.str,
+ vers_info->hist_part->partition_name, "INTERVAL");
}
- return;
-warn:
- my_error(WARN_VERS_PART_FULL, MYF(ME_WARNING|ME_ERROR_LOG),
- table->s->db.str, table->s->table_name.str,
- vers_info->hist_part->partition_name);
-}
-
-
-bool partition_info::vers_setup_expression(THD * thd, uint32 alter_add)
-{
- if (!table->versioned())
- {
- // frm must be corrupted, normally CREATE/ALTER TABLE checks for that
- my_error(ER_FILE_CORRUPT, MYF(0), table->s->path.str);
- return true;
- }
-
- DBUG_ASSERT(part_type == VERSIONING_PARTITION);
- DBUG_ASSERT(table->versioned(VERS_TIMESTAMP));
-
- if (!alter_add)
- {
- Field *row_end= table->vers_end_field();
- // needed in handle_list_of_fields()
- row_end->flags|= GET_FIXED_FIELDS_FLAG;
- Name_resolution_context *context= &thd->lex->current_select->context;
- Item *row_end_item= new (thd->mem_root) Item_field(thd, context, row_end);
- Item *row_end_ts= new (thd->mem_root) Item_func_unix_timestamp(thd, row_end_item);
- set_part_expr(thd, row_end_ts, false);
- }
-
- if (alter_add)
- {
- List_iterator<partition_element> it(partitions);
- partition_element *el;
- for(uint32 id= 0; ((el= it++)); id++)
- {
- DBUG_ASSERT(el->type != partition_element::CONVENTIONAL);
- /* Newly added element is inserted before AS_OF_NOW. */
- if (el->id == UINT_MAX32 || el->type == partition_element::CURRENT)
- {
- el->id= id;
- if (el->type == partition_element::CURRENT)
- break;
- }
- }
- }
- return false;
}
@@ -1189,7 +1133,7 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
part_type == LIST_PARTITION ||
part_type == VERSIONING_PARTITION))))
{
- /* Only RANGE and LIST partitioning can be subpartitioned */
+ /* Only RANGE, LIST and SYSTEM_TIME partitioning can be subpartitioned */
my_error(ER_SUBPARTITION_ERROR, MYF(0));
goto end;
}
@@ -1253,7 +1197,7 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
if (part_type == VERSIONING_PARTITION)
{
DBUG_ASSERT(vers_info);
- if (num_parts < 2 || !vers_info->now_part)
+ if (num_parts < 2 || !(use_default_partitions || vers_info->now_part))
{
DBUG_ASSERT(info);
DBUG_ASSERT(info->alias.str);
@@ -1403,9 +1347,8 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
if (add_or_reorg_part)
{
- if (unlikely(part_type == VERSIONING_PARTITION &&
- vers_setup_expression(thd, add_or_reorg_part->partitions.elements)))
- goto end;
+ if (part_type == VERSIONING_PARTITION && add_or_reorg_part->partitions.elements)
+ vers_update_el_ids();
if (check_constants(thd, this))
goto end;
}
@@ -2140,7 +2083,6 @@ bool partition_info::fix_column_value_functions(THD *thd,
{
uchar *val_ptr;
uint len= field->pack_length();
- sql_mode_t save_sql_mode;
bool save_got_warning;
if (!(column_item= get_column_item(column_item, field)))
@@ -2148,20 +2090,17 @@ bool partition_info::fix_column_value_functions(THD *thd,
result= TRUE;
goto end;
}
- save_sql_mode= thd->variables.sql_mode;
- thd->variables.sql_mode= 0;
+ Sql_mode_instant_set sms(thd, 0);
save_got_warning= thd->got_warning;
thd->got_warning= 0;
if (column_item->save_in_field(field, TRUE) ||
thd->got_warning)
{
my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
- thd->variables.sql_mode= save_sql_mode;
result= TRUE;
goto end;
}
thd->got_warning= save_got_warning;
- thd->variables.sql_mode= save_sql_mode;
if (!(val_ptr= (uchar*) thd->memdup(field->ptr, len)))
{
result= TRUE;
@@ -2698,6 +2637,102 @@ bool partition_info::vers_init_info(THD * thd)
}
+/**
+ Assign INTERVAL and STARTS for SYSTEM_TIME partitions.
+
+ @return true on error
+*/
+
+bool partition_info::vers_set_interval(THD* thd, Item* interval,
+ interval_type int_type, Item* starts,
+ const char *table_name)
+{
+ DBUG_ASSERT(part_type == VERSIONING_PARTITION);
+
+ MYSQL_TIME ltime;
+ uint err;
+ vers_info->interval.type= int_type;
+
+ /* 1. assign INTERVAL to interval.step */
+ if (interval->fix_fields_if_needed_for_scalar(thd, &interval))
+ return true;
+ bool error= get_interval_value(thd, interval, 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 ||
+ vers_info->interval.step.minute || vers_info->interval.step.second);
+ if (error)
+ {
+ my_error(ER_PART_WRONG_VALUE, MYF(0), table_name, "INTERVAL");
+ return true;
+ }
+
+ /* 2. assign STARTS to interval.start */
+ if (starts)
+ {
+ if (starts->fix_fields_if_needed_for_scalar(thd, &starts))
+ return true;
+ switch (starts->result_type())
+ {
+ case INT_RESULT:
+ case DECIMAL_RESULT:
+ case REAL_RESULT:
+ /* When table member is defined, we are inside mysql_unpack_partition(). */
+ if (!table || starts->val_int() > TIMESTAMP_MAX_VALUE)
+ goto interval_starts_error;
+ vers_info->interval.start= (my_time_t) starts->val_int();
+ break;
+ case STRING_RESULT:
+ case TIME_RESULT:
+ {
+ Datetime::Options opt(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE, thd);
+ starts->get_date(thd, &ltime, opt);
+ vers_info->interval.start= TIME_to_timestamp(thd, &ltime, &err);
+ if (err)
+ goto interval_starts_error;
+ break;
+ }
+ case ROW_RESULT:
+ default:
+ goto interval_starts_error;
+ }
+ if (!table)
+ {
+ if (thd->query_start() < vers_info->interval.start) {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_PART_STARTS_BEYOND_INTERVAL,
+ ER_THD(thd, ER_PART_STARTS_BEYOND_INTERVAL),
+ table_name);
+ }
+ }
+ }
+ else // calculate default STARTS depending on INTERVAL
+ {
+ thd->variables.time_zone->gmt_sec_to_TIME(&ltime, thd->query_start());
+ if (vers_info->interval.step.second)
+ goto interval_set_starts;
+ ltime.second= 0;
+ if (vers_info->interval.step.minute)
+ goto interval_set_starts;
+ ltime.minute= 0;
+ if (vers_info->interval.step.hour)
+ goto interval_set_starts;
+ ltime.hour= 0;
+
+interval_set_starts:
+ vers_info->interval.start= TIME_to_timestamp(thd, &ltime, &err);
+ if (err)
+ goto interval_starts_error;
+ }
+
+ return false;
+
+interval_starts_error:
+ my_error(ER_PART_WRONG_VALUE, MYF(0), table_name, "STARTS");
+ return true;
+}
+
+
bool partition_info::error_if_requires_values() const
{
switch (part_type) {
diff --git a/sql/partition_info.h b/sql/partition_info.h
index 00ef815ce09..eb8e53a381a 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -385,36 +385,16 @@ private:
uint start_no);
char *create_default_subpartition_name(THD *thd, uint subpart_no,
const char *part_name);
- // FIXME: prune_partition_bitmaps() is duplicate of set_read_partitions()
- bool prune_partition_bitmaps(List<String> *partition_names);
+ bool prune_partition_bitmaps(List<String> *partition_names); // set_read_partitions() in 8.0
bool add_named_partition(const char *part_name, size_t length);
public:
- bool set_read_partitions(List<char> *partition_names);
bool has_unique_name(partition_element *element);
bool field_in_partition_expr(Field *field) const;
bool vers_init_info(THD *thd);
- 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;
- if (item->fix_fields_if_needed_for_scalar(thd, &item))
- return true;
- bool error= 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 ||
- vers_info->interval.step.minute || vers_info->interval.step.second);
- if (error)
- {
- my_error(ER_PART_WRONG_VALUE, MYF(0),
- thd->lex->create_last_non_select_table->table_name.str,
- "INTERVAL");
- }
- return error;
- }
+ bool vers_set_interval(THD *thd, Item *interval,
+ interval_type int_type, Item *starts,
+ const char *table_name);
bool vers_set_limit(ulonglong limit)
{
DBUG_ASSERT(part_type == VERSIONING_PARTITION);
@@ -422,7 +402,8 @@ public:
return !limit;
}
void vers_set_hist_part(THD *thd);
- bool vers_setup_expression(THD *thd, uint32 alter_add= 0); /* Stage 1. */
+ bool vers_fix_field_list(THD *thd);
+ void vers_update_el_ids();
partition_element *get_partition(uint part_id)
{
List_iterator<partition_element> it(partitions);
@@ -463,4 +444,60 @@ void init_all_partitions_iterator(partition_info *part_info,
part_iter->get_next= get_next_partition_id_range;
}
+
+/**
+ @brief Update part_field_list by row_end field name
+
+ @returns true on error; false on success
+*/
+inline
+bool partition_info::vers_fix_field_list(THD * thd)
+{
+ if (!table->versioned())
+ {
+ // frm must be corrupted, normally CREATE/ALTER TABLE checks for that
+ my_error(ER_FILE_CORRUPT, MYF(0), table->s->path.str);
+ return true;
+ }
+ DBUG_ASSERT(part_type == VERSIONING_PARTITION);
+ DBUG_ASSERT(table->versioned(VERS_TIMESTAMP));
+
+ Field *row_end= table->vers_end_field();
+ // needed in handle_list_of_fields()
+ row_end->flags|= GET_FIXED_FIELDS_FLAG;
+ Name_resolution_context *context= &thd->lex->current_select->context;
+ Item *row_end_item= new (thd->mem_root) Item_field(thd, context, row_end);
+ Item *row_end_ts= new (thd->mem_root) Item_func_unix_timestamp(thd, row_end_item);
+ set_part_expr(thd, row_end_ts, false);
+
+ return false;
+}
+
+
+/**
+ @brief Update partition_element's id
+
+ @returns true on error; false on success
+*/
+inline
+void partition_info::vers_update_el_ids()
+{
+ DBUG_ASSERT(part_type == VERSIONING_PARTITION);
+ DBUG_ASSERT(table->versioned(VERS_TIMESTAMP));
+
+ List_iterator<partition_element> it(partitions);
+ partition_element *el;
+ for(uint32 id= 0; ((el= it++)); id++)
+ {
+ DBUG_ASSERT(el->type != partition_element::CONVENTIONAL);
+ /* Newly added element is inserted before AS_OF_NOW. */
+ if (el->id == UINT_MAX32 || el->type == partition_element::CURRENT)
+ {
+ el->id= id;
+ if (el->type == partition_element::CURRENT)
+ break;
+ }
+ }
+}
+
#endif /* PARTITION_INFO_INCLUDED */
diff --git a/sql/privilege.h b/sql/privilege.h
new file mode 100644
index 00000000000..37cdf4da01a
--- /dev/null
+++ b/sql/privilege.h
@@ -0,0 +1,738 @@
+#ifndef PRIVILEGE_H_INCLUDED
+#define PRIVILEGE_H_INCLUDED
+
+/* Copyright (c) 2020, 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 St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "my_global.h" // ulonglong
+
+
+/*
+ A strict enum to store privilege bits.
+
+ We should eventually make if even stricter using "enum class privilege_t" and:
+ - Replace all code pieces like `if (priv)` to `if (priv != NO_ACL)`
+ - Remove "delete" comparison operators below
+*/
+enum privilege_t: unsigned long long
+{
+ NO_ACL = (0),
+ SELECT_ACL = (1UL << 0),
+ INSERT_ACL = (1UL << 1),
+ UPDATE_ACL = (1UL << 2),
+ DELETE_ACL = (1UL << 3),
+ CREATE_ACL = (1UL << 4),
+ DROP_ACL = (1UL << 5),
+ RELOAD_ACL = (1UL << 6),
+ SHUTDOWN_ACL = (1UL << 7),
+ PROCESS_ACL = (1UL << 8),
+ FILE_ACL = (1UL << 9),
+ GRANT_ACL = (1UL << 10),
+ REFERENCES_ACL = (1UL << 11),
+ INDEX_ACL = (1UL << 12),
+ ALTER_ACL = (1UL << 13),
+ SHOW_DB_ACL = (1UL << 14),
+ SUPER_ACL = (1UL << 15),
+ CREATE_TMP_ACL = (1UL << 16),
+ LOCK_TABLES_ACL = (1UL << 17),
+ EXECUTE_ACL = (1UL << 18),
+ REPL_SLAVE_ACL = (1UL << 19),
+ BINLOG_MONITOR_ACL = (1UL << 20), // Was REPL_CLIENT_ACL prior to 10.5.2
+ CREATE_VIEW_ACL = (1UL << 21),
+ SHOW_VIEW_ACL = (1UL << 22),
+ CREATE_PROC_ACL = (1UL << 23),
+ ALTER_PROC_ACL = (1UL << 24),
+ CREATE_USER_ACL = (1UL << 25),
+ EVENT_ACL = (1UL << 26),
+ TRIGGER_ACL = (1UL << 27),
+ CREATE_TABLESPACE_ACL = (1UL << 28),
+ DELETE_HISTORY_ACL = (1UL << 29), // Added in 10.3.4
+ SET_USER_ACL = (1UL << 30), // Added in 10.5.2
+ FEDERATED_ADMIN_ACL = (1UL << 31), // Added in 10.5.2
+ CONNECTION_ADMIN_ACL = (1ULL << 32), // Added in 10.5.2
+ READ_ONLY_ADMIN_ACL = (1ULL << 33), // Added in 10.5.2
+ REPL_SLAVE_ADMIN_ACL = (1ULL << 34), // Added in 10.5.2
+ REPL_MASTER_ADMIN_ACL = (1ULL << 35), // Added in 10.5.2
+ BINLOG_ADMIN_ACL = (1ULL << 36), // Added in 10.5.2
+ BINLOG_REPLAY_ACL = (1ULL << 37) // Added in 10.5.2
+ /*
+ When adding new privilege bits, don't forget to update:
+ In this file:
+ - Add a new LAST_version_ACL
+ - Add a new ALL_KNOWN_ACL_version
+ - Change ALL_KNOWN_ACL to ALL_KNOWN_ACL_version
+ - Change GLOBAL_ACLS if needed
+ - Change SUPER_ADDED_SINCE_USER_TABLE_ACL if needed
+
+ In other files:
+ - static struct show_privileges_st sys_privileges[]
+ - static const char *command_array[] and static uint command_lengths[]
+ - mysql_system_tables.sql and mysql_system_tables_fix.sql
+ - acl_init() or whatever - to define behaviour for old privilege tables
+ - Update User_table_json::get_access()
+ - sql_yacc.yy - for GRANT/REVOKE to work
+
+ Important: the enum should contain only single-bit values.
+ In this case, debuggers print bit combinations in the readable form:
+ (gdb) p (privilege_t) (15)
+ $8 = (SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL)
+
+ Bit-OR combinations of the above values should be declared outside!
+ */
+};
+
+
+// Version markers
+constexpr privilege_t LAST_100304_ACL= DELETE_HISTORY_ACL;
+constexpr privilege_t LAST_100502_ACL= BINLOG_REPLAY_ACL;
+
+// Current version markers
+constexpr privilege_t LAST_CURRENT_ACL= LAST_100502_ACL;
+constexpr uint PRIVILEGE_T_MAX_BIT=
+ my_bit_log2_uint64((ulonglong) LAST_CURRENT_ACL);
+
+static_assert((privilege_t)(1ULL << PRIVILEGE_T_MAX_BIT) == LAST_CURRENT_ACL,
+ "Something went fatally badly: "
+ "LAST_CURRENT_ACL and PRIVILEGE_T_MAX_BIT do not match");
+
+// A combination of all bits defined in 10.3.4 (and earlier)
+constexpr privilege_t ALL_KNOWN_ACL_100304 =
+ (privilege_t) ((LAST_100304_ACL << 1) - 1);
+
+// A combination of all bits defined in 10.5.2
+constexpr privilege_t ALL_KNOWN_ACL_100502=
+ (privilege_t) ((LAST_100502_ACL << 1) - 1);
+
+// A combination of all bits defined as of the current version
+constexpr privilege_t ALL_KNOWN_ACL= ALL_KNOWN_ACL_100502;
+
+
+// Unary operators
+static inline constexpr ulonglong operator~(privilege_t access)
+{
+ return ~static_cast<ulonglong>(access);
+}
+
+/*
+ Comparison operators.
+ Delete automatic conversion between to/from integer types as much as possible.
+ This forces to use `(priv == NO_ACL)` instead of `(priv == 0)`.
+
+ Note: these operators will be gone when we change privilege_t to
+ "enum class privilege_t". See comments above.
+*/
+static inline bool operator==(privilege_t, ulonglong)= delete;
+static inline bool operator==(privilege_t, ulong)= delete;
+static inline bool operator==(privilege_t, uint)= delete;
+static inline bool operator==(privilege_t, uchar)= delete;
+static inline bool operator==(privilege_t, longlong)= delete;
+static inline bool operator==(privilege_t, long)= delete;
+static inline bool operator==(privilege_t, int)= delete;
+static inline bool operator==(privilege_t, char)= delete;
+static inline bool operator==(privilege_t, bool)= delete;
+
+static inline bool operator==(ulonglong, privilege_t)= delete;
+static inline bool operator==(ulong, privilege_t)= delete;
+static inline bool operator==(uint, privilege_t)= delete;
+static inline bool operator==(uchar, privilege_t)= delete;
+static inline bool operator==(longlong, privilege_t)= delete;
+static inline bool operator==(long, privilege_t)= delete;
+static inline bool operator==(int, privilege_t)= delete;
+static inline bool operator==(char, privilege_t)= delete;
+static inline bool operator==(bool, privilege_t)= delete;
+
+static inline bool operator!=(privilege_t, ulonglong)= delete;
+static inline bool operator!=(privilege_t, ulong)= delete;
+static inline bool operator!=(privilege_t, uint)= delete;
+static inline bool operator!=(privilege_t, uchar)= delete;
+static inline bool operator!=(privilege_t, longlong)= delete;
+static inline bool operator!=(privilege_t, long)= delete;
+static inline bool operator!=(privilege_t, int)= delete;
+static inline bool operator!=(privilege_t, char)= delete;
+static inline bool operator!=(privilege_t, bool)= delete;
+
+static inline bool operator!=(ulonglong, privilege_t)= delete;
+static inline bool operator!=(ulong, privilege_t)= delete;
+static inline bool operator!=(uint, privilege_t)= delete;
+static inline bool operator!=(uchar, privilege_t)= delete;
+static inline bool operator!=(longlong, privilege_t)= delete;
+static inline bool operator!=(long, privilege_t)= delete;
+static inline bool operator!=(int, privilege_t)= delete;
+static inline bool operator!=(char, privilege_t)= delete;
+static inline bool operator!=(bool, privilege_t)= delete;
+
+
+// Dyadic bitwise operators
+static inline constexpr privilege_t operator&(privilege_t a, privilege_t b)
+{
+ return static_cast<privilege_t>(static_cast<ulonglong>(a) &
+ static_cast<ulonglong>(b));
+}
+
+static inline constexpr privilege_t operator&(ulonglong a, privilege_t b)
+{
+ return static_cast<privilege_t>(a & static_cast<ulonglong>(b));
+}
+
+static inline constexpr privilege_t operator&(privilege_t a, ulonglong b)
+{
+ return static_cast<privilege_t>(static_cast<ulonglong>(a) & b);
+}
+
+static inline constexpr privilege_t operator|(privilege_t a, privilege_t b)
+{
+ return static_cast<privilege_t>(static_cast<ulonglong>(a) |
+ static_cast<ulonglong>(b));
+}
+
+
+// Dyadyc bitwise assignment operators
+static inline privilege_t& operator&=(privilege_t &a, privilege_t b)
+{
+ return a= a & b;
+}
+
+static inline privilege_t& operator&=(privilege_t &a, ulonglong b)
+{
+ return a= a & b;
+}
+
+static inline privilege_t& operator|=(privilege_t &a, privilege_t b)
+{
+ return a= a | b;
+}
+
+
+/*
+ A combination of all SUPER privileges added since the old user table format.
+ These privileges are automatically added when upgrading from the
+ old format mysql.user table if a user has the SUPER privilege.
+*/
+constexpr privilege_t GLOBAL_SUPER_ADDED_SINCE_USER_TABLE_ACLS=
+ SET_USER_ACL |
+ FEDERATED_ADMIN_ACL |
+ CONNECTION_ADMIN_ACL |
+ READ_ONLY_ADMIN_ACL |
+ REPL_SLAVE_ADMIN_ACL |
+ BINLOG_ADMIN_ACL |
+ BINLOG_REPLAY_ACL;
+
+
+constexpr privilege_t COL_DML_ACLS=
+ SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL;
+
+constexpr privilege_t VIEW_ACLS=
+ CREATE_VIEW_ACL | SHOW_VIEW_ACL;
+
+constexpr privilege_t STD_TABLE_DDL_ACLS=
+ CREATE_ACL | DROP_ACL | ALTER_ACL;
+
+constexpr privilege_t ALL_TABLE_DDL_ACLS=
+ STD_TABLE_DDL_ACLS | INDEX_ACL;
+
+constexpr privilege_t COL_ACLS=
+ SELECT_ACL | INSERT_ACL | UPDATE_ACL | REFERENCES_ACL;
+
+constexpr privilege_t PROC_DDL_ACLS=
+ CREATE_PROC_ACL | ALTER_PROC_ACL;
+
+constexpr privilege_t SHOW_PROC_ACLS=
+ PROC_DDL_ACLS | EXECUTE_ACL;
+
+constexpr privilege_t TABLE_ACLS=
+ COL_DML_ACLS | ALL_TABLE_DDL_ACLS | VIEW_ACLS |
+ GRANT_ACL | REFERENCES_ACL |
+ TRIGGER_ACL | DELETE_HISTORY_ACL;
+
+constexpr privilege_t DB_ACLS=
+ TABLE_ACLS | PROC_DDL_ACLS | EXECUTE_ACL |
+ CREATE_TMP_ACL | LOCK_TABLES_ACL | EVENT_ACL;
+
+constexpr privilege_t PROC_ACLS=
+ ALTER_PROC_ACL | EXECUTE_ACL | GRANT_ACL;
+
+constexpr privilege_t GLOBAL_ACLS=
+ DB_ACLS | SHOW_DB_ACL |
+ CREATE_USER_ACL | CREATE_TABLESPACE_ACL |
+ SUPER_ACL | RELOAD_ACL | SHUTDOWN_ACL | PROCESS_ACL | FILE_ACL |
+ REPL_SLAVE_ACL | BINLOG_MONITOR_ACL |
+ GLOBAL_SUPER_ADDED_SINCE_USER_TABLE_ACLS |
+ REPL_MASTER_ADMIN_ACL;
+
+constexpr privilege_t DEFAULT_CREATE_PROC_ACLS=
+ ALTER_PROC_ACL | EXECUTE_ACL;
+
+constexpr privilege_t SHOW_CREATE_TABLE_ACLS=
+ COL_DML_ACLS | ALL_TABLE_DDL_ACLS |
+ TRIGGER_ACL | REFERENCES_ACL | GRANT_ACL | VIEW_ACLS;
+
+/**
+ Table-level privileges which are automatically "granted" to everyone on
+ existing temporary tables (CREATE_ACL is necessary for ALTER ... RENAME).
+*/
+constexpr privilege_t TMP_TABLE_ACLS=
+ COL_DML_ACLS | ALL_TABLE_DDL_ACLS;
+
+
+
+/*
+ Allow to set an object definer:
+ CREATE DEFINER=xxx {TRIGGER|VIEW|FUNCTION|PROCEDURE}
+ Was SUPER prior to 10.5.2
+*/
+constexpr privilege_t PRIV_DEFINER_CLAUSE= SET_USER_ACL | SUPER_ACL;
+/*
+ If a VIEW has a `definer=invoker@host` clause and
+ the specified definer does not exists, then
+ - The invoker with REVEAL_MISSING_DEFINER_ACL gets:
+ ERROR: The user specified as a definer ('definer1'@'localhost') doesn't exist
+ - The invoker without MISSING_DEFINER_ACL gets a generic access error,
+ without revealing details that the definer does not exists.
+
+ TODO: we should eventually test the same privilege when processing
+ other objects that have the DEFINER clause (e.g. routines, triggers).
+ Currently the missing definer is revealed for non-privileged invokers
+ in case of routines, triggers, etc.
+
+ Was SUPER prior to 10.5.2
+*/
+constexpr privilege_t PRIV_REVEAL_MISSING_DEFINER= SET_USER_ACL | SUPER_ACL;
+
+/* Actions that require only the SUPER privilege */
+constexpr privilege_t PRIV_DES_DECRYPT_ONE_ARG= SUPER_ACL;
+constexpr privilege_t PRIV_LOG_BIN_TRUSTED_SP_CREATOR= SUPER_ACL;
+constexpr privilege_t PRIV_DEBUG= SUPER_ACL;
+constexpr privilege_t PRIV_SET_GLOBAL_SYSTEM_VARIABLE= SUPER_ACL;
+constexpr privilege_t PRIV_SET_RESTRICTED_SESSION_SYSTEM_VARIABLE= SUPER_ACL;
+
+/* The following variables respected only SUPER_ACL prior to 10.5.2 */
+constexpr privilege_t PRIV_SET_SYSTEM_VAR_BINLOG_FORMAT=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_VAR_BINLOG_DIRECT_NON_TRANSACTIONAL_UPDATES=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_VAR_BINLOG_ANNOTATE_ROW_EVENTS=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_VAR_BINLOG_ROW_IMAGE=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_VAR_SQL_LOG_BIN=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_CACHE_SIZE=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_FILE_CACHE_SIZE=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_STMT_CACHE_SIZE=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_COMMIT_WAIT_COUNT=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_COMMIT_WAIT_USEC=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_ROW_METADATA=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_EXPIRE_LOGS_DAYS=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_LOG_BIN_COMPRESS=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_LOG_BIN_COMPRESS_MIN_LEN=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_LOG_BIN_TRUST_FUNCTION_CREATORS=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_BINLOG_CACHE_SIZE=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_BINLOG_STMT_CACHE_SIZE=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_BINLOG_SIZE=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SYNC_BINLOG=
+ SUPER_ACL | BINLOG_ADMIN_ACL;
+
+
+
+/* Privileges related to --read-only */
+// Was super prior to 10.5.2
+constexpr privilege_t PRIV_IGNORE_READ_ONLY= READ_ONLY_ADMIN_ACL | SUPER_ACL;
+// Was super prior to 10.5.2
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_READ_ONLY=
+ READ_ONLY_ADMIN_ACL | SUPER_ACL;
+
+/*
+ Privileges related to connection handling.
+*/
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_IGNORE_INIT_CONNECT= CONNECTION_ADMIN_ACL | SUPER_ACL;
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_IGNORE_MAX_USER_CONNECTIONS= CONNECTION_ADMIN_ACL | SUPER_ACL;
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_IGNORE_MAX_CONNECTIONS= CONNECTION_ADMIN_ACL | SUPER_ACL;
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_IGNORE_MAX_PASSWORD_ERRORS= CONNECTION_ADMIN_ACL | SUPER_ACL;
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_KILL_OTHER_USER_PROCESS= CONNECTION_ADMIN_ACL | SUPER_ACL;
+
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_CONNECT_TIMEOUT=
+ CONNECTION_ADMIN_ACL | SUPER_ACL;
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_DISCONNECT_ON_EXPIRED_PASSWORD=
+ CONNECTION_ADMIN_ACL | SUPER_ACL;
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_EXTRA_MAX_CONNECTIONS=
+ CONNECTION_ADMIN_ACL | SUPER_ACL;
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_INIT_CONNECT=
+ CONNECTION_ADMIN_ACL | SUPER_ACL;
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_CONNECTIONS=
+ CONNECTION_ADMIN_ACL | SUPER_ACL;
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_CONNECT_ERRORS=
+ CONNECTION_ADMIN_ACL | SUPER_ACL;
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_PASSWORD_ERRORS=
+ CONNECTION_ADMIN_ACL | SUPER_ACL;
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_PROXY_PROTOCOL_NETWORKS=
+ CONNECTION_ADMIN_ACL | SUPER_ACL;
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SECURE_AUTH=
+ CONNECTION_ADMIN_ACL | SUPER_ACL;
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLOW_LAUNCH_TIME=
+ CONNECTION_ADMIN_ACL | SUPER_ACL;
+
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_THREAD_POOL=
+ CONNECTION_ADMIN_ACL | SUPER_ACL;
+
+
+/*
+ Binary log related privileges that are checked regardless
+ of active replication running.
+*/
+
+/*
+ This command was renamed from "SHOW MASTER STATUS"
+ to "SHOW BINLOG STATUS" in 10.5.2.
+ Was SUPER_ACL | REPL_CLIENT_ACL prior to 10.5.2
+ REPL_CLIENT_ACL was renamed to BINLOG_MONITOR_ACL.
+*/
+constexpr privilege_t PRIV_STMT_SHOW_BINLOG_STATUS= BINLOG_MONITOR_ACL | SUPER_ACL;
+
+/*
+ Was SUPER_ACL | REPL_CLIENT_ACL prior to 10.5.2
+ REPL_CLIENT_ACL was renamed to BINLOG_MONITOR_ACL.
+*/
+constexpr privilege_t PRIV_STMT_SHOW_BINARY_LOGS= BINLOG_MONITOR_ACL | SUPER_ACL;
+
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_STMT_PURGE_BINLOG= BINLOG_ADMIN_ACL | SUPER_ACL;
+
+// Was REPL_SLAVE_ACL prior to 10.5.2
+constexpr privilege_t PRIV_STMT_SHOW_BINLOG_EVENTS= BINLOG_MONITOR_ACL;
+
+
+/*
+ Privileges for replication related statements and commands
+ that are executed on the master.
+*/
+constexpr privilege_t PRIV_COM_REGISTER_SLAVE= REPL_SLAVE_ACL;
+constexpr privilege_t PRIV_COM_BINLOG_DUMP= REPL_SLAVE_ACL;
+// Was REPL_SLAVE_ACL prior to 10.5.2
+constexpr privilege_t PRIV_STMT_SHOW_SLAVE_HOSTS= REPL_MASTER_ADMIN_ACL;
+
+/*
+ Replication master related variable privileges.
+ Where SUPER prior to 10.5.2
+*/
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_MASTER_ENABLED=
+ REPL_MASTER_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_MASTER_TIMEOUT=
+ REPL_MASTER_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_MASTER_WAIT_NO_SLAVE=
+ REPL_MASTER_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_MASTER_TRACE_LEVEL=
+ REPL_MASTER_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_MASTER_WAIT_POINT=
+ REPL_MASTER_ADMIN_ACL | SUPER_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_MASTER_VERIFY_CHECKSUM=
+ REPL_MASTER_ADMIN_ACL | SUPER_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_BINLOG_STATE=
+ REPL_MASTER_ADMIN_ACL | SUPER_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SERVER_ID=
+ REPL_MASTER_ADMIN_ACL | SUPER_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_DOMAIN_ID=
+ REPL_MASTER_ADMIN_ACL | SUPER_ACL;
+
+
+/* Privileges for statements that are executed on the slave */
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_STMT_START_SLAVE= REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_STMT_STOP_SLAVE= REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_STMT_CHANGE_MASTER= REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+// Was (SUPER_ACL | REPL_CLIENT_ACL) prior to 10.5.2
+constexpr privilege_t PRIV_STMT_SHOW_SLAVE_STATUS= REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+// Was REPL_SLAVE_ACL prior to 10.5.2
+constexpr privilege_t PRIV_STMT_SHOW_RELAYLOG_EVENTS= REPL_SLAVE_ADMIN_ACL;
+
+/*
+ Privileges related to binlog replying.
+ Were SUPER_ACL prior to 10.5.2
+*/
+constexpr privilege_t PRIV_STMT_BINLOG= BINLOG_REPLAY_ACL | SUPER_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_SESSION_VAR_GTID_SEQ_NO=
+ BINLOG_REPLAY_ACL | SUPER_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_SESSION_VAR_PSEUDO_THREAD_ID=
+ BINLOG_REPLAY_ACL | SUPER_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_SESSION_VAR_SERVER_ID=
+ BINLOG_REPLAY_ACL | SUPER_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_SESSION_VAR_GTID_DOMAIN_ID=
+ BINLOG_REPLAY_ACL | SUPER_ACL;
+
+/*
+ Privileges for slave related global variables.
+ Were SUPER prior to 10.5.2.
+*/
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_EVENTS_MARKED_FOR_SKIP=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_DO_DB=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_DO_TABLE=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_IGNORE_DB=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_IGNORE_TABLE=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_WILD_DO_TABLE=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_WILD_IGNORE_TABLE=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_READ_BINLOG_SPEED_LIMIT=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_COMPRESSED_PROTOCOL=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_DDL_EXEC_MODE=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_DOMAIN_PARALLEL_THREADS=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_EXEC_MODE=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_MAX_ALLOWED_PACKET=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_NET_TIMEOUT=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_PARALLEL_MAX_QUEUED=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_PARALLEL_MODE=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_PARALLEL_THREADS=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_PARALLEL_WORKERS=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_RUN_TRIGGERS_FOR_RBR=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_SQL_VERIFY_CHECKSUM=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_TRANSACTION_RETRY_INTERVAL=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_TYPE_CONVERSIONS=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_INIT_SLAVE=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_SLAVE_ENABLED=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_SLAVE_TRACE_LEVEL=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_SLAVE_DELAY_MASTER=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_SLAVE_KILL_CONN_TIMEOUT=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RELAY_LOG_PURGE=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RELAY_LOG_RECOVERY=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SYNC_MASTER_INFO=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SYNC_RELAY_LOG=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SYNC_RELAY_LOG_INFO=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_CLEANUP_BATCH_SIZE=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_IGNORE_DUPLICATES=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_POS_AUTO_ENGINES=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_SLAVE_POS=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_STRICT_MODE=
+ REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
+
+
+/* Privileges for federated database related statements */
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_STMT_CREATE_SERVER= FEDERATED_ADMIN_ACL | SUPER_ACL;
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_STMT_ALTER_SERVER= FEDERATED_ADMIN_ACL | SUPER_ACL;
+// Was SUPER_ACL prior to 10.5.2
+constexpr privilege_t PRIV_STMT_DROP_SERVER= FEDERATED_ADMIN_ACL | SUPER_ACL;
+
+
+/* Privileges related to processes */
+constexpr privilege_t PRIV_COM_PROCESS_INFO= PROCESS_ACL;
+constexpr privilege_t PRIV_STMT_SHOW_EXPLAIN= PROCESS_ACL;
+constexpr privilege_t PRIV_STMT_SHOW_ENGINE_STATUS= PROCESS_ACL;
+constexpr privilege_t PRIV_STMT_SHOW_ENGINE_MUTEX= PROCESS_ACL;
+constexpr privilege_t PRIV_STMT_SHOW_PROCESSLIST= PROCESS_ACL;
+
+
+/*
+ Defines to change the above bits to how things are stored in tables
+ This is needed as the 'host' and 'db' table is missing a few privileges
+*/
+
+/* Privileges that need to be reallocated (in continous chunks) */
+constexpr privilege_t DB_CHUNK0 (COL_DML_ACLS | CREATE_ACL | DROP_ACL);
+constexpr privilege_t DB_CHUNK1 (GRANT_ACL | REFERENCES_ACL | INDEX_ACL | ALTER_ACL);
+constexpr privilege_t DB_CHUNK2 (CREATE_TMP_ACL | LOCK_TABLES_ACL);
+constexpr privilege_t DB_CHUNK3 (VIEW_ACLS | PROC_DDL_ACLS);
+constexpr privilege_t DB_CHUNK4 (EXECUTE_ACL);
+constexpr privilege_t DB_CHUNK5 (EVENT_ACL | TRIGGER_ACL);
+constexpr privilege_t DB_CHUNK6 (DELETE_HISTORY_ACL);
+
+
+static inline privilege_t fix_rights_for_db(privilege_t access)
+{
+ ulonglong A(access);
+ return static_cast<privilege_t>
+ (((A) & DB_CHUNK0) |
+ ((A << 4) & DB_CHUNK1) |
+ ((A << 6) & DB_CHUNK2) |
+ ((A << 9) & DB_CHUNK3) |
+ ((A << 2) & DB_CHUNK4) |
+ ((A << 9) & DB_CHUNK5) |
+ ((A << 10) & DB_CHUNK6));
+}
+
+static inline privilege_t get_rights_for_db(privilege_t access)
+{
+ ulonglong A(access);
+ return static_cast<privilege_t>
+ ((A & DB_CHUNK0) |
+ ((A & DB_CHUNK1) >> 4) |
+ ((A & DB_CHUNK2) >> 6) |
+ ((A & DB_CHUNK3) >> 9) |
+ ((A & DB_CHUNK4) >> 2) |
+ ((A & DB_CHUNK5) >> 9) |
+ ((A & DB_CHUNK6) >> 10));
+}
+
+
+#define TBL_CHUNK0 DB_CHUNK0
+#define TBL_CHUNK1 DB_CHUNK1
+#define TBL_CHUNK2 (CREATE_VIEW_ACL | SHOW_VIEW_ACL)
+#define TBL_CHUNK3 TRIGGER_ACL
+#define TBL_CHUNK4 (DELETE_HISTORY_ACL)
+
+
+static inline privilege_t fix_rights_for_table(privilege_t access)
+{
+ ulonglong A(access);
+ return static_cast<privilege_t>
+ ((A & TBL_CHUNK0) |
+ ((A << 4) & TBL_CHUNK1) |
+ ((A << 11) & TBL_CHUNK2) |
+ ((A << 15) & TBL_CHUNK3) |
+ ((A << 16) & TBL_CHUNK4));
+}
+
+
+static inline privilege_t get_rights_for_table(privilege_t access)
+{
+ ulonglong A(access);
+ return static_cast<privilege_t>
+ ((A & TBL_CHUNK0) |
+ ((A & TBL_CHUNK1) >> 4) |
+ ((A & TBL_CHUNK2) >> 11) |
+ ((A & TBL_CHUNK3) >> 15) |
+ ((A & TBL_CHUNK4) >> 16));
+}
+
+
+static inline privilege_t fix_rights_for_column(privilege_t A)
+{
+ const ulonglong mask(SELECT_ACL | INSERT_ACL | UPDATE_ACL);
+ return (A & mask) | static_cast<privilege_t>((A & ~mask) << 8);
+}
+
+
+static inline privilege_t get_rights_for_column(privilege_t A)
+{
+ const ulonglong mask(SELECT_ACL | INSERT_ACL | UPDATE_ACL);
+ return static_cast<privilege_t>((static_cast<ulonglong>(A) & mask) |
+ (static_cast<ulonglong>(A) >> 8));
+}
+
+
+static inline privilege_t fix_rights_for_procedure(privilege_t access)
+{
+ ulonglong A(access);
+ return static_cast<privilege_t>
+ (((A << 18) & EXECUTE_ACL) |
+ ((A << 23) & ALTER_PROC_ACL) |
+ ((A << 8) & GRANT_ACL));
+}
+
+
+static inline privilege_t get_rights_for_procedure(privilege_t access)
+{
+ ulonglong A(access);
+ return static_cast<privilege_t>
+ (((A & EXECUTE_ACL) >> 18) |
+ ((A & ALTER_PROC_ACL) >> 23) |
+ ((A & GRANT_ACL) >> 8));
+}
+
+
+#endif /* PRIVILEGE_H_INCLUDED */
diff --git a/sql/procedure.h b/sql/procedure.h
index 15fd525ec65..769eac5f217 100644
--- a/sql/procedure.h
+++ b/sql/procedure.h
@@ -2,6 +2,7 @@
#define PROCEDURE_INCLUDED
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2009, 2020, 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
@@ -44,7 +45,7 @@ public:
this->name.length= strlen(name_par);
}
enum Type type() const { return Item::PROC_ITEM; }
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
/*
@@ -52,7 +53,7 @@ public:
DECLARE c CURSOR FOR SELECT * FROM t1 PROCEDURE analyse();
OPEN c;
*/
- return create_tmp_field_ex_simple(table, src, param);
+ return create_tmp_field_ex_simple(root, table, src, param);
}
virtual void set(double nr)=0;
virtual void set(const char *str,uint length,CHARSET_INFO *cs)=0;
@@ -88,7 +89,7 @@ public:
{
int err_not_used;
char *end_not_used;
- value= my_strntod(cs,(char*) str,length, &end_not_used, &err_not_used);
+ value= cs->strntod((char*) str,length, &end_not_used, &err_not_used);
}
double val_real() { return value; }
longlong val_int() { return (longlong) value; }
@@ -107,11 +108,16 @@ class Item_proc_int :public Item_proc
public:
Item_proc_int(THD *thd, const char *name_par): Item_proc(thd, name_par)
{ max_length=11; }
- const Type_handler *type_handler() const { return &type_handler_longlong; }
+ const Type_handler *type_handler() const
+ {
+ if (unsigned_flag)
+ return &type_handler_ulonglong;
+ return &type_handler_slonglong;
+ }
void set(double nr) { value=(longlong) nr; }
void set(longlong nr) { value=nr; }
void set(const char *str,uint length, CHARSET_INFO *cs)
- { int err; value=my_strntoll(cs,str,length,10,NULL,&err); }
+ { int err; value= cs->strntoll(str,length,10,NULL,&err); }
double val_real() { return (double) value; }
longlong val_int() { return value; }
String *val_str(String *s) { s->set(value, default_charset()); return s; }
@@ -135,14 +141,14 @@ public:
int err_not_used;
char *end_not_used;
CHARSET_INFO *cs= str_value.charset();
- return my_strntod(cs, (char*) str_value.ptr(), str_value.length(),
- &end_not_used, &err_not_used);
+ return cs->strntod((char*) str_value.ptr(), str_value.length(),
+ &end_not_used, &err_not_used);
}
longlong val_int()
{
int err;
CHARSET_INFO *cs=str_value.charset();
- return my_strntoll(cs,str_value.ptr(),str_value.length(),10,NULL,&err);
+ return cs->strntoll(str_value.ptr(),str_value.length(),10,NULL,&err);
}
String *val_str(String*)
{
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 8c7eeaec90c..21efac46c52 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -799,6 +799,41 @@ bool Protocol::flush()
#ifndef EMBEDDED_LIBRARY
+
+class Send_field_packed_extended_metadata: public Binary_string
+{
+public:
+ bool append_chunk(mariadb_field_attr_t type, const LEX_CSTRING &value)
+ {
+ /*
+ If we eventually support many metadata chunk types and long metadata
+ values, we'll need to encode type and length using net_store_length()
+ and do corresponding changes to the unpacking code in libmariadb.
+ For now let's just assert that type and length fit into one byte.
+ */
+ DBUG_ASSERT(net_length_size(type) == 1);
+ DBUG_ASSERT(net_length_size(value.length) == 1);
+ size_t nbytes= 1/*type*/ + 1/*length*/ + value.length;
+ if (reserve(nbytes))
+ return true;
+ qs_append((char) (uchar) type);
+ qs_append((char) (uchar) value.length);
+ qs_append(&value);
+ return false;
+ }
+ bool pack(const Send_field_extended_metadata &src)
+ {
+ for (uint i= 0 ; i <= MARIADB_FIELD_ATTR_LAST; i++)
+ {
+ const LEX_CSTRING attr= src.attr(i);
+ if (attr.str && append_chunk((mariadb_field_attr_t) i, attr))
+ return true;
+ }
+ return false;
+ }
+};
+
+
bool Protocol_text::store_field_metadata(const THD * thd,
const Send_field &field,
CHARSET_INFO *charset_for_protocol,
@@ -816,8 +851,20 @@ bool Protocol_text::store_field_metadata(const THD * thd,
store_str(field.table_name, cs, thd_charset) ||
store_str(field.org_table_name, cs, thd_charset) ||
store_str(field.col_name, cs, thd_charset) ||
- store_str(field.org_col_name, cs, thd_charset) ||
- packet->realloc(packet->length() + 12))
+ store_str(field.org_col_name, cs, thd_charset))
+ return true;
+ if (thd->client_capabilities & MARIADB_CLIENT_EXTENDED_METADATA)
+ {
+ Send_field_packed_extended_metadata metadata;
+ metadata.pack(field);
+ /*
+ Don't apply character set conversion:
+ extended metadata is a binary encoded data.
+ */
+ if (store_str(metadata.lex_cstring(), cs, &my_charset_bin))
+ return true;
+ }
+ if (packet->realloc(packet->length() + 12))
return true;
/* Store fixed length fields */
pos= (char*) packet->end();
@@ -1001,7 +1048,7 @@ bool Protocol_text::store_field_metadata_for_list_fields(const THD *thd,
uint pos)
{
Send_field field= tl->view ?
- Send_field(fld, tl->view_db.str, tl->view_name.str) :
+ Send_field(fld, tl->view_db, tl->view_name) :
Send_field(fld);
return store_field_metadata(thd, field, fld->charset_for_protocol(), pos);
}
@@ -1143,6 +1190,18 @@ bool Protocol::store_string_aux(const char *from, size_t length,
}
+bool Protocol::store_warning(const char *from, size_t length)
+{
+ BinaryStringBuffer<MYSQL_ERRMSG_SIZE> tmp;
+ CHARSET_INFO *cs= thd->variables.character_set_results;
+ if (cs == &my_charset_bin)
+ cs= system_charset_info;
+ if (tmp.copy_printable_hhhh(cs, system_charset_info, from, length))
+ return net_store_data((const uchar*)"", 0);
+ return net_store_data((const uchar *) tmp.ptr(), tmp.length());
+}
+
+
bool Protocol_text::store(const char *from, size_t length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
{
diff --git a/sql/protocol.h b/sql/protocol.h
index 3b2c905ed9e..661ca11d3a1 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -90,6 +90,7 @@ public:
bool store(I_List<i_string> *str_list);
bool store(const char *from, CHARSET_INFO *cs);
+ bool store_warning(const char *from, size_t length);
String *storage_packet() { return packet; }
inline void free() { packet->free(); }
virtual bool write();
@@ -122,11 +123,6 @@ public:
virtual bool store(const char *from, size_t length, CHARSET_INFO *cs)=0;
virtual bool store(const char *from, size_t length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs)=0;
- bool store_str(const char *s, CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
- {
- DBUG_ASSERT(s);
- return store(s, (uint) strlen(s), fromcs, tocs);
- }
bool store_str(const LEX_CSTRING &s, CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
{
return store(s.str, (uint) s.length, fromcs, tocs);
diff --git a/sql/proxy_protocol.cc b/sql/proxy_protocol.cc
index 550813c6457..689d1af88f0 100644
--- a/sql/proxy_protocol.cc
+++ b/sql/proxy_protocol.cc
@@ -364,7 +364,8 @@ static int parse_networks(const char *subnets_str, subnet **out_subnets, size_t
}
max_subnets= MY_MAX(3,strlen(subnets_str)/2);
- subnets= (subnet *)my_malloc(max_subnets * sizeof(subnet),MY_ZEROFILL);
+ subnets= (subnet *)my_malloc(PSI_INSTRUMENT_ME,
+ max_subnets * sizeof(subnet), MY_ZEROFILL);
/* Check for special case '*'. */
if (strcmp(subnets_str, "*") == 0)
diff --git a/sql/records.cc b/sql/records.cc
index 3d709182a4e..e1766322e2f 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -38,8 +38,8 @@
static int rr_quick(READ_RECORD *info);
int rr_sequential(READ_RECORD *info);
static int rr_from_tempfile(READ_RECORD *info);
-static int rr_unpack_from_tempfile(READ_RECORD *info);
-static int rr_unpack_from_buffer(READ_RECORD *info);
+template<bool> static int rr_unpack_from_tempfile(READ_RECORD *info);
+template<bool,bool> static int rr_unpack_from_buffer(READ_RECORD *info);
int rr_from_pointers(READ_RECORD *info);
static int rr_from_cache(READ_RECORD *info);
static int init_rr_cache(THD *thd, READ_RECORD *info);
@@ -187,23 +187,24 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
bool disable_rr_cache)
{
IO_CACHE *tempfile;
- SORT_ADDON_FIELD *addon_field= filesort ? filesort->addon_field : 0;
DBUG_ENTER("init_read_record");
+ const bool using_addon_fields= filesort && filesort->using_addon_fields();
+ bool using_packed_sortkeys= filesort && filesort->using_packed_sortkeys();
+
bzero((char*) info,sizeof(*info));
info->thd=thd;
info->table=table;
- info->addon_field= addon_field;
+ info->sort_info= filesort;
if ((table->s->tmp_table == INTERNAL_TMP_TABLE) &&
- !addon_field)
+ !using_addon_fields)
(void) table->file->extra(HA_EXTRA_MMAP);
- if (addon_field)
+ if (using_addon_fields)
{
- info->rec_buf= (uchar*) filesort->addon_buf.str;
- info->ref_length= (uint)filesort->addon_buf.length;
- info->unpack= filesort->unpack;
+ info->rec_buf= filesort->addon_fields->get_addon_buf();
+ info->ref_length= filesort->addon_fields->get_addon_buf_length();
}
else
{
@@ -223,9 +224,20 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
if (tempfile && !(select && select->quick))
{
- DBUG_PRINT("info",("using rr_from_tempfile"));
- info->read_record_func=
- addon_field ? rr_unpack_from_tempfile : rr_from_tempfile;
+ if (using_addon_fields)
+ {
+ DBUG_PRINT("info",("using rr_from_tempfile"));
+ if (filesort->addon_fields->using_packed_addons())
+ info->read_record_func= rr_unpack_from_tempfile<true>;
+ else
+ info->read_record_func= rr_unpack_from_tempfile<false>;
+ }
+ else
+ {
+ DBUG_PRINT("info",("using rr_from_tempfile"));
+ info->read_record_func= rr_from_tempfile;
+ }
+
info->io_cache= tempfile;
reinit_io_cache(info->io_cache,READ_CACHE,0L,0,0);
info->ref_pos=table->file->ref;
@@ -239,7 +251,7 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
and filesort->io_cache is read sequentially
*/
if (!disable_rr_cache &&
- !addon_field &&
+ !using_addon_fields &&
thd->variables.read_rnd_buff_size &&
!(table->file->ha_table_flags() & HA_FAST_KEY_READ) &&
(table->db_stat & HA_READ_ONLY ||
@@ -264,16 +276,38 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
DBUG_PRINT("info",("using rr_quick"));
info->read_record_func= rr_quick;
}
- else if (filesort && filesort->record_pointers)
+ else if (filesort && filesort->has_filesort_result_in_memory())
{
DBUG_PRINT("info",("using record_pointers"));
if (unlikely(table->file->ha_rnd_init_with_error(0)))
DBUG_RETURN(1);
+
info->cache_pos= filesort->record_pointers;
- info->cache_end= (info->cache_pos+
- filesort->return_rows * info->ref_length);
- info->read_record_func=
- addon_field ? rr_unpack_from_buffer : rr_from_pointers;
+ if (using_addon_fields)
+ {
+ DBUG_PRINT("info",("using rr_unpack_from_buffer"));
+ DBUG_ASSERT(filesort->sorted_result_in_fsbuf);
+ info->unpack_counter= 0;
+
+ if (filesort->using_packed_addons())
+ {
+ info->read_record_func= using_packed_sortkeys ?
+ rr_unpack_from_buffer<true, true> :
+ rr_unpack_from_buffer<true, false>;
+ }
+ else
+ {
+ info->read_record_func= using_packed_sortkeys ?
+ rr_unpack_from_buffer<false, true> :
+ rr_unpack_from_buffer<false, false>;
+ }
+ }
+ else
+ {
+ info->cache_end= (info->cache_pos+
+ filesort->return_rows * info->ref_length);
+ info->read_record_func= rr_from_pointers;
+ }
}
else if (table->file->keyread_enabled())
{
@@ -510,7 +544,11 @@ static int rr_from_tempfile(READ_RECORD *info)
the fields values use in the result set from this buffer into their
positions in the regular record buffer.
- @param info Reference to the context including record descriptors
+ @param info Reference to the context including record
+ descriptors
+ @param Packed_addon_fields Are the addon fields packed?
+ This is a compile-time constant, to
+ avoid if (....) tests during execution.
@retval
0 Record successfully read.
@@ -518,12 +556,38 @@ static int rr_from_tempfile(READ_RECORD *info)
-1 There is no record to be read anymore.
*/
+template<bool Packed_addon_fields>
static int rr_unpack_from_tempfile(READ_RECORD *info)
{
- if (my_b_read(info->io_cache, info->rec_buf, info->ref_length))
- return -1;
- (*info->unpack)(info->addon_field, info->rec_buf,
- info->rec_buf + info->ref_length);
+ uchar *destination= info->rec_buf;
+#ifndef DBUG_OFF
+ my_off_t where= my_b_tell(info->io_cache);
+#endif
+ if (Packed_addon_fields)
+ {
+ const uint len_sz= Addon_fields::size_of_length_field;
+
+ // First read length of the record.
+ if (my_b_read(info->io_cache, destination, len_sz))
+ return -1;
+ uint res_length= Addon_fields::read_addon_length(destination);
+ DBUG_PRINT("info", ("rr_unpack from %llu to %p sz %u",
+ static_cast<ulonglong>(where),
+ destination, res_length));
+ DBUG_ASSERT(res_length > len_sz);
+ DBUG_ASSERT(info->sort_info->using_addon_fields());
+
+ // Then read the rest of the record.
+ if (my_b_read(info->io_cache, destination + len_sz, res_length - len_sz))
+ return -1; /* purecov: inspected */
+ }
+ else
+ {
+ if (my_b_read(info->io_cache, destination, info->ref_length))
+ return -1;
+ }
+
+ info->sort_info->unpack_addon_fields<Packed_addon_fields>(destination);
return 0;
}
@@ -560,7 +624,11 @@ int rr_from_pointers(READ_RECORD *info)
the fields values use in the result set from this buffer into their
positions in the regular record buffer.
- @param info Reference to the context including record descriptors
+ @param info Reference to the context including record
+ descriptors
+ @param Packed_addon_fields Are the addon fields packed?
+ This is a compile-time constant, to
+ avoid if (....) tests during execution.
@retval
0 Record successfully read.
@@ -568,13 +636,22 @@ int rr_from_pointers(READ_RECORD *info)
-1 There is no record to be read anymore.
*/
+template<bool Packed_addon_fields, bool Packed_sort_keys>
static int rr_unpack_from_buffer(READ_RECORD *info)
{
- if (info->cache_pos == info->cache_end)
+ if (info->unpack_counter == info->sort_info->return_rows)
return -1; /* End of buffer */
- (*info->unpack)(info->addon_field, info->cache_pos,
- info->cache_end);
- info->cache_pos+= info->ref_length;
+
+ uchar *record= info->sort_info->get_sorted_record(
+ static_cast<uint>(info->unpack_counter));
+
+ uint sort_length= Packed_sort_keys ?
+ Sort_keys::read_sortkey_length(record):
+ info->sort_info->get_sort_length();
+
+ uchar *plen= record + sort_length;
+ info->sort_info->unpack_addon_fields<Packed_addon_fields>(plen);
+ info->unpack_counter++;
return 0;
}
/* cacheing of records from a database */
@@ -709,3 +786,39 @@ static int rr_cmp(uchar *a,uchar *b)
return (int) a[7] - (int) b[7];
#endif
}
+
+
+/**
+ Copy (unpack) values appended to sorted fields from a buffer back to
+ their regular positions specified by the Field::ptr pointers.
+
+ @param addon_field Array of descriptors for appended fields
+ @param buff Buffer which to unpack the value from
+
+ @note
+ The function is supposed to be used only as a callback function
+ when getting field values for the sorted result set.
+
+*/
+template<bool Packed_addon_fields>
+inline void SORT_INFO::unpack_addon_fields(uchar *buff)
+{
+ SORT_ADDON_FIELD *addonf= addon_fields->begin();
+ uchar *buff_end= buff + sort_buffer_size();
+ const uchar *start_of_record= buff + addonf->offset;
+
+ for ( ; addonf != addon_fields->end() ; addonf++)
+ {
+ Field *field= addonf->field;
+ if (addonf->null_bit && (addonf->null_bit & buff[addonf->null_offset]))
+ {
+ field->set_null();
+ continue;
+ }
+ field->set_notnull();
+ if (Packed_addon_fields)
+ start_of_record= field->unpack(field->ptr, start_of_record, buff_end, 0);
+ else
+ field->unpack(field->ptr, buff + addonf->offset, buff_end, 0);
+ }
+}
diff --git a/sql/records.h b/sql/records.h
index faf0d13c9a9..04dc06b3c74 100644
--- a/sql/records.h
+++ b/sql/records.h
@@ -58,13 +58,23 @@ struct READ_RECORD
THD *thd;
SQL_SELECT *select;
uint ref_length, reclength, rec_cache_size, error_offset;
+
+ /**
+ Counting records when reading result from filesort().
+ Used when filesort leaves the result in the filesort buffer.
+ */
+ ha_rows unpack_counter;
+
uchar *ref_pos; /* pointer to form->refpos */
uchar *rec_buf; /* to read field values after filesort */
uchar *cache,*cache_pos,*cache_end,*read_positions;
- struct st_sort_addon_field *addon_field; /* Pointer to the fields info */
+
+ /*
+ Structure storing information about sorting
+ */
+ SORT_INFO *sort_info;
struct st_io_cache *io_cache;
bool print_error;
- void (*unpack)(struct st_sort_addon_field *, uchar *, uchar *);
int read_record() { return read_record_func(this); }
uchar *record() const { return table->record[0]; }
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 18fc3d9431a..1df85759a9c 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -101,7 +101,7 @@ void THD::unregister_slave()
mysql_mutex_lock(&LOCK_thd_data);
slave_info= 0;
mysql_mutex_unlock(&LOCK_thd_data);
- delete old_si;
+ my_free(old_si);
binlog_dump_thread_count--;
}
}
@@ -122,9 +122,10 @@ int THD::register_slave(uchar *packet, size_t packet_length)
uchar *p= packet, *p_end= packet + packet_length;
const char *errmsg= "Wrong parameters to function register_slave";
- if (check_access(this, REPL_SLAVE_ACL, any_db, NULL, NULL, 0, 0))
+ if (check_access(this, PRIV_COM_REGISTER_SLAVE, any_db, NULL, NULL, 0, 0))
return 1;
- if (!(si= new Slave_info))
+ if (!(si= (Slave_info*)my_malloc(key_memory_SLAVE_INFO, sizeof(Slave_info),
+ MYF(MY_WME))))
return 1;
variables.server_id= si->server_id= uint4korr(p);
@@ -147,6 +148,9 @@ int THD::register_slave(uchar *packet, size_t packet_length)
if (!(si->master_id= uint4korr(p)))
si->master_id= global_system_variables.server_id;
+ if (!*si->host)
+ ::strmake(si->host, main_security_ctx.host_or_ip, sizeof(si->host));
+
unregister_slave();
mysql_mutex_lock(&LOCK_thd_data);
slave_info= si;
diff --git a/sql/rpl_filter.cc b/sql/rpl_filter.cc
index b167b849923..635a0f4e2d6 100644
--- a/sql/rpl_filter.cc
+++ b/sql/rpl_filter.cc
@@ -1,4 +1,5 @@
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2009, 2020, 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
@@ -24,7 +25,7 @@
#define TABLE_RULE_ARR_SIZE 16
Rpl_filter::Rpl_filter() :
- parallel_mode(SLAVE_PARALLEL_CONSERVATIVE),
+ parallel_mode(SLAVE_PARALLEL_OPTIMISTIC),
table_rules_on(0),
do_table_inited(0), ignore_table_inited(0),
wild_do_table_inited(0), wild_ignore_table_inited(0)
@@ -285,7 +286,7 @@ Rpl_filter::parse_filter_rule(const char* spec, Add_filter add)
if (!spec)
return false;
- if (! (ptr= my_strdup(spec, MYF(MY_WME))))
+ if (! (ptr= my_strdup(key_memory_rpl_filter, spec, MYF(MY_WME))))
return true;
pstr= ptr;
@@ -460,8 +461,9 @@ Rpl_filter::add_table_rule(HASH* h, const char* table_spec)
if (!dot) return 1;
// len is always > 0 because we know the there exists a '.'
uint len = (uint)strlen(table_spec);
- TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
- + len, MYF(MY_WME));
+ TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(key_memory_TABLE_RULE_ENT,
+ sizeof(TABLE_RULE_ENT) + len,
+ MYF(MY_WME));
if (!e) return 1;
e->db= (char*)e + sizeof(TABLE_RULE_ENT);
e->tbl_name= e->db + (dot - table_spec) + 1;
@@ -482,8 +484,9 @@ Rpl_filter::add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
const char* dot = strchr(table_spec, '.');
if (!dot) return 1;
uint len = (uint)strlen(table_spec);
- TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
- + len, MYF(MY_WME));
+ TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(key_memory_TABLE_RULE_ENT,
+ sizeof(TABLE_RULE_ENT) + len,
+ MYF(MY_WME));
if (!e) return 1;
e->db= (char*)e + sizeof(TABLE_RULE_ENT);
e->tbl_name= e->db + (dot - table_spec) + 1;
@@ -499,7 +502,7 @@ Rpl_filter::add_string_list(I_List<i_string> *list, const char* spec)
char *str;
i_string *node;
- if (! (str= my_strdup(spec, MYF(MY_WME))))
+ if (! (str= my_strdup(key_memory_rpl_filter, spec, MYF(MY_WME))))
return true;
if (! (node= new i_string(str)))
@@ -570,8 +573,9 @@ void free_table_ent(void* a)
void
Rpl_filter::init_table_rule_hash(HASH* h, bool* h_inited)
{
- my_hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0,
- get_table_key, free_table_ent, 0);
+ my_hash_init(key_memory_TABLE_RULE_ENT, h,
+ system_charset_info,TABLE_RULE_HASH_SIZE,0,0, get_table_key,
+ free_table_ent, 0);
*h_inited = 1;
}
@@ -579,8 +583,8 @@ Rpl_filter::init_table_rule_hash(HASH* h, bool* h_inited)
void
Rpl_filter::init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited)
{
- my_init_dynamic_array(a, sizeof(TABLE_RULE_ENT*), TABLE_RULE_ARR_SIZE,
- TABLE_RULE_ARR_SIZE, MYF(0));
+ my_init_dynamic_array(key_memory_TABLE_RULE_ENT, a, sizeof(TABLE_RULE_ENT*),
+ TABLE_RULE_ARR_SIZE, TABLE_RULE_ARR_SIZE, MYF(0));
*a_inited = 1;
}
@@ -595,10 +599,10 @@ Rpl_filter::find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
{
TABLE_RULE_ENT* e ;
get_dynamic(a, (uchar*)&e, i);
- if (!my_wildcmp(system_charset_info, key, key_end,
- (const char*)e->db,
- (const char*)(e->db + e->key_len),
- '\\',wild_one,wild_many))
+ if (!system_charset_info->wildcmp(key, key_end,
+ (const char*)e->db,
+ (const char*)(e->db + e->key_len),
+ '\\', wild_one, wild_many))
return e;
}
diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc
index 5681f8652a4..e7ad4c02a19 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -249,9 +249,10 @@ rpl_slave_state::rpl_slave_state()
{
mysql_mutex_init(key_LOCK_slave_state, &LOCK_slave_state,
MY_MUTEX_INIT_SLOW);
- my_hash_init(&hash, &my_charset_bin, 32, offsetof(element, domain_id),
+ my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32, offsetof(element, domain_id),
sizeof(uint32), NULL, rpl_slave_state_free_element, HASH_UNIQUE);
- my_init_dynamic_array(&gtid_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0));
+ my_init_dynamic_array(PSI_INSTRUMENT_ME, &gtid_sort_array, sizeof(rpl_gtid),
+ 8, 8, MYF(0));
}
@@ -334,7 +335,8 @@ rpl_slave_state::update(uint32 domain_id, uint32 server_id, uint64 sub_id,
rgi->gtid_ignore_duplicate_state= rpl_group_info::GTID_DUPLICATE_NULL;
}
- if (!(list_elem= (list_element *)my_malloc(sizeof(*list_elem), MYF(MY_WME))))
+ if (!(list_elem= (list_element *)my_malloc(PSI_INSTRUMENT_ME,
+ sizeof(*list_elem), MYF(MY_WME))))
return 1;
list_elem->domain_id= domain_id;
list_elem->server_id= server_id;
@@ -368,7 +370,7 @@ rpl_slave_state::get_element(uint32 domain_id)
if (elem)
return elem;
- if (!(elem= (element *)my_malloc(sizeof(*elem), MYF(MY_WME))))
+ if (!(elem= (element *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*elem), MYF(MY_WME))))
return NULL;
elem->list= NULL;
elem->domain_id= domain_id;
@@ -426,7 +428,7 @@ rpl_slave_state::truncate_state_table(THD *thd)
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);
+ rpl_gtid_slave_state_table_name.str);
err= tlist.table->file->ha_truncate();
if (err)
@@ -1112,8 +1114,9 @@ rpl_slave_state::iterate(int (*cb)(rpl_gtid *, void *), void *data,
int res= 1;
bool locked= false;
- my_hash_init(&gtid_hash, &my_charset_bin, 32, offsetof(rpl_gtid, domain_id),
- sizeof(uint32), NULL, NULL, HASH_UNIQUE);
+ my_hash_init(PSI_INSTRUMENT_ME, &gtid_hash, &my_charset_bin, 32,
+ offsetof(rpl_gtid, domain_id), sizeof(uint32), NULL, NULL,
+ HASH_UNIQUE);
for (i= 0; i < num_extra; ++i)
if (extra_gtids[i].server_id == global_system_variables.server_id &&
my_hash_insert(&gtid_hash, (uchar *)(&extra_gtids[i])))
@@ -1330,7 +1333,7 @@ gtid_parse_string_to_list(const char *str, size_t str_len, uint32 *out_len)
}
if ((!list || len >= alloc_len) &&
!(list=
- (rpl_gtid *)my_realloc(list,
+ (rpl_gtid *)my_realloc(PSI_INSTRUMENT_ME, list,
(alloc_len= alloc_len*2) * sizeof(rpl_gtid),
MYF(MY_FREE_ON_ERROR|MY_ALLOW_ZERO_PTR))))
return NULL;
@@ -1467,10 +1470,8 @@ rpl_slave_state::alloc_gtid_pos_table(LEX_CSTRING *table_name, void *hton,
struct gtid_pos_table *p;
char *allocated_str;
- if (!my_multi_malloc(MYF(MY_WME),
- &p, sizeof(*p),
- &allocated_str, table_name->length+1,
- NULL))
+ if (!my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME), &p, sizeof(*p),
+ &allocated_str, table_name->length+1, NULL))
{
my_error(ER_OUTOFMEMORY, MYF(0), (int)(sizeof(*p) + table_name->length+1));
return NULL;
@@ -1487,9 +1488,9 @@ rpl_slave_state::alloc_gtid_pos_table(LEX_CSTRING *table_name, void *hton,
void rpl_binlog_state::init()
{
- my_hash_init(&hash, &my_charset_bin, 32, offsetof(element, domain_id),
+ my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32, offsetof(element, domain_id),
sizeof(uint32), NULL, my_free, HASH_UNIQUE);
- my_init_dynamic_array(&gtid_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0));
+ my_init_dynamic_array(PSI_INSTRUMENT_ME, &gtid_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0));
mysql_mutex_init(key_LOCK_binlog_state, &LOCK_binlog_state,
MY_MUTEX_INIT_SLOW);
initialized= 1;
@@ -1686,7 +1687,8 @@ rpl_binlog_state::element::update_element(const rpl_gtid *gtid)
}
/* Allocate a new GTID and insert it. */
- lookup_gtid= (rpl_gtid *)my_malloc(sizeof(*lookup_gtid), MYF(MY_WME));
+ lookup_gtid= (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*lookup_gtid),
+ MYF(MY_WME));
if (!lookup_gtid)
return 1;
memcpy(lookup_gtid, gtid, sizeof(*lookup_gtid));
@@ -1707,12 +1709,13 @@ rpl_binlog_state::alloc_element_nolock(const rpl_gtid *gtid)
rpl_gtid *lookup_gtid;
/* First time we see this domain_id; allocate a new element. */
- elem= (element *)my_malloc(sizeof(*elem), MYF(MY_WME));
- lookup_gtid= (rpl_gtid *)my_malloc(sizeof(*lookup_gtid), MYF(MY_WME));
+ elem= (element *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*elem), MYF(MY_WME));
+ lookup_gtid= (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*lookup_gtid),
+ MYF(MY_WME));
if (elem && lookup_gtid)
{
elem->domain_id= gtid->domain_id;
- my_hash_init(&elem->hash, &my_charset_bin, 32,
+ my_hash_init(PSI_INSTRUMENT_ME, &elem->hash, &my_charset_bin, 32,
offsetof(rpl_gtid, server_id), sizeof(uint32), NULL, my_free,
HASH_UNIQUE);
elem->last_gtid= lookup_gtid;
@@ -1785,14 +1788,15 @@ rpl_binlog_state::bump_seq_no_if_needed(uint32 domain_id, uint64 seq_no)
}
/* We need to allocate a new, empty element to remember the next seq_no. */
- if (!(elem= (element *)my_malloc(sizeof(*elem), MYF(MY_WME))))
+ if (!(elem= (element *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*elem),
+ MYF(MY_WME))))
{
res= 1;
goto end;
}
elem->domain_id= domain_id;
- my_hash_init(&elem->hash, &my_charset_bin, 32,
+ my_hash_init(PSI_INSTRUMENT_ME, &elem->hash, &my_charset_bin, 32,
offsetof(rpl_gtid, server_id), sizeof(uint32), NULL, my_free,
HASH_UNIQUE);
elem->last_gtid= NULL;
@@ -2007,8 +2011,8 @@ rpl_binlog_state::get_most_recent_gtid_list(rpl_gtid **list, uint32 *size)
out_size= 0;
mysql_mutex_lock(&LOCK_binlog_state);
alloc_size= hash.records;
- if (!(*list= (rpl_gtid *)my_malloc(alloc_size * sizeof(rpl_gtid),
- MYF(MY_WME))))
+ if (!(*list= (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME,
+ alloc_size * sizeof(rpl_gtid), MYF(MY_WME))))
{
res= 1;
goto end;
@@ -2123,7 +2127,7 @@ rpl_binlog_state::drop_domain(DYNAMIC_ARRAY *ids,
DBUG_ENTER("rpl_binlog_state::drop_domain");
- my_init_dynamic_array2(&domain_unique,
+ my_init_dynamic_array2(PSI_INSTRUMENT_ME, &domain_unique,
sizeof(element*), domain_unique_buffer,
sizeof(domain_unique_buffer) / sizeof(element*), 4, 0);
@@ -2248,10 +2252,10 @@ end:
slave_connection_state::slave_connection_state()
{
- my_hash_init(&hash, &my_charset_bin, 32,
+ my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32,
offsetof(entry, gtid) + offsetof(rpl_gtid, domain_id),
sizeof(uint32), NULL, my_free, HASH_UNIQUE);
- my_init_dynamic_array(&gtid_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0));
+ my_init_dynamic_array(PSI_INSTRUMENT_ME, &gtid_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0));
}
@@ -2295,7 +2299,7 @@ slave_connection_state::load(const char *slave_request, size_t len)
return 0;
for (;;)
{
- if (!(rec= (uchar *)my_malloc(sizeof(entry), MYF(MY_WME))))
+ if (!(rec= (uchar *)my_malloc(PSI_INSTRUMENT_ME, sizeof(entry), MYF(MY_WME))))
return 1;
gtid= &((entry *)rec)->gtid;
if (gtid_parser_helper(&p, end, gtid))
@@ -2398,7 +2402,7 @@ slave_connection_state::update(const rpl_gtid *in_gtid)
return 0;
}
- if (!(e= (entry *)my_malloc(sizeof(*e), MYF(MY_WME))))
+ if (!(e= (entry *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*e), MYF(MY_WME))))
return 1;
e->gtid= *in_gtid;
e->flags= 0;
@@ -2875,7 +2879,7 @@ free_hash_element(void *p)
void
gtid_waiting::init()
{
- my_hash_init(&hash, &my_charset_bin, 32,
+ my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32,
offsetof(hash_element, domain_id), sizeof(uint32), NULL,
free_hash_element, HASH_UNIQUE);
mysql_mutex_init(key_LOCK_gtid_waiting, &LOCK_gtid_waiting, 0);
@@ -2912,7 +2916,7 @@ gtid_waiting::get_entry(uint32 domain_id)
if ((e= (hash_element *)my_hash_search(&hash, (const uchar *)&domain_id, 0)))
return e;
- if (!(e= (hash_element *)my_malloc(sizeof(*e), MYF(MY_WME))))
+ if (!(e= (hash_element *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*e), MYF(MY_WME))))
return NULL;
if (init_queue(&e->queue, 8, offsetof(queue_element, wait_seq_no), 0,
diff --git a/sql/rpl_gtid.h b/sql/rpl_gtid.h
index 167d7461a7e..523af4856ae 100644
--- a/sql/rpl_gtid.h
+++ b/sql/rpl_gtid.h
@@ -27,6 +27,8 @@ extern const LEX_CSTRING rpl_gtid_slave_state_table_name;
class String;
+#define GTID_MAX_STR_LENGTH (10+1+10+1+20)
+
struct rpl_gtid
{
uint32 domain_id;
diff --git a/sql/rpl_injector.cc b/sql/rpl_injector.cc
index 597a357e4e2..b0b6e30bed6 100644
--- a/sql/rpl_injector.cc
+++ b/sql/rpl_injector.cc
@@ -37,7 +37,8 @@ injector::transaction::transaction(MYSQL_BIN_LOG *log, THD *thd)
LOG_INFO log_info;
log->get_current_log(&log_info);
/* !!! binlog_pos does not follow RAII !!! */
- m_start_pos.m_file_name= my_strdup(log_info.log_file_name, MYF(0));
+ m_start_pos.m_file_name= my_strdup(key_memory_binlog_pos,
+ log_info.log_file_name, MYF(0));
m_start_pos.m_file_pos= log_info.pos;
m_thd->lex->start_transaction_opt= 0; /* for begin_trans() */
diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc
index 43a02147496..0649a8f05e8 100644
--- a/sql/rpl_mi.cc
+++ b/sql/rpl_mi.cc
@@ -58,7 +58,7 @@ Master_info::Master_info(LEX_CSTRING *connection_name_arg,
connection_name.length= cmp_connection_name.length=
connection_name_arg->length;
if ((connection_name.str= tmp= (char*)
- my_malloc(connection_name_arg->length*2+2, MYF(MY_WME))))
+ my_malloc(PSI_INSTRUMENT_ME, connection_name_arg->length*2+2, MYF(MY_WME))))
{
strmake(tmp, connection_name_arg->str, connection_name.length);
tmp+= connection_name_arg->length+1;
@@ -77,7 +77,7 @@ Master_info::Master_info(LEX_CSTRING *connection_name_arg,
parallel_mode= rpl_filter->get_parallel_mode();
- my_init_dynamic_array(&ignore_server_ids,
+ my_init_dynamic_array(PSI_INSTRUMENT_ME, &ignore_server_ids,
sizeof(global_system_variables.server_id), 16, 16,
MYF(0));
bzero((char*) &file, sizeof(file));
@@ -742,7 +742,8 @@ int flush_master_info(Master_info* mi,
char* ignore_server_ids_buf;
{
ignore_server_ids_buf=
- (char *) my_malloc((sizeof(global_system_variables.server_id) * 3 + 1) *
+ (char *) my_malloc(PSI_INSTRUMENT_ME,
+ (sizeof(global_system_variables.server_id) * 3 + 1) *
(1 + mi->ignore_server_ids.elements), MYF(MY_WME));
if (!ignore_server_ids_buf)
DBUG_RETURN(1); /* error */
@@ -1098,7 +1099,7 @@ bool Master_info_index::init_all_master_info()
}
/* Initialize Master_info Hash Table */
- if (my_hash_init(&master_info_hash, system_charset_info,
+ if (my_hash_init(PSI_INSTRUMENT_ME, &master_info_hash, system_charset_info,
MAX_REPLICATION_THREAD, 0, 0,
(my_hash_get_key) get_key_master_info,
(my_hash_free_key)free_key_master_info, HASH_UNIQUE))
@@ -1570,6 +1571,8 @@ uint any_slave_sql_running(bool already_locked)
if (!already_locked)
mysql_mutex_lock(&LOCK_active_mi);
+ else
+ mysql_mutex_assert_owner(&LOCK_active_mi);
if (unlikely(abort_loop || !master_info_index))
count= 1;
else
@@ -1739,7 +1742,8 @@ Domain_id_filter::Domain_id_filter() : m_filter(false)
{
for (int i= DO_DOMAIN_IDS; i <= IGNORE_DOMAIN_IDS; i ++)
{
- my_init_dynamic_array(&m_domain_ids[i], sizeof(ulong), 16, 16, MYF(0));
+ my_init_dynamic_array(PSI_INSTRUMENT_ME, &m_domain_ids[i], sizeof(ulong),
+ 16, 16, MYF(0));
}
}
@@ -1902,7 +1906,7 @@ char *Domain_id_filter::as_string(enum_list_type type)
sz= (sizeof(ulong) * 3 + 1) * (1 + ids->elements);
- if (!(buf= (char *) my_malloc(sz, MYF(MY_WME))))
+ if (!(buf= (char *) my_malloc(PSI_INSTRUMENT_ME, sz, MYF(MY_WME))))
return NULL;
// Store the total number of elements followed by the individual elements.
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc
index 4313840119e..ce612999eaf 100644
--- a/sql/rpl_parallel.cc
+++ b/sql/rpl_parallel.cc
@@ -672,12 +672,14 @@ convert_kill_to_deadlock_error(rpl_group_info *rgi)
static int
is_group_ending(Log_event *ev, Log_event_type event_type)
{
- if (event_type == XID_EVENT)
+ if (event_type == XID_EVENT || event_type == XA_PREPARE_LOG_EVENT)
return 1;
if (event_type == QUERY_EVENT) // COMMIT/ROLLBACK are never compressed
{
Query_log_event *qev = (Query_log_event *)ev;
- if (qev->is_commit())
+ if (qev->is_commit() ||
+ !strncmp(qev->query, STRING_WITH_LEN("XA COMMIT")) ||
+ !strncmp(qev->query, STRING_WITH_LEN("XA ROLLBACK")))
return 1;
if (qev->is_rollback())
return 2;
@@ -793,7 +795,7 @@ do_retry:
else
{
/*
- A failure of a preceeding "parent" transaction may not be
+ A failure of a preceding "parent" transaction may not be
seen by the current one through its own worker_error.
Such induced error gets set by ourselves now.
*/
@@ -1557,7 +1559,7 @@ rpl_parallel_change_thread_count(rpl_parallel_thread_pool *pool,
to allocate, and will not be left with a half-functional thread pool.
*/
if (new_count &&
- !my_multi_malloc(MYF(MY_WME|MY_ZEROFILL),
+ !my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME|MY_ZEROFILL),
&new_list, new_count*sizeof(*new_list),
&rpt_array, new_count*sizeof(*rpt_array),
NULL))
@@ -1789,7 +1791,7 @@ rpl_parallel_thread::get_qev_common(Log_event *ev, ulonglong event_size)
mysql_mutex_assert_owner(&LOCK_rpl_thread);
if ((qev= qev_free_list))
qev_free_list= qev->next;
- else if(!(qev= (queued_event *)my_malloc(sizeof(*qev), MYF(0))))
+ else if(!(qev= (queued_event *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*qev), MYF(0))))
{
my_error(ER_OUTOFMEMORY, MYF(0), (int)sizeof(*qev));
return NULL;
@@ -1952,7 +1954,7 @@ rpl_parallel_thread::get_gco(uint64 wait_count, group_commit_orderer *prev,
mysql_mutex_assert_owner(&LOCK_rpl_thread);
if ((gco= gco_free_list))
gco_free_list= gco->next_gco;
- else if(!(gco= (group_commit_orderer *)my_malloc(sizeof(*gco), MYF(0))))
+ else if(!(gco= (group_commit_orderer *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*gco), MYF(0))))
{
my_error(ER_OUTOFMEMORY, MYF(0), (int)sizeof(*gco));
return NULL;
@@ -2088,23 +2090,34 @@ rpl_parallel_thread_pool::release_thread(rpl_parallel_thread *rpt)
and the LOCK_rpl_thread must be released with THD::EXIT_COND() instead
of mysql_mutex_unlock.
- If the flag `reuse' is set, the last worker thread will be returned again,
+ When `gtid_ev' is not NULL the last worker thread will be returned again,
if it is still available. Otherwise a new worker thread is allocated.
+
+ A worker for XA transaction is determined through xid hashing which
+ ensure for a XA-complete to be scheduled to the same-xid XA-prepare worker.
*/
rpl_parallel_thread *
rpl_parallel_entry::choose_thread(rpl_group_info *rgi, bool *did_enter_cond,
- PSI_stage_info *old_stage, bool reuse)
+ PSI_stage_info *old_stage,
+ Gtid_log_event *gtid_ev)
{
uint32 idx;
Relay_log_info *rli= rgi->rli;
rpl_parallel_thread *thr;
idx= rpl_thread_idx;
- if (!reuse)
+ if (gtid_ev)
{
- ++idx;
- if (idx >= rpl_thread_max)
- idx= 0;
+ if (gtid_ev->flags2 &
+ (Gtid_log_event::FL_COMPLETED_XA | Gtid_log_event::FL_PREPARED_XA))
+ idx= my_hash_sort(&my_charset_bin, gtid_ev->xid.key(),
+ gtid_ev->xid.key_length()) % rpl_thread_max;
+ else
+ {
+ ++idx;
+ if (idx >= rpl_thread_max)
+ idx= 0;
+ }
rpl_thread_idx= idx;
}
thr= rpl_threads[idx];
@@ -2199,7 +2212,7 @@ free_rpl_parallel_entry(void *element)
rpl_parallel::rpl_parallel() :
current(NULL), sql_thread_stopping(false)
{
- my_hash_init(&domain_hash, &my_charset_bin, 32,
+ my_hash_init(PSI_INSTRUMENT_ME, &domain_hash, &my_charset_bin, 32,
offsetof(rpl_parallel_entry, domain_id), sizeof(uint32),
NULL, free_rpl_parallel_entry, HASH_UNIQUE);
}
@@ -2233,7 +2246,7 @@ rpl_parallel::find(uint32 domain_id)
if (count == 0 || count > opt_slave_parallel_threads)
count= opt_slave_parallel_threads;
rpl_parallel_thread **p;
- if (!my_multi_malloc(MYF(MY_WME|MY_ZEROFILL),
+ if (!my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME|MY_ZEROFILL),
&e, sizeof(*e),
&p, count*sizeof(*p),
NULL))
@@ -2662,7 +2675,7 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
else
{
DBUG_ASSERT(rli->gtid_skip_flag == GTID_SKIP_TRANSACTION);
- if (typ == XID_EVENT ||
+ if (typ == XID_EVENT || typ == XA_PREPARE_LOG_EVENT ||
(typ == QUERY_EVENT && // COMMIT/ROLLBACK are never compressed
(((Query_log_event *)ev)->is_commit() ||
((Query_log_event *)ev)->is_rollback())))
@@ -2673,10 +2686,11 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
}
}
+ Gtid_log_event *gtid_ev= NULL;
if (typ == GTID_EVENT)
{
rpl_gtid gtid;
- Gtid_log_event *gtid_ev= static_cast<Gtid_log_event *>(ev);
+ gtid_ev= static_cast<Gtid_log_event *>(ev);
uint32 domain_id= (rli->mi->using_gtid == Master_info::USE_GTID_NO ||
rli->mi->parallel_mode <= SLAVE_PARALLEL_MINIMAL ?
0 : gtid_ev->domain_id);
@@ -2715,8 +2729,7 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
instead re-use a thread that we queued for previously.
*/
cur_thread=
- e->choose_thread(serial_rgi, &did_enter_cond, &old_stage,
- typ != GTID_EVENT);
+ e->choose_thread(serial_rgi, &did_enter_cond, &old_stage, gtid_ev);
if (!cur_thread)
{
/* This means we were killed. The error is already signalled. */
@@ -2734,7 +2747,6 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
if (typ == GTID_EVENT)
{
- Gtid_log_event *gtid_ev= static_cast<Gtid_log_event *>(ev);
bool new_gco;
enum_slave_parallel_mode mode= rli->mi->parallel_mode;
uchar gtid_flags= gtid_ev->flags2;
diff --git a/sql/rpl_parallel.h b/sql/rpl_parallel.h
index 4579d0da9bc..9d9fa63125c 100644
--- a/sql/rpl_parallel.h
+++ b/sql/rpl_parallel.h
@@ -345,7 +345,8 @@ struct rpl_parallel_entry {
group_commit_orderer *current_gco;
rpl_parallel_thread * choose_thread(rpl_group_info *rgi, bool *did_enter_cond,
- PSI_stage_info *old_stage, bool reuse);
+ PSI_stage_info *old_stage,
+ Gtid_log_event *gtid_ev);
int queue_master_restart(rpl_group_info *rgi,
Format_description_log_event *fdev);
};
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index d645fea6968..c8914fcb5b0 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -35,7 +35,7 @@
#include "sql_table.h"
static int count_relay_log_space(Relay_log_info* rli);
-
+bool xa_trans_force_rollback(THD *thd);
/**
Current replication state (hash of last GTID executed, per replication
domain).
@@ -73,7 +73,9 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery)
key_RELAYLOG_COND_relay_log_updated,
key_RELAYLOG_COND_bin_log_updated,
key_file_relaylog,
+ key_file_relaylog_cache,
key_file_relaylog_index,
+ key_file_relaylog_index_cache,
key_RELAYLOG_COND_queue_busy,
key_LOCK_relaylog_end_pos);
#endif
@@ -237,7 +239,7 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
*/
mysql_mutex_lock(log_lock);
if (relay_log.open_index_file(buf_relaylog_index_name, ln, TRUE) ||
- relay_log.open(ln, LOG_BIN, 0, 0, SEQ_READ_APPEND,
+ relay_log.open(ln, 0, 0, SEQ_READ_APPEND,
(ulong)max_relay_log_size, 1, TRUE))
{
mysql_mutex_unlock(log_lock);
@@ -1178,7 +1180,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
DBUG_RETURN(1);
}
mysql_mutex_lock(rli->relay_log.get_log_lock());
- if (rli->relay_log.open(ln, LOG_BIN, 0, 0, SEQ_READ_APPEND,
+ if (rli->relay_log.open(ln, 0, 0, SEQ_READ_APPEND,
(ulong)(rli->max_relay_log_size ? rli->max_relay_log_size :
max_binlog_size), 1, TRUE))
{
@@ -1435,14 +1437,15 @@ Relay_log_info::alloc_inuse_relaylog(const char *name)
uint32 gtid_count;
rpl_gtid *gtid_list;
- if (!(ir= (inuse_relaylog *)my_malloc(sizeof(*ir), MYF(MY_WME|MY_ZEROFILL))))
+ if (!(ir= (inuse_relaylog *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*ir),
+ MYF(MY_WME|MY_ZEROFILL))))
{
my_error(ER_OUTOFMEMORY, MYF(0), (int)sizeof(*ir));
return 1;
}
gtid_count= relay_log_state.count();
- if (!(gtid_list= (rpl_gtid *)my_malloc(sizeof(*gtid_list)*gtid_count,
- MYF(MY_WME))))
+ if (!(gtid_list= (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME,
+ sizeof(*gtid_list)*gtid_count, MYF(MY_WME))))
{
my_free(ir);
my_error(ER_OUTOFMEMORY, MYF(0), (int)sizeof(*gtid_list)*gtid_count);
@@ -1589,8 +1592,8 @@ scan_one_gtid_slave_pos_table(THD *thd, HASH *hash, DYNAMIC_ARRAY *array,
}
else
{
- if (!(entry= (struct gtid_pos_element *)my_malloc(sizeof(*entry),
- MYF(MY_WME))))
+ if (!(entry= (struct gtid_pos_element *)my_malloc(PSI_INSTRUMENT_ME,
+ sizeof(*entry), MYF(MY_WME))))
{
my_error(ER_OUTOFMEMORY, MYF(0), (int)sizeof(*entry));
err= 1;
@@ -1831,10 +1834,11 @@ rpl_load_gtid_slave_state(THD *thd)
cb_data.table_list= NULL;
cb_data.default_entry= NULL;
- my_hash_init(&hash, &my_charset_bin, 32,
+ my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32,
offsetof(gtid_pos_element, gtid) + offsetof(rpl_gtid, domain_id),
sizeof(uint32), NULL, my_free, HASH_UNIQUE);
- if ((err= my_init_dynamic_array(&array, sizeof(gtid_pos_element), 0, 0, MYF(0))))
+ if ((err= my_init_dynamic_array(PSI_INSTRUMENT_ME, &array,
+ sizeof(gtid_pos_element), 0, 0, MYF(0))))
goto end;
array_inited= true;
@@ -2230,6 +2234,13 @@ void rpl_group_info::cleanup_context(THD *thd, bool error)
if (unlikely(error))
{
+ /*
+ trans_rollback above does not rollback XA transactions
+ (todo/fixme consider to do so.
+ */
+ if (thd->transaction.xid_state.is_explicit_XA())
+ xa_trans_force_rollback(thd);
+
thd->mdl_context.release_transactional_locks();
if (thd == rli->sql_driver_thd)
diff --git a/sql/rpl_tblmap.cc b/sql/rpl_tblmap.cc
index b2da9092e3a..a230b9f6f29 100644
--- a/sql/rpl_tblmap.cc
+++ b/sql/rpl_tblmap.cc
@@ -34,6 +34,12 @@
table_mapping::table_mapping()
: m_free(0)
{
+#ifdef MYSQL_CLIENT
+ PSI_memory_key psi_key= PSI_NOT_INSTRUMENTED;
+#else
+ PSI_memory_key psi_key= key_memory_table_mapping_root;
+#endif
+
DBUG_ENTER("table_mapping::table_mapping");
/*
No "free_element" function for entries passed here, as the entries are
@@ -42,12 +48,11 @@ table_mapping::table_mapping()
Note that below we don't test if my_hash_init() succeeded. This
constructor is called at startup only.
*/
- (void) my_hash_init(&m_table_ids,&my_charset_bin,TABLE_ID_HASH_SIZE,
+ (void) my_hash_init(psi_key, &m_table_ids,&my_charset_bin,TABLE_ID_HASH_SIZE,
offsetof(entry,table_id),sizeof(ulonglong),
- 0,0,0);
+ 0,0,0);
/* We don't preallocate any block, this is consistent with m_free=0 above */
- init_alloc_root(&m_mem_root, "table_mapping",
- TABLE_ID_HASH_SIZE*sizeof(entry), 0, MYF(0));
+ init_alloc_root(psi_key, &m_mem_root, TABLE_ID_HASH_SIZE*sizeof(entry), 0, MYF(0));
DBUG_VOID_RETURN;
}
diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc
index 437d58d772f..7c347eba51f 100644
--- a/sql/rpl_utility.cc
+++ b/sql/rpl_utility.cc
@@ -19,185 +19,7 @@
#include "rpl_utility.h"
#include "log_event.h"
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-#include "rpl_rli.h"
-#include "sql_select.h"
-/**
- Calculate display length for MySQL56 temporal data types from their metadata.
- It contains fractional precision in the low 16-bit word.
-*/
-static uint32
-max_display_length_for_temporal2_field(uint32 int_display_length,
- unsigned int metadata)
-{
- metadata&= 0x00ff;
- return int_display_length + metadata + (metadata ? 1 : 0);
-}
-
-
-/**
- Compute the maximum display length of a field.
-
- @param sql_type Type of the field
- @param metadata The metadata from the master for the field.
- @return Maximum length of the field in bytes.
-
- The precise values calculated by field->max_display_length() and
- calculated by max_display_length_for_field() can differ (by +1 or -1)
- for integer data types (TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT).
- This slight difference is not important here, because we call
- this function only for two *different* integer data types.
- */
-static uint32
-max_display_length_for_field(enum_field_types sql_type, unsigned int metadata)
-{
- DBUG_PRINT("debug", ("sql_type: %d, metadata: 0x%x", sql_type, metadata));
- DBUG_ASSERT(metadata >> 16 == 0);
-
- switch (sql_type) {
- case MYSQL_TYPE_NEWDECIMAL:
- return metadata >> 8;
-
- case MYSQL_TYPE_FLOAT:
- return 12;
-
- case MYSQL_TYPE_DOUBLE:
- return 22;
-
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_ENUM:
- return metadata & 0x00ff;
-
- case MYSQL_TYPE_STRING:
- {
- uchar type= metadata >> 8;
- if (type == MYSQL_TYPE_SET || type == MYSQL_TYPE_ENUM)
- return metadata & 0xff;
- else
- /* This is taken from Field_string::unpack. */
- return (((metadata >> 4) & 0x300) ^ 0x300) + (metadata & 0x00ff);
- }
-
- case MYSQL_TYPE_YEAR:
- case MYSQL_TYPE_TINY:
- return 4;
-
- case MYSQL_TYPE_SHORT:
- return 6;
-
- case MYSQL_TYPE_INT24:
- return 9;
-
- case MYSQL_TYPE_LONG:
- return 11;
-
-#ifdef HAVE_LONG_LONG
- case MYSQL_TYPE_LONGLONG:
- return 20;
-
-#endif
- case MYSQL_TYPE_NULL:
- return 0;
-
- case MYSQL_TYPE_NEWDATE:
- return 3;
-
- case MYSQL_TYPE_DATE:
- return 3;
-
- case MYSQL_TYPE_TIME:
- return MIN_TIME_WIDTH;
-
- case MYSQL_TYPE_TIME2:
- return max_display_length_for_temporal2_field(MIN_TIME_WIDTH, metadata);
-
- case MYSQL_TYPE_TIMESTAMP:
- return MAX_DATETIME_WIDTH;
-
- case MYSQL_TYPE_TIMESTAMP2:
- return max_display_length_for_temporal2_field(MAX_DATETIME_WIDTH, metadata);
-
- case MYSQL_TYPE_DATETIME:
- return MAX_DATETIME_WIDTH;
-
- case MYSQL_TYPE_DATETIME2:
- return max_display_length_for_temporal2_field(MAX_DATETIME_WIDTH, metadata);
-
- case MYSQL_TYPE_BIT:
- /*
- Decode the size of the bit field from the master.
- */
- DBUG_ASSERT((metadata & 0xff) <= 7);
- return 8 * (metadata >> 8U) + (metadata & 0x00ff);
-
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_VARCHAR:
- return metadata;
- case MYSQL_TYPE_VARCHAR_COMPRESSED:
- return metadata - 1;
-
- /*
- The actual length for these types does not really matter since
- they are used to calc_pack_length, which ignores the given
- length for these types.
-
- Since we want this to be accurate for other uses, we return the
- maximum size in bytes of these BLOBs.
- */
-
- case MYSQL_TYPE_TINY_BLOB:
- return (uint32)my_set_bits(1 * 8);
-
- case MYSQL_TYPE_MEDIUM_BLOB:
- return (uint32)my_set_bits(3 * 8);
-
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_BLOB_COMPRESSED:
- /*
- For the blob type, Field::real_type() lies and say that all
- blobs are of type MYSQL_TYPE_BLOB. In that case, we have to look
- at the length instead to decide what the max display size is.
- */
- return (uint32)my_set_bits(metadata * 8);
-
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_GEOMETRY:
- return (uint32)my_set_bits(4 * 8);
-
- default:
- return ~(uint32) 0;
- }
-}
-
-
-/*
- Compare the pack lengths of a source field (on the master) and a
- target field (on the slave).
-
- @param field Target field.
- @param type Source field type.
- @param metadata Source field metadata.
-
- @retval -1 The length of the source field is smaller than the target field.
- @retval 0 The length of the source and target fields are the same.
- @retval 1 The length of the source field is greater than the target field.
- */
-int compare_lengths(Field *field, enum_field_types source_type, uint16 metadata)
-{
- DBUG_ENTER("compare_lengths");
- size_t const source_length=
- max_display_length_for_field(source_type, metadata);
- size_t const target_length= field->max_display_length();
- DBUG_PRINT("debug", ("source_length: %lu, source_type: %u,"
- " target_length: %lu, target_type: %u",
- (unsigned long) source_length, source_type,
- (unsigned long) target_length, field->real_type()));
- int result= source_length < target_length ? -1 : source_length > target_length;
- DBUG_PRINT("result", ("%d", result));
- DBUG_RETURN(result);
-}
-#endif //MYSQL_CLIENT
/*********************************************************************
* table_def member definitions *
*********************************************************************/
@@ -349,750 +171,7 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const
return length;
}
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-/**
- */
-void show_sql_type(enum_field_types type, uint16 metadata, String *str,
- bool char_with_octets)
-{
- DBUG_ENTER("show_sql_type");
- DBUG_PRINT("enter", ("type: %d, metadata: 0x%x", type, metadata));
-
- switch (type)
- {
- case MYSQL_TYPE_TINY:
- str->set_ascii(STRING_WITH_LEN("tinyint"));
- break;
-
- case MYSQL_TYPE_SHORT:
- str->set_ascii(STRING_WITH_LEN("smallint"));
- break;
-
- case MYSQL_TYPE_LONG:
- str->set_ascii(STRING_WITH_LEN("int"));
- break;
-
- case MYSQL_TYPE_FLOAT:
- str->set_ascii(STRING_WITH_LEN("float"));
- break;
-
- case MYSQL_TYPE_DOUBLE:
- str->set_ascii(STRING_WITH_LEN("double"));
- break;
-
- case MYSQL_TYPE_NULL:
- str->set_ascii(STRING_WITH_LEN("null"));
- break;
-
- case MYSQL_TYPE_TIMESTAMP:
- case MYSQL_TYPE_TIMESTAMP2:
- str->set_ascii(STRING_WITH_LEN("timestamp"));
- break;
-
- case MYSQL_TYPE_LONGLONG:
- str->set_ascii(STRING_WITH_LEN("bigint"));
- break;
-
- case MYSQL_TYPE_INT24:
- str->set_ascii(STRING_WITH_LEN("mediumint"));
- break;
-
- case MYSQL_TYPE_NEWDATE:
- case MYSQL_TYPE_DATE:
- str->set_ascii(STRING_WITH_LEN("date"));
- break;
-
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_TIME2:
- str->set_ascii(STRING_WITH_LEN("time"));
- break;
-
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_DATETIME2:
- str->set_ascii(STRING_WITH_LEN("datetime"));
- break;
-
- case MYSQL_TYPE_YEAR:
- str->set_ascii(STRING_WITH_LEN("year"));
- break;
-
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VARCHAR_COMPRESSED:
- {
- CHARSET_INFO *cs= str->charset();
- size_t length=0;
- if (char_with_octets)
- length= cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
- "varchar(%u octets)", metadata);
- else
- length= cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
- "varbinary(%u)", metadata);
- str->length(length);
- }
- break;
-
- case MYSQL_TYPE_BIT:
- {
- CHARSET_INFO *cs= str->charset();
- int bit_length= 8 * (metadata >> 8) + (metadata & 0xFF);
- size_t length=
- cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
- "bit(%d)", bit_length);
- str->length(length);
- }
- break;
-
- case MYSQL_TYPE_DECIMAL:
- {
- CHARSET_INFO *cs= str->charset();
- size_t length=
- cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
- "decimal(%d,?)/*old*/", metadata);
- str->length(length);
- }
- break;
-
- case MYSQL_TYPE_NEWDECIMAL:
- {
- CHARSET_INFO *cs= str->charset();
- size_t length=
- cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
- "decimal(%d,%d)", metadata >> 8, metadata & 0xff);
- str->length(length);
- }
- break;
-
- case MYSQL_TYPE_ENUM:
- str->set_ascii(STRING_WITH_LEN("enum"));
- break;
-
- case MYSQL_TYPE_SET:
- str->set_ascii(STRING_WITH_LEN("set"));
- break;
-
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_BLOB_COMPRESSED:
- /*
- Field::real_type() lies regarding the actual type of a BLOB, so
- it is necessary to check the pack length to figure out what kind
- of blob it really is.
- */
- switch (metadata)
- {
- case 1:
- str->set_ascii(STRING_WITH_LEN("tinyblob"));
- break;
-
- case 2:
- str->set_ascii(STRING_WITH_LEN("blob"));
- break;
-
- case 3:
- str->set_ascii(STRING_WITH_LEN("mediumblob"));
- break;
-
- case 4:
- str->set_ascii(STRING_WITH_LEN("longblob"));
- break;
-
- default:
- DBUG_ASSERT(0);
- break;
- }
-
- if (type == MYSQL_TYPE_BLOB_COMPRESSED)
- str->append(STRING_WITH_LEN(" compressed"));
- break;
-
- case MYSQL_TYPE_STRING:
- {
- /*
- This is taken from Field_string::unpack.
- */
- CHARSET_INFO *cs= str->charset();
- uint bytes= (((metadata >> 4) & 0x300) ^ 0x300) + (metadata & 0x00ff);
- size_t length=0;
- if (char_with_octets)
- length= cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
- "char(%u octets)", bytes);
- else
- length= cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
- "binary(%u)", bytes);
- str->length(length);
- }
- break;
-
- case MYSQL_TYPE_GEOMETRY:
- str->set_ascii(STRING_WITH_LEN("geometry"));
- break;
-
- default:
- str->set_ascii(STRING_WITH_LEN("<unknown type>"));
- }
- DBUG_VOID_RETURN;
-}
-
-
-/**
- Check the order variable and print errors if the order is not
- acceptable according to the current settings.
-
- @param order The computed order of the conversion needed.
- @param rli The relay log info data structure: for error reporting.
- */
-bool is_conversion_ok(int order, Relay_log_info *rli)
-{
- DBUG_ENTER("is_conversion_ok");
- bool allow_non_lossy, allow_lossy;
-
- allow_non_lossy = slave_type_conversions_options &
- (1ULL << SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY);
- allow_lossy= slave_type_conversions_options &
- (1ULL << SLAVE_TYPE_CONVERSIONS_ALL_LOSSY);
-
- DBUG_PRINT("enter", ("order: %d, flags:%s%s", order,
- allow_non_lossy ? " ALL_NON_LOSSY" : "",
- allow_lossy ? " ALL_LOSSY" : ""));
- if (order < 0 && !allow_non_lossy)
- {
- /* !!! Add error message saying that non-lossy conversions need to be allowed. */
- DBUG_RETURN(false);
- }
-
- if (order > 0 && !allow_lossy)
- {
- /* !!! Add error message saying that lossy conversions need to be allowed. */
- DBUG_RETURN(false);
- }
-
- DBUG_RETURN(true);
-}
-
-
-/**
- Can a type potentially be converted to another type?
-
- This function check if the types are convertible and what
- conversion is required.
-
- If conversion is not possible, and error is printed.
-
- If conversion is possible:
-
- - *order will be set to -1 if source type is smaller than target
- type and a non-lossy conversion can be required. This includes
- the case where the field types are different but types could
- actually be converted in either direction.
-
- - *order will be set to 0 if no conversion is required.
-
- - *order will be set to 1 if the source type is strictly larger
- than the target type and that conversion is potentially lossy.
-
- @param[in] field Target field
- @param[in] type Source field type
- @param[in] metadata Source field metadata
- @param[in] rli Relay log info (for error reporting)
- @param[in] mflags Flags from the table map event
- @param[out] order Order between source field and target field
-
- @return @c true if conversion is possible according to the current
- settings, @c false if conversion is not possible according to the
- current setting.
- */
-static bool
-can_convert_field_to(Field *field,
- enum_field_types source_type, uint16 metadata,
- Relay_log_info *rli, uint16 mflags,
- int *order_var)
-{
- DBUG_ENTER("can_convert_field_to");
- bool same_type;
-#ifndef DBUG_OFF
- char field_type_buf[MAX_FIELD_WIDTH];
- String field_type(field_type_buf, sizeof(field_type_buf), &my_charset_latin1);
- field->sql_type(field_type);
- DBUG_PRINT("enter", ("field_type: %s, target_type: %d, source_type: %d, source_metadata: 0x%x",
- field_type.c_ptr_safe(), field->real_type(), source_type, metadata));
-#endif
- /**
- @todo
- Implement Field_varstring_cmopressed::real_type() and
- Field_blob_compressed::real_type() properly. All occurencies
- of Field::real_type() have to be inspected and adjusted if needed.
-
- Until it is not ready we have to compare source_type against
- binlog_type() when replicating from or to compressed data types.
-
- @sa Comment for Field::binlog_type()
- */
- if (source_type == MYSQL_TYPE_VARCHAR_COMPRESSED ||
- source_type == MYSQL_TYPE_BLOB_COMPRESSED ||
- field->binlog_type() == MYSQL_TYPE_VARCHAR_COMPRESSED ||
- field->binlog_type() == MYSQL_TYPE_BLOB_COMPRESSED)
- same_type= field->binlog_type() == source_type;
- else
- same_type= field->real_type() == source_type;
-
- /*
- If the real type is the same, we need to check the metadata to
- decide if conversions are allowed.
- */
- if (same_type)
- {
- if (metadata == 0) // Metadata can only be zero if no metadata was provided
- {
- /*
- If there is no metadata, we either have an old event where no
- metadata were supplied, or a type that does not require any
- metadata. In either case, conversion can be done but no
- conversion table is necessary.
- */
- DBUG_PRINT("debug", ("Base types are identical, but there is no metadata"));
- *order_var= 0;
- DBUG_RETURN(true);
- }
-
- DBUG_PRINT("debug", ("Base types are identical, doing field size comparison"));
- if (field->compatible_field_size(metadata, rli, mflags, order_var))
- DBUG_RETURN(is_conversion_ok(*order_var, rli));
- else
- DBUG_RETURN(false);
- }
- else if (
- /*
- Conversion from MariaDB TIMESTAMP(0), TIME(0), DATETIME(0)
- to the corresponding MySQL56 types is non-lossy.
- */
- (metadata == 0 &&
- ((field->real_type() == MYSQL_TYPE_TIMESTAMP2 &&
- source_type == MYSQL_TYPE_TIMESTAMP) ||
- (field->real_type() == MYSQL_TYPE_TIME2 &&
- source_type == MYSQL_TYPE_TIME) ||
- (field->real_type() == MYSQL_TYPE_DATETIME2 &&
- source_type == MYSQL_TYPE_DATETIME))) ||
- /*
- Conversion from MySQL56 TIMESTAMP(N), TIME(N), DATETIME(N)
- to the corresponding MariaDB or MySQL55 types is non-lossy.
- */
- (metadata == field->decimals() &&
- ((field->real_type() == MYSQL_TYPE_TIMESTAMP &&
- source_type == MYSQL_TYPE_TIMESTAMP2) ||
- (field->real_type() == MYSQL_TYPE_TIME &&
- source_type == MYSQL_TYPE_TIME2) ||
- (field->real_type() == MYSQL_TYPE_DATETIME &&
- source_type == MYSQL_TYPE_DATETIME2))))
- {
- /*
- TS-TODO: conversion from FSP1>FSP2.
- */
- *order_var= -1;
- DBUG_RETURN(true);
- }
- else if (!slave_type_conversions_options)
- DBUG_RETURN(false);
-
- /*
- Here, from and to will always be different. Since the types are
- different, we cannot use the compatible_field_size() function, but
- have to rely on hard-coded max-sizes for fields.
- */
-
- DBUG_PRINT("debug", ("Base types are different, checking conversion"));
- switch (source_type) // Source type (on master)
- {
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_NEWDECIMAL:
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_DOUBLE:
- switch (field->real_type())
- {
- case MYSQL_TYPE_NEWDECIMAL:
- /*
- Then the other type is either FLOAT, DOUBLE, or old style
- DECIMAL, so we require lossy conversion.
- */
- *order_var= 1;
- DBUG_RETURN(is_conversion_ok(*order_var, rli));
-
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_DOUBLE:
- {
- if (source_type == MYSQL_TYPE_NEWDECIMAL ||
- source_type == MYSQL_TYPE_DECIMAL)
- *order_var = 1; // Always require lossy conversions
- else
- *order_var= compare_lengths(field, source_type, metadata);
- DBUG_ASSERT(*order_var != 0);
- DBUG_RETURN(is_conversion_ok(*order_var, rli));
- }
-
- default:
- DBUG_RETURN(false);
- }
- break;
-
- /*
- The length comparison check will do the correct job of comparing
- the field lengths (in bytes) of two integer types.
- */
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_INT24:
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_LONGLONG:
- switch (field->real_type())
- {
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_INT24:
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_LONGLONG:
- /*
- max_display_length_for_field() is not fully precise for the integer
- data types. So its result cannot be compared to the result of
- field->max_dispay_length() when the table field and the binlog field
- are of the same type.
- This code should eventually be rewritten not to use
- compare_lengths(), to detect subtype/supetype relations
- just using the type codes.
- */
- DBUG_ASSERT(source_type != field->real_type());
- *order_var= compare_lengths(field, source_type, metadata);
- DBUG_ASSERT(*order_var != 0);
- DBUG_RETURN(is_conversion_ok(*order_var, rli));
-
- default:
- DBUG_RETURN(false);
- }
- break;
-
- /*
- Since source and target type is different, and it is not possible
- to convert bit types to anything else, this will return false.
- */
- case MYSQL_TYPE_BIT:
- DBUG_RETURN(false);
-
- /*
- If all conversions are disabled, it is not allowed to convert
- between these types. Since the TEXT vs. BINARY is distinguished by
- the charset, and the charset is not replicated, we cannot
- currently distinguish between , e.g., TEXT and BLOB.
- */
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_BLOB_COMPRESSED:
- case MYSQL_TYPE_STRING:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VARCHAR_COMPRESSED:
- switch (field->real_type())
- {
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_BLOB_COMPRESSED:
- case MYSQL_TYPE_STRING:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VARCHAR_COMPRESSED:
- *order_var= compare_lengths(field, source_type, metadata);
- /*
- Here we know that the types are different, so if the order
- gives that they do not require any conversion, we still need
- to have non-lossy conversion enabled to allow conversion
- between different (string) types of the same length.
- */
- if (*order_var == 0)
- *order_var= -1;
- DBUG_RETURN(is_conversion_ok(*order_var, rli));
-
- default:
- DBUG_RETURN(false);
- }
- break;
-
- case MYSQL_TYPE_GEOMETRY:
- case MYSQL_TYPE_TIMESTAMP:
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_YEAR:
- case MYSQL_TYPE_NULL:
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_TIMESTAMP2:
- 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
-}
-
-
-/**
- Is the definition compatible with a table?
-
- This function will compare the master table with an existing table
- on the slave and see if they are compatible with respect to the
- current settings of @c SLAVE_TYPE_CONVERSIONS.
-
- If the tables are compatible and conversions are required, @c
- *tmp_table_var will be set to a virtual temporary table with field
- pointers for the fields that require conversions. This allow simple
- checking of whether a conversion are to be applied or not.
-
- If tables are compatible, but no conversions are necessary, @c
- *tmp_table_var will be set to NULL.
-
- @param rli_arg[in]
- Relay log info, for error reporting.
-
- @param table[in]
- Table to compare with
-
- @param tmp_table_var[out]
- Virtual temporary table for performing conversions, if necessary.
-
- @retval true Master table is compatible with slave table.
- @retval false Master table is not compatible with slave table.
-*/
-bool
-table_def::compatible_with(THD *thd, rpl_group_info *rgi,
- TABLE *table, TABLE **conv_table_var)
- const
-{
- /*
- We only check the initial columns for the tables.
- */
- uint const cols_to_check= MY_MIN(table->s->fields, size());
- Relay_log_info *rli= rgi->rli;
- TABLE *tmp_table= NULL;
-
- for (uint col= 0 ; col < cols_to_check ; ++col)
- {
- Field *const field= table->field[col];
- int order;
- if (can_convert_field_to(field, type(col), field_metadata(col), rli, m_flags, &order))
- {
- DBUG_PRINT("debug", ("Checking column %d -"
- " field '%s' can be converted - order: %d",
- col, field->field_name.str, order));
- DBUG_ASSERT(order >= -1 && order <= 1);
-
- /*
- If order is not 0, a conversion is required, so we need to set
- up the conversion table.
- */
- if (order != 0 && tmp_table == NULL)
- {
- /*
- This will create the full table with all fields. This is
- necessary to ge the correct field lengths for the record.
- */
- tmp_table= create_conversion_table(thd, rgi, table);
- if (tmp_table == NULL)
- return false;
- /*
- Clear all fields up to, but not including, this column.
- */
- for (unsigned int i= 0; i < col; ++i)
- tmp_table->field[i]= NULL;
- }
-
- if (order == 0 && tmp_table != NULL)
- tmp_table->field[col]= NULL;
- }
- else
- {
- DBUG_PRINT("debug", ("Checking column %d -"
- " field '%s' can not be converted",
- col, field->field_name.str));
- DBUG_ASSERT(col < size() && col < table->s->fields);
- DBUG_ASSERT(table->s->db.str && table->s->table_name.str);
- DBUG_ASSERT(table->in_use);
- const char *db_name= table->s->db.str;
- const char *tbl_name= table->s->table_name.str;
- char source_buf[MAX_FIELD_WIDTH];
- char target_buf[MAX_FIELD_WIDTH];
- String source_type(source_buf, sizeof(source_buf), &my_charset_latin1);
- String target_type(target_buf, sizeof(target_buf), &my_charset_latin1);
- THD *thd= table->in_use;
- bool char_with_octets= field->cmp_type() == STRING_RESULT ?
- field->has_charset() : true;
-
- show_sql_type(type(col), field_metadata(col), &source_type,
- char_with_octets);
- field->sql_rpl_type(&target_type);
-
- rli->report(ERROR_LEVEL, ER_SLAVE_CONVERSION_FAILED, rgi->gtid_info(),
- ER_THD(thd, ER_SLAVE_CONVERSION_FAILED),
- col, db_name, tbl_name,
- source_type.c_ptr_safe(), target_type.c_ptr_safe());
- return false;
- }
- }
-
-#ifndef DBUG_OFF
- if (tmp_table)
- {
- for (unsigned int col= 0; col < tmp_table->s->fields; ++col)
- if (tmp_table->field[col])
- {
- char source_buf[MAX_FIELD_WIDTH];
- char target_buf[MAX_FIELD_WIDTH];
- String source_type(source_buf, sizeof(source_buf), &my_charset_latin1);
- String target_type(target_buf, sizeof(target_buf), &my_charset_latin1);
- tmp_table->field[col]->sql_type(source_type);
- table->field[col]->sql_type(target_type);
- DBUG_PRINT("debug", ("Field %s - conversion required."
- " Source type: '%s', Target type: '%s'",
- tmp_table->field[col]->field_name.str,
- source_type.c_ptr_safe(), target_type.c_ptr_safe()));
- }
- }
-#endif
-
- *conv_table_var= tmp_table;
- return true;
-}
-
-
-/**
- A wrapper to Virtual_tmp_table, to get access to its constructor,
- which is protected for safety purposes (against illegal use on stack).
-*/
-class Virtual_conversion_table: public Virtual_tmp_table
-{
-public:
- Virtual_conversion_table(THD *thd) :Virtual_tmp_table(thd) { }
- /**
- Add a new field into the virtual table.
- @param sql_type - The real_type of the field.
- @param metadata - The RBR binary log metadata for this field.
- @param target_field - The field from the target table, to get extra
- attributes from (e.g. typelib in case of ENUM).
- */
- bool add(enum_field_types sql_type,
- uint16 metadata, const Field *target_field)
- {
- const Type_handler *handler= Type_handler::get_handler_by_real_type(sql_type);
- if (!handler)
- {
- sql_print_error("In RBR mode, Slave received unknown field type field %d "
- " for column Name: %s.%s.%s.",
- (int) sql_type,
- target_field->table->s->db.str,
- target_field->table->s->table_name.str,
- target_field->field_name.str);
- return true;
- }
- Field *tmp= handler->make_conversion_table_field(this, metadata,
- target_field);
- if (!tmp)
- return true;
- Virtual_tmp_table::add(tmp);
- DBUG_PRINT("debug", ("sql_type: %d, target_field: '%s', max_length: %d, decimals: %d,"
- " maybe_null: %d, unsigned_flag: %d, pack_length: %u",
- sql_type, target_field->field_name.str,
- tmp->field_length, tmp->decimals(), TRUE,
- tmp->flags, tmp->pack_length()));
- return false;
- }
-};
-
-
-/**
- Create a conversion table.
-
- If the function is unable to create the conversion table, an error
- will be printed and NULL will be returned.
-
- @return Pointer to conversion table, or NULL if unable to create
- conversion table.
- */
-
-TABLE *table_def::create_conversion_table(THD *thd, rpl_group_info *rgi,
- TABLE *target_table) const
-{
- DBUG_ENTER("table_def::create_conversion_table");
-
- Virtual_conversion_table *conv_table;
- Relay_log_info *rli= rgi->rli;
- /*
- At slave, columns may differ. So we should create
- MY_MIN(columns@master, columns@slave) columns in the
- conversion table.
- */
- uint const cols_to_create= MY_MIN(target_table->s->fields, size());
- if (!(conv_table= new(thd) Virtual_conversion_table(thd)) ||
- conv_table->init(cols_to_create))
- goto err;
- for (uint col= 0 ; col < cols_to_create; ++col)
- {
- if (conv_table->add(type(col), field_metadata(col),
- target_table->field[col]))
- {
- DBUG_PRINT("debug", ("binlog_type: %d, metadata: %04X, target_field: '%s'"
- " make_conversion_table_field() failed",
- binlog_type(col), field_metadata(col),
- target_table->field[col]->field_name.str));
- goto err;
- }
- }
-
- if (conv_table->open())
- goto err; // Could not allocate record buffer?
-
- DBUG_RETURN(conv_table);
-
-err:
- if (conv_table)
- delete conv_table;
- rli->report(ERROR_LEVEL, ER_SLAVE_CANT_CREATE_CONVERSION, rgi->gtid_info(),
- ER_THD(thd, ER_SLAVE_CANT_CREATE_CONVERSION),
- target_table->s->db.str,
- target_table->s->table_name.str);
- DBUG_RETURN(NULL);
-}
-#endif /* MYSQL_CLIENT */
+PSI_memory_key key_memory_table_def_memory;
table_def::table_def(unsigned char *types, ulong size,
uchar *field_metadata, int metadata_size,
@@ -1101,7 +180,7 @@ table_def::table_def(unsigned char *types, ulong size,
m_field_metadata(0), m_null_bits(0), m_flags(flags),
m_memory(NULL)
{
- m_memory= (uchar *)my_multi_malloc(MYF(MY_WME),
+ m_memory= (uchar *)my_multi_malloc(key_memory_table_def_memory, MYF(MY_WME),
&m_type, size,
&m_field_metadata,
size * sizeof(uint16),
@@ -1256,67 +335,3 @@ bool event_checksum_test(uchar *event_buf, ulong event_len, enum enum_binlog_che
}
return res;
}
-
-#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
-
-Deferred_log_events::Deferred_log_events(Relay_log_info *rli) : last_added(NULL)
-{
- my_init_dynamic_array(&array, sizeof(Log_event *), 32, 16, MYF(0));
-}
-
-Deferred_log_events::~Deferred_log_events()
-{
- delete_dynamic(&array);
-}
-
-int Deferred_log_events::add(Log_event *ev)
-{
- last_added= ev;
- insert_dynamic(&array, (uchar*) &ev);
- return 0;
-}
-
-bool Deferred_log_events::is_empty()
-{
- return array.elements == 0;
-}
-
-bool Deferred_log_events::execute(rpl_group_info *rgi)
-{
- bool res= false;
- DBUG_ENTER("Deferred_log_events::execute");
- DBUG_ASSERT(rgi->deferred_events_collecting);
-
- rgi->deferred_events_collecting= false;
- for (uint i= 0; !res && i < array.elements; i++)
- {
- Log_event *ev= (* (Log_event **)
- dynamic_array_ptr(&array, i));
- res= ev->apply_event(rgi);
- }
- rgi->deferred_events_collecting= true;
- DBUG_RETURN(res);
-}
-
-void Deferred_log_events::rewind()
-{
- /*
- Reset preceding Query log event events which execution was
- deferred because of slave side filtering.
- */
- if (!is_empty())
- {
- for (uint i= 0; i < array.elements; i++)
- {
- Log_event *ev= *(Log_event **) dynamic_array_ptr(&array, i);
- delete ev;
- }
- last_added= NULL;
- if (array.elements > array.max_element)
- freeze_size(&array);
- reset_dynamic(&array);
- }
- last_added= NULL;
-}
-
-#endif
diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h
index b42b11231e0..c28e8aa10eb 100644
--- a/sql/rpl_utility.h
+++ b/sql/rpl_utility.h
@@ -118,7 +118,9 @@ public:
return source_type;
}
-
+#ifdef MYSQL_SERVER
+ const Type_handler *field_type_handler(uint index) const;
+#endif
/*
This function allows callers to get the extra field data from the
diff --git a/sql/rpl_utility_server.cc b/sql/rpl_utility_server.cc
new file mode 100644
index 00000000000..8110b142e74
--- /dev/null
+++ b/sql/rpl_utility_server.cc
@@ -0,0 +1,1185 @@
+/* Copyright (c) 2006, 2013, Oracle and/or its affiliates.
+ Copyright (c) 2011, 2013, Monty Program Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "mariadb.h"
+#include <my_bit.h>
+#include "rpl_utility.h"
+#include "log_event.h"
+
+#if defined(MYSQL_CLIENT)
+#error MYSQL_CLIENT must not be defined here
+#endif
+
+#if !defined(MYSQL_SERVER)
+#error MYSQL_SERVER must be defined here
+#endif
+
+#if defined(HAVE_REPLICATION)
+#include "rpl_rli.h"
+#include "sql_select.h"
+#endif
+
+
+/**
+ Compute the maximum display length of a field.
+
+ @param sql_type Type of the field
+ @param metadata The metadata from the master for the field.
+ @return Maximum length of the field in bytes.
+
+ The precise values calculated by field->max_display_length() and
+ calculated by max_display_length_for_field() can differ (by +1 or -1)
+ for integer data types (TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT).
+ This slight difference is not important here, because we call
+ this function only for two *different* integer data types.
+ */
+static uint32
+max_display_length_for_field(const Conv_source &source)
+{
+ DBUG_PRINT("debug", ("sql_type: %s, metadata: 0x%x",
+ source.type_handler()->name().ptr(), source.metadata()));
+ return source.type_handler()->max_display_length_for_field(source);
+}
+
+
+/*
+ Compare the pack lengths of a source field (on the master) and a
+ target field (on the slave).
+
+ @param sh Source type handler
+ @param source_length Source length
+ @param th Target type hander
+ @param target_length Target length
+
+ @retval CONV_TYPE_SUBSET_TO_SUPERSET The length of the source field is
+ smaller than the target field.
+ @retval CONV_TYPE_PRECISE The length of the source and
+ the target fields are equal.
+ @retval CONV_TYPE_SUPERSET_TO_SUBSET The length of the source field is
+ greater than the target field.
+ */
+static enum_conv_type
+compare_lengths(const Type_handler *sh, uint32 source_length,
+ const Type_handler *th, uint32 target_length)
+{
+ DBUG_ENTER("compare_lengths");
+ DBUG_PRINT("debug", ("source_length: %lu, source_type: %s,"
+ " target_length: %lu, target_type: %s",
+ (unsigned long) source_length, sh->name().ptr(),
+ (unsigned long) target_length, th->name().ptr()));
+ enum_conv_type result=
+ source_length < target_length ? CONV_TYPE_SUBSET_TO_SUPERSET :
+ source_length > target_length ? CONV_TYPE_SUPERSET_TO_SUBSET :
+ CONV_TYPE_PRECISE;
+ DBUG_PRINT("result", ("%d", result));
+ DBUG_RETURN(result);
+}
+
+
+/**
+ Calculate display length for MySQL56 temporal data types from their metadata.
+ It contains fractional precision in the low 16-bit word.
+*/
+static uint32
+max_display_length_for_temporal2_field(uint32 int_display_length,
+ unsigned int metadata)
+{
+ metadata&= 0x00ff;
+ return int_display_length + metadata + (metadata ? 1 : 0);
+}
+
+
+uint32
+Type_handler_newdecimal::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return src.metadata() >> 8;
+}
+
+
+uint32
+Type_handler_typelib::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ /*
+ Field_enum::rpl_conv_type_from() does not use compare_lengths().
+ So we should not come here.
+ */
+ DBUG_ASSERT(0);
+ return src.metadata() & 0x00ff;
+}
+
+
+uint32
+Type_handler_string::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ /*
+ ENUM and SET are transferred using as STRING,
+ with the exact type code in metadata.
+ Make sure that we previously detected ENUM/SET and
+ translated them into a proper type handler.
+ See table_def::field_type_handler() for details.
+ */
+ DBUG_ASSERT((src.metadata() >> 8) != MYSQL_TYPE_SET);
+ DBUG_ASSERT((src.metadata() >> 8) != MYSQL_TYPE_ENUM);
+ /* This is taken from Field_string::unpack. */
+ return (((src.metadata() >> 4) & 0x300) ^ 0x300) + (src.metadata() & 0x00ff);
+}
+
+
+uint32
+Type_handler_time2::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return max_display_length_for_temporal2_field(MIN_TIME_WIDTH,
+ src.metadata());
+}
+
+
+uint32
+Type_handler_timestamp2::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return max_display_length_for_temporal2_field(MAX_DATETIME_WIDTH,
+ src.metadata());
+}
+
+
+uint32
+Type_handler_datetime2::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return max_display_length_for_temporal2_field(MAX_DATETIME_WIDTH,
+ src.metadata());
+}
+
+
+uint32
+Type_handler_bit::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ /*
+ Decode the size of the bit field from the master.
+ */
+ DBUG_ASSERT((src.metadata() & 0xff) <= 7);
+ return 8 * (src.metadata() >> 8U) + (src.metadata() & 0x00ff);
+}
+
+
+uint32
+Type_handler_var_string::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return src.metadata();
+}
+
+
+uint32
+Type_handler_varchar::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return src.metadata();
+}
+
+
+uint32
+Type_handler_varchar_compressed::
+ max_display_length_for_field(const Conv_source &src) const
+{
+ DBUG_ASSERT(src.metadata() > 0);
+ return src.metadata() - 1;
+}
+
+
+/*
+ The actual length for these types does not really matter since
+ they are used to calc_pack_length, which ignores the given
+ length for these types.
+
+ Since we want this to be accurate for other uses, we return the
+ maximum size in bytes of these BLOBs.
+*/
+uint32
+Type_handler_tiny_blob::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return (uint32) my_set_bits(1 * 8);
+}
+
+
+uint32
+Type_handler_medium_blob::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return (uint32) my_set_bits(3 * 8);
+}
+
+
+uint32
+Type_handler_blob::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ /*
+ For the blob type, Field::real_type() lies and say that all
+ blobs are of type MYSQL_TYPE_BLOB. In that case, we have to look
+ at the length instead to decide what the max display size is.
+ */
+ return (uint32) my_set_bits(src.metadata() * 8);
+}
+
+
+uint32
+Type_handler_blob_compressed::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return (uint32) my_set_bits(src.metadata() * 8);
+}
+
+
+uint32
+Type_handler_long_blob::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return (uint32) my_set_bits(4 * 8);
+}
+
+
+uint32
+Type_handler_olddecimal::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return ~(uint32) 0;
+}
+
+
+void Type_handler::show_binlog_type(const Conv_source &src, const Field &,
+ String *str) const
+{
+ str->set_ascii(name().ptr(), name().length());
+}
+
+
+void Type_handler_var_string::show_binlog_type(const Conv_source &src,
+ const Field &dst,
+ String *str) const
+{
+ CHARSET_INFO *cs= str->charset();
+ const char* fmt= dst.cmp_type() != STRING_RESULT || dst.has_charset()
+ ? "char(%u octets)" : "binary(%u)";
+ size_t length= cs->cset->snprintf(cs, (char*) str->ptr(),
+ str->alloced_length(),
+ fmt, src.metadata());
+ str->length(length);
+}
+
+
+void Type_handler_varchar::show_binlog_type(const Conv_source &src,
+ const Field &dst,
+ String *str) const
+{
+ CHARSET_INFO *cs= str->charset();
+ const char* fmt= dst.cmp_type() != STRING_RESULT || dst.has_charset()
+ ? "varchar(%u octets)" : "varbinary(%u)";
+ size_t length= cs->cset->snprintf(cs, (char*) str->ptr(),
+ str->alloced_length(),
+ fmt, src.metadata());
+ str->length(length);
+}
+
+
+void Type_handler_varchar_compressed::show_binlog_type(const Conv_source &src,
+ const Field &dst,
+ String *str) const
+{
+ CHARSET_INFO *cs= str->charset();
+ const char* fmt= dst.cmp_type() != STRING_RESULT || dst.has_charset()
+ ? "varchar(%u octets) compressed" : "varbinary(%u) compressed";
+ size_t length= cs->cset->snprintf(cs, (char*) str->ptr(),
+ str->alloced_length(),
+ fmt, src.metadata());
+ str->length(length);
+}
+
+void Type_handler_bit::show_binlog_type(const Conv_source &src, const Field &,
+ String *str) const
+{
+ CHARSET_INFO *cs= str->charset();
+ int bit_length= 8 * (src.metadata() >> 8) + (src.metadata() & 0xFF);
+ size_t length=
+ cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
+ "bit(%d)", bit_length);
+ str->length(length);
+}
+
+
+void Type_handler_olddecimal::show_binlog_type(const Conv_source &src,
+ const Field &,
+ String *str) const
+{
+ CHARSET_INFO *cs= str->charset();
+ size_t length=
+ cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
+ "decimal(%d,?)/*old*/", src.metadata());
+ str->length(length);
+
+}
+
+
+void Type_handler_newdecimal::show_binlog_type(const Conv_source &src,
+ const Field &,
+ String *str) const
+{
+ CHARSET_INFO *cs= str->charset();
+ size_t length=
+ cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
+ "decimal(%d,%d)",
+ src.metadata() >> 8, src.metadata() & 0xff);
+ str->length(length);
+}
+
+
+void Type_handler_blob_compressed::show_binlog_type(const Conv_source &src,
+ const Field &,
+ String *str) const
+{
+ /*
+ Field::real_type() lies regarding the actual type of a BLOB, so
+ it is necessary to check the pack length to figure out what kind
+ of blob it really is.
+ */
+ switch (src.metadata()) {
+ case 1:
+ str->set_ascii(STRING_WITH_LEN("tinyblob compressed"));
+ break;
+ case 2:
+ str->set_ascii(STRING_WITH_LEN("blob compressed"));
+ break;
+ case 3:
+ str->set_ascii(STRING_WITH_LEN("mediumblob compressed"));
+ break;
+ default:
+ DBUG_ASSERT(0);
+ // Fall through
+ case 4:
+ str->set_ascii(STRING_WITH_LEN("longblob compressed"));
+ }
+}
+
+
+void Type_handler_string::show_binlog_type(const Conv_source &src,
+ const Field &dst,
+ String *str) const
+{
+ /*
+ This is taken from Field_string::unpack.
+ */
+ CHARSET_INFO *cs= str->charset();
+ uint bytes= (((src.metadata() >> 4) & 0x300) ^ 0x300) +
+ (src.metadata() & 0x00ff);
+ const char* fmt= dst.cmp_type() != STRING_RESULT || dst.has_charset()
+ ? "char(%u octets)" : "binary(%u)";
+ size_t length= cs->cset->snprintf(cs, (char*) str->ptr(),
+ str->alloced_length(),
+ fmt, bytes);
+ str->length(length);
+}
+
+
+enum_conv_type
+Field::rpl_conv_type_from_same_data_type(uint16 metadata,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (metadata == 0) // Metadata can only be zero if no metadata was provided
+ {
+ /*
+ If there is no metadata, we either have an old event where no
+ metadata were supplied, or a type that does not require any
+ metadata. In either case, conversion can be done but no
+ conversion table is necessary.
+ */
+ DBUG_PRINT("debug", ("Base types are identical, but there is no metadata"));
+ return CONV_TYPE_PRECISE;
+ }
+
+ DBUG_PRINT("debug", ("Base types are identical, doing field size comparison"));
+ int order= 0;
+ if (!compatible_field_size(metadata, rli, param.table_def_flags(), &order))
+ return CONV_TYPE_IMPOSSIBLE;
+ return order == 0 ? CONV_TYPE_PRECISE :
+ order < 0 ? CONV_TYPE_SUBSET_TO_SUPERSET :
+ CONV_TYPE_SUPERSET_TO_SUBSET;
+}
+
+
+enum_conv_type
+Field_new_decimal::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ if (source.type_handler() == &type_handler_olddecimal ||
+ source.type_handler() == &type_handler_newdecimal ||
+ source.type_handler() == &type_handler_float ||
+ source.type_handler() == &type_handler_double)
+ {
+ /*
+ Then the other type is either FLOAT, DOUBLE, or old style
+ DECIMAL, so we require lossy conversion.
+ */
+ return CONV_TYPE_SUPERSET_TO_SUBSET;
+ }
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+/*
+ This covers FLOAT, DOUBLE and old DECIMAL
+*/
+enum_conv_type
+Field_real::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ if (source.type_handler() == &type_handler_olddecimal ||
+ source.type_handler() == &type_handler_newdecimal)
+ return CONV_TYPE_SUPERSET_TO_SUBSET; // Always require lossy conversions
+ if (source.type_handler() == &type_handler_float ||
+ source.type_handler() == &type_handler_double)
+ {
+ enum_conv_type order= compare_lengths(source.type_handler(),
+ max_display_length_for_field(source),
+ type_handler(), max_display_length());
+ DBUG_ASSERT(order != CONV_TYPE_PRECISE);
+ return order;
+ }
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_int::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ /*
+ The length comparison check will do the correct job of comparing
+ the field lengths (in bytes) of two integer types.
+ */
+ if (source.type_handler() == &type_handler_stiny ||
+ source.type_handler() == &type_handler_sshort ||
+ source.type_handler() == &type_handler_sint24 ||
+ source.type_handler() == &type_handler_slong ||
+ source.type_handler() == &type_handler_slonglong)
+ {
+ /*
+ max_display_length_for_field() is not fully precise for the integer
+ data types. So its result cannot be compared to the result of
+ max_dispay_length() when the table field and the binlog field
+ are of the same type.
+ This code should eventually be rewritten not to use
+ compare_lengths(), to detect subtype/supetype relations
+ just using the type codes.
+ */
+ DBUG_ASSERT(source.real_field_type() != real_type());
+ enum_conv_type order= compare_lengths(source.type_handler(),
+ max_display_length_for_field(source),
+ type_handler(), max_display_length());
+ DBUG_ASSERT(order != CONV_TYPE_PRECISE);
+ return order;
+ }
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_enum::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ /*
+ For some reasons Field_enum and Field_set store MYSQL_TYPE_STRING
+ as a type code in the binary log and encode the real type in metadata.
+ So we need to test real_type() here instread of binlog_type().
+ */
+ return real_type() == source.real_field_type() ?
+ rpl_conv_type_from_same_data_type(source.metadata(), rli, param) :
+ CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_longstr::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ /**
+ @todo
+ Implement Field_varstring_compressed::real_type() and
+ Field_blob_compressed::real_type() properly. All occurencies
+ of Field::real_type() have to be inspected and adjusted if needed.
+
+ Until it is not ready we have to compare source_type against
+ binlog_type() when replicating from or to compressed data types.
+
+ @sa Comment for Field::binlog_type()
+ */
+ bool same_type;
+ if (source.real_field_type() == MYSQL_TYPE_VARCHAR_COMPRESSED ||
+ source.real_field_type() == MYSQL_TYPE_BLOB_COMPRESSED ||
+ binlog_type() == MYSQL_TYPE_VARCHAR_COMPRESSED ||
+ binlog_type() == MYSQL_TYPE_BLOB_COMPRESSED)
+ same_type= binlog_type() == source.real_field_type();
+ else
+ same_type= type_handler() == source.type_handler();
+
+ if (same_type)
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+
+ if (source.type_handler() == &type_handler_tiny_blob ||
+ source.type_handler() == &type_handler_medium_blob ||
+ source.type_handler() == &type_handler_long_blob ||
+ source.type_handler() == &type_handler_blob ||
+ source.type_handler() == &type_handler_blob_compressed ||
+ source.type_handler() == &type_handler_string ||
+ source.type_handler() == &type_handler_var_string ||
+ source.type_handler() == &type_handler_varchar ||
+ source.type_handler() == &type_handler_varchar_compressed)
+ {
+ enum_conv_type order= compare_lengths(source.type_handler(),
+ max_display_length_for_field(source),
+ type_handler(), max_display_length());
+ /*
+ Here we know that the types are different, so if the order
+ gives that they do not require any conversion, we still need
+ to have non-lossy conversion enabled to allow conversion
+ between different (string) types of the same length.
+
+ Also, if all conversions are disabled, it is not allowed to convert
+ between these types. Since the TEXT vs. BINARY is distinguished by
+ the charset, and the charset is not replicated, we cannot
+ currently distinguish between , e.g., TEXT and BLOB.
+ */
+ if (order == CONV_TYPE_PRECISE)
+ order= CONV_TYPE_SUBSET_TO_SUPERSET;
+ return order;
+ }
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_newdate::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (real_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ if (source.type_handler() == &type_handler_datetime2)
+ return CONV_TYPE_SUPERSET_TO_SUBSET;
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_time::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ // 'MySQL56 TIME(N)' -> 'MariaDB-5.3 TIME(N)' is non-lossy
+ if (decimals() == source.metadata() &&
+ source.type_handler() == &type_handler_time2)
+ return CONV_TYPE_VARIANT; // TODO: conversion from FSP1>FSP2
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_timef::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ /*
+ See comment in Field_datetimef::rpl_conv_type_from()
+ 'MariaDB-5.3 TIME(0)' to 'MySQL56 TIME(0)' is non-lossy
+ */
+ if (source.metadata() == 0 && source.type_handler() == &type_handler_time)
+ return CONV_TYPE_VARIANT;
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_timestamp::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ // 'MySQL56 TIMESTAMP(N)' -> MariaDB-5.3 TIMESTAMP(N)' is non-lossy
+ if (source.metadata() == decimals() &&
+ source.type_handler() == &type_handler_timestamp2)
+ return CONV_TYPE_VARIANT; // TODO: conversion from FSP1>FSP2
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_timestampf::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ /*
+ See comment in Field_datetimef::rpl_conv_type_from()
+ 'MariaDB-5.3 TIMESTAMP(0)' to 'MySQL56 TIMESTAMP(0)' is non-lossy
+ */
+ if (source.metadata() == 0 &&
+ source.type_handler() == &type_handler_timestamp)
+ return CONV_TYPE_VARIANT;
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_datetime::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ // 'MySQL56 DATETIME(N)' -> MariaDB-5.3 DATETIME(N) is non-lossy
+ if (source.metadata() == decimals() &&
+ source.type_handler() == &type_handler_datetime2)
+ return CONV_TYPE_VARIANT; // TODO: conversion from FSP1>FSP2
+ if (source.type_handler() == &type_handler_newdate)
+ return CONV_TYPE_SUBSET_TO_SUPERSET;
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_datetimef::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ /*
+ 'MariaDB-5.3 DATETIME(N)' does not provide information about fractional
+ precision in metadata. So we assume the precision on the master is equal
+ to the precision on the slave.
+ TODO: See MDEV-17394 what happend in case precisions are in case different
+ 'MariaDB-5.3 DATETIME(0)' to 'MySQL56 DATETIME(0)' is non-lossy
+ */
+ if (source.metadata() == 0 &&
+ source.type_handler() == &type_handler_datetime)
+ return CONV_TYPE_VARIANT;
+ if (source.type_handler() == &type_handler_newdate)
+ return CONV_TYPE_SUBSET_TO_SUPERSET;
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_date::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ // old DATE
+ return binlog_type() == source.real_field_type() ?
+ rpl_conv_type_from_same_data_type(source.metadata(), rli, param) :
+ CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_bit::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ return binlog_type() == source.real_field_type() ?
+ rpl_conv_type_from_same_data_type(source.metadata(), rli, param) :
+ CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_year::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ return binlog_type() == source.real_field_type() ?
+ rpl_conv_type_from_same_data_type(source.metadata(), rli, param) :
+ CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_null::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ DBUG_ASSERT(0);
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+/**********************************************************************/
+
+
+#if defined(HAVE_REPLICATION)
+
+/**
+ */
+static void show_sql_type(const Conv_source &src, const Field &dst,
+ String *str)
+{
+ DBUG_ENTER("show_sql_type");
+ DBUG_ASSERT(src.type_handler() != NULL);
+ DBUG_PRINT("enter", ("type: %s, metadata: 0x%x",
+ src.type_handler()->name().ptr(), src.metadata()));
+ src.type_handler()->show_binlog_type(src, dst, str);
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Check the order variable and print errors if the order is not
+ acceptable according to the current settings.
+
+ @param order The computed order of the conversion needed.
+ @param rli The relay log info data structure: for error reporting.
+ */
+static bool is_conversion_ok(enum_conv_type type, const Relay_log_info *rli,
+ ulonglong type_conversion_options)
+{
+ DBUG_ENTER("is_conversion_ok");
+ bool allow_non_lossy, allow_lossy;
+
+ allow_non_lossy= type_conversion_options &
+ (1ULL << SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY);
+ allow_lossy= type_conversion_options &
+ (1ULL << SLAVE_TYPE_CONVERSIONS_ALL_LOSSY);
+
+ DBUG_PRINT("enter", ("order: %d, flags:%s%s", (int) type,
+ allow_non_lossy ? " ALL_NON_LOSSY" : "",
+ allow_lossy ? " ALL_LOSSY" : ""));
+ switch (type) {
+ case CONV_TYPE_PRECISE:
+ case CONV_TYPE_VARIANT:
+ DBUG_RETURN(true);
+ case CONV_TYPE_SUBSET_TO_SUPERSET:
+ /* !!! Add error message saying that non-lossy conversions need to be allowed. */
+ DBUG_RETURN(allow_non_lossy);
+ case CONV_TYPE_SUPERSET_TO_SUBSET:
+ /* !!! Add error message saying that lossy conversions need to be allowed. */
+ DBUG_RETURN(allow_lossy);
+ case CONV_TYPE_IMPOSSIBLE:
+ DBUG_RETURN(false);
+ }
+
+ DBUG_RETURN(false);
+}
+
+
+/**
+ Can a type potentially be converted to another type?
+
+ This function check if the types are convertible and what
+ conversion is required.
+
+ If conversion is not possible, and error is printed.
+
+ If conversion is possible:
+
+ - *order will be set to -1 if source type is smaller than target
+ type and a non-lossy conversion can be required. This includes
+ the case where the field types are different but types could
+ actually be converted in either direction.
+
+ - *order will be set to 0 if no conversion is required.
+
+ - *order will be set to 1 if the source type is strictly larger
+ than the target type and that conversion is potentially lossy.
+
+ @param[in] field Target field
+ @param[in] type Source field type
+ @param[in] metadata Source field metadata
+ @param[in] rli Relay log info (for error reporting)
+ @param[in] mflags Flags from the table map event
+ @param[out] order Order between source field and target field
+
+ @return @c true if conversion is possible according to the current
+ settings, @c false if conversion is not possible according to the
+ current setting.
+ */
+static enum_conv_type
+can_convert_field_to(Field *field, const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param)
+{
+ DBUG_ENTER("can_convert_field_to");
+#ifndef DBUG_OFF
+ char field_type_buf[MAX_FIELD_WIDTH];
+ String field_type(field_type_buf, sizeof(field_type_buf), &my_charset_latin1);
+ field->sql_type(field_type);
+ DBUG_PRINT("enter", ("field_type: %s, target_type: %d, source_type: %d, source_metadata: 0x%x",
+ field_type.c_ptr_safe(), field->real_type(),
+ source.real_field_type(), source.metadata()));
+#endif
+ DBUG_RETURN(field->rpl_conv_type_from(source, rli, param));
+}
+
+
+const Type_handler *table_def::field_type_handler(uint col) const
+{
+ enum_field_types typecode= binlog_type(col);
+ uint16 metadata= field_metadata(col);
+ DBUG_ASSERT(typecode != MYSQL_TYPE_ENUM);
+ DBUG_ASSERT(typecode != MYSQL_TYPE_SET);
+
+ if (typecode == MYSQL_TYPE_BLOB)
+ {
+ switch (metadata & 0xff) {
+ case 1: return &type_handler_tiny_blob;
+ case 2: return &type_handler_blob;
+ case 3: return &type_handler_medium_blob;
+ case 4: return &type_handler_long_blob;
+ default: return NULL;
+ }
+ }
+ if (typecode == MYSQL_TYPE_STRING)
+ {
+ uchar typecode2= metadata >> 8;
+ if (typecode2 == MYSQL_TYPE_SET)
+ return &type_handler_set;
+ if (typecode2 == MYSQL_TYPE_ENUM)
+ return &type_handler_enum;
+ return &type_handler_string;
+ }
+ /*
+ This type has not been used since before row-based replication,
+ so we can safely assume that it really is MYSQL_TYPE_NEWDATE.
+ */
+ if (typecode == MYSQL_TYPE_DATE)
+ return &type_handler_newdate;
+ return Type_handler::get_handler_by_real_type(typecode);
+}
+
+
+/**
+ Is the definition compatible with a table?
+
+ This function will compare the master table with an existing table
+ on the slave and see if they are compatible with respect to the
+ current settings of @c SLAVE_TYPE_CONVERSIONS.
+
+ If the tables are compatible and conversions are required, @c
+ *tmp_table_var will be set to a virtual temporary table with field
+ pointers for the fields that require conversions. This allow simple
+ checking of whether a conversion are to be applied or not.
+
+ If tables are compatible, but no conversions are necessary, @c
+ *tmp_table_var will be set to NULL.
+
+ @param rli_arg[in]
+ Relay log info, for error reporting.
+
+ @param table[in]
+ Table to compare with
+
+ @param tmp_table_var[out]
+ Virtual temporary table for performing conversions, if necessary.
+
+ @retval true Master table is compatible with slave table.
+ @retval false Master table is not compatible with slave table.
+*/
+bool
+table_def::compatible_with(THD *thd, rpl_group_info *rgi,
+ TABLE *table, TABLE **conv_table_var)
+ const
+{
+ /*
+ We only check the initial columns for the tables.
+ */
+ uint const cols_to_check= MY_MIN(table->s->fields, size());
+ Relay_log_info *rli= rgi->rli;
+ TABLE *tmp_table= NULL;
+
+ for (uint col= 0 ; col < cols_to_check ; ++col)
+ {
+ Field *const field= table->field[col];
+ const Type_handler *h= field_type_handler(col);
+ if (!h)
+ {
+ sql_print_error("In RBR mode, Slave received unknown field type field %d "
+ " for column Name: %s.%s.%s.",
+ binlog_type(col),
+ field->table->s->db.str,
+ field->table->s->table_name.str,
+ field->field_name.str);
+ return false;
+ }
+
+ if (!h)
+ return false; // An unknown data type found in the binary log
+ Conv_source source(h, field_metadata(col), field->charset());
+ enum_conv_type convtype= can_convert_field_to(field, source, rli,
+ Conv_param(m_flags));
+ if (is_conversion_ok(convtype, rli, slave_type_conversions_options))
+ {
+ DBUG_PRINT("debug", ("Checking column %d -"
+ " field '%s' can be converted - order: %d",
+ col, field->field_name.str, convtype));
+ /*
+ If conversion type is not CONV_TYPE_RECISE, a conversion is required,
+ so we need to set up the conversion table.
+ */
+ if (convtype != CONV_TYPE_PRECISE && tmp_table == NULL)
+ {
+ /*
+ This will create the full table with all fields. This is
+ necessary to ge the correct field lengths for the record.
+ */
+ tmp_table= create_conversion_table(thd, rgi, table);
+ if (tmp_table == NULL)
+ return false;
+ /*
+ Clear all fields up to, but not including, this column.
+ */
+ for (unsigned int i= 0; i < col; ++i)
+ tmp_table->field[i]= NULL;
+ }
+
+ if (convtype == CONV_TYPE_PRECISE && tmp_table != NULL)
+ tmp_table->field[col]= NULL;
+ }
+ else
+ {
+ DBUG_PRINT("debug", ("Checking column %d -"
+ " field '%s' can not be converted",
+ col, field->field_name.str));
+ DBUG_ASSERT(col < size() && col < table->s->fields);
+ DBUG_ASSERT(table->s->db.str && table->s->table_name.str);
+ DBUG_ASSERT(table->in_use);
+ const char *db_name= table->s->db.str;
+ const char *tbl_name= table->s->table_name.str;
+ StringBuffer<MAX_FIELD_WIDTH> source_type(&my_charset_latin1);
+ StringBuffer<MAX_FIELD_WIDTH> target_type(&my_charset_latin1);
+ THD *thd= table->in_use;
+
+ show_sql_type(source, *field, &source_type);
+ field->sql_rpl_type(&target_type);
+ DBUG_ASSERT(source_type.length() > 0);
+ DBUG_ASSERT(target_type.length() > 0);
+ rli->report(ERROR_LEVEL, ER_SLAVE_CONVERSION_FAILED, rgi->gtid_info(),
+ ER_THD(thd, ER_SLAVE_CONVERSION_FAILED),
+ col, db_name, tbl_name,
+ source_type.c_ptr_safe(), target_type.c_ptr_safe());
+ return false;
+ }
+ }
+
+#ifndef DBUG_OFF
+ if (tmp_table)
+ {
+ for (unsigned int col= 0; col < tmp_table->s->fields; ++col)
+ if (tmp_table->field[col])
+ {
+ char source_buf[MAX_FIELD_WIDTH];
+ char target_buf[MAX_FIELD_WIDTH];
+ String source_type(source_buf, sizeof(source_buf), &my_charset_latin1);
+ String target_type(target_buf, sizeof(target_buf), &my_charset_latin1);
+ tmp_table->field[col]->sql_type(source_type);
+ table->field[col]->sql_type(target_type);
+ DBUG_PRINT("debug", ("Field %s - conversion required."
+ " Source type: '%s', Target type: '%s'",
+ tmp_table->field[col]->field_name.str,
+ source_type.c_ptr_safe(), target_type.c_ptr_safe()));
+ }
+ }
+#endif
+
+ *conv_table_var= tmp_table;
+ return true;
+}
+
+
+/**
+ A wrapper to Virtual_tmp_table, to get access to its constructor,
+ which is protected for safety purposes (against illegal use on stack).
+*/
+class Virtual_conversion_table: public Virtual_tmp_table
+{
+public:
+ Virtual_conversion_table(THD *thd) :Virtual_tmp_table(thd) { }
+ /**
+ Add a new field into the virtual table.
+ @param handler - The type handler of the field.
+ @param metadata - The RBR binary log metadata for this field.
+ @param target_field - The field from the target table, to get extra
+ attributes from (e.g. typelib in case of ENUM).
+ */
+ bool add(const Type_handler *handler,
+ uint16 metadata, const Field *target_field)
+ {
+ Field *tmp= handler->make_conversion_table_field(in_use->mem_root,
+ this, metadata,
+ target_field);
+ if (!tmp)
+ return true;
+ Virtual_tmp_table::add(tmp);
+ DBUG_PRINT("debug", ("sql_type: %s, target_field: '%s', max_length: %d, decimals: %d,"
+ " maybe_null: %d, unsigned_flag: %d, pack_length: %u",
+ handler->name().ptr(), target_field->field_name.str,
+ tmp->field_length, tmp->decimals(), TRUE,
+ tmp->flags, tmp->pack_length()));
+ return false;
+ }
+};
+
+
+/**
+ Create a conversion table.
+
+ If the function is unable to create the conversion table, an error
+ will be printed and NULL will be returned.
+
+ @return Pointer to conversion table, or NULL if unable to create
+ conversion table.
+ */
+
+TABLE *table_def::create_conversion_table(THD *thd, rpl_group_info *rgi,
+ TABLE *target_table) const
+{
+ DBUG_ENTER("table_def::create_conversion_table");
+
+ Virtual_conversion_table *conv_table;
+ Relay_log_info *rli= rgi->rli;
+ /*
+ At slave, columns may differ. So we should create
+ MY_MIN(columns@master, columns@slave) columns in the
+ conversion table.
+ */
+ uint const cols_to_create= MY_MIN(target_table->s->fields, size());
+ if (!(conv_table= new(thd) Virtual_conversion_table(thd)) ||
+ conv_table->init(cols_to_create))
+ goto err;
+ for (uint col= 0 ; col < cols_to_create; ++col)
+ {
+ const Type_handler *ha= field_type_handler(col);
+ DBUG_ASSERT(ha); // Checked at compatible_with() time
+ if (conv_table->add(ha, field_metadata(col), target_table->field[col]))
+ {
+ DBUG_PRINT("debug", ("binlog_type: %d, metadata: %04X, target_field: '%s'"
+ " make_conversion_table_field() failed",
+ binlog_type(col), field_metadata(col),
+ target_table->field[col]->field_name.str));
+ goto err;
+ }
+ }
+
+ if (conv_table->open())
+ goto err; // Could not allocate record buffer?
+
+ DBUG_RETURN(conv_table);
+
+err:
+ if (conv_table)
+ delete conv_table;
+ rli->report(ERROR_LEVEL, ER_SLAVE_CANT_CREATE_CONVERSION, rgi->gtid_info(),
+ ER_THD(thd, ER_SLAVE_CANT_CREATE_CONVERSION),
+ target_table->s->db.str,
+ target_table->s->table_name.str);
+ DBUG_RETURN(NULL);
+}
+
+
+
+Deferred_log_events::Deferred_log_events(Relay_log_info *rli) : last_added(NULL)
+{
+ my_init_dynamic_array(PSI_INSTRUMENT_ME, &array, sizeof(Log_event *), 32, 16, MYF(0));
+}
+
+Deferred_log_events::~Deferred_log_events()
+{
+ delete_dynamic(&array);
+}
+
+int Deferred_log_events::add(Log_event *ev)
+{
+ last_added= ev;
+ insert_dynamic(&array, (uchar*) &ev);
+ return 0;
+}
+
+bool Deferred_log_events::is_empty()
+{
+ return array.elements == 0;
+}
+
+bool Deferred_log_events::execute(rpl_group_info *rgi)
+{
+ bool res= false;
+ DBUG_ENTER("Deferred_log_events::execute");
+ DBUG_ASSERT(rgi->deferred_events_collecting);
+
+ rgi->deferred_events_collecting= false;
+ for (uint i= 0; !res && i < array.elements; i++)
+ {
+ Log_event *ev= (* (Log_event **)
+ dynamic_array_ptr(&array, i));
+ res= ev->apply_event(rgi);
+ }
+ rgi->deferred_events_collecting= true;
+ DBUG_RETURN(res);
+}
+
+void Deferred_log_events::rewind()
+{
+ /*
+ Reset preceding Query log event events which execution was
+ deferred because of slave side filtering.
+ */
+ if (!is_empty())
+ {
+ for (uint i= 0; i < array.elements; i++)
+ {
+ Log_event *ev= *(Log_event **) dynamic_array_ptr(&array, i);
+ delete ev;
+ }
+ last_added= NULL;
+ if (array.elements > array.max_element)
+ freeze_size(&array);
+ reset_dynamic(&array);
+ }
+ last_added= NULL;
+}
+
+#endif // defined(HAVE_REPLICATION)
+
diff --git a/sql/scheduler.cc b/sql/scheduler.cc
index 5a20566c89e..7380b134f13 100644
--- a/sql/scheduler.cc
+++ b/sql/scheduler.cc
@@ -24,26 +24,11 @@
#include "mariadb.h"
#include "mysqld.h"
-#include "sql_connect.h" // init_new_connection_handler_thread
#include "scheduler.h"
#include "sql_class.h"
#include "sql_callback.h"
#include <violite.h>
-/*
- End connection, in case when we are using 'no-threads'
-*/
-
-static bool no_threads_end(THD *thd, bool put_in_cache)
-{
- if (thd)
- {
- unlink_thd(thd);
- delete thd;
- }
- return 1; // Abort handle_one_connection
-}
-
/** @internal
Helper functions to allow mysys to call the thread scheduler when
waiting for locks.
@@ -127,22 +112,16 @@ void post_kill_notification(THD *thd)
void one_thread_per_connection_scheduler(scheduler_functions *func,
ulong *arg_max_connections,
- uint *arg_connection_count)
+ Atomic_counter<uint> *arg_connection_count)
{
scheduler_init();
func->max_threads= *arg_max_connections + 1;
func->max_connections= arg_max_connections;
func->connection_count= arg_connection_count;
- func->init_new_connection_thread= init_new_connection_handler_thread;
func->add_connection= create_thread_to_handle_connection;
- func->end_thread= one_thread_per_connection_end;
func->post_kill_notification= post_kill_notification;
}
#else
-bool init_new_connection_handler_thread()
-{
- return 0;
-}
void handle_connection_in_main_thread(CONNECT *connect)
{
}
@@ -158,7 +137,5 @@ void one_thread_scheduler(scheduler_functions *func)
func->max_threads= 1;
func->max_connections= &max_connections;
func->connection_count= &connection_count;
- func->init_new_connection_thread= init_new_connection_handler_thread;
func->add_connection= handle_connection_in_main_thread;
- func->end_thread= no_threads_end;
}
diff --git a/sql/scheduler.h b/sql/scheduler.h
index 42895134c83..ebf8d6e9e64 100644
--- a/sql/scheduler.h
+++ b/sql/scheduler.h
@@ -31,15 +31,14 @@ class THD;
struct scheduler_functions
{
- uint max_threads, *connection_count;
+ uint max_threads;
+ Atomic_counter<uint> *connection_count;
ulong *max_connections;
bool (*init)(void);
- bool (*init_new_connection_thread)(void);
void (*add_connection)(CONNECT *connect);
void (*thd_wait_begin)(THD *thd, int wait_type);
void (*thd_wait_end)(THD *thd);
void (*post_kill_notification)(THD *thd);
- bool (*end_thread)(THD *thd, bool cache_thread);
void (*end)(void);
};
@@ -72,7 +71,7 @@ enum scheduler_types
};
void one_thread_per_connection_scheduler(scheduler_functions *func,
- ulong *arg_max_connections, uint *arg_connection_count);
+ ulong *arg_max_connections, Atomic_counter<uint> *arg_connection_count);
void one_thread_scheduler(scheduler_functions *func);
extern void scheduler_init();
@@ -83,24 +82,13 @@ extern void post_kill_notification(THD *);
struct thd_scheduler
{
public:
- /*
- Thread instrumentation for the user job.
- This member holds the instrumentation while the user job is not run
- by a thread.
-
- Note that this member is not conditionally declared
- (ifdef HAVE_PSI_INTERFACE), because doing so will change the binary
- layout of THD, which is exposed to plugin code that may be compiled
- differently.
- */
- PSI_thread *m_psi;
void *data; /* scheduler-specific data structure */
};
#ifdef HAVE_POOL_OF_THREADS
void pool_of_threads_scheduler(scheduler_functions* func,
ulong *arg_max_connections,
- uint *arg_connection_count);
+ Atomic_counter<uint> *arg_connection_count);
#else
#define pool_of_threads_scheduler(A,B,C) \
one_thread_per_connection_scheduler(A, B, C)
diff --git a/sql/select_handler.cc b/sql/select_handler.cc
index b364cb12341..4d2cacd1a6e 100644
--- a/sql/select_handler.cc
+++ b/sql/select_handler.cc
@@ -77,18 +77,17 @@ bool Pushdown_select::init()
bool Pushdown_select::send_result_set_metadata()
{
- THD *thd= handler->thd;
- Protocol *protocol= thd->protocol;
DBUG_ENTER("Pushdown_select::send_result_set_metadata");
#ifdef WITH_WSREP
+ THD *thd= handler->thd;
if (WSREP(thd) && thd->wsrep_retry_query)
{
WSREP_DEBUG("skipping select metadata");
DBUG_RETURN(false);
}
#endif /* WITH_WSREP */
- if (protocol->send_result_set_metadata(&result_columns,
+ if (select->join->result->send_result_set_metadata(result_columns,
Protocol::SEND_NUM_ROWS |
Protocol::SEND_EOF))
DBUG_RETURN(true);
@@ -99,24 +98,10 @@ bool Pushdown_select::send_result_set_metadata()
bool Pushdown_select::send_data()
{
- THD *thd= handler->thd;
- Protocol *protocol= thd->protocol;
DBUG_ENTER("Pushdown_select::send_data");
- if (thd->killed == ABORT_QUERY)
- DBUG_RETURN(false);
-
- protocol->prepare_for_resend();
- if (protocol->send_result_set_row(&result_columns))
- {
- protocol->remove_last_row();
+ if (select->join->result->send_data(result_columns))
DBUG_RETURN(true);
- }
-
- thd->inc_sent_row_count(1);
-
- if (thd->vio_ok())
- DBUG_RETURN(protocol->write());
DBUG_RETURN(false);
}
@@ -124,16 +109,10 @@ bool Pushdown_select::send_data()
bool Pushdown_select::send_eof()
{
- THD *thd= handler->thd;
DBUG_ENTER("Pushdown_select::send_eof");
- /*
- Don't send EOF if we're in error condition (which implies we've already
- sent or are sending an error)
- */
- if (thd->is_error())
+ if (select->join->result->send_eof())
DBUG_RETURN(true);
- ::my_eof(thd);
DBUG_RETURN(false);
}
diff --git a/sql/semisync_master.cc b/sql/semisync_master.cc
index b239a9776a7..79634d142eb 100644
--- a/sql/semisync_master.cc
+++ b/sql/semisync_master.cc
@@ -724,8 +724,8 @@ int Repl_semi_sync_master::report_binlog_update(THD* thd, const char *log_file,
if (!(log_info= thd->semisync_info))
{
- if(!(log_info=
- (Trans_binlog_info*) my_malloc(sizeof(Trans_binlog_info), MYF(0))))
+ if(!(log_info= (Trans_binlog_info*)my_malloc(PSI_INSTRUMENT_ME,
+ sizeof(Trans_binlog_info), MYF(0))))
return 1;
thd->semisync_info= log_info;
}
diff --git a/sql/semisync_master.h b/sql/semisync_master.h
index 74f6c24c8ea..9f0acf57a60 100644
--- a/sql/semisync_master.h
+++ b/sql/semisync_master.h
@@ -231,7 +231,7 @@ private:
*/
int allocate_block()
{
- Block *block= (Block *)my_malloc(sizeof(Block), MYF(0));
+ Block *block= (Block *)my_malloc(PSI_INSTRUMENT_ME, sizeof(Block), MYF(0));
if (block)
{
block->next= NULL;
diff --git a/sql/semisync_master_ack_receiver.cc b/sql/semisync_master_ack_receiver.cc
index e189fc5f631..6340b4bd661 100644
--- a/sql/semisync_master_ack_receiver.cc
+++ b/sql/semisync_master_ack_receiver.cc
@@ -164,7 +164,7 @@ void Ack_receiver::remove_slave(THD *thd)
inline void Ack_receiver::set_stage_info(const PSI_stage_info &stage)
{
- MYSQL_SET_STAGE(stage.m_key, __FILE__, __LINE__);
+ (void)MYSQL_SET_STAGE(stage.m_key, __FILE__, __LINE__);
}
inline void Ack_receiver::wait_for_slave_connection()
diff --git a/sql/service_wsrep.cc b/sql/service_wsrep.cc
index 6634bfa7e7a..013ec65d3f5 100644
--- a/sql/service_wsrep.cc
+++ b/sql/service_wsrep.cc
@@ -52,13 +52,14 @@ extern "C" const char* wsrep_thd_transaction_state_str(const THD *thd)
return wsrep::to_c_string(thd->wsrep_cs().transaction().state());
}
-
extern "C" const char *wsrep_thd_query(const THD *thd)
{
- if (thd)
+ if (!thd)
+ return "NULL";
+
+ switch(thd->lex->sql_command)
{
- switch(thd->lex->sql_command)
- {
+ // Mask away some security related details from error log
case SQLCOM_CREATE_USER:
return "CREATE USER";
case SQLCOM_GRANT:
@@ -67,12 +68,10 @@ extern "C" const char *wsrep_thd_query(const THD *thd)
return "REVOKE";
case SQLCOM_SET_OPTION:
if (thd->lex->definer)
- return "SET PASSWORD";
+ return "SET PASSWORD";
/* fallthrough */
default:
- if (thd->query())
- return thd->query();
- }
+ return (thd->query() ? thd->query() : "NULL");
}
return "NULL";
}
@@ -282,15 +281,51 @@ extern "C" int wsrep_thd_append_key(THD *thd,
}
ret= client_state.append_key(wsrep_key);
}
+ /*
+ In case of `wsrep_gtid_mode` when WS will be replicated, we need to set
+ `server_id` for events that are going to be written in IO, and in case of
+ manual SET gtid_seq_no=X we are ignoring value.
+ */
+ if (!ret && wsrep_gtid_mode && !thd->slave_thread && !wsrep_thd_is_applying(thd))
+ {
+ thd->variables.server_id= wsrep_gtid_server.server_id;
+ thd->variables.gtid_seq_no= 0;
+ }
return ret;
}
extern "C" void wsrep_commit_ordered(THD *thd)
{
if (wsrep_is_active(thd) &&
- thd->wsrep_trx().state() == wsrep::transaction::s_committing &&
- !wsrep_commit_will_write_binlog(thd))
+ (thd->wsrep_trx().state() == wsrep::transaction::s_committing ||
+ thd->wsrep_trx().state() == wsrep::transaction::s_ordered_commit))
{
- thd->wsrep_cs().ordered_commit();
+ wsrep_gtid_server.signal_waiters(thd->wsrep_current_gtid_seqno, false);
+ if (wsrep_thd_is_local(thd))
+ {
+ thd->wsrep_last_written_gtid_seqno= thd->wsrep_current_gtid_seqno;
+ }
+ if (!wsrep_commit_will_write_binlog(thd))
+ {
+ thd->wsrep_cs().ordered_commit();
+ }
}
}
+
+extern "C" my_bool wsrep_thd_has_ignored_error(const THD *thd)
+{
+ return thd->wsrep_has_ignored_error;
+}
+
+extern "C" void wsrep_thd_set_ignored_error(THD *thd, my_bool val)
+{
+ thd->wsrep_has_ignored_error= val;
+}
+
+extern "C" ulong wsrep_OSU_method_get(const MYSQL_THD thd)
+{
+ if (thd)
+ return(thd->variables.wsrep_OSU_method);
+ else
+ return(global_system_variables.wsrep_OSU_method);
+}
diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc
index e6c380fcb5c..e1c2ec37644 100644
--- a/sql/session_tracker.cc
+++ b/sql/session_tracker.cc
@@ -16,7 +16,6 @@
#include "sql_plugin.h"
-#include "hash.h"
#include "table.h"
#include "rpl_gtid.h"
#include "sql_class.h"
@@ -24,7 +23,7 @@
#include "sql_plugin.h"
#include "set_var.h"
-void State_tracker::mark_as_changed(THD *thd, LEX_CSTRING *tracked_item_name)
+void State_tracker::set_changed(THD *thd)
{
m_changed= true;
thd->lex->safe_to_cache_query= 0;
@@ -73,7 +72,8 @@ void Session_sysvars_tracker::vars_list::copy(vars_list* from, THD *thd)
bool Session_sysvars_tracker::vars_list::insert(const sys_var *svar)
{
sysvar_node_st *node;
- if (!(node= (sysvar_node_st *) my_malloc(sizeof(sysvar_node_st),
+ if (!(node= (sysvar_node_st *) my_malloc(PSI_INSTRUMENT_ME,
+ sizeof(sysvar_node_st),
MYF(MY_WME |
(mysqld_server_initialized ?
MY_THREAD_SPECIFIC : 0)))))
@@ -327,7 +327,8 @@ void Session_sysvars_tracker::init(THD *thd)
global_system_variables.session_track_system_variables);
DBUG_ASSERT(global_system_variables.session_track_system_variables);
thd->variables.session_track_system_variables=
- my_strdup(global_system_variables.session_track_system_variables,
+ my_strdup(PSI_INSTRUMENT_ME,
+ global_system_variables.session_track_system_variables,
MYF(MY_WME | MY_THREAD_SPECIFIC));
}
@@ -384,11 +385,11 @@ bool Session_sysvars_tracker::update(THD *thd, set_var *var)
size_t length= 1;
if (var->save_result.string_value.str)
- copy= my_memdup(var->save_result.string_value.str,
+ copy= my_memdup(PSI_INSTRUMENT_ME, var->save_result.string_value.str,
(length= var->save_result.string_value.length + 1),
MYF(MY_WME | MY_THREAD_SPECIFIC));
else
- copy= my_strdup("", MYF(MY_WME | MY_THREAD_SPECIFIC));
+ copy= my_strdup(PSI_INSTRUMENT_ME, "", MYF(MY_WME | MY_THREAD_SPECIFIC));
if (!copy)
return true;
@@ -506,11 +507,12 @@ bool Session_sysvars_tracker::store(THD *thd, String *buf)
@param [IN] pointer on a variable
*/
-void Session_sysvars_tracker::mark_as_changed(THD *thd,
- LEX_CSTRING *var)
+void Session_sysvars_tracker::mark_as_changed(THD *thd, const sys_var *var)
{
sysvar_node_st *node;
- sys_var *svar= (sys_var *)var;
+
+ if (!is_enabled())
+ return;
if (!m_parsed)
{
@@ -529,10 +531,10 @@ void Session_sysvars_tracker::mark_as_changed(THD *thd,
Check if the specified system variable is being tracked, if so
mark it as changed and also set the class's m_changed flag.
*/
- if (orig_list.is_enabled() && (node= orig_list.insert_or_search(svar)))
+ if (orig_list.is_enabled() && (node= orig_list.insert_or_search(var)))
{
node->m_changed= true;
- State_tracker::mark_as_changed(thd, var);
+ set_changed(thd);
}
}
@@ -679,7 +681,7 @@ bool Transaction_state_tracker::update(THD *thd, set_var *)
}
if (thd->variables.session_track_transaction_info == TX_TRACK_CHISTICS)
tx_changed |= TX_CHG_CHISTICS;
- mark_as_changed(thd, NULL);
+ set_changed(thd);
}
else
m_enabled= false;
@@ -1112,7 +1114,7 @@ void Transaction_state_tracker::set_read_flags(THD *thd,
{
tx_read_flags = flags;
tx_changed |= TX_CHG_CHISTICS;
- mark_as_changed(thd, NULL);
+ set_changed(thd);
}
}
@@ -1131,7 +1133,7 @@ void Transaction_state_tracker::set_isol_level(THD *thd,
{
tx_isol_level = level;
tx_changed |= TX_CHG_CHISTICS;
- mark_as_changed(thd, NULL);
+ set_changed(thd);
}
}
@@ -1181,6 +1183,38 @@ bool Session_state_change_tracker::store(THD *thd, String *buf)
return false;
}
+
+bool User_variables_tracker::update(THD *thd, set_var *)
+{
+ m_enabled= thd->variables.session_track_user_variables;
+ return false;
+}
+
+
+bool User_variables_tracker::store(THD *thd, String *buf)
+{
+ for (ulong i= 0; i < m_changed_user_variables.size(); i++)
+ {
+ auto var= m_changed_user_variables.at(i);
+ String value_str;
+ bool null_value;
+
+ var->val_str(&null_value, &value_str, DECIMAL_MAX_SCALE);
+ buf->q_append(static_cast<char>(SESSION_TRACK_USER_VARIABLES));
+ ulonglong length= net_length_size(var->name.length) + var->name.length;
+ if (!null_value)
+ length+= net_length_size(value_str.length()) + value_str.length();
+ buf->q_net_store_length(length);
+ buf->q_net_store_data(reinterpret_cast<const uchar*>(var->name.str),
+ var->name.length);
+ if (!null_value)
+ buf->q_net_store_data(reinterpret_cast<const uchar*>(value_str.ptr()),
+ value_str.length());
+ }
+ m_changed_user_variables.clear();
+ return false;
+}
+
///////////////////////////////////////////////////////////////////////////////
/**
diff --git a/sql/session_tracker.h b/sql/session_tracker.h
index 226b026d590..7db1feb1b1a 100644
--- a/sql/session_tracker.h
+++ b/sql/session_tracker.h
@@ -19,12 +19,14 @@
#include "m_string.h"
#include "thr_lock.h"
+#include "sql_hset.h"
#ifndef EMBEDDED_LIBRARY
/* forward declarations */
class THD;
class set_var;
class String;
+class user_var_entry;
enum enum_session_tracker
@@ -33,6 +35,7 @@ enum enum_session_tracker
CURRENT_SCHEMA_TRACKER, /* Current schema */
SESSION_STATE_CHANGE_TRACKER,
TRANSACTION_INFO_TRACKER, /* Transaction state */
+ USER_VARIABLES_TRACKER,
SESSION_TRACKER_END /* must be the last */
};
@@ -66,6 +69,8 @@ protected:
*/
bool m_enabled;
+ void set_changed(THD *thd);
+
private:
/** Has the session state type changed ? */
bool m_changed;
@@ -102,7 +107,7 @@ public:
virtual bool store(THD *thd, String *buf)= 0;
/** Mark the entity as changed. */
- virtual void mark_as_changed(THD *thd, LEX_CSTRING *name);
+ void mark_as_changed(THD *thd) { if (is_enabled()) set_changed(thd); }
};
@@ -137,10 +142,9 @@ class Session_sysvars_tracker: public State_tracker
bool track_all;
void init()
{
- my_hash_init(&m_registered_sysvars, &my_charset_bin, 0, 0, 0,
- (my_hash_get_key) sysvars_get_key, my_free,
- HASH_UNIQUE | (mysqld_server_initialized ?
- HASH_THREAD_SPECIFIC : 0));
+ my_hash_init(PSI_INSTRUMENT_ME, &m_registered_sysvars, &my_charset_bin,
+ 0, 0, 0, (my_hash_get_key) sysvars_get_key, my_free,
+ HASH_UNIQUE | (mysqld_server_initialized ? HASH_THREAD_SPECIFIC : 0));
}
void free_hash()
{
@@ -207,7 +211,7 @@ public:
bool enable(THD *thd);
bool update(THD *thd, set_var *var);
bool store(THD *thd, String *buf);
- void mark_as_changed(THD *thd, LEX_CSTRING *tracked_item_name);
+ void mark_as_changed(THD *thd, const sys_var *var);
void deinit() { orig_list.deinit(); }
/* callback */
static uchar *sysvars_get_key(const char *entry, size_t *length,
@@ -376,15 +380,41 @@ private:
tx_changed &= uint(~TX_CHG_STATE);
tx_changed |= (tx_curr_state != tx_reported_state) ? TX_CHG_STATE : 0;
if (tx_changed != TX_CHG_NONE)
- mark_as_changed(thd, NULL);
+ set_changed(thd);
}
};
#define TRANSACT_TRACKER(X) \
do { if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) \
thd->session_tracker.transaction_info.X; } while(0)
-#define SESSION_TRACKER_CHANGED(A,B,C) \
- thd->session_tracker.mark_as_changed(A,B,C)
+
+
+/**
+ User_variables_tracker
+
+ This is a tracker class that enables & manages the tracking of user variables.
+*/
+
+class User_variables_tracker: public State_tracker
+{
+ Hash_set<const user_var_entry> m_changed_user_variables;
+public:
+ User_variables_tracker():
+ m_changed_user_variables(PSI_INSTRUMENT_ME, &my_charset_bin, 0, 0,
+ sizeof(const user_var_entry*), 0, 0, HASH_UNIQUE |
+ mysqld_server_initialized ? HASH_THREAD_SPECIFIC : 0) {}
+ bool update(THD *thd, set_var *var);
+ bool store(THD *thd, String *buf);
+ void mark_as_changed(THD *thd, const user_var_entry *var)
+ {
+ if (is_enabled())
+ {
+ m_changed_user_variables.insert(var);
+ set_changed(thd);
+ }
+ }
+ void deinit() { m_changed_user_variables.~Hash_set(); }
+};
/**
@@ -415,6 +445,7 @@ public:
Session_state_change_tracker state_change;
Transaction_state_tracker transaction_info;
Session_sysvars_tracker sysvars;
+ User_variables_tracker user_variables;
Session_tracker()
{
@@ -422,6 +453,7 @@ public:
m_trackers[CURRENT_SCHEMA_TRACKER]= &current_schema;
m_trackers[SESSION_STATE_CHANGE_TRACKER]= &state_change;
m_trackers[TRANSACTION_INFO_TRACKER]= &transaction_info;
+ m_trackers[USER_VARIABLES_TRACKER]= &user_variables;
}
void enable(THD *thd)
@@ -430,14 +462,6 @@ public:
m_trackers[i]->enable(thd);
}
- inline void mark_as_changed(THD *thd, enum enum_session_tracker tracker,
- LEX_CSTRING *data)
- {
- if (m_trackers[tracker]->is_enabled())
- m_trackers[tracker]->mark_as_changed(thd, data);
- }
-
-
void store(THD *thd, String *main_buf);
};
@@ -446,7 +470,20 @@ int session_tracker_init();
#else
#define TRANSACT_TRACKER(X) do{}while(0)
-#define SESSION_TRACKER_CHANGED(A,B,C) do{}while(0)
+
+class Session_tracker
+{
+ class Dummy_tracker
+ {
+ public:
+ void mark_as_changed(THD *thd) {}
+ void mark_as_changed(THD *thd, const sys_var *var) {}
+ };
+public:
+ Dummy_tracker current_schema;
+ Dummy_tracker state_change;
+ Dummy_tracker sysvars;
+};
#endif //EMBEDDED_LIBRARY
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 812f25949eb..0ace4658be7 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -33,9 +33,8 @@
// date_time_format_make
#include "derror.h"
#include "tztime.h" // my_tz_find, my_tz_SYSTEM, struct Time_zone
-#include "sql_acl.h" // SUPER_ACL
#include "sql_select.h" // free_underlaid_joins
-#include "sql_show.h"
+#include "sql_i_s.h"
#include "sql_view.h" // updatable_views_with_limit_typelib
#include "lock.h" // lock_global_read_lock,
// make_global_read_lock_block_commit,
@@ -43,6 +42,7 @@
static HASH system_variable_hash;
static PolyLock_mutex PLock_global_system_variables(&LOCK_global_system_variables);
+static ulonglong system_variable_hash_version= 0;
/**
Return variable name and length for hashing of variables.
@@ -64,7 +64,7 @@ int sys_var_init()
/* Must be already initialized. */
DBUG_ASSERT(system_charset_info != NULL);
- if (my_hash_init(&system_variable_hash, system_charset_info, 700, 0,
+ if (my_hash_init(PSI_INSTRUMENT_ME, &system_variable_hash, system_charset_info, 700, 0,
0, (my_hash_get_key) get_sys_var_length, 0, HASH_UNIQUE))
goto error;
@@ -154,8 +154,7 @@ sys_var::sys_var(sys_var_chain *chain, const char *name_arg,
next(0), binlog_status(binlog_status_arg), value_origin(COMPILE_TIME),
flags(flags_arg), show_val_type(show_val_type_arg),
guard(lock), offset(off), on_check(on_check_func), on_update(on_update_func),
- deprecation_substitute(substitute),
- is_os_charset(FALSE)
+ deprecation_substitute(substitute)
{
/*
There is a limitation in handle_options() related to short options:
@@ -220,13 +219,12 @@ bool sys_var::update(THD *thd, set_var *var)
*/
if ((var->type == OPT_SESSION) && (!ret))
{
- SESSION_TRACKER_CHANGED(thd, SESSION_SYSVARS_TRACKER,
- (LEX_CSTRING*)var->var);
+ thd->session_tracker.sysvars.mark_as_changed(thd, var->var);
/*
Here MySQL sends variable name to avoid reporting change of
the tracker itself, but we decided that it is not needed
*/
- SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
+ thd->session_tracker.state_change.mark_as_changed(thd);
}
return ret;
@@ -510,12 +508,6 @@ bool throw_bounds_warning(THD *thd, const char *name, bool fixed, double v)
return false;
}
-CHARSET_INFO *sys_var::charset(THD *thd)
-{
- return is_os_charset ? thd->variables.character_set_filesystem :
- system_charset_info;
-}
-
typedef struct old_names_map_st
{
@@ -584,6 +576,8 @@ int mysql_add_sys_var_chain(sys_var *first)
goto error;
}
}
+ /* Update system_variable_hash version. */
+ system_variable_hash_version++;
return 0;
error:
@@ -614,6 +608,8 @@ int mysql_del_sys_var_chain(sys_var *first)
result|= my_hash_delete(&system_variable_hash, (uchar*) var);
mysql_prlock_unlock(&LOCK_system_variables_hash);
+ /* Update system_variable_hash version. */
+ system_variable_hash_version++;
return result;
}
@@ -624,6 +620,16 @@ static int show_cmp(SHOW_VAR *a, SHOW_VAR *b)
}
+/*
+ Number of records in the system_variable_hash.
+ Requires lock on LOCK_system_variables_hash.
+*/
+ulong get_system_variable_hash_records(void)
+{
+ return system_variable_hash.records;
+}
+
+
/**
Constructs an array of system variables for display to the user.
@@ -750,6 +756,11 @@ err:
Functions to handle SET mysql_internal_variable=const_expr
*****************************************************************************/
+bool sys_var::on_check_access_global(THD *thd) const
+{
+ return check_global_access(thd, PRIV_SET_GLOBAL_SYSTEM_VARIABLE);
+}
+
/**
Verify that the supplied value is correct.
@@ -774,7 +785,7 @@ int set_var::check(THD *thd)
my_error(err, MYF(0), var->name.str);
return -1;
}
- if ((type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL)))
+ if (type == OPT_GLOBAL && var->on_check_access_global(thd))
return 1;
/* value is a NULL pointer if we are using SET ... = DEFAULT */
if (!value)
@@ -787,6 +798,16 @@ int set_var::check(THD *thd)
my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), var->name.str);
return -1;
}
+ switch (type) {
+ case SHOW_OPT_DEFAULT:
+ case SHOW_OPT_SESSION:
+ DBUG_ASSERT(var->scope() != sys_var::GLOBAL);
+ if (var->on_check_access_session(thd))
+ return -1;
+ break;
+ case SHOW_OPT_GLOBAL: // Checked earlier
+ break;
+ }
return var->check(thd, this) ? -1 : 0;
}
@@ -811,7 +832,8 @@ int set_var::light_check(THD *thd)
my_error(err, MYF(0), var->name.str);
return -1;
}
- if (type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL))
+ if (type == OPT_GLOBAL &&
+ check_global_access(thd, PRIV_SET_GLOBAL_SYSTEM_VARIABLE))
return 1;
if (value && value->fix_fields_if_needed_for_scalar(thd, &value))
@@ -907,7 +929,7 @@ int set_var_user::update(THD *thd)
return -1;
}
- SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
+ thd->session_tracker.state_change.mark_as_changed(thd);
return 0;
}
@@ -957,8 +979,7 @@ int set_var_role::update(THD *thd)
#ifndef NO_EMBEDDED_ACCESS_CHECKS
int res= acl_setrole(thd, role.str, access);
if (!res)
- thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER,
- NULL);
+ thd->session_tracker.state_change.mark_as_changed(thd);
return res;
#else
return 0;
@@ -1015,18 +1036,13 @@ int set_var_collation_client::update(THD *thd)
character_set_results);
/* Mark client collation variables as changed */
-#ifndef EMBEDDED_LIBRARY
- if (thd->session_tracker.sysvars.is_enabled())
- {
- thd->session_tracker.sysvars.
- mark_as_changed(thd, (LEX_CSTRING*)Sys_character_set_client_ptr);
- thd->session_tracker.sysvars.
- mark_as_changed(thd, (LEX_CSTRING*)Sys_character_set_results_ptr);
- thd->session_tracker.sysvars.
- mark_as_changed(thd, (LEX_CSTRING*)Sys_character_set_connection_ptr);
- }
- thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
-#endif //EMBEDDED_LIBRARY
+ thd->session_tracker.sysvars.mark_as_changed(thd,
+ Sys_character_set_client_ptr);
+ thd->session_tracker.sysvars.mark_as_changed(thd,
+ Sys_character_set_results_ptr);
+ thd->session_tracker.sysvars.mark_as_changed(thd,
+ Sys_character_set_connection_ptr);
+ thd->session_tracker.state_change.mark_as_changed(thd);
thd->protocol_text.init(thd);
thd->protocol_binary.init(thd);
@@ -1064,6 +1080,7 @@ int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond)
StringBuffer<STRING_BUFFER_USUAL_SIZE> strbuf(scs);
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : 0;
Field **fields=tables->table->field;
+ bool has_file_acl= !check_access(thd, FILE_ACL, any_db, NULL, NULL, 0, 1);
DBUG_ASSERT(tables->table->in_use == thd);
@@ -1098,6 +1115,7 @@ int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond)
static const LEX_CSTRING origins[]=
{
{ STRING_WITH_LEN("CONFIG") },
+ { STRING_WITH_LEN("COMMAND-LINE") },
{ STRING_WITH_LEN("AUTO") },
{ STRING_WITH_LEN("SQL") },
{ STRING_WITH_LEN("COMPILE-TIME") },
@@ -1226,6 +1244,14 @@ int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond)
fields[13]->store(arg->str, arg->length, scs);
}
+ // GLOBAL_VALUE_PATH
+ if (var->value_origin == sys_var::CONFIG && has_file_acl)
+ {
+ fields[14]->set_notnull();
+ fields[14]->store(var->origin_filename, strlen(var->origin_filename),
+ files_charset_info);
+ }
+
if (schema_table_store_record(thd, tables->table))
goto end;
thd->get_stmt_da()->inc_current_row_for_warning();
@@ -1374,7 +1400,7 @@ resolve_engine_list(THD *thd, const char *str_arg, size_t str_arg_len,
if (temp_copy)
res= (plugin_ref *)thd->calloc((count+1)*sizeof(*res));
else
- res= (plugin_ref *)my_malloc((count+1)*sizeof(*res), MYF(MY_ZEROFILL|MY_WME));
+ res= (plugin_ref *)my_malloc(PSI_INSTRUMENT_ME, (count+1)*sizeof(*res), MYF(MY_ZEROFILL|MY_WME));
if (!res)
{
my_error(ER_OUTOFMEMORY, MYF(0), (int)((count+1)*sizeof(*res)));
@@ -1425,7 +1451,7 @@ copy_engine_list(plugin_ref *list)
for (p= list, count= 0; *p; ++p, ++count)
;
- p= (plugin_ref *)my_malloc((count+1)*sizeof(*p), MYF(0));
+ p= (plugin_ref *)my_malloc(PSI_INSTRUMENT_ME, (count+1)*sizeof(*p), MYF(0));
if (!p)
{
my_error(ER_OUTOFMEMORY, MYF(0), (int)((count+1)*sizeof(*p)));
@@ -1500,3 +1526,13 @@ pretty_print_engine_list(THD *thd, plugin_ref *list)
*pos= '\0';
return buf;
}
+
+/*
+ Current version of the system_variable_hash.
+ Requires lock on LOCK_system_variables_hash.
+*/
+ulonglong get_system_variable_hash_version(void)
+{
+ return system_variable_hash_version;
+}
+
diff --git a/sql/set_var.h b/sql/set_var.h
index 31ff0493942..41a0010acf2 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -66,7 +66,7 @@ public:
READONLY=1024, ALLOCATED=2048, PARSE_EARLY=4096,
NO_SET_STATEMENT=8192, AUTO_SET=16384};
enum { NO_GETOPT=-1, GETOPT_ONLY_HELP=-2 };
- enum where { CONFIG, AUTO, SQL, COMPILE_TIME, ENV };
+ enum where { CONFIG, COMMAND_LINE, AUTO, SQL, COMPILE_TIME, ENV };
/**
Enumeration type to indicate for a system variable whether
@@ -77,6 +77,7 @@ public:
my_option option; ///< min, max, default values are stored here
enum where value_origin;
+ const char *origin_filename;
protected:
typedef bool (*on_check_function)(sys_var *self, THD *thd, set_var *var);
@@ -89,7 +90,6 @@ protected:
on_check_function on_check;
on_update_function on_update;
const char *const deprecation_substitute;
- bool is_os_charset; ///< true if the value is in character_set_filesystem
public:
sys_var(sys_var_chain *chain, const char *name_arg, const char *comment,
@@ -129,7 +129,10 @@ public:
SHOW_TYPE show_type() { return show_val_type; }
int scope() const { return flags & SCOPE_MASK; }
- CHARSET_INFO *charset(THD *thd);
+ virtual CHARSET_INFO *charset(THD *thd) const
+ {
+ return system_charset_info;
+ }
bool is_readonly() const { return flags & READONLY; }
/**
the following is only true for keycache variables,
@@ -211,6 +214,12 @@ public:
virtual uchar *default_value_ptr(THD *thd)
{ return (uchar*)&option.def_value; }
+ virtual bool on_check_access_global(THD *thd) const;
+ virtual bool on_check_access_session(THD *thd) const
+ {
+ return false;
+ }
+
private:
virtual bool do_check(THD *thd, set_var *var) = 0;
/**
@@ -348,9 +357,9 @@ public:
class set_var_role: public set_var_base
{
LEX_CSTRING role;
- ulonglong access;
+ privilege_t access;
public:
- set_var_role(LEX_CSTRING role_arg) : role(role_arg) {}
+ set_var_role(LEX_CSTRING role_arg) : role(role_arg), access(NO_ACL) {}
int check(THD *thd);
int update(THD *thd);
};
@@ -403,6 +412,8 @@ extern SHOW_COMP_OPTION have_openssl;
/*
Prototypes for helper functions
*/
+ulong get_system_variable_hash_records(void);
+ulonglong get_system_variable_hash_version(void);
SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted, enum enum_var_type type);
int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond);
@@ -442,7 +453,7 @@ sql_mode_t expand_sql_mode(sql_mode_t sql_mode);
const char *sql_mode_string_representation(uint bit_number);
bool sql_mode_string_representation(THD *thd, sql_mode_t sql_mode,
LEX_CSTRING *ls);
-int default_regex_flags_pcre(const THD *thd);
+int default_regex_flags_pcre(THD *thd);
extern sys_var *Sys_autocommit_ptr, *Sys_last_gtid_ptr,
*Sys_character_set_client_ptr, *Sys_character_set_connection_ptr,
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index cc635e44f7b..afa9d72f2d8 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -3186,13 +3186,13 @@ ER_INVALID_USE_OF_NULL 22004
swe "Felaktig använding av NULL"
ukr "Хибне використання значення NULL"
ER_REGEXP_ERROR 42000
- cze "Regulární výraz vrátil chybu '%-.64s'"
+ cze "Regulární výraz vrátil chybu: %s"
dan "Fik fejl '%-.64s' fra regexp"
nla "Fout '%-.64s' ontvangen van regexp"
- eng "Got error '%-.64s' from regexp"
- est "regexp tagastas vea '%-.64s'"
+ eng "Regex error '%s'"
+ est "regexp tagastas vea: %s"
fre "Erreur '%-.64s' provenant de regexp"
- ger "regexp lieferte Fehler '%-.64s'"
+ ger "Regexp Fehler %s"
hindi "regexp में '%-.64s' त्रुटि हुई"
hun "'%-.64s' hiba a regularis kifejezes hasznalata soran (regexp)"
ita "Errore '%-.64s' da regexp"
@@ -3200,11 +3200,11 @@ ER_REGEXP_ERROR 42000
kor "regexp에서 '%-.64s'가 났습니다."
por "Obteve erro '%-.64s' em regexp"
rum "Eroarea '%-.64s' obtinuta din expresia regulara (regexp)"
- rus "Получена ошибка '%-.64s' от регулярного выражения"
- serbian "Funkcija regexp je vratila grešku '%-.64s'"
+ rus "Ошибка регулярного выражения: %s"
+ serbian "Funkcija regexp je vratila grešku: %s"
spa "Obtenido error '%-.64s' de regexp"
swe "Fick fel '%-.64s' från REGEXP"
- ukr "Отримано помилку '%-.64s' від регулярного виразу"
+ ukr "Помилка регулярного виразу: %s"
ER_MIX_OF_GROUP_FUNC_AND_FIELDS 42000
cze "Pokud není žádná GROUP BY klauzule, není dovoleno současné použití GROUP položek (MIN(),MAX(),COUNT()...) s ne GROUP položkami"
dan "Sammenblanding af GROUP kolonner (MIN(),MAX(),COUNT()...) uden GROUP kolonner er ikke tilladt, hvis der ikke er noget GROUP BY prædikat"
@@ -7817,7 +7817,7 @@ ER_PARTITION_WRONG_TYPE
eng "Wrong partitioning type, expected type: %`s"
WARN_VERS_PART_FULL
- eng "Versioned table %`s.%`s: partition %`s is full, add more HISTORY partitions"
+ eng "Versioned table %`s.%`s: last HISTORY partition (%`s) is out of %s, need more HISTORY partitions"
WARN_VERS_PARAMETERS
eng "Maybe missing parameters: %s"
@@ -7933,3 +7933,20 @@ ER_PERIOD_CONSTRAINT_DROP
eng "Can't DROP CONSTRAINT `%s`. Use DROP PERIOD `%s` for this"
ER_TOO_LONG_KEYPART 42000 S1009
eng "Specified key part was too long; max key part length is %u bytes"
+ER_TOO_LONG_DATABASE_COMMENT
+ eng "Comment for database '%-.64s' is too long (max = %u)"
+ER_UNKNOWN_DATA_TYPE
+ eng "Unknown data type: '%-.64s'"
+ER_UNKNOWN_OPERATOR
+ eng "Operator does not exists: '%-.128s'"
+ER_WARN_HISTORY_ROW_START_TIME
+ eng "Table `%s.%s` history row start '%s' is later than row end '%s'"
+ER_PART_STARTS_BEYOND_INTERVAL
+ eng "%`s: STARTS is later than query time, first history partition may exceed INTERVAL value"
+ER_GALERA_REPLICATION_NOT_SUPPORTED
+ eng "DDL-statement is forbidden as table storage engine does not support Galera replication"
+ER_LOAD_INFILE_CAPABILITY_DISABLED
+ eng "The used command is not allowed because the MariaDB server or client has disabled the local infile capability"
+ rum "Comanda folosită nu este permisă deoarece clientul sau serverul MariaDB a dezactivat această capabilitate"
+ER_NO_SECURE_TRANSPORTS_CONFIGURED
+ eng "No secure transports are configured, unable to set --require_secure_transport=ON"
diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc
index 51b9d7a2c51..cbf58bb6e57 100644
--- a/sql/signal_handler.cc
+++ b/sql/signal_handler.cc
@@ -42,9 +42,6 @@
static volatile sig_atomic_t segfaulted= 0;
extern ulong max_used_connections;
extern volatile sig_atomic_t calling_initgroups;
-#ifdef HAVE_NPTL
-extern volatile sig_atomic_t ld_assume_kernel_is_set;
-#endif
extern const char *optimizer_switch_names[];
@@ -296,21 +293,6 @@ extern "C" sig_handler handle_fatal_signal(int sig)
}
#endif
-#ifdef HAVE_NPTL
- if (thd_lib_detected == THD_LIB_LT && !ld_assume_kernel_is_set)
- {
- my_safe_printf_stderr("%s",
- "You are running a statically-linked LinuxThreads binary on an NPTL\n"
- "system. This can result in crashes on some distributions due to "
- "LT/NPTL conflicts.\n"
- "You should either build a dynamically-linked binary, "
- "or force LinuxThreads\n"
- "to be used with the LD_ASSUME_KERNEL environment variable.\n"
- "Please consult the documentation for your distribution "
- "on how to do that.\n");
- }
-#endif
-
if (locked_in_memory)
{
my_safe_printf_stderr("%s", "\n"
diff --git a/sql/slave.cc b/sql/slave.cc
index 714e47424fe..e9af0f75186 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
- Copyright (c) 2009, 2017, MariaDB Corporation
+ Copyright (c) 2009, 2020, 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
@@ -57,6 +57,9 @@
#include "wsrep_trans_observer.h"
#endif
+class Master_info_index;
+Master_info_index *master_info_index;
+
#ifdef HAVE_REPLICATION
#include "rpl_tblmap.h"
@@ -81,7 +84,6 @@ char slave_transaction_retry_error_names[SHOW_VAR_FUNC_BUFF_SIZE];
char* slave_load_tmpdir = 0;
Master_info *active_mi= 0;
-Master_info_index *master_info_index;
my_bool replicate_same_server_id;
ulonglong relay_log_space_limit = 0;
ulonglong opt_read_binlog_speed_limit = 0;
@@ -488,6 +490,7 @@ handle_slave_background(void *arg __attribute__((unused)))
#ifdef WITH_WSREP
thd->variables.wsrep_on= 0;
#endif
+ thd->set_psi(PSI_CALL_get_thread());
thd_proc_info(thd, "Loading slave GTID position from table");
if (rpl_load_gtid_slave_state(thd))
@@ -583,7 +586,7 @@ slave_background_kill_request(THD *to_kill)
if (to_kill->rgi_slave->killed_for_retry)
return; // Already deadlock killed.
slave_background_kill_t *p=
- (slave_background_kill_t *)my_malloc(sizeof(*p), MYF(MY_WME));
+ (slave_background_kill_t *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*p), MYF(MY_WME));
if (p)
{
p->to_kill= to_kill;
@@ -611,7 +614,7 @@ slave_background_gtid_pos_create_request(
if (table_entry->state != rpl_slave_state::GTID_POS_AUTO_CREATE)
return;
- p= (slave_background_gtid_pos_create_t *)my_malloc(sizeof(*p), MYF(MY_WME));
+ p= (slave_background_gtid_pos_create_t *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*p), MYF(MY_WME));
if (!p)
return;
mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state);
@@ -934,7 +937,7 @@ bool init_slave_skip_errors(const char* arg)
use_slave_mask= 1;
for (;my_isspace(system_charset_info,*arg);++arg)
/* empty */;
- if (!my_strnncoll(system_charset_info,(uchar*)arg,4,(const uchar*)"all",4))
+ if (!system_charset_info->strnncoll((uchar*)arg,4,(const uchar*)"all",4))
{
bitmap_set_all(&slave_error_mask);
goto end;
@@ -1652,6 +1655,40 @@ const char *print_slave_db_safe(const char* db)
#endif /* HAVE_REPLICATION */
+bool Sql_cmd_show_slave_status::execute(THD *thd)
+{
+#ifndef HAVE_REPLICATION
+ my_ok(thd);
+ return false;
+#else
+ DBUG_ENTER("Sql_cmd_show_slave_status::execute");
+ bool res= true;
+
+ /* Accept one of two privileges */
+ if (check_global_access(thd, PRIV_STMT_SHOW_SLAVE_STATUS))
+ goto error;
+ if (is_show_all_slaves_stat())
+ {
+ mysql_mutex_lock(&LOCK_active_mi);
+ res= show_all_master_info(thd);
+ mysql_mutex_unlock(&LOCK_active_mi);
+ }
+ else
+ {
+ LEX_MASTER_INFO *lex_mi= &thd->lex->mi;
+ Master_info *mi;
+ if ((mi= get_master_info(&lex_mi->connection_name,
+ Sql_condition::WARN_LEVEL_ERROR)))
+ {
+ res= show_master_info(thd, mi, 0);
+ mi->release();
+ }
+ }
+error:
+ DBUG_RETURN(res);
+#endif
+}
+
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
const char *default_val)
{
@@ -1775,7 +1812,8 @@ int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f)
(decimal size + space) - 1 + `\n' + '\0'
*/
size_t max_size= (1 + num_items) * (sizeof(long)*3 + 1) + 1;
- buf_act= (char*) my_malloc(max_size, MYF(MY_WME));
+ buf_act= (char*) my_malloc(key_memory_Rpl_info_file_buffer, max_size,
+ MYF(MY_WME));
memcpy(buf_act, buf, read_size);
snd_size= my_b_gets(f, buf_act + read_size, max_size - read_size);
if (snd_size == 0 ||
@@ -4203,7 +4241,7 @@ inline void update_state_of_relay_log(Relay_log_info *rli, Log_event *ev)
rli->clear_flag(Relay_log_info::IN_TRANSACTION);
}
}
- if (typ == XID_EVENT)
+ if (typ == XID_EVENT || typ == XA_PREPARE_LOG_EVENT)
rli->clear_flag(Relay_log_info::IN_TRANSACTION);
if (typ == GTID_EVENT &&
!(((Gtid_log_event*) ev)->flags2 & Gtid_log_event::FL_STANDALONE))
@@ -4700,6 +4738,8 @@ pthread_handler_t handle_slave_io(void *arg)
THD_CHECK_SENTRY(thd);
mi->io_thd = thd;
+ thd->set_psi(PSI_CALL_get_thread());
+
pthread_detach_this_thread();
thd->thread_stack= (char*) &thd; // remember where our stack is
mi->clear_error();
@@ -5338,6 +5378,8 @@ pthread_handler_t handle_slave_sql(void *arg)
executing SQL queries too.
*/
serial_rgi->thd= rli->sql_driver_thd= thd;
+
+ thd->set_psi(PSI_CALL_get_thread());
/* Inform waiting threads that slave has started */
rli->slave_run_id++;
@@ -6008,7 +6050,8 @@ static int queue_binlog_ver_1_event(Master_info *mi, const char *buf,
*/
if ((uchar)buf[EVENT_TYPE_OFFSET] == LOAD_EVENT)
{
- if (unlikely(!(tmp_buf=(char*)my_malloc(event_len+1,MYF(MY_WME)))))
+ if (unlikely(!(tmp_buf=(char*)my_malloc(key_memory_binlog_ver_1_event,
+ event_len+1,MYF(MY_WME)))))
{
mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, NULL,
ER(ER_SLAVE_FATAL_ERROR), "Memory allocation failed");
@@ -7068,6 +7111,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
buf[EVENT_TYPE_OFFSET])) ||
(!mi->last_queued_gtid_standalone &&
((uchar)buf[EVENT_TYPE_OFFSET] == XID_EVENT ||
+ (uchar)buf[EVENT_TYPE_OFFSET] == XA_PREPARE_LOG_EVENT ||
((uchar)buf[EVENT_TYPE_OFFSET] == QUERY_EVENT && /* QUERY_COMPRESSED_EVENT would never be commmit or rollback */
Query_log_event::peek_is_commit_rollback(buf, event_len,
checksum_alg))))))
diff --git a/sql/sp.cc b/sql/sp.cc
index e8611159df0..51bbeeef368 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2002, 2018, Oracle and/or its affiliates.
- Copyright (c) 2009, 2018, MariaDB
+ Copyright (c) 2009, 2020, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -28,12 +28,12 @@
// mysql_change_db, check_db_dir_existence,
// load_db_opt_by_name
#include "sql_table.h" // write_bin_log
-#include "sql_acl.h" // SUPER_ACL
#include "sp_head.h"
#include "sp_cache.h"
#include "lock.h" // lock_object_name
#include <my_user.h>
+#include "mysql/psi/mysql_sp.h"
sp_cache **Sp_handler_procedure::get_cache(THD *thd) const
{
@@ -683,7 +683,7 @@ Sp_handler::db_find_routine(THD *thd,
longlong modified;
Sp_chistics chistics;
bool saved_time_zone_used= thd->time_zone_used;
- sql_mode_t sql_mode, saved_mode= thd->variables.sql_mode;
+ sql_mode_t sql_mode;
Open_tables_backup open_tables_state_backup;
Stored_program_creation_ctx *creation_ctx;
AUTHID definer;
@@ -698,7 +698,7 @@ Sp_handler::db_find_routine(THD *thd,
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
/* Reset sql_mode during data dictionary operations. */
- thd->variables.sql_mode= 0;
+ Sql_mode_instant_set sms(thd, 0);
if ((ret= db_find_routine_aux(thd, name, table)) != SP_OK)
goto done;
@@ -718,7 +718,7 @@ Sp_handler::db_find_routine(THD *thd,
table->field[MYSQL_PROC_FIELD_PARAM_LIST]->val_str_nopad(thd->mem_root,
&params);
- if (type() != TYPE_ENUM_FUNCTION)
+ if (type() != SP_TYPE_FUNCTION)
returns= empty_clex_str;
else if (table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root,
&returns))
@@ -755,7 +755,6 @@ Sp_handler::db_find_routine(THD *thd,
thd->time_zone_used= saved_time_zone_used;
if (table)
close_system_tables(thd, &open_tables_state_backup);
- thd->variables.sql_mode= saved_mode;
DBUG_RETURN(ret);
}
@@ -867,6 +866,8 @@ static sp_head *sp_compile(THD *thd, String *defstr, sql_mode_t sql_mode,
thd->spcont= old_spcont;
thd->variables.sql_mode= old_sql_mode;
thd->variables.select_limit= old_select_limit;
+ if (sp != NULL)
+ sp->init_psi_share();
return sp;
}
@@ -1002,7 +1003,7 @@ Sp_handler::db_load_routine(THD *thd, const Database_qualified_name *name,
(*sphp)->set_creation_ctx(creation_ctx);
(*sphp)->optimize();
- if (type() == TYPE_ENUM_PACKAGE_BODY)
+ if (type() == SP_TYPE_PACKAGE_BODY)
{
sp_package *package= (*sphp)->get_package();
List_iterator<LEX> it(package->m_routine_implementations);
@@ -1105,6 +1106,9 @@ Sp_handler::sp_drop_routine_internal(THD *thd,
DBUG_ASSERT(spc);
if ((sp= sp_cache_lookup(spc, name)))
sp_cache_flush_obsolete(spc, &sp);
+ /* Drop statistics for this stored program from performance schema. */
+ MYSQL_DROP_SP(type(), name->m_db.str, static_cast<uint>(name->m_db.length),
+ name->m_name.str, static_cast<uint>(name->m_name.length));
DBUG_RETURN(SP_OK);
}
@@ -1232,17 +1236,17 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const
if (lex->create_info.or_replace())
{
switch (type()) {
- case TYPE_ENUM_PACKAGE:
+ case SP_TYPE_PACKAGE:
// Drop together with its PACKAGE BODY mysql.proc record
ret= sp_handler_package_spec.sp_find_and_drop_routine(thd, table, sp);
break;
- case TYPE_ENUM_PACKAGE_BODY:
- case TYPE_ENUM_FUNCTION:
- case TYPE_ENUM_PROCEDURE:
+ case SP_TYPE_PACKAGE_BODY:
+ case SP_TYPE_FUNCTION:
+ case SP_TYPE_PROCEDURE:
ret= sp_drop_routine_internal(thd, sp, table);
break;
- case TYPE_ENUM_TRIGGER:
- case TYPE_ENUM_PROXY:
+ case SP_TYPE_TRIGGER:
+ case SP_TYPE_EVENT:
DBUG_ASSERT(0);
ret= SP_OK;
}
@@ -1259,7 +1263,7 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const
ret= FALSE;
// Setting retstr as it is used for logging.
- if (type() == TYPE_ENUM_FUNCTION)
+ if (type() == SP_TYPE_FUNCTION)
{
sp_returns_type(thd, retstr, sp);
returns= retstr.lex_cstring();
@@ -1284,9 +1288,8 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const
goto done;
}
- if (system_charset_info->cset->numchars(system_charset_info,
- sp->m_name.str,
- sp->m_name.str+sp->m_name.length) >
+ if (system_charset_info->numchars(sp->m_name.str,
+ sp->m_name.str + sp->m_name.length) >
table->field[MYSQL_PROC_FIELD_NAME]->char_length())
{
my_error(ER_TOO_LONG_IDENT, MYF(0), sp->m_name.str);
@@ -1343,7 +1346,7 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const
table->field[MYSQL_PROC_FIELD_PARAM_LIST]->
store(sp->m_params, system_charset_info);
- if (type() == TYPE_ENUM_FUNCTION)
+ if (type() == SP_TYPE_FUNCTION)
{
sp_returns_type(thd, retstr, sp);
returns= retstr.lex_cstring();
@@ -1361,8 +1364,8 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const
table->field[MYSQL_PROC_FIELD_DEFINER]->
store(definer, system_charset_info);
- ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_CREATED])->set_time();
- ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_MODIFIED])->set_time();
+ table->field[MYSQL_PROC_FIELD_CREATED]->set_time();
+ table->field[MYSQL_PROC_FIELD_MODIFIED]->set_time();
store_failed= store_failed ||
table->field[MYSQL_PROC_FIELD_SQL_MODE]->
@@ -1375,7 +1378,7 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const
store(sp->comment(), system_charset_info);
}
- if (type() == TYPE_ENUM_FUNCTION &&
+ if (type() == SP_TYPE_FUNCTION &&
!trust_function_creators && mysql_bin_log.is_open())
{
if (!sp->detistic())
@@ -1394,7 +1397,7 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const
goto done;
}
}
- if (!(thd->security_ctx->master_access & SUPER_ACL))
+ if (!(thd->security_ctx->master_access & PRIV_LOG_BIN_TRUSTED_SP_CREATOR))
{
my_error(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER,MYF(0));
goto done;
@@ -1524,8 +1527,7 @@ Sp_handler_package::show_create_sp(THD *thd, String *buf,
const DDL_options_st ddl_options,
sql_mode_t sql_mode) const
{
- sql_mode_t old_sql_mode= thd->variables.sql_mode;
- thd->variables.sql_mode= sql_mode;
+ Sql_mode_instant_set sms(thd, sql_mode);
bool rc=
buf->append(STRING_WITH_LEN("CREATE ")) ||
(ddl_options.or_replace() &&
@@ -1542,7 +1544,6 @@ Sp_handler_package::show_create_sp(THD *thd, String *buf,
append_package_chistics(buf, chistics) ||
buf->append(" ", 1) ||
buf->append(body.str, body.length);
- thd->variables.sql_mode= old_sql_mode;
return rc;
}
@@ -1629,7 +1630,7 @@ Sp_handler::sp_update_routine(THD *thd, const Database_qualified_name *name,
if ((ret= db_find_routine_aux(thd, name, table)) == SP_OK)
{
- if (type() == TYPE_ENUM_FUNCTION && ! trust_function_creators &&
+ if (type() == SP_TYPE_FUNCTION && ! trust_function_creators &&
mysql_bin_log.is_open() &&
(chistics->daccess == SP_CONTAINS_SQL ||
chistics->daccess == SP_MODIFIES_SQL_DATA))
@@ -1654,7 +1655,7 @@ Sp_handler::sp_update_routine(THD *thd, const Database_qualified_name *name,
}
store_record(table,record[1]);
- ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_MODIFIED])->set_time();
+ table->field[MYSQL_PROC_FIELD_MODIFIED]->set_time();
if (chistics->suid != SP_IS_DEFAULT_SUID)
table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]->
store((longlong)chistics->suid, TRUE);
@@ -1775,11 +1776,11 @@ bool lock_db_routines(THD *thd, const char *db)
longlong sp_type= table->field[MYSQL_PROC_MYSQL_TYPE]->val_int();
MDL_request *mdl_request= new (thd->mem_root) MDL_request;
- const Sp_handler *sph= Sp_handler::handler((stored_procedure_type)
+ const Sp_handler *sph= Sp_handler::handler((enum_sp_type)
sp_type);
if (!sph)
sph= &sp_handler_procedure;
- mdl_request->init(sph->get_mdl_type(), db, sp_name,
+ MDL_REQUEST_INIT(mdl_request, sph->get_mdl_type(), db, sp_name,
MDL_EXCLUSIVE, MDL_TRANSACTION);
mdl_requests.push_front(mdl_request);
} while (! (nxtres= table->file->ha_index_next_same(table->record[0], keybuf, key_len)));
@@ -1818,6 +1819,8 @@ sp_drop_db_routines(THD *thd, const char *db)
uint key_len;
MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
uchar keybuf[MAX_KEY_LENGTH];
+ size_t db_length= strlen(db);
+ Sql_mode_instant_remove smir(thd, MODE_PAD_CHAR_TO_FULL_LENGTH); // see below
DBUG_ENTER("sp_drop_db_routines");
DBUG_PRINT("enter", ("db: %s", db));
@@ -1825,7 +1828,7 @@ sp_drop_db_routines(THD *thd, const char *db)
if (!(table= open_proc_table_for_update(thd)))
goto err;
- table->field[MYSQL_PROC_FIELD_DB]->store(db, strlen(db), system_charset_info);
+ table->field[MYSQL_PROC_FIELD_DB]->store(db, db_length, system_charset_info);
key_len= table->key_info->key_part[0].store_length;
table->field[MYSQL_PROC_FIELD_DB]->get_key_image(keybuf, key_len, Field::itRAW);
@@ -1844,7 +1847,18 @@ sp_drop_db_routines(THD *thd, const char *db)
do
{
if (! table->file->ha_delete_row(table->record[0]))
+ {
deleted= TRUE; /* We deleted something */
+#ifdef HAVE_PSI_SP_INTERFACE
+ String buf;
+ // the following assumes MODE_PAD_CHAR_TO_FULL_LENGTH being *unset*
+ String *name= table->field[MYSQL_PROC_FIELD_NAME]->val_str(&buf);
+
+ enum_sp_type sp_type= (enum_sp_type) table->field[MYSQL_PROC_MYSQL_TYPE]->ptr[0];
+ /* Drop statistics for this stored program from performance schema. */
+ MYSQL_DROP_SP(sp_type, db, static_cast<uint>(db_length), name->ptr(), name->length());
+#endif
+ }
else
{
ret= SP_DELETE_ROW_FAILED;
@@ -2018,7 +2032,7 @@ Sp_handler::sp_clone_and_link_routine(THD *thd,
DBUG_RETURN(0);
}
- if (type() == TYPE_ENUM_FUNCTION)
+ if (type() == SP_TYPE_FUNCTION)
{
sp_returns_type(thd, retstr, sp);
returns= retstr.lex_cstring();
@@ -2286,7 +2300,7 @@ bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
const Sp_handler *handler,
TABLE_LIST *belong_to_view)
{
- my_hash_init_opt(&prelocking_ctx->sroutines, system_charset_info,
+ my_hash_init_opt(PSI_INSTRUMENT_ME, &prelocking_ctx->sroutines, system_charset_info,
Query_tables_list::START_SROUTINES_HASH_SIZE,
0, 0, sp_sroutine_key, 0, 0);
@@ -2296,7 +2310,7 @@ bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
(Sroutine_hash_entry *)arena->alloc(sizeof(Sroutine_hash_entry));
if (unlikely(!rn)) // OOM. Error will be reported using fatal_error().
return FALSE;
- rn->mdl_request.init(key, MDL_SHARED, MDL_TRANSACTION);
+ MDL_REQUEST_INIT_BY_KEY(&rn->mdl_request, key, MDL_SHARED, MDL_TRANSACTION);
if (my_hash_insert(&prelocking_ctx->sroutines, (uchar *)rn))
return FALSE;
prelocking_ctx->sroutines_list.link_in_list(rn, &rn->next);
@@ -2366,7 +2380,7 @@ is_package_public_routine(THD *thd,
const LEX_CSTRING &db,
const LEX_CSTRING &package,
const LEX_CSTRING &routine,
- stored_procedure_type type)
+ enum_sp_type type)
{
sp_head *sp= NULL;
Database_qualified_name tmp(db, package);
@@ -2400,7 +2414,7 @@ is_package_public_routine_quick(THD *thd,
const LEX_CSTRING &db,
const LEX_CSTRING &pkgname,
const LEX_CSTRING &name,
- stored_procedure_type type)
+ enum_sp_type type)
{
Database_qualified_name tmp(db, pkgname);
sp_head *sp= sp_cache_lookup(&thd->sp_package_spec_cache, &tmp);
@@ -2419,7 +2433,7 @@ static bool
is_package_body_routine(THD *thd, sp_package *pkg,
const LEX_CSTRING &name1,
const LEX_CSTRING &name2,
- stored_procedure_type type)
+ enum_sp_type type)
{
return Sp_handler::eq_routine_name(pkg->m_name, name1) &&
(pkg->m_routine_declarations.find(name2, type) ||
@@ -2761,7 +2775,7 @@ int Sroutine_hash_entry::sp_cache_routine(THD *thd,
@param[out] sp Pointer to sp_head object for routine, NULL if routine was
not found.
- @retval 0 Either routine is found and was succesfully loaded into cache
+ @retval 0 Either routine is found and was successfully loaded into cache
or it does not exist.
@retval non-0 Error while loading routine from mysql,proc table.
*/
@@ -2847,7 +2861,7 @@ Sp_handler::sp_cache_package_routine(THD *thd,
bool lookup_only, sp_head **sp) const
{
DBUG_ENTER("sp_cache_package_routine");
- DBUG_ASSERT(type() == TYPE_ENUM_FUNCTION || type() == TYPE_ENUM_PROCEDURE);
+ DBUG_ASSERT(type() == SP_TYPE_FUNCTION || type() == SP_TYPE_PROCEDURE);
sp_name pkgname(&name->m_db, &pkgname_cstr, false);
sp_head *ph= NULL;
int ret= sp_handler_package_body.sp_cache_routine(thd, &pkgname,
@@ -2914,7 +2928,6 @@ Sp_handler::show_create_sp(THD *thd, String *buf,
const DDL_options_st ddl_options,
sql_mode_t sql_mode) const
{
- sql_mode_t old_sql_mode= thd->variables.sql_mode;
size_t agglen= (chistics.agg_type == GROUP_AGGREGATE)? 10 : 0;
LEX_CSTRING tmp;
@@ -2925,7 +2938,7 @@ Sp_handler::show_create_sp(THD *thd, String *buf,
agglen + USER_HOST_BUFF_SIZE))
return true;
- thd->variables.sql_mode= sql_mode;
+ Sql_mode_instant_set sms(thd, sql_mode);
buf->append(STRING_WITH_LEN("CREATE "));
if (ddl_options.or_replace())
buf->append(STRING_WITH_LEN("OR REPLACE "));
@@ -2947,7 +2960,7 @@ Sp_handler::show_create_sp(THD *thd, String *buf,
buf->append('(');
buf->append(&params);
buf->append(')');
- if (type() == TYPE_ENUM_FUNCTION)
+ if (type() == SP_TYPE_FUNCTION)
{
if (sql_mode & MODE_ORACLE)
buf->append(STRING_WITH_LEN(" RETURN "));
@@ -2976,7 +2989,6 @@ Sp_handler::show_create_sp(THD *thd, String *buf,
append_suid(buf, chistics.suid);
append_comment(buf, chistics.comment);
buf->append(body.str, body.length); // Not \0 terminated
- thd->variables.sql_mode= old_sql_mode;
return false;
}
diff --git a/sql/sp.h b/sql/sp.h
index 49bf1eb93cf..72485632261 100644
--- a/sql/sp.h
+++ b/sql/sp.h
@@ -1,5 +1,6 @@
/* -*- C++ -*- */
/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2009, 2020, 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
@@ -46,18 +47,18 @@ template <typename T> class SQL_I_List;
/*
Values for the type enum. This reflects the order of the enum declaration
in the CREATE TABLE command.
+ See also storage/perfschema/my_thread.h
*/
-enum stored_procedure_type
+enum enum_sp_type
{
- TYPE_ENUM_FUNCTION=1,
- TYPE_ENUM_PROCEDURE=2,
- TYPE_ENUM_PACKAGE=3,
- TYPE_ENUM_PACKAGE_BODY=4,
- TYPE_ENUM_TRIGGER=5,
- TYPE_ENUM_PROXY=6
+ SP_TYPE_FUNCTION=1,
+ SP_TYPE_PROCEDURE=2,
+ SP_TYPE_PACKAGE=3,
+ SP_TYPE_PACKAGE_BODY=4,
+ SP_TYPE_TRIGGER=5,
+ SP_TYPE_EVENT=6,
};
-
class Sp_handler
{
bool sp_resolve_package_routine_explicit(THD *thd,
@@ -120,13 +121,13 @@ public: // TODO: make it private or protected
public:
virtual ~Sp_handler() {}
static const Sp_handler *handler(enum enum_sql_command cmd);
- static const Sp_handler *handler(stored_procedure_type type);
+ static const Sp_handler *handler(enum_sp_type type);
static const Sp_handler *handler(MDL_key::enum_mdl_namespace ns);
/*
Return a handler only those SP objects that store
definitions in the mysql.proc system table
*/
- static const Sp_handler *handler_mysql_proc(stored_procedure_type type)
+ static const Sp_handler *handler_mysql_proc(enum_sp_type type)
{
const Sp_handler *sph= handler(type);
return sph ? sph->sp_handler_mysql_proc() : NULL;
@@ -135,9 +136,8 @@ public:
static bool eq_routine_name(const LEX_CSTRING &name1,
const LEX_CSTRING &name2)
{
- return my_strnncoll(system_charset_info,
- (const uchar *) name1.str, name1.length,
- (const uchar *) name2.str, name2.length) == 0;
+ return system_charset_info->strnncoll(name1.str, name1.length,
+ name2.str, name2.length) == 0;
}
const char *type_str() const { return type_lex_cstring().str; }
virtual const char *show_create_routine_col1_caption() const
@@ -154,7 +154,7 @@ public:
{
return this;
}
- virtual stored_procedure_type type() const= 0;
+ virtual enum_sp_type type() const= 0;
virtual LEX_CSTRING type_lex_cstring() const= 0;
virtual LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const
{
@@ -249,7 +249,7 @@ public:
class Sp_handler_procedure: public Sp_handler
{
public:
- stored_procedure_type type() const { return TYPE_ENUM_PROCEDURE; }
+ enum_sp_type type() const { return SP_TYPE_PROCEDURE; }
LEX_CSTRING type_lex_cstring() const
{
static LEX_CSTRING m_type_str= { STRING_WITH_LEN("PROCEDURE")};
@@ -299,7 +299,7 @@ public:
class Sp_handler_function: public Sp_handler
{
public:
- stored_procedure_type type() const { return TYPE_ENUM_FUNCTION; }
+ enum_sp_type type() const { return SP_TYPE_FUNCTION; }
LEX_CSTRING type_lex_cstring() const
{
static LEX_CSTRING m_type_str= { STRING_WITH_LEN("FUNCTION")};
@@ -368,7 +368,7 @@ public: // TODO: make it private or protected
const Database_qualified_name *name)
const;
public:
- stored_procedure_type type() const { return TYPE_ENUM_PACKAGE; }
+ enum_sp_type type() const { return SP_TYPE_PACKAGE; }
LEX_CSTRING type_lex_cstring() const
{
static LEX_CSTRING m_type_str= {STRING_WITH_LEN("PACKAGE")};
@@ -401,7 +401,7 @@ public:
class Sp_handler_package_body: public Sp_handler_package
{
public:
- stored_procedure_type type() const { return TYPE_ENUM_PACKAGE_BODY; }
+ enum_sp_type type() const { return SP_TYPE_PACKAGE_BODY; }
LEX_CSTRING type_lex_cstring() const
{
static LEX_CSTRING m_type_str= {STRING_WITH_LEN("PACKAGE BODY")};
@@ -434,7 +434,7 @@ public:
class Sp_handler_trigger: public Sp_handler
{
public:
- stored_procedure_type type() const { return TYPE_ENUM_TRIGGER; }
+ enum_sp_type type() const { return SP_TYPE_TRIGGER; }
LEX_CSTRING type_lex_cstring() const
{
static LEX_CSTRING m_type_str= { STRING_WITH_LEN("TRIGGER")};
@@ -493,20 +493,20 @@ inline const Sp_handler *Sp_handler::handler(enum_sql_command cmd)
}
-inline const Sp_handler *Sp_handler::handler(stored_procedure_type type)
+inline const Sp_handler *Sp_handler::handler(enum_sp_type type)
{
switch (type) {
- case TYPE_ENUM_PROCEDURE:
+ case SP_TYPE_PROCEDURE:
return &sp_handler_procedure;
- case TYPE_ENUM_FUNCTION:
+ case SP_TYPE_FUNCTION:
return &sp_handler_function;
- case TYPE_ENUM_PACKAGE:
+ case SP_TYPE_PACKAGE:
return &sp_handler_package_spec;
- case TYPE_ENUM_PACKAGE_BODY:
+ case SP_TYPE_PACKAGE_BODY:
return &sp_handler_package_body;
- case TYPE_ENUM_TRIGGER:
+ case SP_TYPE_TRIGGER:
return &sp_handler_trigger;
- case TYPE_ENUM_PROXY:
+ case SP_TYPE_EVENT:
break;
}
return NULL;
diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc
index e4ffbdcb155..b3949a94751 100644
--- a/sql/sp_cache.cc
+++ b/sql/sp_cache.cc
@@ -27,7 +27,7 @@ static ulong volatile Cversion= 1;
/*
- Cache of stored routines.
+ Cache of stored routines.
*/
class sp_cache
@@ -149,8 +149,8 @@ void sp_cache_end()
sp_cache_insert()
cp The cache to put routine into
sp Routine to insert.
-
- TODO: Perhaps it will be more straightforward if in case we returned an
+
+ TODO: Perhaps it will be more straightforward if in case we returned an
error from this function when we couldn't allocate sp_cache. (right
now failure to put routine into cache will cause a 'SP not found'
error to be reported at some later time)
@@ -173,18 +173,18 @@ void sp_cache_insert(sp_cache **cp, sp_head *sp)
}
-/*
+/*
Look up a routine in the cache.
SYNOPSIS
sp_cache_lookup()
cp Cache to look into
name Name of rutine to find
-
+
NOTE
An obsolete (but not more obsolete then since last
sp_cache_flush_obsolete call) routine may be returned.
- RETURN
+ RETURN
The routine or
NULL if the routine not found.
*/
@@ -204,7 +204,7 @@ sp_head *sp_cache_lookup(sp_cache **cp, const Database_qualified_name *name)
SYNOPSIS
sp_cache_invalidate()
-
+
NOTE
This is called when a VIEW definition is created or modified (and in some
other contexts). We can't destroy sp_head objects here as one may modify
@@ -225,7 +225,7 @@ void sp_cache_invalidate()
@param[in] sp SP to remove.
@note This invalidates pointers to sp_head objects this thread
- uses. In practice that means 'dont call this function when
+ uses. In practice that means don't call this function when
inside SP'.
*/
@@ -264,7 +264,7 @@ sp_cache_enforce_limit(sp_cache *c, ulong upper_limit_for_elements)
}
/*************************************************************************
- Internal functions
+ Internal functions
*************************************************************************/
extern "C" uchar *hash_get_key_for_sp_head(const uchar *ptr, size_t *plen,
@@ -302,7 +302,7 @@ sp_cache::~sp_cache()
void
sp_cache::init()
{
- my_hash_init(&m_hashtable, system_charset_info, 0, 0, 0,
+ my_hash_init(key_memory_sp_cache, &m_hashtable, system_charset_info, 0, 0, 0,
hash_get_key_for_sp_head, hash_free_sp_head, 0);
}
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 6f1b720806c..f840904def3 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -23,7 +23,6 @@
#include "probes_mysql.h"
#include "sql_show.h" // append_identifier
#include "sql_db.h" // mysql_opt_change_db, mysql_change_db
-#include "sql_acl.h" // *_ACL
#include "sql_array.h" // Dynamic_array
#include "log_event.h" // Query_log_event
#include "sql_derived.h" // mysql_handle_derived
@@ -56,8 +55,51 @@
#define SP_INSTR_UINT_MAXLEN 8
#define SP_STMT_PRINT_MAXLEN 40
-
#include <my_user.h>
+#include "mysql/psi/mysql_statement.h"
+#include "mysql/psi/mysql_sp.h"
+
+#ifdef HAVE_PSI_INTERFACE
+void init_sp_psi_keys()
+{
+ const char *category= "sp";
+ const int num __attribute__((unused)) = __LINE__ + 3;
+
+ PSI_server->register_statement(category, & sp_instr_stmt::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_set::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_set_trigger_field::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_jump::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_jump_if_not::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_freturn::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_preturn::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_hpush_jump::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_hpop::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_hreturn::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_cpush::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_cpop::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_copen::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_cclose::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_cfetch::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_agg_cfetch::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_cursor_copy_struct::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_error::psi_info, 1);
+ PSI_server->register_statement(category, & sp_instr_set_case_expr::psi_info, 1);
+
+ DBUG_ASSERT(SP_PSI_STATEMENT_INFO_COUNT == __LINE__ - num);
+}
+#endif
+
+#ifdef HAVE_PSI_SP_INTERFACE
+#define MYSQL_RUN_SP(SP,CODE) \
+ do { \
+ PSI_sp_locker_state psi_state; \
+ PSI_sp_locker *locker= MYSQL_START_SP(&psi_state, (SP)->m_sp_share); \
+ CODE; \
+ MYSQL_END_SP(locker); \
+ } while(0)
+#else
+#define MYSQL_RUN_SP(SP, CODE) do { CODE; } while(0)
+#endif
extern "C" uchar *sp_table_key(const uchar *ptr, size_t *plen, my_bool first);
@@ -188,7 +230,7 @@ sp_get_flags_for_command(LEX *lex)
case SQLCOM_SHOW_ENGINE_MUTEX:
case SQLCOM_SHOW_EVENTS:
case SQLCOM_SHOW_KEYS:
- case SQLCOM_SHOW_MASTER_STAT:
+ case SQLCOM_SHOW_BINLOG_STAT:
case SQLCOM_SHOW_OPEN_TABLES:
case SQLCOM_SHOW_PRIVILEGES:
case SQLCOM_SHOW_PROCESSLIST:
@@ -290,6 +332,10 @@ sp_get_flags_for_command(LEX *lex)
break;
case SQLCOM_DELETE:
case SQLCOM_DELETE_MULTI:
+ case SQLCOM_INSERT:
+ case SQLCOM_REPLACE:
+ case SQLCOM_REPLACE_SELECT:
+ case SQLCOM_INSERT_SELECT:
{
/*
DELETE normally doesn't return resultset, but there are 3 exceptions:
@@ -297,8 +343,7 @@ sp_get_flags_for_command(LEX *lex)
- EXPLAIN DELETE ...
- ANALYZE DELETE ...
*/
- if (lex->first_select_lex()->item_list.is_empty() &&
- !lex->describe && !lex->analyze_stmt)
+ if (!lex->has_returning() && !lex->describe && !lex->analyze_stmt)
flags= 0;
else
flags= sp_head::MULTI_RESULTS;
@@ -306,10 +351,6 @@ sp_get_flags_for_command(LEX *lex)
}
case SQLCOM_UPDATE:
case SQLCOM_UPDATE_MULTI:
- case SQLCOM_INSERT:
- case SQLCOM_REPLACE:
- case SQLCOM_REPLACE_SELECT:
- case SQLCOM_INSERT_SELECT:
{
if (!lex->describe && !lex->analyze_stmt)
flags= 0;
@@ -456,8 +497,8 @@ sp_head *sp_head::create(sp_package *parent, const Sp_handler *handler,
enum_sp_aggregate_type agg_type)
{
MEM_ROOT own_root;
- init_sql_alloc(&own_root, "sp_head", MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC,
- MYF(0));
+ init_sql_alloc(key_memory_sp_head_main_root, &own_root, MEM_ROOT_BLOCK_SIZE,
+ MEM_ROOT_PREALLOC, MYF(0));
sp_head *sp;
if (!(sp= new (&own_root) sp_head(&own_root, parent, handler, agg_type)))
free_root(&own_root, MYF(0));
@@ -538,11 +579,12 @@ sp_head::sp_head(MEM_ROOT *mem_root_arg, sp_package *parent,
m_backpatch_goto.empty();
m_cont_backpatch.empty();
m_lex.empty();
- my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8, MYF(0));
- my_hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
- my_hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key,
- 0, 0);
- m_security_ctx.init();
+ my_init_dynamic_array(key_memory_sp_head_main_root, &m_instr,
+ sizeof(sp_instr *), 16, 8, MYF(0));
+ my_hash_init(key_memory_sp_head_main_root, &m_sptabs, system_charset_info, 0,
+ 0, 0, sp_table_key, 0, 0);
+ my_hash_init(key_memory_sp_head_main_root, &m_sroutines, system_charset_info,
+ 0, 0, 0, sp_sroutine_key, 0, 0);
DBUG_VOID_RETURN;
}
@@ -552,7 +594,7 @@ sp_package *sp_package::create(LEX *top_level_lex, const sp_name *name,
const Sp_handler *sph)
{
MEM_ROOT own_root;
- init_sql_alloc(&own_root, "sp_package", MEM_ROOT_BLOCK_SIZE,
+ init_sql_alloc(key_memory_sp_head_main_root, &own_root, MEM_ROOT_BLOCK_SIZE,
MEM_ROOT_PREALLOC, MYF(0));
sp_package *sp;
if (!(sp= new (&own_root) sp_package(&own_root, top_level_lex, name, sph)))
@@ -605,7 +647,7 @@ bool sp_head::eq_routine_spec(const sp_head *sp) const
bool sp_package::validate_after_parser(THD *thd)
{
- if (m_handler->type() != TYPE_ENUM_PACKAGE_BODY)
+ if (m_handler->type() != SP_TYPE_PACKAGE_BODY)
return false;
sp_head *sp= sp_cache_lookup(&thd->sp_package_spec_cache, this);
sp_package *spec= sp ? sp->get_package() : NULL;
@@ -684,7 +726,7 @@ bool sp_package::validate_private_routines(THD *thd)
LEX *sp_package::LexList::find(const LEX_CSTRING &name,
- stored_procedure_type type)
+ enum_sp_type type)
{
List_iterator<LEX> it(*this);
for (LEX *lex; (lex= it++); )
@@ -707,7 +749,7 @@ LEX *sp_package::LexList::find(const LEX_CSTRING &name,
LEX *sp_package::LexList::find_qualified(const LEX_CSTRING &name,
- stored_procedure_type type)
+ enum_sp_type type)
{
List_iterator<LEX> it(*this);
for (LEX *lex; (lex= it++); )
@@ -721,6 +763,17 @@ LEX *sp_package::LexList::find_qualified(const LEX_CSTRING &name,
}
+void sp_package::init_psi_share()
+{
+ List_iterator<LEX> it(m_routine_implementations);
+ for (LEX *lex; (lex= it++); )
+ {
+ DBUG_ASSERT(lex->sphead);
+ lex->sphead->init_psi_share();
+ }
+ sp_head::init_psi_share();
+}
+
void
sp_head::init(LEX *lex)
{
@@ -756,6 +809,13 @@ sp_head::init_sp_name(const sp_name *spname)
DBUG_VOID_RETURN;
}
+void
+sp_head::init_psi_share()
+{
+ m_sp_share= MYSQL_GET_SP_SHARE(m_handler->type(), m_db.str, static_cast<uint>(m_db.length),
+ m_name.str, static_cast<uint>(m_name.length));
+}
+
void
sp_head::set_body_start(THD *thd, const char *begin_ptr)
@@ -1039,7 +1099,7 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
{
DBUG_ENTER("subst_spvars");
- Dynamic_array<Rewritable_query_parameter*> rewritables;
+ Dynamic_array<Rewritable_query_parameter*> rewritables(PSI_INSTRUMENT_MEM);
char *pbuf;
StringBuffer<512> qbuf;
Copy_query_with_rewrite acc(thd, query_str->str, query_str->length, &qbuf);
@@ -1171,7 +1231,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
opt_trace_disable_if_no_security_context_access(thd);
/* init per-instruction memroot */
- init_sql_alloc(&execute_mem_root, "per_instruction_memroot",
+ init_sql_alloc(key_memory_sp_head_execute_root, &execute_mem_root,
MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
DBUG_ASSERT(!(m_flags & IS_INVOKED));
@@ -1358,8 +1418,24 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
WSREP_DEBUG("assigned new next trx ID for SP, trx id: %" PRIu64, thd->wsrep_next_trx_id());
}
#endif /* WITH_WSREP */
+
+#ifdef HAVE_PSI_STATEMENT_INTERFACE
+ PSI_statement_locker_state state;
+ PSI_statement_locker *parent_locker;
+ PSI_statement_info *psi_info = i->get_psi_info();
+
+ parent_locker= thd->m_statement_psi;
+ thd->m_statement_psi= MYSQL_START_STATEMENT(& state, psi_info->m_key,
+ thd->db.str, thd->db.length, thd->charset(), m_sp_share);
+#endif
+
err_status= i->execute(thd, &ip);
+#ifdef HAVE_PSI_STATEMENT_INTERFACE
+ MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
+ thd->m_statement_psi= parent_locker;
+#endif
+
#ifdef WITH_WSREP
if (WSREP(thd))
{
@@ -1396,7 +1472,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
/*
Reset the return code to zero if the transaction was
- replayed succesfully.
+ replayed successfully.
*/
if (must_replay && !wsrep_current_error(thd))
{
@@ -1816,8 +1892,8 @@ sp_head::execute_trigger(THD *thd,
TODO: we should create sp_rcontext once per command and reuse it
on subsequent executions of a trigger.
*/
- init_sql_alloc(&call_mem_root, "execute_trigger", MEM_ROOT_BLOCK_SIZE, 0,
- MYF(0));
+ init_sql_alloc(key_memory_sp_head_call_root,
+ &call_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
thd->set_n_backup_active_arena(&call_arena, &backup_arena);
Row_definition_list defs;
@@ -1830,7 +1906,7 @@ sp_head::execute_trigger(THD *thd,
thd->spcont= nctx;
- err_status= execute(thd, FALSE);
+ MYSQL_RUN_SP(this, err_status= execute(thd, FALSE));
err_with_cleanup:
thd->restore_active_arena(&call_arena, &backup_arena);
@@ -2080,7 +2156,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
*/
thd->set_n_backup_active_arena(call_arena, &backup_arena);
- err_status= execute(thd, TRUE);
+ MYSQL_RUN_SP(this, err_status= execute(thd, TRUE));
thd->restore_active_arena(call_arena, &backup_arena);
@@ -2361,11 +2437,9 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
#endif
opt_trace_disable_if_no_stored_proc_func_access(thd, this);
+
if (!err_status)
- {
- err_status= execute(thd, TRUE);
- DBUG_PRINT("info", ("execute returned %d", (int) err_status));
- }
+ MYSQL_RUN_SP(this, err_status= execute(thd, TRUE));
if (save_log_general)
thd->variables.option_bits &= ~OPTION_LOG_OFF;
@@ -2411,11 +2485,10 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
break;
}
- Send_field *out_param_info= new (thd->mem_root) Send_field();
- nctx->get_parameter(i)->make_send_field(thd, out_param_info);
- out_param_info->db_name= m_db.str;
- out_param_info->table_name= m_name.str;
- out_param_info->org_table_name= m_name.str;
+ Send_field *out_param_info= new (thd->mem_root) Send_field(thd, nctx->get_parameter(i));
+ out_param_info->db_name= m_db;
+ out_param_info->table_name= m_name;
+ out_param_info->org_table_name= m_name;
out_param_info->col_name= spvar->name;
out_param_info->org_col_name= spvar->name;
@@ -2854,7 +2927,7 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
*full_access= ((!check_table_access(thd, SELECT_ACL, &tables, FALSE,
1, TRUE) &&
- (tables.grant.privilege & SELECT_ACL) != 0) ||
+ (tables.grant.privilege & SELECT_ACL) != NO_ACL) ||
/* Check if user owns the routine. */
(!strcmp(sp->m_definer.user.str,
thd->security_ctx->priv_user) &&
@@ -3095,7 +3168,7 @@ bool sp_head::add_instr_freturn(THD *thd, sp_pcontext *spcont,
{
sp_instr_freturn *i= new (thd->mem_root)
sp_instr_freturn(instructions(), spcont, item,
- m_return_field_def.type_handler(), thd->lex);
+ m_return_field_def.type_handler(), lex);
if (i == NULL || add_instr(i))
return true;
m_flags|= sp_head::HAS_RETURN;
@@ -3446,7 +3519,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
thd->mdl_context.release_statement_locks();
}
}
- //TODO: why is this here if log_slow_query is in sp_instr_stmt_execute?
+ //TODO: why is this here if log_slow_query is in sp_instr_stmt::execute?
delete_explain_query(m_lex);
if (m_lex->query_tables_own_last)
@@ -3555,6 +3628,9 @@ int sp_instr::exec_core(THD *thd, uint *nextp)
sp_instr_stmt class functions
*/
+PSI_statement_info sp_instr_stmt::psi_info=
+{ 0, "stmt", 0};
+
int
sp_instr_stmt::execute(THD *thd, uint *nextp)
{
@@ -3565,6 +3641,8 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
DBUG_ENTER("sp_instr_stmt::execute");
DBUG_PRINT("info", ("command: %d", m_lex_keeper.sql_command()));
+ MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, m_query.str, static_cast<uint>(m_query.length));
+
#if defined(ENABLED_PROFILING)
/* This s-p instr is profilable and will be captured. */
thd->profiling.set_query_source(m_query.str, m_query.length);
@@ -3691,6 +3769,9 @@ sp_instr_stmt::exec_core(THD *thd, uint *nextp)
sp_instr_set class functions
*/
+PSI_statement_info sp_instr_set::psi_info=
+{ 0, "set", 0};
+
int
sp_instr_set::execute(THD *thd, uint *nextp)
{
@@ -3841,6 +3922,9 @@ sp_instr_set_row_field_by_name::print(String *str)
sp_instr_set_trigger_field class functions
*/
+PSI_statement_info sp_instr_set_trigger_field::psi_info=
+{ 0, "set_trigger_field", 0};
+
int
sp_instr_set_trigger_field::execute(THD *thd, uint *nextp)
{
@@ -3853,10 +3937,8 @@ sp_instr_set_trigger_field::execute(THD *thd, uint *nextp)
int
sp_instr_set_trigger_field::exec_core(THD *thd, uint *nextp)
{
- bool sav_abort_on_warning= thd->abort_on_warning;
- thd->abort_on_warning= thd->is_strict_mode() && !thd->lex->ignore;
+ Abort_on_warning_instant_set aws(thd, thd->is_strict_mode() && !thd->lex->ignore);
const int res= (trigger_field->set_value(thd, &value) ? -1 : 0);
- thd->abort_on_warning= sav_abort_on_warning;
*nextp = m_ip+1;
return res;
}
@@ -3886,6 +3968,9 @@ uint sp_instr_opt_meta::get_cont_dest() const
sp_instr_jump class functions
*/
+PSI_statement_info sp_instr_jump::psi_info=
+{ 0, "jump", 0};
+
int
sp_instr_jump::execute(THD *thd, uint *nextp)
{
@@ -3951,6 +4036,9 @@ sp_instr_jump::opt_move(uint dst, List<sp_instr> *bp)
sp_instr_jump_if_not class functions
*/
+PSI_statement_info sp_instr_jump_if_not::psi_info=
+{ 0, "jump_if_not", 0};
+
int
sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
{
@@ -4046,6 +4134,9 @@ sp_instr_jump_if_not::opt_move(uint dst, List<sp_instr> *bp)
sp_instr_freturn class functions
*/
+PSI_statement_info sp_instr_freturn::psi_info=
+{ 0, "freturn", 0};
+
int
sp_instr_freturn::execute(THD *thd, uint *nextp)
{
@@ -4110,9 +4201,33 @@ sp_instr_freturn::print(String *str)
}
/*
+ sp_instr_preturn class functions
+*/
+
+PSI_statement_info sp_instr_preturn::psi_info=
+{ 0, "preturn", 0};
+
+int
+sp_instr_preturn::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_preturn::execute");
+ *nextp= UINT_MAX;
+ DBUG_RETURN(0);
+}
+
+void
+sp_instr_preturn::print(String *str)
+{
+ str->append(STRING_WITH_LEN("preturn"));
+}
+
+/*
sp_instr_hpush_jump class functions
*/
+PSI_statement_info sp_instr_hpush_jump::psi_info=
+{ 0, "hpush_jump", 0};
+
int
sp_instr_hpush_jump::execute(THD *thd, uint *nextp)
{
@@ -4189,6 +4304,9 @@ sp_instr_hpush_jump::opt_mark(sp_head *sp, List<sp_instr> *leads)
sp_instr_hpop class functions
*/
+PSI_statement_info sp_instr_hpop::psi_info=
+{ 0, "hpop", 0};
+
int
sp_instr_hpop::execute(THD *thd, uint *nextp)
{
@@ -4213,6 +4331,9 @@ sp_instr_hpop::print(String *str)
sp_instr_hreturn class functions
*/
+PSI_statement_info sp_instr_hreturn::psi_info=
+{ 0, "hreturn", 0};
+
int
sp_instr_hreturn::execute(THD *thd, uint *nextp)
{
@@ -4272,6 +4393,9 @@ sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads)
sp_instr_cpush class functions
*/
+PSI_statement_info sp_instr_cpush::psi_info=
+{ 0, "cpush", 0};
+
int
sp_instr_cpush::execute(THD *thd, uint *nextp)
{
@@ -4313,6 +4437,9 @@ sp_instr_cpush::print(String *str)
sp_instr_cpop class functions
*/
+PSI_statement_info sp_instr_cpop::psi_info=
+{ 0, "cpop", 0};
+
int
sp_instr_cpop::execute(THD *thd, uint *nextp)
{
@@ -4343,6 +4470,9 @@ sp_instr_cpop::print(String *str)
Assert that we either have an error or a cursor
*/
+PSI_statement_info sp_instr_copen::psi_info=
+{ 0, "copen", 0};
+
int
sp_instr_copen::execute(THD *thd, uint *nextp)
{
@@ -4401,6 +4531,9 @@ sp_instr_copen::print(String *str)
sp_instr_cclose class functions
*/
+PSI_statement_info sp_instr_cclose::psi_info=
+{ 0, "cclose", 0};
+
int
sp_instr_cclose::execute(THD *thd, uint *nextp)
{
@@ -4443,6 +4576,9 @@ sp_instr_cclose::print(String *str)
sp_instr_cfetch class functions
*/
+PSI_statement_info sp_instr_cfetch::psi_info=
+{ 0, "cfetch", 0};
+
int
sp_instr_cfetch::execute(THD *thd, uint *nextp)
{
@@ -4490,6 +4626,13 @@ sp_instr_cfetch::print(String *str)
}
}
+/*
+ sp_instr_agg_cfetch class functions
+*/
+
+PSI_statement_info sp_instr_agg_cfetch::psi_info=
+{ 0, "agg_cfetch", 0};
+
int
sp_instr_agg_cfetch::execute(THD *thd, uint *nextp)
{
@@ -4542,6 +4685,9 @@ sp_instr_agg_cfetch::print(String *str)
- copies the cursor structure to the associated %ROWTYPE variable.
*/
+PSI_statement_info sp_instr_cursor_copy_struct::psi_info=
+{ 0, "cursor_copy_struct", 0};
+
int
sp_instr_cursor_copy_struct::exec_core(THD *thd, uint *nextp)
{
@@ -4614,6 +4760,9 @@ sp_instr_cursor_copy_struct::print(String *str)
sp_instr_error class functions
*/
+PSI_statement_info sp_instr_error::psi_info=
+{ 0, "error", 0};
+
int
sp_instr_error::execute(THD *thd, uint *nextp)
{
@@ -4640,6 +4789,9 @@ sp_instr_error::print(String *str)
sp_instr_set_case_expr class implementation
**************************************************************************/
+PSI_statement_info sp_instr_set_case_expr::psi_info=
+{ 0, "set_case_expr", 0};
+
int
sp_instr_set_case_expr::execute(THD *thd, uint *nextp)
{
@@ -4980,8 +5132,8 @@ sp_add_to_query_tables(THD *thd, LEX *lex,
table->lock_type= locktype;
table->select_lex= lex->current_select;
table->cacheable_table= 1;
- table->mdl_request.init(MDL_key::TABLE, table->db.str, table->table_name.str,
- mdl_type, MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&table->mdl_request, MDL_key::TABLE, table->db.str,
+ table->table_name.str, mdl_type, MDL_TRANSACTION);
lex->add_to_query_tables(table);
return table;
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 6cf4610c466..913be1aace7 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -47,6 +47,14 @@ class sp_instr;
class sp_instr_opt_meta;
class sp_instr_jump_if_not;
+/**
+ Number of PSI_statement_info instruments
+ for internal stored programs statements.
+*/
+#ifdef HAVE_PSI_INTERFACE
+void init_sp_psi_keys(void);
+#endif
+
/*************************************************************************/
/**
@@ -174,6 +182,11 @@ public:
const Sp_handler *m_handler;
uint m_flags; // Boolean attributes of a stored routine
+ /**
+ Instrumentation interface for SP.
+ */
+ PSI_sp_share *m_sp_share;
+
Column_definition m_return_field_def; /**< This is used for FUNCTIONs only. */
const char *m_tmp_query; ///< Temporary pointer to sub query string
@@ -856,6 +869,8 @@ public:
return NULL;
}
+ virtual void init_psi_share();
+
protected:
MEM_ROOT *m_thd_root; ///< Temp. store for thd's mem_root
@@ -931,9 +946,9 @@ public:
public:
LexList() { elements= 0; }
// Find a package routine by a non qualified name
- LEX *find(const LEX_CSTRING &name, stored_procedure_type type);
+ LEX *find(const LEX_CSTRING &name, enum_sp_type type);
// Find a package routine by a package-qualified name, e.g. 'pkg.proc'
- LEX *find_qualified(const LEX_CSTRING &name, stored_procedure_type type);
+ LEX *find_qualified(const LEX_CSTRING &name, enum_sp_type type);
// Check if a routine with the given qualified name already exists
bool check_dup_qualified(const LEX_CSTRING &name, const Sp_handler *sph)
{
@@ -990,6 +1005,7 @@ public:
m_routine_implementations.push_back(lex, &main_mem_root);
}
sp_package *get_package() { return this; }
+ void init_psi_share();
bool is_invoked() const
{
/*
@@ -1156,6 +1172,7 @@ public:
{
m_ip= dst;
}
+ virtual PSI_statement_info* get_psi_info() = 0;
}; // class sp_instr : public Sql_alloc
@@ -1282,6 +1299,10 @@ private:
sp_lex_keeper m_lex_keeper;
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
+
}; // class sp_instr_stmt : public sp_instr
@@ -1316,6 +1337,10 @@ protected:
uint m_offset; ///< Frame offset
Item *m_value;
sp_lex_keeper m_lex_keeper;
+
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
}; // class sp_instr_set : public sp_instr
@@ -1424,6 +1449,10 @@ private:
Item_trigger_field *trigger_field;
Item *value;
sp_lex_keeper m_lex_keeper;
+
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
}; // class sp_instr_trigger_field : public sp_instr
@@ -1510,6 +1539,9 @@ public:
m_dest= new_dest;
}
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
}; // class sp_instr_jump : public sp_instr_opt_meta
@@ -1561,6 +1593,9 @@ private:
Item *m_expr; ///< The condition
sp_lex_keeper m_lex_keeper;
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
}; // class sp_instr_jump_if_not : public sp_instr_jump
@@ -1578,17 +1613,9 @@ public:
virtual ~sp_instr_preturn()
{}
- virtual int execute(THD *thd, uint *nextp)
- {
- DBUG_ENTER("sp_instr_preturn::execute");
- *nextp= UINT_MAX;
- DBUG_RETURN(0);
- }
+ virtual int execute(THD *thd, uint *nextp);
- virtual void print(String *str)
- {
- str->append(STRING_WITH_LEN("preturn"));
- }
+ virtual void print(String *str);
virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads)
{
@@ -1596,6 +1623,9 @@ public:
return UINT_MAX;
}
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
}; // class sp_instr_preturn : public sp_instr
@@ -1633,6 +1663,9 @@ protected:
const Type_handler *m_type_handler;
sp_lex_keeper m_lex_keeper;
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
}; // class sp_instr_freturn : public sp_instr
@@ -1698,6 +1731,9 @@ private:
// debug version only). It's used in print().
uint m_frame;
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
}; // class sp_instr_hpush_jump : public sp_instr_jump
@@ -1728,6 +1764,9 @@ private:
uint m_count;
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
}; // class sp_instr_hpop : public sp_instr
@@ -1762,12 +1801,14 @@ private:
uint m_frame;
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
}; // class sp_instr_hreturn : public sp_instr_jump
/** This is DECLARE CURSOR */
-class sp_instr_cpush : public sp_instr,
- public sp_cursor
+class sp_instr_cpush : public sp_instr, public sp_cursor
{
sp_instr_cpush(const sp_instr_cpush &); /**< Prevent use of these */
void operator=(sp_instr_cpush &);
@@ -1796,6 +1837,9 @@ private:
sp_lex_keeper m_lex_keeper;
uint m_cursor; /**< Frame offset (for debugging) */
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
}; // class sp_instr_cpush : public sp_instr
@@ -1826,6 +1870,9 @@ private:
uint m_count;
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
}; // class sp_instr_cpop : public sp_instr
@@ -1853,6 +1900,9 @@ private:
uint m_cursor; ///< Stack index
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
}; // class sp_instr_copen : public sp_instr_stmt
@@ -1880,6 +1930,10 @@ public:
virtual int execute(THD *thd, uint *nextp);
virtual int exec_core(THD *thd, uint *nextp);
virtual void print(String *str);
+
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
};
@@ -1905,6 +1959,9 @@ private:
uint m_cursor;
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
}; // class sp_instr_cclose : public sp_instr
@@ -1939,6 +1996,9 @@ private:
List<sp_variable> m_varlist;
bool m_error_on_no_data;
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
}; // class sp_instr_cfetch : public sp_instr
/*
@@ -1963,6 +2023,10 @@ public:
virtual int execute(THD *thd, uint *nextp);
virtual void print(String *str);
+
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
}; // class sp_instr_agg_cfetch : public sp_instr
@@ -1996,6 +2060,9 @@ private:
int m_errcode;
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
}; // class sp_instr_error : public sp_instr
@@ -2035,6 +2102,9 @@ private:
Item *m_case_expr;
sp_lex_keeper m_lex_keeper;
+public:
+ virtual PSI_statement_info* get_psi_info() { return & psi_info; }
+ static PSI_statement_info psi_info;
}; // class sp_instr_set_case_expr : public sp_instr_opt_meta
bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access);
diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
index 433efda479b..848d1f0c655 100644
--- a/sql/sp_pcontext.cc
+++ b/sql/sp_pcontext.cc
@@ -1,4 +1,5 @@
/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2009, 2020, 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
@@ -95,6 +96,9 @@ sp_pcontext::sp_pcontext()
: Sql_alloc(),
m_max_var_index(0), m_max_cursor_index(0),
m_parent(NULL), m_pboundary(0),
+ m_vars(PSI_INSTRUMENT_MEM), m_case_expr_ids(PSI_INSTRUMENT_MEM),
+ m_conditions(PSI_INSTRUMENT_MEM), m_cursors(PSI_INSTRUMENT_MEM),
+ m_handlers(PSI_INSTRUMENT_MEM), m_children(PSI_INSTRUMENT_MEM),
m_scope(REGULAR_SCOPE)
{
init(0, 0, 0);
@@ -105,6 +109,9 @@ sp_pcontext::sp_pcontext(sp_pcontext *prev, sp_pcontext::enum_scope scope)
: Sql_alloc(),
m_max_var_index(0), m_max_cursor_index(0),
m_parent(prev), m_pboundary(0),
+ m_vars(PSI_INSTRUMENT_MEM), m_case_expr_ids(PSI_INSTRUMENT_MEM),
+ m_conditions(PSI_INSTRUMENT_MEM), m_cursors(PSI_INSTRUMENT_MEM),
+ m_handlers(PSI_INSTRUMENT_MEM), m_children(PSI_INSTRUMENT_MEM),
m_scope(scope)
{
init(prev->m_var_offset + prev->m_max_var_index,
@@ -208,9 +215,8 @@ sp_variable *sp_pcontext::find_variable(const LEX_CSTRING *name,
{
sp_variable *p= m_vars.at(i);
- if (my_strnncoll(system_charset_info,
- (const uchar *)name->str, name->length,
- (const uchar *)p->name.str, p->name.length) == 0)
+ if (system_charset_info->strnncoll(name->str, name->length,
+ p->name.str, p->name.length) == 0)
{
return p;
}
@@ -624,9 +630,8 @@ const sp_pcursor *sp_pcontext::find_cursor(const LEX_CSTRING *name,
{
LEX_CSTRING n= m_cursors.at(i);
- if (my_strnncoll(system_charset_info,
- (const uchar *) name->str, name->length,
- (const uchar *) n.str, n.length) == 0)
+ if (system_charset_info->strnncoll(name->str, name->length,
+ n.str, n.length) == 0)
{
*poff= m_cursor_offset + i;
return &m_cursors.at(i);
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index b1d77234f54..ffc9c0e19af 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -1,5 +1,6 @@
/* -*- C++ -*- */
/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2009, 2020, 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
@@ -260,9 +261,8 @@ public:
}
bool eq_name(const LEX_CSTRING *str) const
{
- return my_strnncoll(system_charset_info,
- (const uchar *) name.str, name.length,
- (const uchar *) str->str, str->length) == 0;
+ return system_charset_info->strnncoll(name.str, name.length,
+ str->str, str->length) == 0;
}
};
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index 17b4c83b7bc..c4c19dd39f6 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -74,6 +74,7 @@ sp_rcontext::sp_rcontext(const sp_head *owner,
m_return_value_fld(return_value_fld),
m_return_value_set(false),
m_in_sub_stmt(in_sub_stmt),
+ m_handlers(PSI_INSTRUMENT_MEM), m_handler_call_stack(PSI_INSTRUMENT_MEM),
m_ccount(0)
{
}
diff --git a/sql/spatial.cc b/sql/spatial.cc
index 2b36468e158..301d50f5d1e 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2002, 2013, Oracle and/or its affiliates.
- Copyright (c) 2011, 2013, Monty Program Ab.
+ Copyright (c) 2011, 2020, 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
@@ -241,9 +241,8 @@ Geometry::Class_info *Geometry::find_class(const char *name, size_t len)
{
if (*cur_rt &&
((*cur_rt)->m_name.length == len) &&
- (my_strnncoll(&my_charset_latin1,
- (const uchar*) (*cur_rt)->m_name.str, len,
- (const uchar*) name, len) == 0))
+ (my_charset_latin1.strnncoll((*cur_rt)->m_name.str, len,
+ name, len) == 0))
return *cur_rt;
}
return 0;
@@ -277,6 +276,33 @@ Geometry *Geometry::construct(Geometry_buffer *buffer,
}
+uint Geometry::get_key_image_itMBR(LEX_CSTRING &src, uchar *buff, uint length)
+{
+ const char *dummy;
+ MBR mbr;
+ Geometry_buffer buffer;
+ Geometry *gobj;
+ const uint image_length= SIZEOF_STORED_DOUBLE*4;
+
+ if (src.length < SRID_SIZE)
+ {
+ bzero(buff, image_length);
+ return image_length;
+ }
+ gobj= Geometry::construct(&buffer, (char*) src.str, (uint32) src.length);
+ if (!gobj || gobj->get_mbr(&mbr, &dummy))
+ bzero(buff, image_length);
+ else
+ {
+ float8store(buff, mbr.xmin);
+ float8store(buff+8, mbr.xmax);
+ float8store(buff+16, mbr.ymin);
+ float8store(buff+24, mbr.ymax);
+ }
+ return image_length;
+}
+
+
Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer,
Gis_read_stream *trs, String *wkt,
bool init_stream)
@@ -520,8 +546,8 @@ Geometry *Geometry::create_from_json(Geometry_buffer *buffer,
goto create_geom;
}
else if (je->value_len == feature_coll_type_len &&
- my_strnncoll(&my_charset_latin1, je->value, je->value_len,
- feature_coll_type, feature_coll_type_len) == 0)
+ my_charset_latin1.strnncoll(je->value, je->value_len,
+ feature_coll_type, feature_coll_type_len) == 0)
{
/*
'FeatureCollection' type found. Handle the 'Featurecollection'/'features'
@@ -532,8 +558,8 @@ Geometry *Geometry::create_from_json(Geometry_buffer *buffer,
fcoll_type_found= 1;
}
else if (je->value_len == feature_type_len &&
- my_strnncoll(&my_charset_latin1, je->value, je->value_len,
- feature_type, feature_type_len) == 0)
+ my_charset_latin1.strnncoll(je->value, je->value_len,
+ feature_type, feature_type_len) == 0)
{
if (geometry_start)
goto handle_geometry_key;
@@ -925,8 +951,7 @@ static int read_point_from_json(json_engine_t *je, bool er_on_3D,
goto bad_coordinates;
d= (n_coord == 0) ? x : ((n_coord == 1) ? y : &tmp);
- *d= my_strntod(je->s.cs, (char *) je->value,
- je->value_len, &endptr, &err);
+ *d= je->s.cs->strntod((char *) je->value, je->value_len, &endptr, &err);
if (err)
goto bad_coordinates;
n_coord++;
@@ -3054,9 +3079,7 @@ bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *wkb)
return 1;
if (next_word.length != 5 ||
- (my_strnncoll(&my_charset_latin1,
- (const uchar*) "empty", 5,
- (const uchar*) next_word.str, 5) != 0))
+ (my_charset_latin1.strnncoll("empty", 5, next_word.str, 5) != 0))
{
for (;;)
{
diff --git a/sql/spatial.h b/sql/spatial.h
index 55f450b1b1b..0b998e2e55c 100644
--- a/sql/spatial.h
+++ b/sql/spatial.h
@@ -317,6 +317,7 @@ public:
bool er_on_3D, String *res);
static Geometry *create_from_opresult(Geometry_buffer *g_buf,
String *res, Gcalc_result_receiver &rr);
+ static uint get_key_image_itMBR(LEX_CSTRING &src, uchar *buff, uint length);
int as_wkt(String *wkt, const char **end);
int as_json(String *wkt, uint max_dec_digits, const char **end);
int bbox_as_json(String *wkt);
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 457120d518b..a89b887ca95 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2018, Oracle and/or its affiliates.
- Copyright (c) 2009, 2019, MariaDB Corporation.
+ Copyright (c) 2009, 2020, 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
@@ -63,8 +63,19 @@ bool mysql_user_table_is_in_short_password_format= false;
bool using_global_priv_table= true;
// set that from field length in acl_load?
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
const uint max_hostname_length= 60;
const uint max_dbname_length= 64;
+#endif
+
+const char *safe_vio_type_name(Vio *vio)
+{
+ size_t unused;
+#ifdef EMBEDDED_LIBRARY
+ if (!vio) return "Internal";
+#endif
+ return vio_type_name(vio_type(vio), &unused);
+}
#include "sql_acl_getsort.ic"
@@ -124,9 +135,9 @@ static bool compare_hostname(const acl_host_and_ip *, const char *, const char *
class ACL_ACCESS {
public:
ulonglong sort;
- ulong access;
+ privilege_t access;
ACL_ACCESS()
- :sort(0), access(0)
+ :sort(0), access(NO_ACL)
{ }
};
@@ -191,7 +202,7 @@ public:
ACL_USER() { }
ACL_USER(THD *thd, const LEX_USER &combo,
const Account_options &options,
- const ulong privileges);
+ const privilege_t privileges);
ACL_USER *copy(MEM_ROOT *root)
{
@@ -257,7 +268,7 @@ public:
the ACL_USER::access field needs to be reset first. The field
initial_role_access holds initial grants, as granted directly to the role
*/
- ulong initial_role_access;
+ privilege_t initial_role_access;
/*
In subgraph traversal, when we need to traverse only a part of the graph
(e.g. all direct and indirect grantees of a role X), the counter holds the
@@ -268,16 +279,17 @@ public:
DYNAMIC_ARRAY parent_grantee; // array of backlinks to elements granted
ACL_ROLE(ACL_USER * user, MEM_ROOT *mem);
- ACL_ROLE(const char * rolename, ulong privileges, MEM_ROOT *mem);
+ ACL_ROLE(const char * rolename, privilege_t privileges, MEM_ROOT *mem);
};
class ACL_DB :public ACL_ACCESS
{
public:
+ ACL_DB() :initial_access(NO_ACL) { }
acl_host_and_ip host;
const char *user,*db;
- ulong initial_access; /* access bits present in the table */
+ privilege_t initial_access; /* access bits present in the table */
const char *get_username() { return user; }
};
@@ -518,7 +530,7 @@ public:
class acl_entry :public hash_filo_element
{
public:
- ulong access;
+ privilege_t access;
uint16 length;
char key[1]; // Key will be stored here
};
@@ -642,7 +654,7 @@ bool ROLE_GRANT_PAIR::init(MEM_ROOT *mem, const char *username,
#define ROLE_OPENED (1L << 3)
static DYNAMIC_ARRAY acl_hosts, acl_users, acl_proxy_users;
-static Dynamic_array<ACL_DB> acl_dbs(0U,50U);
+static Dynamic_array<ACL_DB> acl_dbs(PSI_INSTRUMENT_MEM, 0U, 50U);
typedef Dynamic_array<ACL_DB>::CMP_FUNC acl_dbs_cmp;
static HASH acl_roles;
/*
@@ -660,7 +672,7 @@ static HASH package_spec_priv_hash, package_body_priv_hash;
static DYNAMIC_ARRAY acl_wild_hosts;
static Hash_filo<acl_entry> *acl_cache;
static uint grant_version=0; /* Version of priv tables. incremented by acl_load */
-static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0);
+static privilege_t get_access(TABLE *form, uint fieldnr, uint *next_field=0);
static int acl_compare(const ACL_ACCESS *a, const ACL_ACCESS *b);
static int acl_user_compare(const ACL_USER *a, const ACL_USER *b);
static void rebuild_acl_users();
@@ -798,15 +810,15 @@ class Grant_table_base
/* Return the underlying TABLE handle. */
TABLE* table() const { return m_table; }
- ulong get_access() const
+ privilege_t get_access() const
{
- ulong access_bits= 0, bit= 1;
+ ulonglong access_bits= 0, bit= 1;
for (uint i = start_priv_columns; i < end_priv_columns; i++, bit<<=1)
{
if (get_YN_as_bool(m_table->field[i]))
access_bits|= bit;
}
- return access_bits;
+ return ALL_KNOWN_ACL & access_bits;
}
protected:
@@ -860,8 +872,8 @@ class User_table: public Grant_table_base
virtual LEX_CSTRING& name() const = 0;
virtual int get_auth(THD *, MEM_ROOT *, ACL_USER *u) const= 0;
virtual bool set_auth(const ACL_USER &u) const = 0;
- virtual ulong get_access() const = 0;
- virtual void set_access(ulong rights, bool revoke) const = 0;
+ virtual privilege_t get_access() const = 0;
+ virtual void set_access(const privilege_t rights, bool revoke) const = 0;
char *get_host(MEM_ROOT *root) const
{ return ::get_field(root, m_table->field[0]); }
@@ -979,9 +991,9 @@ class User_table_tabular: public User_table
return 0;
}
- ulong get_access() const
+ privilege_t get_access() const
{
- ulong access= Grant_table_base::get_access();
+ privilege_t access(Grant_table_base::get_access());
if ((num_fields() <= 13) && (access & CREATE_ACL))
access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
@@ -989,7 +1001,8 @@ class User_table_tabular: public User_table
{
access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL;
if (access & FILE_ACL)
- access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL;
+ access|= BINLOG_MONITOR_ACL | REPL_SLAVE_ACL | BINLOG_ADMIN_ACL |
+ BINLOG_REPLAY_ACL;
if (access & PROCESS_ACL)
access|= SUPER_ACL | EXECUTE_ACL;
}
@@ -1017,12 +1030,18 @@ class User_table_tabular: public User_table
if (num_fields() <= 46 && (access & DELETE_ACL))
access|= DELETE_HISTORY_ACL;
+ if (access & SUPER_ACL)
+ access|= GLOBAL_SUPER_ADDED_SINCE_USER_TABLE_ACLS;
+
+ if (access & REPL_SLAVE_ACL)
+ access|= REPL_MASTER_ADMIN_ACL;
+
return access & GLOBAL_ACLS;
}
- void set_access(ulong rights, bool revoke) const
+ void set_access(const privilege_t rights, bool revoke) const
{
- ulong priv= SELECT_ACL;
+ ulonglong priv(SELECT_ACL);
for (uint i= start_priv_columns; i < end_priv_columns; i++, priv <<= 1)
{
if (priv & rights)
@@ -1467,23 +1486,88 @@ class User_table_json: public User_table
set_str_value("authentication_string",
u.auth[i].auth_string.str, u.auth[i].auth_string.length);
}
- ulong get_access() const
+
+ void print_warning_bad_version_id(ulonglong version_id) const
+ {
+ sql_print_warning("'user' entry '%s@%s' has a wrong 'version_id' value %lld",
+ safe_str(get_user(current_thd->mem_root)),
+ safe_str(get_host(current_thd->mem_root)),
+ version_id);
+ }
+
+ void print_warning_bad_access(ulonglong version_id,
+ privilege_t mask,
+ ulonglong access) const
+ {
+ sql_print_warning("'user' entry '%s@%s' "
+ "has a wrong 'access' value 0x%llx "
+ "(allowed mask is 0x%llx, version_id=%lld)",
+ safe_str(get_user(current_thd->mem_root)),
+ safe_str(get_host(current_thd->mem_root)),
+ access, mask, version_id);
+ }
+
+ privilege_t adjust_access(ulonglong version_id, ulonglong access) const
+ {
+ privilege_t mask= ALL_KNOWN_ACL_100304;
+ ulonglong orig_access= access;
+ if (version_id >= 100502)
+ {
+ mask= ALL_KNOWN_ACL_100502;
+ }
+ else // 100501 or earlier
+ {
+ if (access & SUPER_ACL)
+ access|= GLOBAL_SUPER_ADDED_SINCE_USER_TABLE_ACLS;
+
+ if (access & REPL_SLAVE_ACL)
+ access|= REPL_MASTER_ADMIN_ACL;
+ }
+
+ if (orig_access & ~mask)
+ {
+ print_warning_bad_access(version_id, mask, orig_access);
+ return NO_ACL;
+ }
+ return access & ALL_KNOWN_ACL;
+ }
+
+ privilege_t get_access() const
{
+ ulonglong version_id= (ulonglong) get_int_value("version_id");
+ ulonglong access= (ulonglong) get_int_value("access");
+
+ /*
+ Special case:
+ mysql_system_tables_data.sql populates "ALL PRIVILEGES"
+ for the super user this way:
+ {"access":18446744073709551615}
+ */
+ if (access == (ulonglong) ~0)
+ return GLOBAL_ACLS;
+
/*
- when new privileges will be added, we'll start storing GLOBAL_ACLS
- (or, for example, my_count_bits(GLOBAL_ACLS))
- in the json too, and it'll allow us to do privilege upgrades
+ Reject obviously bad (negative and too large) version_id values.
+ Also reject versions before 10.4.0 (when JSON table was added).
*/
- return get_int_value("access") & GLOBAL_ACLS;
+ if ((longlong) version_id < 0 || version_id > 999999 ||
+ (version_id > 0 && version_id < 100400))
+ {
+ print_warning_bad_version_id(version_id);
+ return NO_ACL;
+ }
+ return adjust_access(version_id, access) & GLOBAL_ACLS;
}
- void set_access(ulong rights, bool revoke) const
+
+ void set_access(const privilege_t rights, bool revoke) const
{
- ulong access= get_access();
+ privilege_t access= get_access();
if (revoke)
access&= ~rights;
else
access|= rights;
- set_int_value("access", access & GLOBAL_ACLS);
+ set_int_value("access", (longlong) (access & GLOBAL_ACLS));
+ set_int_value("version_id", (longlong) MYSQL_VERSION_ID);
}
const char *unsafe_str(const char *s) const
{ return s[0] ? s : NULL; }
@@ -1967,17 +2051,20 @@ enum enum_acl_lists
ROLES_MAPPINGS_HASH
};
-ACL_ROLE::ACL_ROLE(ACL_USER *user, MEM_ROOT *root) : counter(0)
+ACL_ROLE::ACL_ROLE(ACL_USER *user, MEM_ROOT *root)
+ :
+ /* set initial role access the same as the table row privileges */
+ initial_role_access(user->access),
+ counter(0)
{
access= user->access;
- /* set initial role access the same as the table row privileges */
- initial_role_access= user->access;
this->user= user->user;
bzero(&parent_grantee, sizeof(parent_grantee));
flags= IS_ROLE;
}
-ACL_ROLE::ACL_ROLE(const char * rolename, ulong privileges, MEM_ROOT *root) :
+ACL_ROLE::ACL_ROLE(const char * rolename, privilege_t privileges,
+ MEM_ROOT *root) :
initial_role_access(privileges), counter(0)
{
this->access= initial_role_access;
@@ -2241,10 +2328,10 @@ bool acl_init(bool dont_read_acl_tables)
bool return_val;
DBUG_ENTER("acl_init");
- acl_cache= new Hash_filo<acl_entry>(ACL_CACHE_SIZE, 0, 0,
+ acl_cache= new Hash_filo<acl_entry>(key_memory_acl_cache, ACL_CACHE_SIZE, 0, 0,
(my_hash_get_key) acl_entry_get_key,
- (my_hash_free_key) free,
- &my_charset_utf8_bin);
+ (my_hash_free_key) my_free,
+ &my_charset_utf8mb3_bin);
/*
cache built-in native authentication plugins,
@@ -2318,7 +2405,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
grant_version++; /* Privileges updated */
const Host_table& host_table= tables.host_table();
- init_sql_alloc(&acl_memroot, "ACL", ACL_ALLOC_BLOCK_SIZE, 0, MYF(0));
+ init_sql_alloc(key_memory_acl_mem, &acl_memroot, ACL_ALLOC_BLOCK_SIZE, 0, MYF(0));
if (host_table.table_exists()) // "host" table may not exist (e.g. in MySQL 5.6.7+)
{
if (host_table.init_read_record(&read_record_info))
@@ -2395,7 +2482,8 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
user.sort= get_magic_sort("hu", user.host.hostname, user.user.str);
user.hostname_length= safe_strlen(user.host.hostname);
- my_init_dynamic_array(&user.role_grants, sizeof(ACL_ROLE *), 0, 8, MYF(0));
+ my_init_dynamic_array(key_memory_acl_mem, &user.role_grants,
+ sizeof(ACL_ROLE *), 0, 8, MYF(0));
user.account_locked= user_table.get_account_locked();
@@ -2413,7 +2501,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
ACL_ROLE *entry= new (&acl_memroot) ACL_ROLE(&user, &acl_memroot);
entry->role_grants = user.role_grants;
- my_init_dynamic_array(&entry->parent_grantee,
+ my_init_dynamic_array(key_memory_acl_mem, &entry->parent_grantee,
sizeof(ACL_USER_BASE *), 0, 8, MYF(0));
my_hash_insert(&acl_roles, (uchar *)entry);
@@ -2558,7 +2646,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
DBUG_RETURN(TRUE);
MEM_ROOT temp_root;
- init_alloc_root(&temp_root, "ACL_tmp", ACL_ALLOC_BLOCK_SIZE, 0, MYF(0));
+ init_alloc_root(key_memory_acl_mem, &temp_root, ACL_ALLOC_BLOCK_SIZE, 0, MYF(0));
while (!(read_record_info.read_record()))
{
char *hostname= safe_str(get_field(&temp_root, roles_mapping_table.host()));
@@ -2677,15 +2765,16 @@ bool acl_reload(THD *thd)
old_acl_roles_mappings= acl_roles_mappings;
old_acl_proxy_users= acl_proxy_users;
old_acl_dbs= acl_dbs;
- my_init_dynamic_array(&acl_hosts, sizeof(ACL_HOST), 20, 50, MYF(0));
- my_init_dynamic_array(&acl_users, sizeof(ACL_USER), 50, 100, MYF(0));
- acl_dbs.init(50, 100);
- my_init_dynamic_array(&acl_proxy_users, sizeof(ACL_PROXY_USER), 50, 100, MYF(0));
- my_hash_init2(&acl_roles,50, &my_charset_utf8_bin,
+ my_init_dynamic_array(key_memory_acl_mem, &acl_hosts, sizeof(ACL_HOST), 20, 50, MYF(0));
+ my_init_dynamic_array(key_memory_acl_mem, &acl_users, sizeof(ACL_USER), 50, 100, MYF(0));
+ acl_dbs.init(key_memory_acl_mem, 50, 100);
+ my_init_dynamic_array(key_memory_acl_mem, &acl_proxy_users, sizeof(ACL_PROXY_USER), 50, 100, MYF(0));
+ my_hash_init2(key_memory_acl_mem, &acl_roles,50, &my_charset_utf8mb3_bin,
0, 0, 0, (my_hash_get_key) acl_role_get_key, 0,
(void (*)(void *))free_acl_role, 0);
- my_hash_init2(&acl_roles_mappings, 50, &my_charset_utf8_bin, 0, 0, 0,
- (my_hash_get_key) acl_role_map_get_key, 0, 0, 0);
+ my_hash_init2(key_memory_acl_mem, &acl_roles_mappings, 50,
+ &my_charset_utf8mb3_bin, 0, 0, 0, (my_hash_get_key)
+ acl_role_map_get_key, 0, 0, 0);
old_mem= acl_memroot;
delete_dynamic(&acl_wild_hosts);
my_hash_free(&acl_check_hosts);
@@ -2738,9 +2827,9 @@ end:
privilege mask
*/
-static ulong get_access(TABLE *form, uint fieldnr, uint *next_field)
+static privilege_t get_access(TABLE *form, uint fieldnr, uint *next_field)
{
- ulong access_bits=0,bit;
+ ulonglong access_bits=0,bit;
char buff[2];
String res(buff,sizeof(buff),&my_charset_latin1);
Field **pos;
@@ -2755,7 +2844,7 @@ static ulong get_access(TABLE *form, uint fieldnr, uint *next_field)
}
if (next_field)
*next_field=fieldnr;
- return access_bits;
+ return ALL_KNOWN_ACL & access_bits;
}
@@ -2959,7 +3048,7 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host,
mysql_mutex_lock(&acl_cache->lock);
- sctx->db_access= 0;
+ sctx->db_access= NO_ACL;
if (host[0]) // User, not Role
{
@@ -2999,7 +3088,7 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host,
}
static int check_user_can_set_role(const char *user, const char *host,
- const char *ip, const char *rolename, ulonglong *access)
+ const char *ip, const char *rolename, privilege_t *access)
{
ACL_ROLE *role;
ACL_USER_BASE *acl_user_base;
@@ -3067,7 +3156,7 @@ end:
}
-int acl_check_setrole(THD *thd, const char *rolename, ulonglong *access)
+int acl_check_setrole(THD *thd, const char *rolename, privilege_t *access)
{
/* Yes! priv_user@host. Don't ask why - that's what check_access() does. */
return check_user_can_set_role(thd->security_ctx->priv_user,
@@ -3075,11 +3164,11 @@ int acl_check_setrole(THD *thd, const char *rolename, ulonglong *access)
}
-int acl_setrole(THD *thd, const char *rolename, ulonglong access)
+int acl_setrole(THD *thd, const char *rolename, privilege_t access)
{
/* merge the privileges */
Security_context *sctx= thd->security_ctx;
- sctx->master_access= static_cast<ulong>(access);
+ sctx->master_access= access;
if (thd->db.str)
sctx->db_access= acl_get(sctx->host, sctx->ip, sctx->user, thd->db.str, FALSE);
@@ -3105,7 +3194,7 @@ static uchar* check_get_key(ACL_USER *buff, size_t *length,
}
-static void acl_update_role(const char *rolename, ulong privileges)
+static void acl_update_role(const char *rolename, const privilege_t privileges)
{
ACL_ROLE *role= find_acl_role(rolename);
if (role)
@@ -3115,7 +3204,7 @@ static void acl_update_role(const char *rolename, ulong privileges)
ACL_USER::ACL_USER(THD *thd, const LEX_USER &combo,
const Account_options &options,
- const ulong privileges)
+ const privilege_t privileges)
{
user= safe_lexcstrdup_root(&acl_memroot, combo.user);
update_hostname(&host, safe_strdup_root(&acl_memroot, combo.host.str));
@@ -3123,14 +3212,14 @@ ACL_USER::ACL_USER(THD *thd, const LEX_USER &combo,
sort= get_magic_sort("hu", host.hostname, user.str);
password_last_changed= thd->query_start();
password_lifetime= -1;
- my_init_dynamic_array(&role_grants, sizeof(ACL_USER *), 0, 8, MYF(0));
+ my_init_dynamic_array(PSI_INSTRUMENT_ME, &role_grants, sizeof(ACL_USER *), 0, 8, MYF(0));
}
static int acl_user_update(THD *thd, ACL_USER *acl_user, uint nauth,
const LEX_USER &combo,
const Account_options &options,
- const ulong privileges)
+ const privilege_t privileges)
{
if (nauth)
{
@@ -3202,22 +3291,23 @@ static int acl_user_update(THD *thd, ACL_USER *acl_user, uint nauth,
}
-static void acl_insert_role(const char *rolename, ulong privileges)
+static void acl_insert_role(const char *rolename, privilege_t privileges)
{
ACL_ROLE *entry;
mysql_mutex_assert_owner(&acl_cache->lock);
entry= new (&acl_memroot) ACL_ROLE(rolename, privileges, &acl_memroot);
- my_init_dynamic_array(&entry->parent_grantee,
+ my_init_dynamic_array(key_memory_acl_mem, &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_init_dynamic_array(key_memory_acl_mem, &entry->role_grants,
+ sizeof(ACL_ROLE *), 0, 8, MYF(0));
my_hash_insert(&acl_roles, (uchar *)entry);
}
static bool acl_update_db(const char *user, const char *host, const char *db,
- ulong privileges)
+ privilege_t privileges)
{
mysql_mutex_assert_owner(&acl_cache->lock);
@@ -3269,7 +3359,7 @@ static bool acl_update_db(const char *user, const char *host, const char *db,
*/
static void acl_insert_db(const char *user, const char *host, const char *db,
- ulong privileges)
+ const privilege_t privileges)
{
ACL_DB acl_db;
mysql_mutex_assert_owner(&acl_cache->lock);
@@ -3290,10 +3380,10 @@ static void acl_insert_db(const char *user, const char *host, const char *db,
acl_cache is not used if db_is_pattern is set.
*/
-ulong acl_get(const char *host, const char *ip,
- const char *user, const char *db, my_bool db_is_pattern)
+privilege_t acl_get(const char *host, const char *ip,
+ const char *user, const char *db, my_bool db_is_pattern)
{
- ulong host_access= ~(ulong)0, db_access= 0;
+ privilege_t host_access(ALL_KNOWN_ACL), db_access(NO_ACL);
uint i;
size_t key_length;
char key[ACL_KEY_LENGTH],*tmp_db,*end;
@@ -3304,7 +3394,7 @@ ulong acl_get(const char *host, const char *ip,
end= strnmov(tmp_db, db, key + sizeof(key) - tmp_db);
if (end >= key + sizeof(key)) // db name was truncated
- DBUG_RETURN(0); // no privileges for an invalid db name
+ DBUG_RETURN(NO_ACL); // no privileges for an invalid db name
if (lower_case_table_names)
{
@@ -3318,7 +3408,7 @@ ulong acl_get(const char *host, const char *ip,
{
db_access=entry->access;
mysql_mutex_unlock(&acl_cache->lock);
- DBUG_PRINT("exit", ("access: 0x%lx", db_access));
+ DBUG_PRINT("exit", ("access: 0x%llx", (longlong) db_access));
DBUG_RETURN(db_access);
}
@@ -3341,7 +3431,7 @@ ulong acl_get(const char *host, const char *ip,
/*
No host specified for user. Get hostdata from host table
*/
- host_access=0; // Host must be found
+ host_access= NO_ACL; // Host must be found
for (i=0 ; i < acl_hosts.elements ; i++)
{
ACL_HOST *acl_host=dynamic_element(&acl_hosts,i,ACL_HOST*);
@@ -3357,7 +3447,8 @@ ulong acl_get(const char *host, const char *ip,
exit:
/* Save entry in cache for quick retrieval */
if (!db_is_pattern &&
- (entry= (acl_entry*) malloc(sizeof(acl_entry)+key_length)))
+ (entry= (acl_entry*) my_malloc(key_memory_acl_cache,
+ sizeof(acl_entry)+key_length, MYF(MY_WME))))
{
entry->access=(db_access & host_access);
DBUG_ASSERT(key_length < 0xffff);
@@ -3366,7 +3457,7 @@ exit:
acl_cache->add(entry);
}
mysql_mutex_unlock(&acl_cache->lock);
- DBUG_PRINT("exit", ("access: 0x%lx", db_access & host_access));
+ DBUG_PRINT("exit", ("access: 0x%llx", (longlong) (db_access & host_access)));
DBUG_RETURN(db_access & host_access);
}
@@ -3381,9 +3472,10 @@ exit:
static void init_check_host(void)
{
DBUG_ENTER("init_check_host");
- (void) my_init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip),
+ (void) my_init_dynamic_array(key_memory_acl_mem, &acl_wild_hosts,
+ sizeof(struct acl_host_and_ip),
acl_users.elements, 1, MYF(0));
- (void) my_hash_init(&acl_check_hosts,system_charset_info,
+ (void) my_hash_init(key_memory_acl_mem, &acl_check_hosts,system_charset_info,
acl_users.elements, 0, 0,
(my_hash_get_key) check_get_key, 0, 0);
if (!allow_all_hosts)
@@ -4168,7 +4260,7 @@ bool hostname_requires_resolving(const char *hostname)
if (hostname == my_localhost ||
(hostname_len == localhost_len &&
- !my_strnncoll(system_charset_info,
+ !system_charset_info->strnncoll(
(const uchar *) hostname, hostname_len,
(const uchar *) my_localhost, strlen(my_localhost))))
{
@@ -4279,7 +4371,7 @@ static bool test_if_create_new_users(THD *thd)
if (!create_new_users)
{
TABLE_LIST tl;
- ulong db_access;
+ privilege_t db_access(NO_ACL);
tl.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_TABLE_NAME[USER_TABLE],
NULL, TL_WRITE);
create_new_users= 1;
@@ -4304,7 +4396,7 @@ static bool test_if_create_new_users(THD *thd)
static USER_AUTH auth_no_password;
static int replace_user_table(THD *thd, const User_table &user_table,
- LEX_USER * const combo, ulong rights,
+ LEX_USER * const combo, privilege_t rights,
const bool revoke_grant, const bool can_create_user,
const bool no_auto_create)
{
@@ -4559,10 +4651,11 @@ end:
static int replace_db_table(TABLE *table, const char *db,
const LEX_USER &combo,
- ulong rights, const bool revoke_grant)
+ privilege_t rights, const bool revoke_grant)
{
uint i;
- ulong priv,store_rights;
+ ulonglong priv;
+ privilege_t store_rights(NO_ACL);
bool old_row_exists=0;
int error;
char what= revoke_grant ? 'N' : 'Y';
@@ -4968,17 +5061,17 @@ class GRANT_COLUMN :public Sql_alloc
{
public:
char *column;
- ulong rights;
- ulong init_rights;
+ privilege_t rights;
+ privilege_t init_rights;
uint key_length;
- GRANT_COLUMN(String &c, ulong y) :rights (y), init_rights(y)
+ GRANT_COLUMN(String &c, privilege_t y) :rights (y), init_rights(y)
{
column= (char*) memdup_root(&grant_memroot,c.ptr(), key_length=c.length());
}
/* this constructor assumes thas source->column is allocated in grant_memroot */
GRANT_COLUMN(GRANT_COLUMN *source) : column(source->column),
- rights (source->rights), init_rights(0), key_length(source->key_length) { }
+ rights (source->rights), init_rights(NO_ACL), key_length(source->key_length) { }
};
@@ -4994,37 +5087,43 @@ class GRANT_NAME :public Sql_alloc
public:
acl_host_and_ip host;
char *db, *user, *tname, *hash_key;
- ulong privs;
- ulong init_privs; /* privileges found in physical table */
+ privilege_t privs;
+ privilege_t init_privs; /* privileges found in physical table */
ulonglong sort;
size_t key_length;
GRANT_NAME(const char *h, const char *d,const char *u,
- const char *t, ulong p, bool is_routine);
+ const char *t, privilege_t p, bool is_routine);
GRANT_NAME (TABLE *form, bool is_routine);
virtual ~GRANT_NAME() {};
- virtual bool ok() { return privs != 0; }
+ virtual bool ok() { return privs != NO_ACL; }
void set_user_details(const char *h, const char *d,
const char *u, const char *t,
bool is_routine);
};
+static privilege_t get_access_value_from_val_int(Field *field)
+{
+ return privilege_t(ALL_KNOWN_ACL & (ulonglong) field->val_int());
+}
+
+
class GRANT_TABLE :public GRANT_NAME
{
public:
- ulong cols;
- ulong init_cols; /* privileges found in physical table */
+ privilege_t cols;
+ privilege_t init_cols; /* privileges found in physical table */
HASH hash_columns;
GRANT_TABLE(const char *h, const char *d,const char *u,
- const char *t, ulong p, ulong c);
+ const char *t, privilege_t p, privilege_t c);
GRANT_TABLE (TABLE *form, TABLE *col_privs);
~GRANT_TABLE();
- bool ok() { return privs != 0 || cols != 0; }
+ bool ok() { return privs != NO_ACL || cols != NO_ACL; }
void init_hash()
{
- my_hash_init2(&hash_columns, 4, system_charset_info, 0, 0, 0,
- (my_hash_get_key) get_key_column, 0, 0, 0);
+ my_hash_init2(key_memory_acl_memex, &hash_columns, 4, system_charset_info,
+ 0, 0, 0, (my_hash_get_key) get_key_column, 0, 0, 0);
}
};
@@ -5055,15 +5154,15 @@ void GRANT_NAME::set_user_details(const char *h, const char *d,
}
GRANT_NAME::GRANT_NAME(const char *h, const char *d,const char *u,
- const char *t, ulong p, bool is_routine)
+ const char *t, privilege_t p, bool is_routine)
:db(0), tname(0), privs(p), init_privs(p)
{
set_user_details(h, d, u, t, is_routine);
}
GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u,
- const char *t, ulong p, ulong c)
- :GRANT_NAME(h,d,u,t,p, FALSE), cols(c)
+ const char *t, privilege_t p, privilege_t c)
+ :GRANT_NAME(h,d,u,t,p, FALSE), cols(c), init_cols(NO_ACL)
{
init_hash();
}
@@ -5073,6 +5172,7 @@ GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u,
to 0
*/
GRANT_NAME::GRANT_NAME(TABLE *form, bool is_routine)
+ :privs(NO_ACL), init_privs(NO_ACL)
{
user= safe_str(get_field(&grant_memroot,form->field[2]));
@@ -5088,7 +5188,6 @@ GRANT_NAME::GRANT_NAME(TABLE *form, bool is_routine)
if (!db || !tname)
{
/* Wrong table row; Ignore it */
- privs= 0;
return; /* purecov: inspected */
}
sort= get_magic_sort("hdu", host.hostname, db, user);
@@ -5103,14 +5202,14 @@ GRANT_NAME::GRANT_NAME(TABLE *form, bool is_routine)
key_length= (strlen(db) + strlen(user) + strlen(tname) + 3);
hash_key= (char*) alloc_root(&grant_memroot, key_length);
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
- privs = (ulong) form->field[6]->val_int();
+ privs = get_access_value_from_val_int(form->field[6]);
privs = fix_rights_for_table(privs);
init_privs= privs;
}
GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
- :GRANT_NAME(form, FALSE)
+ :GRANT_NAME(form, FALSE), cols(NO_ACL), init_cols(NO_ACL)
{
uchar key[MAX_KEY_LENGTH];
@@ -5118,10 +5217,10 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
{
/* Wrong table row; Ignore it */
my_hash_clear(&hash_columns); /* allow for destruction */
- cols= 0;
+ cols= NO_ACL;
return;
}
- cols= (ulong) form->field[7]->val_int();
+ cols= get_access_value_from_val_int(form->field[7]);
cols= fix_rights_for_column(cols);
/*
Initial columns privileges are the same as column privileges on creation.
@@ -5153,8 +5252,8 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
if (col_privs->file->ha_index_init(0, 1))
{
- cols= 0;
- init_cols= 0;
+ cols= NO_ACL;
+ init_cols= NO_ACL;
return;
}
@@ -5162,8 +5261,8 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
(key_part_map)15,
HA_READ_KEY_EXACT))
{
- cols= 0; /* purecov: deadcode */
- init_cols= 0;
+ cols= NO_ACL; /* purecov: deadcode */
+ init_cols= NO_ACL;
col_privs->file->ha_index_end();
return;
}
@@ -5173,18 +5272,18 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
GRANT_COLUMN *mem_check;
/* As column name is a string, we don't have to supply a buffer */
res=col_privs->field[4]->val_str(&column_name);
- ulong priv= (ulong) col_privs->field[6]->val_int();
+ privilege_t priv= get_access_value_from_val_int(col_privs->field[6]);
if (!(mem_check = new GRANT_COLUMN(*res,
fix_rights_for_column(priv))))
{
/* Don't use this entry */
- privs= cols= init_privs= init_cols=0; /* purecov: deadcode */
+ privs= cols= init_privs= init_cols= NO_ACL; /* purecov: deadcode */
return; /* purecov: deadcode */
}
if (my_hash_insert(&hash_columns, (uchar *) mem_check))
{
/* Invalidate this entry */
- privs= cols= init_privs= init_cols=0;
+ privs= cols= init_privs= init_cols= NO_ACL;
return;
}
} while (!col_privs->file->ha_index_next(col_privs->record[0]) &&
@@ -5290,8 +5389,7 @@ column_hash_search(GRANT_TABLE *t, const char *cname, size_t length)
{
if (!my_hash_inited(&t->hash_columns))
return (GRANT_COLUMN*) 0;
- return (GRANT_COLUMN*) my_hash_search(&t->hash_columns,
- (uchar*) cname, length);
+ return (GRANT_COLUMN*)my_hash_search(&t->hash_columns, (uchar*)cname, length);
}
@@ -5299,7 +5397,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
TABLE *table, const LEX_USER &combo,
List <LEX_COLUMN> &columns,
const char *db, const char *table_name,
- ulong rights, bool revoke_grant)
+ privilege_t rights, bool revoke_grant)
{
int result=0;
uchar key[MAX_KEY_LENGTH];
@@ -5337,7 +5435,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
while ((column= iter++))
{
- ulong privileges= column->rights;
+ privilege_t privileges= column->rights;
bool old_row_exists=0;
uchar user_key[MAX_KEY_LENGTH];
@@ -5369,7 +5467,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
}
else
{
- ulong tmp= (ulong) table->field[6]->val_int();
+ privilege_t tmp= get_access_value_from_val_int(table->field[6]);
tmp=fix_rights_for_column(tmp);
if (revoke_grant)
@@ -5439,7 +5537,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
/* Scan through all rows with the same host,db,user and table */
do
{
- ulong privileges = (ulong) table->field[6]->val_int();
+ privilege_t privileges = get_access_value_from_val_int(table->field[6]);
privileges=fix_rights_for_column(privileges);
store_record(table,record[1]);
@@ -5452,7 +5550,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
privileges&= ~rights;
table->field[6]->store((longlong)
- get_rights_for_column(privileges), TRUE);
+ get_rights_for_column(privileges), TRUE);
table->field[4]->val_str(&column_name);
grant_column = column_hash_search(g_t,
column_name.ptr(),
@@ -5516,13 +5614,13 @@ static inline void get_grantor(THD *thd, char *grantor)
static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
TABLE *table, const LEX_USER &combo,
const char *db, const char *table_name,
- ulong rights, ulong col_rights,
+ privilege_t rights, privilege_t col_rights,
bool revoke_grant)
{
char grantor[USER_HOST_BUFF_SIZE];
int old_row_exists = 1;
int error=0;
- ulong store_table_rights, store_col_rights;
+ privilege_t store_table_rights(NO_ACL), store_col_rights(NO_ACL);
uchar user_key[MAX_KEY_LENGTH];
DBUG_ENTER("replace_table_table");
@@ -5578,10 +5676,9 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
store_col_rights= get_rights_for_column(col_rights);
if (old_row_exists)
{
- ulong j,k;
store_record(table,record[1]);
- j = (ulong) table->field[6]->val_int();
- k = (ulong) table->field[7]->val_int();
+ privilege_t j= get_access_value_from_val_int(table->field[6]);
+ privilege_t k= get_access_value_from_val_int(table->field[7]);
if (revoke_grant)
{
@@ -5649,12 +5746,11 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
TABLE *table, const LEX_USER &combo,
const char *db, const char *routine_name,
const Sp_handler *sph,
- ulong rights, bool revoke_grant)
+ privilege_t rights, bool revoke_grant)
{
char grantor[USER_HOST_BUFF_SIZE];
int old_row_exists= 1;
int error=0;
- ulong store_proc_rights;
HASH *hash= sph->get_priv_hash();
DBUG_ENTER("replace_routine_table");
@@ -5712,12 +5808,11 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
restore_record(table,record[1]); // Get saved record
}
- store_proc_rights= get_rights_for_procedure(rights);
+ privilege_t store_proc_rights= get_rights_for_procedure(rights);
if (old_row_exists)
{
- ulong j;
store_record(table,record[1]);
- j= (ulong) table->field[6]->val_int();
+ privilege_t j= get_access_value_from_val_int(table->field[6]);
if (revoke_grant)
{
@@ -5810,19 +5905,19 @@ struct PRIVS_TO_MERGE
};
-static enum PRIVS_TO_MERGE::what sp_privs_to_merge(stored_procedure_type type)
+static enum PRIVS_TO_MERGE::what sp_privs_to_merge(enum_sp_type type)
{
switch (type) {
- case TYPE_ENUM_FUNCTION:
+ case SP_TYPE_FUNCTION:
return PRIVS_TO_MERGE::FUNC;
- case TYPE_ENUM_PROCEDURE:
+ case SP_TYPE_PROCEDURE:
return PRIVS_TO_MERGE::PROC;
- case TYPE_ENUM_PACKAGE:
+ case SP_TYPE_PACKAGE:
return PRIVS_TO_MERGE::PACKAGE_SPEC;
- case TYPE_ENUM_PACKAGE_BODY:
+ case SP_TYPE_PACKAGE_BODY:
return PRIVS_TO_MERGE::PACKAGE_BODY;
- case TYPE_ENUM_TRIGGER:
- case TYPE_ENUM_PROXY:
+ case SP_TYPE_EVENT:
+ case SP_TYPE_TRIGGER:
break;
}
DBUG_ASSERT(0);
@@ -6120,7 +6215,7 @@ typedef Hash_set<ACL_ROLE> role_hash_t;
static bool merge_role_global_privileges(ACL_ROLE *grantee)
{
- ulong old= grantee->access;
+ privilege_t old= grantee->access;
grantee->access= grantee->initial_role_access;
DBUG_EXECUTE_IF("role_merge_stats", role_global_merges++;);
@@ -6151,7 +6246,7 @@ static int db_name_sort(const int *db1, const int *db2)
2 - ACL_DB was added
4 - ACL_DB was deleted
*/
-static int update_role_db(int merged, int first, ulong access,
+static int update_role_db(int merged, int first, privilege_t access,
const char *role)
{
if (first < 0)
@@ -6176,12 +6271,12 @@ static int update_role_db(int merged, int first, ulong access,
acl_db.host.ip= acl_db.host.ip_mask= 0;
acl_db.db= acl_dbs.at(first).db;
acl_db.access= access;
- acl_db.initial_access= 0;
+ acl_db.initial_access= NO_ACL;
acl_db.sort= get_magic_sort("hdu", "", acl_db.db, role);
acl_dbs.push(acl_db);
return 2;
}
- else if (access == 0)
+ else if (access == NO_ACL)
{
/*
there is ACL_DB but the role has no db privileges granted
@@ -6215,7 +6310,7 @@ static int update_role_db(int merged, int first, ulong access,
static bool merge_role_db_privileges(ACL_ROLE *grantee, const char *dbname,
role_hash_t *rhash)
{
- Dynamic_array<int> dbs;
+ Dynamic_array<int> dbs(PSI_INSTRUMENT_MEM);
/*
Supposedly acl_dbs can be huge, but only a handful of db grants
@@ -6243,14 +6338,15 @@ static bool merge_role_db_privileges(ACL_ROLE *grantee, const char *dbname,
is not necessarily the first and may be not present at all.
*/
int first= -1, merged= -1;
- ulong access= 0, update_flags= 0;
+ privilege_t access(NO_ACL);
+ ulong update_flags= 0;
for (int *p= dbs.front(); p <= dbs.back(); p++)
{
if (first<0 || (!dbname && strcmp(acl_dbs.at(p[0]).db, acl_dbs.at(p[-1]).db)))
{ // new db name series
update_flags|= update_role_db(merged, first, access, grantee->user.str);
merged= -1;
- access= 0;
+ access= NO_ACL;
first= *p;
}
if (strcmp(acl_dbs.at(*p).user, grantee->user.str) == 0)
@@ -6308,7 +6404,7 @@ static int update_role_columns(GRANT_TABLE *merged,
GRANT_TABLE **cur, GRANT_TABLE **last)
{
- ulong rights __attribute__((unused))= 0;
+ privilege_t rights __attribute__((unused)) (NO_ACL);
int changed= 0;
if (!merged->cols)
{
@@ -6378,7 +6474,8 @@ static int update_role_columns(GRANT_TABLE *merged,
*/
static int update_role_table_columns(GRANT_TABLE *merged,
GRANT_TABLE **first, GRANT_TABLE **last,
- ulong privs, ulong cols, const char *role)
+ privilege_t privs, privilege_t cols,
+ const char *role)
{
if (!first)
return 0;
@@ -6394,12 +6491,12 @@ static int update_role_table_columns(GRANT_TABLE *merged,
DBUG_ASSERT(privs | cols);
merged= new (&grant_memroot) GRANT_TABLE("", first[0]->db, role, first[0]->tname,
privs, cols);
- merged->init_privs= merged->init_cols= 0;
+ merged->init_privs= merged->init_cols= NO_ACL;
update_role_columns(merged, first, last);
my_hash_insert(&column_priv_hash,(uchar*) merged);
return 2;
}
- else if ((privs | cols) == 0)
+ else if ((privs | cols) == NO_ACL)
{
/*
there is GRANT_TABLE object but the role has no table or column
@@ -6432,7 +6529,7 @@ static int update_role_table_columns(GRANT_TABLE *merged,
static bool merge_role_table_and_column_privileges(ACL_ROLE *grantee,
const char *db, const char *tname, role_hash_t *rhash)
{
- Dynamic_array<GRANT_TABLE *> grants;
+ Dynamic_array<GRANT_TABLE *> grants(PSI_INSTRUMENT_MEM);
DBUG_ASSERT(MY_TEST(db) == MY_TEST(tname)); // both must be set, or neither
/*
@@ -6454,7 +6551,8 @@ static bool merge_role_table_and_column_privileges(ACL_ROLE *grantee,
grants.sort(table_name_sort);
GRANT_TABLE **first= NULL, *merged= NULL, **cur;
- ulong privs= 0, cols= 0, update_flags= 0;
+ privilege_t privs(NO_ACL), cols(NO_ACL);
+ ulong update_flags= 0;
for (cur= grants.front(); cur <= grants.back(); cur++)
{
if (!first ||
@@ -6464,7 +6562,7 @@ static bool merge_role_table_and_column_privileges(ACL_ROLE *grantee,
update_flags|= update_role_table_columns(merged, first, cur,
privs, cols, grantee->user.str);
merged= NULL;
- privs= cols= 0;
+ privs= cols= NO_ACL;
first= cur;
}
if (strcmp(cur[0]->user, grantee->user.str) == 0)
@@ -6507,7 +6605,7 @@ static int routine_name_sort(GRANT_NAME * const *r1, GRANT_NAME * const *r2)
4 - GRANT_NAME was deleted
*/
static int update_role_routines(GRANT_NAME *merged, GRANT_NAME **first,
- ulong privs, const char *role, HASH *hash)
+ privilege_t privs, const char *role, HASH *hash)
{
if (!first)
return 0;
@@ -6523,11 +6621,11 @@ static int update_role_routines(GRANT_NAME *merged, GRANT_NAME **first,
DBUG_ASSERT(privs);
merged= new (&grant_memroot) GRANT_NAME("", first[0]->db, role, first[0]->tname,
privs, true);
- merged->init_privs= 0; // all privs are inherited
+ merged->init_privs= NO_ACL; // all privs are inherited
my_hash_insert(hash, (uchar *)merged);
return 2;
}
- else if (privs == 0)
+ else if (privs == NO_ACL)
{
/*
there is GRANT_NAME but the role has no privileges granted
@@ -6560,7 +6658,7 @@ static bool merge_role_routine_grant_privileges(ACL_ROLE *grantee,
DBUG_ASSERT(MY_TEST(db) == MY_TEST(tname)); // both must be set, or neither
- Dynamic_array<GRANT_NAME *> grants;
+ Dynamic_array<GRANT_NAME *> grants(PSI_INSTRUMENT_MEM);
/* first, collect routine privileges granted to roles in question */
for (uint i=0 ; i < hash->records ; i++)
@@ -6578,7 +6676,7 @@ static bool merge_role_routine_grant_privileges(ACL_ROLE *grantee,
grants.sort(routine_name_sort);
GRANT_NAME **first= NULL, *merged= NULL;
- ulong privs= 0 ;
+ privilege_t privs(NO_ACL);
for (GRANT_NAME **cur= grants.front(); cur <= grants.back(); cur++)
{
if (!first ||
@@ -6588,7 +6686,7 @@ static bool merge_role_routine_grant_privileges(ACL_ROLE *grantee,
update_flags|= update_role_routines(merged, first, privs,
grantee->user.str, hash);
merged= NULL;
- privs= 0;
+ privs= NO_ACL;
first= cur;
}
if (strcmp(cur[0]->user, grantee->user.str) == 0)
@@ -6621,7 +6719,7 @@ static int merge_role_privileges(ACL_ROLE *role __attribute__((unused)),
grantee->counter= 1; // Mark the grantee as merged.
/* if we'll do db/table/routine privileges, create a hash of role names */
- role_hash_t role_hash(role_key);
+ role_hash_t role_hash(PSI_INSTRUMENT_MEM, role_key);
if (data->what != PRIVS_TO_MERGE::GLOBAL)
{
role_hash.insert(grantee);
@@ -6712,10 +6810,10 @@ static bool copy_and_check_auth(LEX_USER *to, LEX_USER *from, THD *thd)
int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
List <LEX_USER> &user_list,
- List <LEX_COLUMN> &columns, ulong rights,
+ List <LEX_COLUMN> &columns, privilege_t rights,
bool revoke_grant)
{
- ulong column_priv= 0;
+ privilege_t column_priv(NO_ACL);
int result;
List_iterator <LEX_USER> str_list (user_list);
LEX_USER *Str, *tmp_Str;
@@ -6835,7 +6933,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,
- 0, revoke_grant, create_new_users,
+ NO_ACL, revoke_grant, create_new_users,
MY_TEST(thd->variables.sql_mode &
MODE_NO_AUTO_CREATE_USER));
if (unlikely(error))
@@ -6888,7 +6986,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
grant_column->rights&= ~(column->rights | rights);
}
/* scan trough all columns to get new column grant */
- column_priv= 0;
+ column_priv= NO_ACL;
for (uint idx=0 ; idx < grant_table->hash_columns.records ; idx++)
{
grant_column= (GRANT_COLUMN*)
@@ -6965,7 +7063,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list,
const Sp_handler *sph,
- List <LEX_USER> &user_list, ulong rights,
+ List <LEX_USER> &user_list, privilege_t rights,
bool revoke_grant, bool write_to_binlog)
{
List_iterator <LEX_USER> str_list (user_list);
@@ -7015,7 +7113,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,
- 0, revoke_grant, create_new_users,
+ NO_ACL, revoke_grant, create_new_users,
MY_TEST(thd->variables.sql_mode &
MODE_NO_AUTO_CREATE_USER)))
{
@@ -7286,7 +7384,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, NO_ACL,
false, create_new_user,
no_auto_create_user))
{
@@ -7399,7 +7497,7 @@ bool mysql_grant_role(THD *thd, List <LEX_USER> &list, bool revoke)
bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
- ulong rights, bool revoke_grant, bool is_proxy)
+ privilege_t rights, bool revoke_grant, bool is_proxy)
{
List_iterator <LEX_USER> str_list (list);
LEX_USER *Str, *tmp_Str, *proxied_user= NULL;
@@ -7458,13 +7556,14 @@ 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,
- (!db ? rights : 0), revoke_grant, create_new_users,
+ (!db ? rights : NO_ACL),
+ revoke_grant, create_new_users,
MY_TEST(thd->variables.sql_mode &
MODE_NO_AUTO_CREATE_USER)))
result= true;
else if (db)
{
- ulong db_rights= rights & DB_ACLS;
+ privilege_t db_rights(rights & DB_ACLS);
if (db_rights == rights)
{
if (replace_db_table(tables.db_table().table(), db, *Str, db_rights,
@@ -7568,23 +7667,26 @@ static bool grant_load(THD *thd,
TABLE *t_table, *c_table, *p_table;
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
MEM_ROOT *save_mem_root= thd->mem_root;
- sql_mode_t old_sql_mode= thd->variables.sql_mode;
DBUG_ENTER("grant_load");
- thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
-
- (void) my_hash_init(&column_priv_hash, &my_charset_utf8_bin,
- 0,0,0, (my_hash_get_key) get_grant_table,
- (my_hash_free_key) free_grant_table,0);
- (void) my_hash_init(&proc_priv_hash, &my_charset_utf8_bin,
- 0,0,0, (my_hash_get_key) get_grant_table, 0,0);
- (void) my_hash_init(&func_priv_hash, &my_charset_utf8_bin,
- 0,0,0, (my_hash_get_key) get_grant_table, 0,0);
- (void) my_hash_init(&package_spec_priv_hash, &my_charset_utf8_bin,
- 0,0,0, (my_hash_get_key) get_grant_table, 0,0);
- (void) my_hash_init(&package_body_priv_hash, &my_charset_utf8_bin,
- 0,0,0, (my_hash_get_key) get_grant_table, 0,0);
- init_sql_alloc(&grant_memroot, "GRANT", ACL_ALLOC_BLOCK_SIZE, 0, MYF(0));
+ Sql_mode_instant_remove sms(thd, MODE_PAD_CHAR_TO_FULL_LENGTH);
+
+ (void) my_hash_init(key_memory_acl_memex, &column_priv_hash,
+ &my_charset_utf8mb3_bin, 0,0,0, (my_hash_get_key)
+ get_grant_table, (my_hash_free_key) free_grant_table, 0);
+ (void) my_hash_init(key_memory_acl_memex, &proc_priv_hash,
+ &my_charset_utf8mb3_bin, 0,0,0, (my_hash_get_key)
+ get_grant_table, 0,0);
+ (void) my_hash_init(key_memory_acl_memex, &func_priv_hash,
+ &my_charset_utf8mb3_bin, 0,0,0, (my_hash_get_key)
+ get_grant_table, 0,0);
+ (void) my_hash_init(key_memory_acl_memex, &package_spec_priv_hash,
+ &my_charset_utf8mb3_bin, 0,0,0, (my_hash_get_key)
+ get_grant_table, 0,0);
+ (void) my_hash_init(key_memory_acl_memex, &package_body_priv_hash,
+ &my_charset_utf8mb3_bin, 0,0,0, (my_hash_get_key)
+ get_grant_table, 0,0);
+ init_sql_alloc(key_memory_acl_mem, &grant_memroot, ACL_ALLOC_BLOCK_SIZE, 0, MYF(0));
t_table= tables_priv.table();
c_table= columns_priv.table();
@@ -7665,7 +7767,7 @@ static bool grant_load(THD *thd,
continue;
}
}
- stored_procedure_type type= (stored_procedure_type)procs_priv.routine_type()->val_int();
+ enum_sp_type type= (enum_sp_type)procs_priv.routine_type()->val_int();
const Sp_handler *sph= Sp_handler::handler(type);
if (!sph || !(hash= sph->get_priv_hash()))
{
@@ -7696,7 +7798,6 @@ end_unlock:
t_table->file->ha_index_end();
thd->mem_root= save_mem_root;
end_index_init:
- thd->variables.sql_mode= old_sql_mode;
DBUG_RETURN(return_val);
}
@@ -7840,14 +7941,14 @@ bool grant_reload(THD *thd)
*/
-bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
+bool check_grant(THD *thd, privilege_t want_access, TABLE_LIST *tables,
bool any_combination_will_do, uint number, bool no_errors)
{
TABLE_LIST *tl;
TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
Security_context *sctx= thd->security_ctx;
uint i;
- ulong original_want_access= want_access;
+ privilege_t original_want_access(want_access);
bool locked= 0;
GRANT_TABLE *grant_table;
GRANT_TABLE *grant_table_role= NULL;
@@ -7881,7 +7982,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
TABLE_LIST *const t_ref=
tl->correspondent_table ? tl->correspondent_table : tl;
sctx= t_ref->security_ctx ? t_ref->security_ctx : thd->security_ctx;
- ulong orig_want_access= original_want_access;
+ privilege_t orig_want_access(original_want_access);
/*
If sequence is used as part of NEXT VALUE, PREVIOUS VALUE or SELECT,
@@ -7914,15 +8015,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
switch(access->check(orig_want_access, &t_ref->grant.privilege))
{
case ACL_INTERNAL_ACCESS_GRANTED:
- /*
- Currently,
- - the information_schema does not subclass ACL_internal_table_access,
- there are no per table privilege checks for I_S,
- - the performance schema does use per tables checks, but at most
- returns 'CHECK_GRANT', and never 'ACCESS_GRANTED'.
- so this branch is not used.
- */
- DBUG_ASSERT(0);
+ continue;
case ACL_INTERNAL_ACCESS_DENIED:
goto err;
case ACL_INTERNAL_ACCESS_CHECK_GRANT:
@@ -7952,7 +8045,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
clause, or an INFORMATION_SCHEMA table, drop the request for
a privilege.
*/
- t_ref->grant.want_privilege= 0;
+ t_ref->grant.want_privilege= NO_ACL;
}
continue;
}
@@ -7966,7 +8059,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
if user has CREATE_TMP_ACL.
*/
t_ref->grant.privilege|= TMP_TABLE_ACLS;
- t_ref->grant.want_privilege= 0;
+ t_ref->grant.want_privilege= NO_ACL;
continue;
}
@@ -8003,15 +8096,15 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
t_ref->grant.grant_table_user= grant_table; // Remember for column test
t_ref->grant.grant_table_role= grant_table_role;
t_ref->grant.version= grant_version;
- t_ref->grant.privilege|= grant_table ? grant_table->privs : 0;
- t_ref->grant.privilege|= grant_table_role ? grant_table_role->privs : 0;
+ t_ref->grant.privilege|= grant_table ? grant_table->privs : NO_ACL;
+ t_ref->grant.privilege|= grant_table_role ? grant_table_role->privs : NO_ACL;
t_ref->grant.want_privilege= ((want_access & COL_ACLS) & ~t_ref->grant.privilege);
if (!(~t_ref->grant.privilege & want_access))
continue;
- if ((want_access&= ~((grant_table ? grant_table->cols : 0) |
- (grant_table_role ? grant_table_role->cols : 0) |
+ if ((want_access&= ~((grant_table ? grant_table->cols : NO_ACL) |
+ (grant_table_role ? grant_table_role->cols : NO_ACL) |
t_ref->grant.privilege)))
{
goto err; // impossible
@@ -8065,9 +8158,10 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant,
GRANT_TABLE *grant_table;
GRANT_TABLE *grant_table_role;
GRANT_COLUMN *grant_column;
- ulong want_access= grant->want_privilege & ~grant->privilege;
+ privilege_t want_access(grant->want_privilege & ~grant->privilege);
DBUG_ENTER("check_grant_column");
- DBUG_PRINT("enter", ("table: %s want_access: %lu", table_name, want_access));
+ DBUG_PRINT("enter", ("table: %s want_access: %llx",
+ table_name, (longlong) want_access));
if (!want_access)
DBUG_RETURN(0); // Already checked
@@ -8172,7 +8266,7 @@ bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
if (table_ref->view || table_ref->field_translation)
{
/* View or derived information schema table. */
- ulong view_privs;
+ privilege_t view_privs(NO_ACL);
grant= &(table_ref->grant);
db_name= table_ref->view_db.str;
table_name= table_ref->view_name.str;
@@ -8223,11 +8317,11 @@ bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
For each table it will retrieve the grant information and will use it
to check the required access privileges for the fields requested from it.
*/
-bool check_grant_all_columns(THD *thd, ulong want_access_arg,
+bool check_grant_all_columns(THD *thd, privilege_t want_access_arg,
Field_iterator_table_ref *fields)
{
Security_context *sctx= thd->security_ctx;
- ulong UNINIT_VAR(want_access);
+ privilege_t want_access(NO_ACL);
const char *table_name= NULL;
const char* db_name;
GRANT_INFO *grant;
@@ -8279,7 +8373,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg,
if (want_access)
{
- ulong have_access= 0;
+ privilege_t have_access(NO_ACL);
if (grant_table)
{
GRANT_COLUMN *grant_column=
@@ -8446,7 +8540,7 @@ bool check_grant_db(THD *thd, const char *db)
1 Error: User did not have the requested privielges
****************************************************************************/
-bool check_grant_routine(THD *thd, ulong want_access,
+bool check_grant_routine(THD *thd, privilege_t want_access,
TABLE_LIST *procs, const Sp_handler *sph,
bool no_errors)
{
@@ -8549,9 +8643,8 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name,
Functions to retrieve the grant for a table/column (for SHOW functions)
*****************************************************************************/
-ulong get_table_grant(THD *thd, TABLE_LIST *table)
+privilege_t get_table_grant(THD *thd, TABLE_LIST *table)
{
- ulong privilege;
Security_context *sctx= thd->security_ctx;
const char *db = table->db.str ? table->db.str : thd->db.str;
GRANT_TABLE *grant_table;
@@ -8575,7 +8668,7 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table)
table->grant.privilege|= grant_table->privs;
if (grant_table_role)
table->grant.privilege|= grant_table_role->privs;
- privilege= table->grant.privilege;
+ privilege_t privilege(table->grant.privilege);
mysql_rwlock_unlock(&LOCK_grant);
return privilege;
}
@@ -8599,14 +8692,14 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table)
The access priviliges for the field db_name.table_name.field_name
*/
-ulong get_column_grant(THD *thd, GRANT_INFO *grant,
- const char *db_name, const char *table_name,
- const char *field_name)
+privilege_t get_column_grant(THD *thd, GRANT_INFO *grant,
+ const char *db_name, const char *table_name,
+ const char *field_name)
{
GRANT_TABLE *grant_table;
GRANT_TABLE *grant_table_role;
GRANT_COLUMN *grant_column;
- ulong priv= 0;
+ privilege_t priv(NO_ACL);
mysql_rwlock_rdlock(&LOCK_grant);
/* reload table if someone has modified any grants */
@@ -8785,19 +8878,34 @@ static const char *command_array[]=
"SELECT", "INSERT", "UPDATE", "DELETE", "CREATE", "DROP", "RELOAD",
"SHUTDOWN", "PROCESS","FILE", "GRANT", "REFERENCES", "INDEX",
"ALTER", "SHOW DATABASES", "SUPER", "CREATE TEMPORARY TABLES",
- "LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "REPLICATION CLIENT",
+ "LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "BINLOG MONITOR",
"CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE", "ALTER ROUTINE",
- "CREATE USER", "EVENT", "TRIGGER", "CREATE TABLESPACE",
- "DELETE HISTORY"
+ "CREATE USER", "EVENT", "TRIGGER", "CREATE TABLESPACE", "DELETE HISTORY",
+ "SET USER", "FEDERATED ADMIN", "CONNECTION ADMIN", "READ_ONLY ADMIN",
+ "REPLICATION SLAVE ADMIN", "REPLICATION MASTER ADMIN", "BINLOG ADMIN",
+ "BINLOG REPLAY"
};
static uint command_lengths[]=
{
- 6, 6, 6, 6, 6, 4, 6, 8, 7, 4, 5, 10, 5, 5, 14, 5, 23, 11, 7, 17, 18, 11, 9,
- 14, 13, 11, 5, 7, 17, 14,
+ 6, 6, 6, 6, 6, 4, 6,
+ 8, 7, 4, 5, 10, 5,
+ 5, 14, 5, 23,
+ 11, 7, 17, 14,
+ 11, 9, 14, 13,
+ 11, 5, 7, 17, 14,
+ 8, 15, 16, 15,
+ 23, 24, 12,
+ 13
};
+static_assert(array_elements(command_array) == PRIVILEGE_T_MAX_BIT + 1,
+ "The definition of command_array does not match privilege_t");
+static_assert(array_elements(command_lengths) == PRIVILEGE_T_MAX_BIT + 1,
+ "The definition of command_lengths does not match privilege_t");
+
+
static bool print_grants_for_role(THD *thd, ACL_ROLE * role)
{
char buff[1024];
@@ -9176,7 +9284,7 @@ static bool show_global_privileges(THD *thd, ACL_USER_BASE *acl_entry,
char *buff, size_t buffsize)
{
uint counter;
- ulong want_access;
+ privilege_t want_access(NO_ACL);
Protocol *protocol= thd->protocol;
String global(buff,sizeof(buff),system_charset_info);
@@ -9194,7 +9302,8 @@ static bool show_global_privileges(THD *thd, ACL_USER_BASE *acl_entry,
else
{
bool found=0;
- ulong j,test_access= want_access & ~GRANT_ACL;
+ ulonglong j;
+ privilege_t test_access(want_access & ~GRANT_ACL);
for (counter=0, j = SELECT_ACL;j <= GLOBAL_ACLS;counter++,j <<= 1)
{
if (test_access & j)
@@ -9241,7 +9350,7 @@ static bool show_database_privileges(THD *thd, const char *username,
const char *hostname,
char *buff, size_t buffsize)
{
- ulong want_access;
+ privilege_t want_access(NO_ACL);
Protocol *protocol= thd->protocol;
for (uint i=0 ; i < acl_dbs.elements() ; i++)
@@ -9283,7 +9392,8 @@ static bool show_database_privileges(THD *thd, const char *username,
else
{
int found=0, cnt;
- ulong j,test_access= want_access & ~GRANT_ACL;
+ ulonglong j;
+ privilege_t test_access(want_access & ~GRANT_ACL);
for (cnt=0, j = SELECT_ACL; j <= DB_ACLS; cnt++,j <<= 1)
{
if (test_access & j)
@@ -9340,8 +9450,8 @@ static bool show_table_and_column_privileges(THD *thd, const char *username,
if (!strcmp(username,user) &&
!my_strcasecmp(system_charset_info, hostname, host))
{
- ulong table_access;
- ulong cols_access;
+ privilege_t table_access(NO_ACL);
+ privilege_t cols_access(NO_ACL);
if (*hostname) // User
{
table_access= grant_table->privs;
@@ -9353,10 +9463,10 @@ static bool show_table_and_column_privileges(THD *thd, const char *username,
cols_access= grant_table->init_cols;
}
- if ((table_access | cols_access) != 0)
+ if ((table_access | cols_access) != NO_ACL)
{
String global(buff, sizeof(buff), system_charset_info);
- ulong test_access= (table_access | cols_access) & ~GRANT_ACL;
+ privilege_t test_access= (table_access | cols_access) & ~GRANT_ACL;
global.length(0);
global.append(STRING_WITH_LEN("GRANT "));
@@ -9369,7 +9479,7 @@ static bool show_table_and_column_privileges(THD *thd, const char *username,
{
/* Add specific column access */
int found= 0;
- ulong j;
+ ulonglong j;
for (counter= 0, j= SELECT_ACL; j <= TABLE_ACLS; counter++, j<<= 1)
{
@@ -9473,16 +9583,16 @@ static int show_routine_grants(THD* thd,
if (!strcmp(username, user) &&
!my_strcasecmp(system_charset_info, hostname, host))
{
- ulong proc_access;
+ privilege_t proc_access(NO_ACL);
if (*hostname) // User
proc_access= grant_proc->privs;
else // Role
proc_access= grant_proc->init_privs;
- if (proc_access != 0)
+ if (proc_access != NO_ACL)
{
String global(buff, buffsize, system_charset_info);
- ulong test_access= proc_access & ~GRANT_ACL;
+ privilege_t test_access(proc_access & ~GRANT_ACL);
global.length(0);
global.append(STRING_WITH_LEN("GRANT "));
@@ -9493,7 +9603,7 @@ static int show_routine_grants(THD* thd,
{
/* Add specific procedure access */
int found= 0;
- ulong j;
+ ulonglong j;
for (counter= 0, j= SELECT_ACL; j <= PROC_ACLS; counter++, j<<= 1)
{
@@ -9536,13 +9646,13 @@ static int show_routine_grants(THD* thd,
Make a clear-text version of the requested privilege.
*/
-void get_privilege_desc(char *to, uint max_length, ulong access)
+void get_privilege_desc(char *to, uint max_length, privilege_t access_arg)
{
uint pos;
char *start=to;
DBUG_ASSERT(max_length >= 30); // For end ', ' removal
- if (access)
+ if (ulonglong access= access_arg)
{
max_length--; // Reserve place for end-zero
for (pos=0 ; access ; pos++, access>>=1)
@@ -10580,7 +10690,8 @@ 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,
+ NO_ACL, 0, 1, 0))
{
append_user(thd, &wrong_users, user_name);
result= TRUE;
@@ -10665,7 +10776,6 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list, bool handle_as_role)
LEX_USER *user_name, *tmp_user_name;
List_iterator <LEX_USER> user_list(list);
bool binlog= false;
- sql_mode_t old_sql_mode= thd->variables.sql_mode;
DBUG_ENTER("mysql_drop_user");
DBUG_PRINT("entry", ("Handle as %s", handle_as_role ? "role" : "user"));
@@ -10677,7 +10787,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list, bool handle_as_role)
if ((result= tables.open_and_lock(thd, tables_to_open, TL_WRITE)))
DBUG_RETURN(result != 1);
- thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
+ Sql_mode_instant_remove sms(thd, MODE_PAD_CHAR_TO_FULL_LENGTH);
mysql_rwlock_wrlock(&LOCK_grant);
mysql_mutex_lock(&acl_cache->lock);
@@ -10752,7 +10862,6 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list, bool handle_as_role)
result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
mysql_rwlock_unlock(&LOCK_grant);
- thd->variables.sql_mode= old_sql_mode;
DBUG_RETURN(result);
}
@@ -10884,8 +10993,9 @@ 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 || 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, NO_ACL,
+ false, false, true))
{
thd->clear_error();
append_user(thd, &wrong_users, tmp_lex_user);
@@ -10947,7 +11057,7 @@ mysql_revoke_sp_privs(THD *thd, Grant_tables *tables, const Sp_handler *sph,
tables->procs_priv_table().table(),
*lex_user,
grant_proc->db, grant_proc->tname,
- sph, ~(ulong)0, 1) == 0)
+ sph, ALL_KNOWN_ACL, 1) == 0)
{
revoked= 1;
continue;
@@ -11013,7 +11123,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
}
if (replace_user_table(thd, tables.user_table(), lex_user,
- ~(ulong)0, 1, 0, 0))
+ ALL_KNOWN_ACL, 1, 0, 0))
{
result= -1;
continue;
@@ -11042,7 +11152,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
/* TODO(cvicentiu) refactor replace_db_table to use
Db_table instead of TABLE directly. */
if (!replace_db_table(tables.db_table().table(), acl_db->db, *lex_user,
- ~(ulong)0, 1))
+ ALL_KNOWN_ACL, 1))
{
/*
Don't increment counter as replace_db_table deleted the
@@ -11076,7 +11186,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
if (replace_table_table(thd, grant_table,
tables.tables_priv_table().table(),
*lex_user, grant_table->db,
- grant_table->tname, ~(ulong)0, 0, 1))
+ grant_table->tname, ALL_KNOWN_ACL, NO_ACL, 1))
{
result= -1;
}
@@ -11093,7 +11203,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
if (!replace_column_table(grant_table,
tables.columns_priv_table().table(),
*lex_user, columns, grant_table->db,
- grant_table->tname, ~(ulong)0, 1))
+ grant_table->tname, ALL_KNOWN_ACL, 1))
{
revoked= 1;
continue;
@@ -11291,7 +11401,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
for (counter= 0, revoked= 0 ; counter < hash->records ; )
{
GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter);
- if (!my_strcasecmp(&my_charset_utf8_bin, grant_proc->db, sp_db) &&
+ if (!my_strcasecmp(&my_charset_utf8mb3_bin, grant_proc->db, sp_db) &&
!my_strcasecmp(system_charset_info, grant_proc->tname, sp_name))
{
LEX_USER lex_user;
@@ -11302,7 +11412,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
if (replace_routine_table(thd, grant_proc,
tables.procs_priv_table().table(), lex_user,
grant_proc->db, grant_proc->tname,
- sph, ~(ulong)0, 1) == 0)
+ sph, ALL_KNOWN_ACL, 1) == 0)
{
revoked= 1;
continue;
@@ -11636,10 +11746,231 @@ static int show_database_grants(THD *thd, SHOW_VAR *var, char *buff,
#else
static bool set_user_salt_if_needed(ACL_USER *, int, plugin_ref)
{ return 0; }
-bool check_grant(THD *, ulong, TABLE_LIST *, bool, uint, bool)
+bool check_grant(THD *, privilege_t, TABLE_LIST *, bool, uint, bool)
{ return 0; }
#endif /*NO_EMBEDDED_ACCESS_CHECKS */
+
+#ifdef NO_EMBEDDED_ACCESS_CHECKS
+
+bool Sql_cmd_grant_proxy::execute(THD *thd)
+{
+ my_ok(thd);
+ return false;
+}
+
+bool Sql_cmd_grant_table::execute(THD *thd)
+{
+ my_ok(thd);
+ return false;
+}
+
+
+bool Sql_cmd_grant_sp::execute(THD *thd)
+{
+ my_ok(thd);
+ return false;
+}
+
+#else // not NO_EMBEDDED_ACCESS_CHECKS
+
+
+void Sql_cmd_grant::warn_hostname_requires_resolving(THD *thd,
+ List<LEX_USER> &users)
+{
+ LEX_USER *user;
+ List_iterator <LEX_USER> it(users);
+ while ((user= it++))
+ {
+ if (specialflag & SPECIAL_NO_RESOLVE &&
+ hostname_requires_resolving(user->host.str))
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_HOSTNAME_WONT_WORK,
+ ER_THD(thd, ER_WARN_HOSTNAME_WONT_WORK));
+ }
+}
+
+
+void Sql_cmd_grant::grant_stage0(THD *thd)
+{
+ thd->binlog_invoker(false); // Replicate current user as grantor
+ if (thd->security_ctx->user) // If not replication
+ warn_hostname_requires_resolving(thd, thd->lex->users_list);
+}
+
+
+bool Sql_cmd_grant::user_list_reset_mqh(THD *thd, List<LEX_USER> &users)
+{
+ List_iterator <LEX_USER> it(users);
+ LEX_USER *user, *tmp_user;
+ while ((tmp_user= it++))
+ {
+ if (!(user= get_current_user(thd, tmp_user)))
+ return true;
+ reset_mqh(user, 0);
+ }
+ return false;
+}
+
+
+bool Sql_cmd_grant_proxy::check_access_proxy(THD *thd, List<LEX_USER> &users)
+{
+ LEX_USER *user;
+ List_iterator <LEX_USER> it(users);
+ if ((user= it++))
+ {
+ // GRANT/REVOKE PROXY has the target user as a first entry in the list
+ if (!(user= get_current_user(thd, user)) || !user->host.str)
+ return true;
+ if (acl_check_proxy_grant_access(thd, user->host.str, user->user.str,
+ m_grant_option & GRANT_ACL))
+ return true;
+ }
+ return false;
+}
+
+
+bool Sql_cmd_grant_proxy::execute(THD *thd)
+{
+ LEX *lex= thd->lex;
+
+ DBUG_ASSERT(lex->first_select_lex()->table_list.first == NULL);
+ DBUG_ASSERT((m_grant_option & ~GRANT_ACL) == NO_ACL); // only WITH GRANT OPTION
+
+ grant_stage0(thd);
+
+ if (thd->security_ctx->user /* If not replication */ &&
+ check_access_proxy(thd, lex->users_list))
+ return true;
+
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+ /* Conditionally writes to binlog */
+ if (mysql_grant(thd, NULL/*db*/, lex->users_list, m_grant_option,
+ is_revoke(), true/*proxy*/))
+ return true;
+
+ return !is_revoke() && user_list_reset_mqh(thd, lex->users_list);
+
+#ifdef WITH_WSREP
+wsrep_error_label:
+ return true;
+#endif // WITH_WSREP
+}
+
+
+bool Sql_cmd_grant_object::grant_stage0_exact_object(THD *thd,
+ TABLE_LIST *table)
+{
+ privilege_t priv= m_object_privilege | m_column_privilege_total | GRANT_ACL;
+ if (check_access(thd, priv, table->db.str,
+ &table->grant.privilege, &table->grant.m_internal,
+ 0, 0))
+ return true;
+ grant_stage0(thd);
+ return false;
+}
+
+
+bool Sql_cmd_grant_table::execute_exact_table(THD *thd, TABLE_LIST *table)
+{
+ LEX *lex= thd->lex;
+ if (grant_stage0_exact_object(thd, table) ||
+ check_grant(thd, m_object_privilege | m_column_privilege_total | GRANT_ACL,
+ lex->query_tables, FALSE, UINT_MAX, FALSE))
+ return true;
+ /* Conditionally writes to binlog */
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+ return mysql_table_grant(thd, lex->query_tables, lex->users_list,
+ m_columns, m_object_privilege,
+ is_revoke());
+#ifdef WITH_WSREP
+wsrep_error_label:
+ return true;
+#endif // WITH_WSREP
+}
+
+
+bool Sql_cmd_grant_sp::execute(THD *thd)
+{
+ DBUG_ASSERT(!m_columns.elements);
+ DBUG_ASSERT(!m_column_privilege_total);
+ LEX *lex= thd->lex;
+ TABLE_LIST *table= lex->first_select_lex()->table_list.first;
+ privilege_t grants= m_all_privileges
+ ? (PROC_ACLS & ~GRANT_ACL) | (m_object_privilege & GRANT_ACL)
+ : m_object_privilege;
+
+ if (!table) // e.g: GRANT EXECUTE ON PROCEDURE *.*
+ {
+ my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER_THD(thd, ER_ILLEGAL_GRANT_FOR_TABLE),
+ MYF(0));
+ return true;
+ }
+
+ if (grant_stage0_exact_object(thd, table) ||
+ check_grant_routine(thd, grants|GRANT_ACL, lex->query_tables, &m_sph, 0))
+ return true;
+
+ /* Conditionally writes to binlog */
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+ if (mysql_routine_grant(thd, lex->query_tables, &m_sph,
+ lex->users_list, grants,
+ is_revoke(), true))
+ return true;
+ my_ok(thd);
+ return false;
+#ifdef WITH_WSREP
+wsrep_error_label:
+ return true;
+#endif // WITH_WSREP
+}
+
+
+bool Sql_cmd_grant_table::execute_table_mask(THD *thd)
+{
+ LEX *lex= thd->lex;
+ DBUG_ASSERT(lex->first_select_lex()->table_list.first == NULL);
+
+ if (check_access(thd, m_object_privilege | m_column_privilege_total | GRANT_ACL,
+ m_db.str, NULL, NULL, 1, 0))
+ return true;
+
+ grant_stage0(thd);
+
+ if (m_columns.elements) // e.g. GRANT SELECT (a) ON *.*
+ {
+ my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER_THD(thd, ER_ILLEGAL_GRANT_FOR_TABLE),
+ MYF(0));
+ return true;
+ }
+
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+ /* Conditionally writes to binlog */
+ if (mysql_grant(thd, m_db.str, lex->users_list, m_object_privilege,
+ is_revoke(), false/*not proxy*/))
+ return true;
+
+ return !is_revoke() && user_list_reset_mqh(thd, lex->users_list);
+
+#ifdef WITH_WSREP
+wsrep_error_label:
+ return true;
+#endif // WITH_WSREP
+}
+
+
+bool Sql_cmd_grant_table::execute(THD *thd)
+{
+ TABLE_LIST *table= thd->lex->first_select_lex()->table_list.first;
+ return table ? execute_exact_table(thd, table) :
+ execute_table_mask(thd);
+}
+
+
+#endif // NO_EMBEDDED_ACCESS_CHECKS
+
+
+
SHOW_VAR acl_statistics[] = {
#ifndef NO_EMBEDDED_ACCESS_CHECKS
{"column_grants", (char*)show_column_grants, SHOW_SIMPLE_FUNC},
@@ -11831,7 +12162,6 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
int error= 0;
uint counter;
ACL_USER *acl_user;
- ulong want_access;
char buff[100];
TABLE *table= tables->table;
bool no_global_access= check_access(thd, SELECT_ACL, "mysql",
@@ -11853,7 +12183,7 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
!thd->security_ctx->is_priv_user(user, host))
continue;
- want_access= acl_user->access;
+ privilege_t want_access(acl_user->access);
if (!(want_access & GRANT_ACL))
is_grantable= "NO";
@@ -11870,7 +12200,8 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
else
{
uint priv_id;
- ulong j,test_access= want_access & ~GRANT_ACL;
+ ulonglong j;
+ privilege_t test_access(want_access & ~GRANT_ACL);
for (priv_id=0, j = SELECT_ACL;j <= GLOBAL_ACLS; priv_id++,j <<= 1)
{
if (test_access & j)
@@ -11902,7 +12233,6 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
int error= 0;
uint counter;
ACL_DB *acl_db;
- ulong want_access;
char buff[100];
TABLE *table= tables->table;
bool no_global_access= check_access(thd, SELECT_ACL, "mysql",
@@ -11925,7 +12255,7 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
!thd->security_ctx->is_priv_user(user, host))
continue;
- want_access=acl_db->access;
+ privilege_t want_access(acl_db->access);
if (want_access)
{
if (!(want_access & GRANT_ACL))
@@ -11945,7 +12275,8 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
else
{
int cnt;
- ulong j,test_access= want_access & ~GRANT_ACL;
+ ulonglong j;
+ privilege_t test_access(want_access & ~GRANT_ACL);
for (cnt=0, j = SELECT_ACL; j <= DB_ACLS; cnt++,j <<= 1)
if (test_access & j)
{
@@ -11995,10 +12326,10 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
!thd->security_ctx->is_priv_user(user, host))
continue;
- ulong table_access= grant_table->privs;
+ privilege_t table_access(grant_table->privs);
if (table_access)
{
- ulong test_access= table_access & ~GRANT_ACL;
+ privilege_t test_access(table_access & ~GRANT_ACL);
/*
We should skip 'usage' privilege on table if
we have any privileges on column(s) of this table
@@ -12021,7 +12352,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
}
else
{
- ulong j;
+ ulonglong j;
int cnt;
for (cnt= 0, j= SELECT_ACL; j <= TABLE_ACLS; cnt++, j<<= 1)
{
@@ -12075,19 +12406,19 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
!thd->security_ctx->is_priv_user(user, host))
continue;
- ulong table_access= grant_table->cols;
- if (table_access != 0)
+ privilege_t table_access(grant_table->cols);
+ if (table_access != NO_ACL)
{
if (!(grant_table->privs & GRANT_ACL))
is_grantable= "NO";
- ulong test_access= table_access & ~GRANT_ACL;
+ privilege_t test_access(table_access & ~GRANT_ACL);
strxmov(buff, "'", user, "'@'", host, "'", NullS);
if (!test_access)
continue;
else
{
- ulong j;
+ ulonglong j;
int cnt;
for (cnt= 0, j= SELECT_ACL; j <= TABLE_ACLS; cnt++, j<<= 1)
{
@@ -12151,8 +12482,8 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
if (!initialized)
{
DBUG_PRINT("info", ("skip grants"));
- grant->privilege= ~NO_ACCESS; // everything is allowed
- DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
+ grant->privilege= ALL_KNOWN_ACL; // everything is allowed
+ DBUG_PRINT("info", ("privilege 0x%llx", (longlong) grant->privilege));
DBUG_VOID_RETURN;
}
@@ -12196,7 +12527,7 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
}
mysql_rwlock_unlock(&LOCK_grant);
- DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
+ DBUG_PRINT("info", ("privilege 0x%llx", (longlong) grant->privilege));
DBUG_VOID_RETURN;
}
@@ -12698,7 +13029,7 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
static bool ignore_max_password_errors(const ACL_USER *acl_user)
{
const char *host= acl_user->host.hostname;
- return (acl_user->access & SUPER_ACL)
+ return (acl_user->access & PRIV_IGNORE_MAX_PASSWORD_ERRORS)
&& (!strcasecmp(host, "localhost") ||
!strcmp(host, "127.0.0.1") ||
!strcmp(host, "::1"));
@@ -12750,7 +13081,7 @@ static bool find_mpvio_user(MPVIO_EXT *mpvio)
*/
ulong nr1=1, nr2=4;
CHARSET_INFO *cs= &my_charset_latin1;
- cs->coll->hash_sort(cs, (uchar*) sctx->user, strlen(sctx->user), &nr1, &nr2);
+ cs->hash_sort((uchar*) sctx->user, strlen(sctx->user), &nr1, &nr2);
mysql_mutex_lock(&acl_cache->lock);
if (!acl_users.elements)
@@ -12886,7 +13217,8 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
system_charset_info, user, user_len,
thd->charset(), &dummy_errors);
- if (!(sctx->user= my_strndup(user_buff, user_len, MYF(MY_WME))))
+ if (!(sctx->user= my_strndup(key_memory_MPVIO_EXT_auth_info, user_buff,
+ user_len, MYF(MY_WME))))
DBUG_RETURN(1);
/* Clear variables that are allocated */
@@ -13145,8 +13477,8 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
Security_context *sctx= thd->security_ctx;
- my_free((char*) sctx->user);
- if (!(sctx->user= my_strndup(user, user_len, MYF(MY_WME))))
+ my_free(const_cast<char*>(sctx->user));
+ if (!(sctx->user= my_strndup(key_memory_MPVIO_EXT_auth_info, user, user_len, MYF(MY_WME))))
return packet_error; /* The error is set by my_strdup(). */
@@ -13403,8 +13735,8 @@ static void server_mpvio_info(MYSQL_PLUGIN_VIO *vio,
static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user)
{
-#ifdef HAVE_OPENSSL
Vio *vio= thd->net.vio;
+#ifdef HAVE_OPENSSL
SSL *ssl= (SSL *) vio->ssl_arg;
X509 *cert;
#endif
@@ -13418,6 +13750,24 @@ static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user)
switch (acl_user->ssl_type) {
case SSL_TYPE_NOT_SPECIFIED: // Impossible
case SSL_TYPE_NONE: // SSL is not required
+ if (opt_require_secure_transport)
+ {
+ enum enum_vio_type type= vio_type(vio);
+#ifdef HAVE_OPENSSL
+ return type != VIO_TYPE_SSL &&
+#ifndef _WIN32
+ type != VIO_TYPE_SOCKET;
+#else
+ type != VIO_TYPE_NAMEDPIPE;
+#endif
+#else
+#ifndef _WIN32
+ return type != VIO_TYPE_SOCKET;
+#else
+ return type != VIO_TYPE_NAMEDPIPE;
+#endif
+#endif
+ }
return 0;
#ifdef HAVE_OPENSSL
case SSL_TYPE_ANY: // Any kind of SSL is ok
@@ -13672,6 +14022,8 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
res= do_auth_once(thd, default_auth_plugin_name, &mpvio);
}
+ PSI_CALL_set_connection_type(vio_type(thd->net.vio));
+
Security_context * const sctx= thd->security_ctx;
const ACL_USER * acl_user= mpvio.acl_user;
if (!acl_user)
@@ -13709,17 +14061,9 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
*/
if (sctx->user)
{
- if (strcmp(sctx->priv_user, sctx->user))
- {
- general_log_print(thd, command, "%s@%s as %s on %s",
- sctx->user, sctx->host_or_ip,
- sctx->priv_user[0] ? sctx->priv_user : "anonymous",
- safe_str(mpvio.db.str));
- }
- else
- general_log_print(thd, command, (char*) "%s@%s on %s",
- sctx->user, sctx->host_or_ip,
- safe_str(mpvio.db.str));
+ general_log_print(thd, command, (char*) "%s@%s on %s using %s",
+ sctx->user, sctx->host_or_ip,
+ safe_str(mpvio.db.str), safe_vio_type_name(thd->net.vio));
}
if (res > CR_OK && mpvio.status != MPVIO_EXT::SUCCESS)
@@ -13894,20 +14238,16 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
DBUG_PRINT("info",
("Capabilities: %llu packet_length: %ld Host: '%s' "
"Login user: '%s' Priv_user: '%s' Using password: %s "
- "Access: %lu db: '%s'",
+ "Access: %llx db: '%s'",
thd->client_capabilities, thd->max_client_packet_length,
sctx->host_or_ip, sctx->user, sctx->priv_user,
thd->password ? "yes": "no",
- sctx->master_access, mpvio.db.str));
+ (longlong) sctx->master_access, mpvio.db.str));
if (command == COM_CONNECT &&
- !(thd->main_security_ctx.master_access & SUPER_ACL))
+ !(thd->main_security_ctx.master_access & PRIV_IGNORE_MAX_CONNECTIONS))
{
- mysql_mutex_lock(&LOCK_connection_count);
- bool count_ok= (*thd->scheduler->connection_count <=
- *thd->scheduler->max_connections);
- mysql_mutex_unlock(&LOCK_connection_count);
- if (!count_ok)
+ if (*thd->scheduler->connection_count > *thd->scheduler->max_connections)
{ // too many connections
my_error(ER_CON_COUNT_ERROR, MYF(0));
DBUG_RETURN(1);
@@ -13919,14 +14259,14 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
set to 0 here because we don't have an active database yet (and we
may not have an active database to set.
*/
- sctx->db_access=0;
+ sctx->db_access= NO_ACL;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
In case the user has a default role set, attempt to set that role
*/
if (initialized && acl_user->default_rolename.length) {
- ulonglong access= 0;
+ privilege_t access(NO_ACL);
int result;
result= acl_check_setrole(thd, acl_user->default_rolename.str, &access);
if (!result)
@@ -13967,16 +14307,17 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
thd->net.net_skip_rest_factor= 2; // skip at most 2*max_packet_size
if (mpvio.auth_info.external_user[0])
- sctx->external_user= my_strdup(mpvio.auth_info.external_user, MYF(0));
+ sctx->external_user= my_strdup(key_memory_MPVIO_EXT_auth_info,
+ mpvio.auth_info.external_user, MYF(0));
if (res == CR_OK_HANDSHAKE_COMPLETE)
thd->get_stmt_da()->disable_status();
else
my_ok(thd);
- PSI_CALL_set_thread_user_host
- (thd->main_security_ctx.user, (uint)strlen(thd->main_security_ctx.user),
- thd->main_security_ctx.host_or_ip, (uint)strlen(thd->main_security_ctx.host_or_ip));
+ PSI_CALL_set_thread_account
+ (thd->main_security_ctx.user, static_cast<uint>(strlen(thd->main_security_ctx.user)),
+ thd->main_security_ctx.host_or_ip, static_cast<uint>(strlen(thd->main_security_ctx.host_or_ip)));
/* Ready to handle queries */
DBUG_RETURN(0);
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 7989367ec44..2cf1637c8db 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -19,145 +19,9 @@
#include "violite.h" /* SSL_type */
#include "sql_class.h" /* LEX_COLUMN */
+#include "grant.h"
+#include "sql_cmd.h" /* Sql_cmd */
-#define SELECT_ACL (1UL << 0)
-#define INSERT_ACL (1UL << 1)
-#define UPDATE_ACL (1UL << 2)
-#define DELETE_ACL (1UL << 3)
-#define CREATE_ACL (1UL << 4)
-#define DROP_ACL (1UL << 5)
-#define RELOAD_ACL (1UL << 6)
-#define SHUTDOWN_ACL (1UL << 7)
-#define PROCESS_ACL (1UL << 8)
-#define FILE_ACL (1UL << 9)
-#define GRANT_ACL (1UL << 10)
-#define REFERENCES_ACL (1UL << 11)
-#define INDEX_ACL (1UL << 12)
-#define ALTER_ACL (1UL << 13)
-#define SHOW_DB_ACL (1UL << 14)
-#define SUPER_ACL (1UL << 15)
-#define CREATE_TMP_ACL (1UL << 16)
-#define LOCK_TABLES_ACL (1UL << 17)
-#define EXECUTE_ACL (1UL << 18)
-#define REPL_SLAVE_ACL (1UL << 19)
-#define REPL_CLIENT_ACL (1UL << 20)
-#define CREATE_VIEW_ACL (1UL << 21)
-#define SHOW_VIEW_ACL (1UL << 22)
-#define CREATE_PROC_ACL (1UL << 23)
-#define ALTER_PROC_ACL (1UL << 24)
-#define CREATE_USER_ACL (1UL << 25)
-#define EVENT_ACL (1UL << 26)
-#define TRIGGER_ACL (1UL << 27)
-#define CREATE_TABLESPACE_ACL (1UL << 28)
-#define DELETE_HISTORY_ACL (1UL << 29)
-/*
- don't forget to update
- 1. static struct show_privileges_st sys_privileges[]
- 2. static const char *command_array[] and static uint command_lengths[]
- 3. mysql_system_tables.sql and mysql_system_tables_fix.sql
- 4. acl_init() or whatever - to define behaviour for old privilege tables
- 5. sql_yacc.yy - for GRANT/REVOKE to work
-*/
-#define NO_ACCESS (1UL << 30)
-#define DB_ACLS \
-(UPDATE_ACL | SELECT_ACL | INSERT_ACL | DELETE_ACL | CREATE_ACL | DROP_ACL | \
- GRANT_ACL | REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_TMP_ACL | \
- LOCK_TABLES_ACL | EXECUTE_ACL | CREATE_VIEW_ACL | SHOW_VIEW_ACL | \
- CREATE_PROC_ACL | ALTER_PROC_ACL | EVENT_ACL | TRIGGER_ACL | \
- DELETE_HISTORY_ACL)
-
-#define TABLE_ACLS \
-(SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL | CREATE_ACL | DROP_ACL | \
- GRANT_ACL | REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_VIEW_ACL | \
- SHOW_VIEW_ACL | TRIGGER_ACL | DELETE_HISTORY_ACL)
-
-#define COL_ACLS \
-(SELECT_ACL | INSERT_ACL | UPDATE_ACL | REFERENCES_ACL)
-
-#define PROC_ACLS \
-(ALTER_PROC_ACL | EXECUTE_ACL | GRANT_ACL)
-
-#define SHOW_PROC_ACLS \
-(ALTER_PROC_ACL | EXECUTE_ACL | CREATE_PROC_ACL)
-
-#define GLOBAL_ACLS \
-(SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL | CREATE_ACL | DROP_ACL | \
- RELOAD_ACL | SHUTDOWN_ACL | PROCESS_ACL | FILE_ACL | GRANT_ACL | \
- REFERENCES_ACL | INDEX_ACL | ALTER_ACL | SHOW_DB_ACL | SUPER_ACL | \
- CREATE_TMP_ACL | LOCK_TABLES_ACL | REPL_SLAVE_ACL | REPL_CLIENT_ACL | \
- EXECUTE_ACL | CREATE_VIEW_ACL | SHOW_VIEW_ACL | CREATE_PROC_ACL | \
- ALTER_PROC_ACL | CREATE_USER_ACL | EVENT_ACL | TRIGGER_ACL | \
- CREATE_TABLESPACE_ACL | DELETE_HISTORY_ACL)
-
-#define DEFAULT_CREATE_PROC_ACLS \
-(ALTER_PROC_ACL | EXECUTE_ACL)
-
-#define SHOW_CREATE_TABLE_ACLS \
-(SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL | \
- CREATE_ACL | DROP_ACL | ALTER_ACL | INDEX_ACL | \
- TRIGGER_ACL | REFERENCES_ACL | GRANT_ACL | CREATE_VIEW_ACL | SHOW_VIEW_ACL)
-
-/**
- Table-level privileges which are automatically "granted" to everyone on
- existing temporary tables (CREATE_ACL is necessary for ALTER ... RENAME).
-*/
-#define TMP_TABLE_ACLS \
-(SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL | CREATE_ACL | DROP_ACL | \
- INDEX_ACL | ALTER_ACL)
-
-/*
- Defines to change the above bits to how things are stored in tables
- This is needed as the 'host' and 'db' table is missing a few privileges
-*/
-
-/* Privileges that needs to be reallocated (in continous chunks) */
-#define DB_CHUNK0 (SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL | \
- CREATE_ACL | DROP_ACL)
-#define DB_CHUNK1 (GRANT_ACL | REFERENCES_ACL | INDEX_ACL | ALTER_ACL)
-#define DB_CHUNK2 (CREATE_TMP_ACL | LOCK_TABLES_ACL)
-#define DB_CHUNK3 (CREATE_VIEW_ACL | SHOW_VIEW_ACL | \
- CREATE_PROC_ACL | ALTER_PROC_ACL )
-#define DB_CHUNK4 (EXECUTE_ACL)
-#define DB_CHUNK5 (EVENT_ACL | TRIGGER_ACL)
-#define DB_CHUNK6 (DELETE_HISTORY_ACL)
-
-#define fix_rights_for_db(A) (((A) & DB_CHUNK0) | \
- (((A) << 4) & DB_CHUNK1) | \
- (((A) << 6) & DB_CHUNK2) | \
- (((A) << 9) & DB_CHUNK3) | \
- (((A) << 2) & DB_CHUNK4) | \
- (((A) << 9) & DB_CHUNK5) | \
- (((A) << 10) & DB_CHUNK6))
-#define get_rights_for_db(A) (((A) & DB_CHUNK0) | \
- (((A) & DB_CHUNK1) >> 4) | \
- (((A) & DB_CHUNK2) >> 6) | \
- (((A) & DB_CHUNK3) >> 9) | \
- (((A) & DB_CHUNK4) >> 2) | \
- (((A) & DB_CHUNK5) >> 9) | \
- (((A) & DB_CHUNK6) >> 10))
-#define TBL_CHUNK0 DB_CHUNK0
-#define TBL_CHUNK1 DB_CHUNK1
-#define TBL_CHUNK2 (CREATE_VIEW_ACL | SHOW_VIEW_ACL)
-#define TBL_CHUNK3 TRIGGER_ACL
-#define TBL_CHUNK4 (DELETE_HISTORY_ACL)
-#define fix_rights_for_table(A) (((A) & TBL_CHUNK0) | \
- (((A) << 4) & TBL_CHUNK1) | \
- (((A) << 11) & TBL_CHUNK2) | \
- (((A) << 15) & TBL_CHUNK3) | \
- (((A) << 16) & TBL_CHUNK4))
-#define get_rights_for_table(A) (((A) & TBL_CHUNK0) | \
- (((A) & TBL_CHUNK1) >> 4) | \
- (((A) & TBL_CHUNK2) >> 11) | \
- (((A) & TBL_CHUNK3) >> 15) | \
- (((A) & TBL_CHUNK4) >> 16))
-#define fix_rights_for_column(A) (((A) & 7) | (((A) & ~7) << 8))
-#define get_rights_for_column(A) (((A) & 7) | ((A) >> 8))
-#define fix_rights_for_procedure(A) ((((A) << 18) & EXECUTE_ACL) | \
- (((A) << 23) & ALTER_PROC_ACL) | \
- (((A) << 8) & GRANT_ACL))
-#define get_rights_for_procedure(A) ((((A) & EXECUTE_ACL) >> 18) | \
- (((A) & ALTER_PROC_ACL) >> 23) | \
- (((A) & GRANT_ACL) >> 8))
enum mysql_db_table_field
{
@@ -212,8 +76,8 @@ bool hostname_requires_resolving(const char *hostname);
bool acl_init(bool dont_read_acl_tables);
bool acl_reload(THD *thd);
void acl_free(bool end=0);
-ulong acl_get(const char *host, const char *ip,
- const char *user, const char *db, my_bool db_is_pattern);
+privilege_t acl_get(const char *host, const char *ip,
+ const char *user, const char *db, my_bool db_is_pattern);
bool acl_authenticate(THD *thd, uint com_change_user_pkt_len);
bool acl_getroot(Security_context *sctx, const char *user, const char *host,
const char *ip, const char *db);
@@ -223,37 +87,38 @@ bool change_password(THD *thd, LEX_USER *user);
bool mysql_grant_role(THD *thd, List<LEX_USER> &user_list, bool revoke);
bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list,
- ulong rights, bool revoke, bool is_proxy);
+ privilege_t rights, bool revoke, bool is_proxy);
int mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list,
- List <LEX_COLUMN> &column_list, ulong rights,
+ List <LEX_COLUMN> &column_list, privilege_t rights,
bool revoke);
bool mysql_routine_grant(THD *thd, TABLE_LIST *table, const Sp_handler *sph,
- List <LEX_USER> &user_list, ulong rights,
+ List <LEX_USER> &user_list, privilege_t rights,
bool revoke, bool write_to_binlog);
bool grant_init();
void grant_free(void);
bool grant_reload(THD *thd);
-bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
+bool check_grant(THD *thd, privilege_t want_access, TABLE_LIST *tables,
bool any_combination_will_do, uint number, bool no_errors);
bool check_grant_column (THD *thd, GRANT_INFO *grant,
const char *db_name, const char *table_name,
const char *name, size_t length, Security_context *sctx);
bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
const char *name, size_t length, Field *fld);
-bool check_grant_all_columns(THD *thd, ulong want_access,
+bool check_grant_all_columns(THD *thd, privilege_t want_access,
Field_iterator_table_ref *fields);
-bool check_grant_routine(THD *thd, ulong want_access,
+bool check_grant_routine(THD *thd, privilege_t want_access,
TABLE_LIST *procs, const Sp_handler *sph,
bool no_error);
bool check_grant_db(THD *thd,const char *db);
-bool check_global_access(THD *thd, ulong want_access, bool no_errors= false);
-bool check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
+bool check_global_access(THD *thd, const privilege_t want_access, bool no_errors= false);
+bool check_access(THD *thd, privilege_t want_access,
+ const char *db, privilege_t *save_priv,
GRANT_INTERNAL_INFO *grant_internal_info,
bool dont_check_global_grants, bool no_errors);
-ulong get_table_grant(THD *thd, TABLE_LIST *table);
-ulong get_column_grant(THD *thd, GRANT_INFO *grant,
- const char *db_name, const char *table_name,
- const char *field_name);
+privilege_t get_table_grant(THD *thd, TABLE_LIST *table);
+privilege_t get_column_grant(THD *thd, GRANT_INFO *grant,
+ const char *db_name, const char *table_name,
+ const char *field_name);
bool get_show_user(THD *thd, LEX_USER *lex_user, const char **username,
const char **hostname, const char **rolename);
void mysql_show_grants_get_fields(THD *thd, List<Item> *fields,
@@ -262,7 +127,7 @@ bool mysql_show_grants(THD *thd, LEX_USER *user);
bool mysql_show_create_user(THD *thd, LEX_USER *user);
int fill_schema_enabled_roles(THD *thd, TABLE_LIST *tables, COND *cond);
int fill_schema_applicable_roles(THD *thd, TABLE_LIST *tables, COND *cond);
-void get_privilege_desc(char *to, uint max_length, ulong access);
+void get_privilege_desc(char *to, uint max_length, privilege_t access);
void get_mqh(const char *user, const char *host, USER_CONN *uc);
bool mysql_create_user(THD *thd, List <LEX_USER> &list, bool handle_as_role);
bool mysql_drop_user(THD *thd, List <LEX_USER> &list, bool handle_as_role);
@@ -302,8 +167,6 @@ enum ACL_internal_access_result
/**
Access granted for all the requested privileges,
do not use the grant tables.
- This flag is used only for the INFORMATION_SCHEMA privileges,
- for compatibility reasons.
*/
ACL_INTERNAL_ACCESS_GRANTED,
/** Access denied, do not use the grant tables. */
@@ -343,8 +206,8 @@ public:
privilege. Requested privileges that are granted, if any, are saved
in save_priv.
*/
- virtual ACL_internal_access_result check(ulong want_access,
- ulong *save_priv) const= 0;
+ virtual ACL_internal_access_result check(privilege_t want_access,
+ privilege_t *save_priv) const= 0;
};
/**
@@ -380,8 +243,8 @@ public:
privilege. Requested privileges that are granted, if any, are saved
in save_priv.
*/
- virtual ACL_internal_access_result check(ulong want_access,
- ulong *save_priv) const= 0;
+ virtual ACL_internal_access_result check(privilege_t want_access,
+ privilege_t *save_priv) const= 0;
/**
Search for per table ACL access rules by table name.
@@ -415,8 +278,8 @@ get_cached_table_access(GRANT_INTERNAL_INFO *grant_internal_info,
bool acl_check_proxy_grant_access (THD *thd, const char *host, const char *user,
bool with_grant);
-int acl_setrole(THD *thd, const char *rolename, ulonglong access);
-int acl_check_setrole(THD *thd, const char *rolename, ulonglong *access);
+int acl_setrole(THD *thd, const char *rolename, privilege_t access);
+int acl_check_setrole(THD *thd, const char *rolename, privilege_t *access);
int acl_check_set_default_role(THD *thd, const char *host, const char *user);
int acl_set_default_role(THD *thd, const char *host, const char *user,
const char *rolename);
@@ -435,4 +298,78 @@ bool check_role_is_granted(const char *username,
extern ulong role_global_merges, role_db_merges, role_table_merges,
role_column_merges, role_routine_merges;
#endif
+
+
+class Sql_cmd_grant: public Sql_cmd
+{
+protected:
+ enum_sql_command m_command;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ void warn_hostname_requires_resolving(THD *thd, List<LEX_USER> &list);
+ bool user_list_reset_mqh(THD *thd, List<LEX_USER> &list);
+ void grant_stage0(THD *thd);
+#endif
+public:
+ Sql_cmd_grant(enum_sql_command command)
+ :m_command(command)
+ { }
+ bool is_revoke() const { return m_command == SQLCOM_REVOKE; }
+ enum_sql_command sql_command_code() const { return m_command; }
+};
+
+
+class Sql_cmd_grant_proxy: public Sql_cmd_grant
+{
+ privilege_t m_grant_option;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ bool check_access_proxy(THD *thd, List<LEX_USER> &list);
+#endif
+public:
+ Sql_cmd_grant_proxy(enum_sql_command command, privilege_t grant_option)
+ :Sql_cmd_grant(command), m_grant_option(grant_option)
+ { }
+ bool execute(THD *thd);
+};
+
+
+class Sql_cmd_grant_object: public Sql_cmd_grant, public Grant_privilege
+{
+protected:
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ bool grant_stage0_exact_object(THD *thd, TABLE_LIST *table);
+#endif
+public:
+ Sql_cmd_grant_object(enum_sql_command command, const Grant_privilege &grant)
+ :Sql_cmd_grant(command), Grant_privilege(grant)
+ { }
+};
+
+
+class Sql_cmd_grant_table: public Sql_cmd_grant_object
+{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ bool execute_table_mask(THD *thd);
+ bool execute_exact_table(THD *thd, TABLE_LIST *table);
+#endif
+public:
+ Sql_cmd_grant_table(enum_sql_command command, const Grant_privilege &grant)
+ :Sql_cmd_grant_object(command, grant)
+ { }
+ bool execute(THD *thd);
+};
+
+
+
+class Sql_cmd_grant_sp: public Sql_cmd_grant_object
+{
+ const Sp_handler &m_sph;
+public:
+ Sql_cmd_grant_sp(enum_sql_command command, const Grant_privilege &grant,
+ const Sp_handler &sph)
+ :Sql_cmd_grant_object(command, grant),
+ m_sph(sph)
+ { }
+ bool execute(THD *thd);
+};
+
#endif /* SQL_ACL_INCLUDED */
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index 6fdbc14a372..cfc48c82b4d 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -26,7 +26,6 @@
#include "sql_view.h" // view_checksum
#include "sql_table.h" // mysql_recreate_table
#include "debug_sync.h" // DEBUG_SYNC
-#include "sql_acl.h" // *_ACL
#include "sp.h" // Sroutine_hash_entry
#include "sql_parse.h" // check_table_access
#include "strfunc.h"
@@ -122,9 +121,9 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
Let us try to open at least a .FRM for this table.
*/
- table_list->mdl_request.init(MDL_key::TABLE,
- table_list->db.str, table_list->table_name.str,
- MDL_EXCLUSIVE, MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&table_list->mdl_request, MDL_key::TABLE,
+ table_list->db.str, table_list->table_name.str,
+ MDL_EXCLUSIVE, MDL_TRANSACTION);
if (lock_table_names(thd, table_list, table_list->next_global,
thd->variables.lock_wait_timeout, 0))
@@ -547,8 +546,9 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
close_thread_tables(thd);
table->table= NULL;
thd->mdl_context.release_transactional_locks();
- table->mdl_request.init(MDL_key::TABLE, table->db.str, table->table_name.str,
- MDL_SHARED_NO_READ_WRITE, MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&table->mdl_request, MDL_key::TABLE, table->db.str,
+ table->table_name.str, MDL_SHARED_NO_READ_WRITE,
+ MDL_TRANSACTION);
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
@@ -822,8 +822,9 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
close_thread_tables(thd);
table->table= NULL;
thd->mdl_context.release_transactional_locks();
- table->mdl_request.init(MDL_key::TABLE, table->db.str, table->table_name.str,
- MDL_SHARED_NO_READ_WRITE, MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&table->mdl_request, MDL_key::TABLE, table->db.str,
+ table->table_name.str, MDL_SHARED_NO_READ_WRITE,
+ MDL_TRANSACTION);
table->mdl_request.set_type(MDL_SHARED_READ);
table->lock_type= TL_READ;
@@ -1158,7 +1159,7 @@ send_result_message:
else if (open_for_modify || fatal_error)
{
tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
- table->db.str, table->table_name.str, FALSE);
+ table->db.str, table->table_name.str);
/*
May be something modified. Consequently, we have to
invalidate the query cache.
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index 0230ee1df12..23e2e3e097f 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -25,6 +25,7 @@ Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root)
:drop_list(rhs.drop_list, mem_root),
alter_list(rhs.alter_list, mem_root),
key_list(rhs.key_list, mem_root),
+ alter_rename_key_list(rhs.alter_rename_key_list, mem_root),
create_list(rhs.create_list, mem_root),
check_constraint_list(rhs.check_constraint_list, mem_root),
flags(rhs.flags), partition_flags(rhs.partition_flags),
@@ -46,6 +47,7 @@ Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root)
list_copy_and_replace_each_value(drop_list, mem_root);
list_copy_and_replace_each_value(alter_list, mem_root);
list_copy_and_replace_each_value(key_list, mem_root);
+ list_copy_and_replace_each_value(alter_rename_key_list, mem_root);
list_copy_and_replace_each_value(create_list, mem_root);
/* partition_names are not deeply copied currently */
}
@@ -239,7 +241,8 @@ bool Alter_info::vers_prohibited(THD *thd) const
Alter_table_ctx::Alter_table_ctx()
- : datetime_field(NULL), error_if_not_empty(false),
+ : implicit_default_value_error_field(NULL),
+ error_if_not_empty(false),
tables_opened(0),
db(null_clex_str), table_name(null_clex_str), alias(null_clex_str),
new_db(null_clex_str), new_name(null_clex_str), new_alias(null_clex_str),
@@ -260,7 +263,7 @@ Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list,
uint tables_opened_arg,
const LEX_CSTRING *new_db_arg,
const LEX_CSTRING *new_name_arg)
- : datetime_field(NULL), error_if_not_empty(false),
+ : implicit_default_value_error_field(NULL), error_if_not_empty(false),
tables_opened(tables_opened_arg),
new_db(*new_db_arg), new_name(*new_name_arg),
fk_error_if_delete_row(false), fk_error_id(NULL),
@@ -352,6 +355,19 @@ Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list,
}
+void Alter_table_ctx::report_implicit_default_value_error(THD *thd,
+ const TABLE_SHARE *s)
+ const
+{
+ Create_field *error_field= implicit_default_value_error_field;
+ const Type_handler *h= error_field->type_handler();
+ thd->push_warning_truncated_value_for_field(Sql_condition::WARN_LEVEL_WARN,
+ h->name().ptr(),
+ h->default_value().ptr(),
+ s, error_field->field_name.str);
+}
+
+
bool Sql_cmd_alter_table::execute(THD *thd)
{
LEX *lex= thd->lex;
@@ -380,8 +396,9 @@ bool Sql_cmd_alter_table::execute(THD *thd)
*/
HA_CREATE_INFO create_info(lex->create_info);
Alter_info alter_info(lex->alter_info, thd->mem_root);
- ulong priv=0;
- ulong priv_needed= ALTER_ACL;
+ create_info.alter_info= &alter_info;
+ privilege_t priv(NO_ACL);
+ privilege_t priv_needed(ALTER_ACL);
bool result;
DBUG_ENTER("Sql_cmd_alter_table::execute");
@@ -490,9 +507,9 @@ bool Sql_cmd_alter_table::execute(THD *thd)
(!thd->is_current_stmt_binlog_format_row() ||
!thd->find_temporary_table(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);
+ WSREP_TO_ISOLATION_BEGIN_ALTER((lex->name.str ? select_lex->db.str : first_table->db.str),
+ (lex->name.str ? lex->name.str : first_table->table_name.str),
+ first_table, &alter_info, used_engine ? &create_info : NULL);
thd->variables.auto_increment_offset = 1;
thd->variables.auto_increment_increment = 1;
diff --git a/sql/sql_alter.h b/sql/sql_alter.h
index 10aafe1ab37..a553c31346a 100644
--- a/sql/sql_alter.h
+++ b/sql/sql_alter.h
@@ -19,6 +19,7 @@
class Alter_drop;
class Alter_column;
+class Alter_rename_key;
class Key;
/**
@@ -87,6 +88,8 @@ public:
List<Alter_column> alter_list;
// List of keys, used by both CREATE and ALTER TABLE.
List<Key> key_list;
+ // List of keys to be renamed.
+ List<Alter_rename_key> alter_rename_key_list;
// List of columns, used by both CREATE and ALTER TABLE.
List<Create_field> create_list;
@@ -123,6 +126,7 @@ public:
drop_list.empty();
alter_list.empty();
key_list.empty();
+ alter_rename_key_list.empty();
create_list.empty();
check_constraint_list.empty();
flags= 0;
@@ -287,8 +291,9 @@ public:
fk_error_table= fk->foreign_table->str;
}
+ void report_implicit_default_value_error(THD *thd, const TABLE_SHARE *) const;
public:
- Create_field *datetime_field;
+ Create_field *implicit_default_value_error_field;
bool error_if_not_empty;
uint tables_opened;
LEX_CSTRING db;
diff --git a/sql/sql_analyze_stmt.cc b/sql/sql_analyze_stmt.cc
index f1c6e2c73ea..2f87b9b0d40 100644
--- a/sql/sql_analyze_stmt.cc
+++ b/sql/sql_analyze_stmt.cc
@@ -26,6 +26,7 @@
void Filesort_tracker::print_json_members(Json_writer *writer)
{
const char *varied_str= "(varied across executions)";
+ String str;
if (!get_r_loops())
writer->add_member("r_loops").add_null();
@@ -78,5 +79,44 @@ void Filesort_tracker::print_json_members(Json_writer *writer)
else
writer->add_size(sort_buffer_size);
}
+
+ get_data_format(&str);
+ writer->add_member("r_sort_mode").add_str(str.c_ptr(), str.length());
+}
+
+void Filesort_tracker::get_data_format(String *str)
+{
+ if (r_sort_keys_packed)
+ str->append("packed_sort_key");
+ else
+ str->append("sort_key");
+ str->append(",");
+
+ if (r_using_addons)
+ {
+ if (r_packed_addon_fields)
+ str->append("packed_addon_fields");
+ else
+ str->append("addon_fields");
+ }
+ else
+ str->append("rowid");
+}
+
+void attach_gap_time_tracker(THD *thd, Gap_time_tracker *gap_tracker,
+ ulonglong timeval)
+{
+ thd->gap_tracker_data.bill_to= gap_tracker;
+ thd->gap_tracker_data.start_time= timeval;
+}
+
+void process_gap_time_tracker(THD *thd, ulonglong timeval)
+{
+ if (thd->gap_tracker_data.bill_to)
+ {
+ thd->gap_tracker_data.bill_to->log_time(thd->gap_tracker_data.start_time,
+ timeval);
+ thd->gap_tracker_data.bill_to= NULL;
+ }
}
diff --git a/sql/sql_analyze_stmt.h b/sql/sql_analyze_stmt.h
index eec52822ae5..990c79fb9ad 100644
--- a/sql/sql_analyze_stmt.h
+++ b/sql/sql_analyze_stmt.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2015 MariaDB Corporation Ab
+ Copyright (c) 2015, 2020, 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
@@ -38,6 +38,10 @@ $stmt").
*/
+class Gap_time_tracker;
+void attach_gap_time_tracker(THD *thd, Gap_time_tracker *gap_tracker, ulonglong timeval);
+void process_gap_time_tracker(THD *thd, ulonglong timeval);
+
/*
A class for tracking time it takes to do a certain action
*/
@@ -48,26 +52,37 @@ protected:
ulonglong cycles;
ulonglong last_start;
- void cycles_stop_tracking()
+ void cycles_stop_tracking(THD *thd)
{
ulonglong end= my_timer_cycles();
cycles += end - last_start;
if (unlikely(end < last_start))
cycles += ULONGLONG_MAX;
+
+ process_gap_time_tracker(thd, end);
+ if (my_gap_tracker)
+ attach_gap_time_tracker(thd, my_gap_tracker, end);
}
public:
- Exec_time_tracker() : count(0), cycles(0) {}
-
+ Exec_time_tracker() : count(0), cycles(0), my_gap_tracker(NULL) {}
+
+ /*
+ The time spent between stop_tracking() call on this object and any
+ other time measurement will be billed to this tracker.
+ */
+ Gap_time_tracker *my_gap_tracker;
+
// interface for collecting time
- void start_tracking()
+ void start_tracking(THD *thd)
{
last_start= my_timer_cycles();
+ process_gap_time_tracker(thd, last_start);
}
- void stop_tracking()
+ void stop_tracking(THD *thd)
{
count++;
- cycles_stop_tracking();
+ cycles_stop_tracking(thd);
}
// interface for getting the time
@@ -75,12 +90,39 @@ public:
double get_time_ms() const
{
// convert 'cycles' to milliseconds.
- return 1000 * ((double)cycles) / sys_timer_info.cycles.frequency;
+ return 1000.0 * static_cast<double>(cycles) /
+ static_cast<double>(sys_timer_info.cycles.frequency);
}
};
/*
+ Tracker for time spent between the calls to Exec_time_tracker's {start|
+ stop}_tracking().
+
+ @seealso Gap_time_tracker_data in sql_class.h
+*/
+class Gap_time_tracker
+{
+ ulonglong cycles;
+public:
+ Gap_time_tracker() : cycles(0) {}
+
+ void log_time(ulonglong start, ulonglong end) {
+ cycles += end - start;
+ }
+
+ double get_time_ms() const
+ {
+ // convert 'cycles' to milliseconds.
+ return 1000.0 * static_cast<double>(cycles) /
+ static_cast<double>(sys_timer_info.cycles.frequency);
+ }
+};
+
+
+
+/*
A class for counting certain actions (in all queries), and optionally
collecting the timings (in ANALYZE queries).
*/
@@ -99,22 +141,22 @@ public:
/*
Unlike Exec_time_tracker::stop_tracking, we don't increase loops.
*/
- void stop_tracking()
+ void stop_tracking(THD *thd)
{
- cycles_stop_tracking();
+ cycles_stop_tracking(thd);
}
};
-#define ANALYZE_START_TRACKING(tracker) \
+#define ANALYZE_START_TRACKING(thd, tracker) \
{ \
(tracker)->incr_loops(); \
if (unlikely((tracker)->timed)) \
- { (tracker)->start_tracking(); } \
+ { (tracker)->start_tracking(thd); } \
}
-#define ANALYZE_STOP_TRACKING(tracker) \
+#define ANALYZE_STOP_TRACKING(thd, tracker) \
if (unlikely((tracker)->timed)) \
- { (tracker)->stop_tracking(); }
+ { (tracker)->stop_tracking(thd); }
/*
A class for collecting read statistics.
@@ -138,24 +180,23 @@ public:
ha_rows r_rows; /* How many rows we've got after that */
ha_rows r_rows_after_where; /* Rows after applying attached part of WHERE */
- bool has_scans() { return (r_scans != 0); }
- ha_rows get_loops() { return r_scans; }
- double get_avg_rows()
+ bool has_scans() const { return (r_scans != 0); }
+ ha_rows get_loops() const { return r_scans; }
+ double get_avg_rows() const
{
- return r_scans ? ((double)r_rows / r_scans): 0;
+ return r_scans
+ ? static_cast<double>(r_rows) / static_cast<double>(r_scans)
+ : 0;
}
- double get_filtered_after_where()
+ double get_filtered_after_where() const
{
- double r_filtered;
- if (r_rows > 0)
- r_filtered= (double)r_rows_after_where / r_rows;
- else
- r_filtered= 1.0;
-
- return r_filtered;
+ return r_rows > 0
+ ? static_cast<double>(r_rows_after_where) /
+ static_cast<double>(r_rows)
+ : 1.0;
}
-
+
inline void on_scan_init() { r_scans++; }
inline void on_record_read() { r_rows++; }
inline void on_record_after_where() { r_rows_after_where++; }
@@ -181,19 +222,22 @@ public:
time_tracker(do_timing), r_limit(0), r_used_pq(0),
r_examined_rows(0), r_sorted_rows(0), r_output_rows(0),
sort_passes(0),
- sort_buffer_size(0)
+ sort_buffer_size(0),
+ r_using_addons(false),
+ r_packed_addon_fields(false),
+ r_sort_keys_packed(false)
{}
/* Functions that filesort uses to report various things about its execution */
- inline void report_use(ha_rows r_limit_arg)
+ inline void report_use(THD *thd, ha_rows r_limit_arg)
{
if (!time_tracker.get_loops())
r_limit= r_limit_arg;
else
r_limit= (r_limit != r_limit_arg)? 0: r_limit_arg;
- ANALYZE_START_TRACKING(&time_tracker);
+ ANALYZE_START_TRACKING(thd, &time_tracker);
}
inline void incr_pq_used() { r_used_pq++; }
@@ -210,9 +254,9 @@ public:
{
sort_passes -= passes;
}
- inline void report_merge_passes_at_end(ulong passes)
+ inline void report_merge_passes_at_end(THD *thd, ulong passes)
{
- ANALYZE_STOP_TRACKING(&time_tracker);
+ ANALYZE_STOP_TRACKING(thd, &time_tracker);
sort_passes += passes;
}
@@ -223,25 +267,39 @@ public:
else
sort_buffer_size= bufsize;
}
-
+
+ inline void report_addon_fields_format(bool addons_packed)
+ {
+ r_using_addons= true;
+ r_packed_addon_fields= addons_packed;
+ }
+ inline void report_sort_keys_format(bool sort_keys_packed)
+ {
+ r_sort_keys_packed= sort_keys_packed;
+ }
+
+ void get_data_format(String *str);
+
/* Functions to get the statistics */
void print_json_members(Json_writer *writer);
-
+
ulonglong get_r_loops() const { return time_tracker.get_loops(); }
- double get_avg_examined_rows()
- {
- return ((double)r_examined_rows) / get_r_loops();
+ double get_avg_examined_rows() const
+ {
+ return static_cast<double>(r_examined_rows) /
+ static_cast<double>(get_r_loops());
}
- double get_avg_returned_rows()
- {
- return ((double)r_output_rows) / get_r_loops();
+ double get_avg_returned_rows() const
+ {
+ return static_cast<double>(r_output_rows) /
+ static_cast<double>(get_r_loops());
}
- double get_r_filtered()
+ double get_r_filtered() const
{
- if (r_examined_rows > 0)
- return ((double)r_sorted_rows / r_examined_rows);
- else
- return 1.0;
+ return r_examined_rows > 0
+ ? static_cast<double>(r_sorted_rows) /
+ static_cast<double>(r_examined_rows)
+ : 1.0;
}
private:
Time_and_counter_tracker time_tracker;
@@ -282,6 +340,9 @@ private:
other - value
*/
ulonglong sort_buffer_size;
+ bool r_using_addons;
+ bool r_packed_addon_fields;
+ bool r_sort_keys_packed;
};
@@ -318,14 +379,14 @@ public:
container_elements(0), n_checks(0), n_positive_checks(0)
{}
- inline void start_tracking()
+ inline void start_tracking(THD *thd)
{
- ANALYZE_START_TRACKING(&time_tracker);
+ ANALYZE_START_TRACKING(thd, &time_tracker);
}
- inline void stop_tracking()
+ inline void stop_tracking(THD *thd)
{
- ANALYZE_STOP_TRACKING(&time_tracker);
+ ANALYZE_STOP_TRACKING(thd, &time_tracker);
}
/* Save container buffer size in bytes */
@@ -339,7 +400,7 @@ public:
return &time_tracker;
}
- double get_time_fill_container_ms()
+ double get_time_fill_container_ms() const
{
return time_tracker.get_time_ms();
}
@@ -353,13 +414,14 @@ public:
inline void increment_container_elements_count() { container_elements++; }
- uint get_container_elements() { return container_elements; }
+ uint get_container_elements() const { return container_elements; }
- double get_r_selectivity_pct()
+ double get_r_selectivity_pct() const
{
- return (double)n_positive_checks/(double)n_checks;
+ return static_cast<double>(n_positive_checks) /
+ static_cast<double>(n_checks);
}
- size_t get_container_buff_size() { return container_buff_size; }
+ size_t get_container_buff_size() const { return container_buff_size; }
};
diff --git a/sql/sql_array.h b/sql/sql_array.h
index bcfbb98ef19..b6de1b18d78 100644
--- a/sql/sql_array.h
+++ b/sql/sql_array.h
@@ -3,6 +3,7 @@
/* Copyright (c) 2003, 2005-2007 MySQL AB, 2009 Sun Microsystems, Inc.
Use is subject to license terms.
+ Copyright (c) 2020, 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
@@ -34,7 +35,7 @@
template <typename Element_type> class Bounds_checked_array
{
public:
- Bounds_checked_array() : m_array(NULL), m_size(0) {}
+ Bounds_checked_array()= default;
Bounds_checked_array(Element_type *el, size_t size_arg)
: m_array(el), m_size(size_arg)
@@ -85,6 +86,10 @@ public:
Element_type *array() const { return m_array; }
+ Element_type *begin() const { return array(); }
+ Element_type *end() const { return array() + m_size; }
+
+
bool operator==(const Bounds_checked_array<Element_type>&rhs) const
{
return m_array == rhs.m_array && m_size == rhs.m_size;
@@ -95,8 +100,8 @@ public:
}
private:
- Element_type *m_array;
- size_t m_size;
+ Element_type *m_array= nullptr;
+ size_t m_size= 0;
};
/*
@@ -109,21 +114,21 @@ template <class Elem> class Dynamic_array
{
DYNAMIC_ARRAY array;
public:
- Dynamic_array(uint prealloc=16, uint increment=16)
+ Dynamic_array(PSI_memory_key psi_key, uint prealloc=16, uint increment=16)
{
- init(prealloc, increment);
+ init(psi_key, prealloc, increment);
}
Dynamic_array(MEM_ROOT *root, uint prealloc=16, uint increment=16)
{
void *init_buffer= alloc_root(root, sizeof(Elem) * prealloc);
- my_init_dynamic_array2(&array, sizeof(Elem), init_buffer,
+ init_dynamic_array2(root->m_psi_key, &array, sizeof(Elem), init_buffer,
prealloc, increment, MYF(0));
}
- void init(uint prealloc=16, uint increment=16)
+ void init(PSI_memory_key psi_key, uint prealloc=16, uint increment=16)
{
- init_dynamic_array2(&array, sizeof(Elem), 0, prealloc, increment, MYF(0));
+ init_dynamic_array2(psi_key, &array, sizeof(Elem), 0, prealloc, increment, MYF(0));
}
/**
@@ -165,6 +170,11 @@ public:
return ((const Elem*)array.buffer) + array.elements - 1;
}
+ const Elem *end() const
+ {
+ return back() + 1;
+ }
+
/// @returns pointer to n-th element
Elem *get_pos(size_t idx)
{
@@ -177,7 +187,6 @@ public:
return ((const Elem*)array.buffer) + idx;
}
-
/**
@retval false ok
@retval true OOM, @c my_error() has been called.
@@ -235,10 +244,16 @@ public:
freeze_size(&array);
}
+ bool reserve(size_t new_size)
+ {
+ return allocate_dynamic(&array, (uint)new_size);
+ }
+
+
bool resize(size_t new_size, Elem default_val)
{
size_t old_size= elements();
- if (unlikely(allocate_dynamic(&array, (uint)new_size)))
+ if (reserve(new_size))
return true;
if (new_size > old_size)
diff --git a/sql/sql_audit.cc b/sql/sql_audit.cc
index ed175ae4865..3e9379ebe33 100644
--- a/sql/sql_audit.cc
+++ b/sql/sql_audit.cc
@@ -88,7 +88,7 @@ static my_bool acquire_plugins(THD *thd, plugin_ref plugin, void *arg)
if (unlikely(!thd->audit_class_plugins.buffer))
{
/* specify some reasonable initialization defaults */
- my_init_dynamic_array(&thd->audit_class_plugins,
+ my_init_dynamic_array(PSI_INSTRUMENT_ME, &thd->audit_class_plugins,
sizeof(plugin_ref), 16, 16, MYF(0));
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 799c85a5675..c41e08e4b8c 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -30,9 +30,6 @@
#include "sql_view.h" // mysql_make_view, VIEW_ANY_ACL
#include "sql_parse.h" // check_table_access
#include "sql_insert.h" // kill_delayed_threads
-#include "sql_acl.h" // *_ACL, check_grant_all_columns,
- // check_column_grant_in_table_ref,
- // get_column_grant
#include "sql_partition.h" // ALTER_PARTITION_PARAM_TYPE
#include "sql_derived.h" // mysql_derived_prepare,
// mysql_handle_derived,
@@ -56,7 +53,6 @@
#include "rpl_filter.h"
#include "sql_table.h" // build_table_filename
#include "datadict.h" // dd_frm_is_view()
-#include "sql_hset.h" // Hash_set
#include "rpl_rli.h" // rpl_group_info
#ifdef __WIN__
#include <io.h>
@@ -262,7 +258,7 @@ static my_bool list_open_tables_callback(TDC_element *element,
arg->table_list.db.length= db_length;
arg->table_list.table_name.str= table_name;
arg->table_list.table_name.length= strlen(table_name);
- arg->table_list.grant.privilege= 0;
+ arg->table_list.grant.privilege= NO_ACL;
if (check_table_access(arg->thd, SELECT_ACL, &arg->table_list, TRUE, 1, TRUE))
return FALSE;
@@ -312,13 +308,9 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild)
/**
Close all tables that are not in use in table definition cache
-
- @param purge_flag Argument for tc_purge. true if we should force all
- shares to be deleted. false if it's enough to just
- evict those that are not in use.
*/
-void purge_tables(bool purge_flag)
+void purge_tables()
{
/*
Force close of all open tables.
@@ -332,7 +324,7 @@ void purge_tables(bool purge_flag)
Get rid of all unused TABLE and TABLE_SHARE instances. By doing
this we automatically close all tables which were marked as "old".
*/
- tc_purge(purge_flag);
+ tc_purge();
/* Free table shares which were not freed implicitly by loop above. */
tdc_purge(true);
}
@@ -361,7 +353,7 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables,
if (!tables)
{
/* Free tables that are not used */
- purge_tables(false);
+ purge_tables();
if (!wait_for_refresh)
DBUG_RETURN(false);
}
@@ -442,7 +434,8 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables,
MDL_request *mdl_request= new (thd->mem_root) MDL_request;
if (mdl_request == NULL)
DBUG_RETURN(true);
- mdl_request->init(&table->mdl_request.key, MDL_EXCLUSIVE, MDL_STATEMENT);
+ MDL_REQUEST_INIT_BY_KEY(mdl_request, &table->mdl_request.key,
+ MDL_EXCLUSIVE, MDL_STATEMENT);
mdl_requests.push_front(mdl_request);
}
@@ -451,7 +444,7 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables,
for (TABLE_LIST *table= tables; table; table= table->next_local)
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db.str,
- table->table_name.str, false);
+ table->table_name.str);
}
DBUG_RETURN(false);
}
@@ -562,7 +555,7 @@ bool flush_tables(THD *thd, flush_tables_type flag)
flush_tables_error_handler error_handler;
DBUG_ENTER("flush_tables");
- purge_tables(false); /* Flush unused tables and shares */
+ purge_tables(); /* Flush unused tables and shares */
/*
Loop over all shares and collect shares that have open tables
@@ -571,12 +564,12 @@ bool flush_tables(THD *thd, flush_tables_type flag)
write after last time all tables was closed.
*/
- if (!(tmp_table= (TABLE*) my_malloc(sizeof(*tmp_table),
+ if (!(tmp_table= (TABLE*) my_malloc(PSI_INSTRUMENT_ME, sizeof(*tmp_table),
MYF(MY_WME | MY_THREAD_SPECIFIC))))
DBUG_RETURN(1);
- my_init_dynamic_array(&collect_arg.shares, sizeof(TABLE_SHARE*), 100, 100,
- MYF(0));
+ my_init_dynamic_array(PSI_INSTRUMENT_ME, &collect_arg.shares,
+ sizeof(TABLE_SHARE*), 100, 100, MYF(0));
collect_arg.flush_type= flag;
if (tdc_iterate(thd, (my_hash_walk_action) tc_collect_used_shares,
&collect_arg, true))
@@ -718,7 +711,7 @@ bool close_cached_connection_tables(THD *thd, LEX_CSTRING *connection)
for (TABLE_LIST *table= argument.tables; table; table= table->next_local)
res|= tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
table->db.str,
- table->table_name.str, TRUE);
+ table->table_name.str);
/* Return true if we found any open connections */
DBUG_RETURN(res);
@@ -847,12 +840,9 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
prev= &table->next;
}
}
+ /* Remove the table share from the cache. */
if (skip_table == NULL)
- {
- /* Remove the table share from the cache. */
- tdc_remove_table(thd, TDC_RT_REMOVE_ALL, db, table_name,
- FALSE);
- }
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, db, table_name);
}
@@ -1405,9 +1395,9 @@ bool wait_while_table_is_used(THD *thd, TABLE *table,
{
DBUG_ENTER("wait_while_table_is_used");
DBUG_ASSERT(!table->s->tmp_table);
- DBUG_PRINT("enter", ("table: '%s' share: %p db_stat: %u version: %lld",
+ DBUG_PRINT("enter", ("table: '%s' share: %p db_stat: %u",
table->s->table_name.str, table->s,
- table->db_stat, table->s->tdc->version));
+ table->db_stat));
if (thd->mdl_context.upgrade_shared_lock(
table->mdl_ticket, MDL_EXCLUSIVE,
@@ -1415,8 +1405,7 @@ bool wait_while_table_is_used(THD *thd, TABLE *table,
DBUG_RETURN(TRUE);
tdc_remove_table(thd, TDC_RT_REMOVE_NOT_OWN,
- table->s->db.str, table->s->table_name.str,
- FALSE);
+ table->s->db.str, table->s->table_name.str);
/* extra() call must come only after all instances above are closed */
if (function != HA_EXTRA_NOT_USED)
(void) table->file->extra(function);
@@ -1457,8 +1446,7 @@ void drop_open_table(THD *thd, TABLE *table, const LEX_CSTRING *db_name,
table->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
close_thread_table(thd, &thd->open_tables);
/* Remove the table share from the table cache. */
- tdc_remove_table(thd, TDC_RT_REMOVE_ALL, db_name->str, table_name->str,
- FALSE);
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, db_name->str, table_name->str);
/* Remove the table from the storage engine and rm the .frm. */
quick_rm_table(thd, table_type, db_name, table_name, 0);
}
@@ -1587,10 +1575,9 @@ open_table_get_mdl_lock(THD *thd, Open_table_context *ot_ctx,
DBUG_ASSERT(!(flags & MYSQL_OPEN_FORCE_SHARED_MDL) ||
!(flags & MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL));
- mdl_request_shared.init(&mdl_request->key,
- (flags & MYSQL_OPEN_FORCE_SHARED_MDL) ?
- MDL_SHARED : MDL_SHARED_HIGH_PRIO,
- MDL_TRANSACTION);
+ MDL_REQUEST_INIT_BY_KEY(&mdl_request_shared, &mdl_request->key,
+ flags & MYSQL_OPEN_FORCE_SHARED_MDL ? MDL_SHARED : MDL_SHARED_HIGH_PRIO,
+ MDL_TRANSACTION);
mdl_request= &mdl_request_shared;
}
@@ -2014,8 +2001,6 @@ retry_share:
{
if (share->tdc->flushed)
{
- DBUG_PRINT("info", ("Found old share version: %lld current: %lld",
- share->tdc->version, tdc_refresh_version()));
/*
We already have an MDL lock. But we have encountered an old
version of table in the table definition cache which is possible
@@ -2076,7 +2061,8 @@ retry_share:
{
enum open_frm_error error;
/* make a new table */
- if (!(table=(TABLE*) my_malloc(sizeof(*table),MYF(MY_WME))))
+ if (!(table=(TABLE*) my_malloc(key_memory_TABLE, sizeof(*table),
+ MYF(MY_WME))))
goto err_lock;
error= open_table_from_share(thd, share, &table_list->alias,
@@ -2162,8 +2148,8 @@ retry_share:
DBUG_RETURN(TRUE);
}
- protection_request.init(MDL_key::BACKUP, "", "", mdl_type,
- MDL_STATEMENT);
+ MDL_REQUEST_INIT(&protection_request, MDL_key::BACKUP, "", "", mdl_type,
+ MDL_STATEMENT);
/*
Install error handler which if possible will convert deadlock error
@@ -3016,7 +3002,7 @@ static bool auto_repair_table(THD *thd, TABLE_LIST *table_list)
thd->clear_error();
- if (!(entry= (TABLE*)my_malloc(sizeof(TABLE), MYF(MY_WME))))
+ if (!(entry= (TABLE*)my_malloc(key_memory_TABLE, sizeof(TABLE), MYF(MY_WME))))
return result;
if (!(share= tdc_acquire_share(thd, table_list, GTS_TABLE)))
@@ -3049,8 +3035,7 @@ static bool auto_repair_table(THD *thd, TABLE_LIST *table_list)
tdc_release_share(share);
/* Remove the repaired share from the table cache. */
tdc_remove_table(thd, TDC_RT_REMOVE_ALL,
- table_list->db.str, table_list->table_name.str,
- FALSE);
+ table_list->db.str, table_list->table_name.str);
end_free:
my_free(entry);
return result;
@@ -3222,7 +3207,7 @@ Open_table_context::recover_from_failed_open()
break;
tdc_remove_table(m_thd, TDC_RT_REMOVE_ALL, m_failed_table->db.str,
- m_failed_table->table_name.str, FALSE);
+ m_failed_table->table_name.str);
m_thd->get_stmt_da()->clear_warning_info(m_thd->query_id);
m_thd->clear_error(); // Clear error message
@@ -3258,7 +3243,7 @@ Open_table_context::recover_from_failed_open()
break;
tdc_remove_table(m_thd, TDC_RT_REMOVE_ALL, m_failed_table->db.str,
- m_failed_table->table_name.str, FALSE);
+ m_failed_table->table_name.str);
result= auto_repair_table(m_thd, m_failed_table);
/*
@@ -4056,9 +4041,8 @@ lock_table_names(THD *thd, const DDL_options_st &options,
MDL_request *schema_request= new (thd->mem_root) MDL_request;
if (schema_request == NULL)
DBUG_RETURN(TRUE);
- schema_request->init(MDL_key::SCHEMA, table->db.str, "",
- MDL_INTENTION_EXCLUSIVE,
- MDL_TRANSACTION);
+ MDL_REQUEST_INIT(schema_request, MDL_key::SCHEMA, table->db.str, "",
+ MDL_INTENTION_EXCLUSIVE, MDL_TRANSACTION);
mdl_requests.push_front(schema_request);
}
@@ -4080,7 +4064,8 @@ lock_table_names(THD *thd, const DDL_options_st &options,
if (thd->has_read_only_protection())
DBUG_RETURN(true);
- global_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_DDL, MDL_STATEMENT);
+ MDL_REQUEST_INIT(&global_request, MDL_key::BACKUP, "", "", MDL_BACKUP_DDL,
+ MDL_STATEMENT);
mdl_savepoint= thd->mdl_context.mdl_savepoint();
while (!thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout) &&
@@ -5780,9 +5765,8 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
replace. If the item was aliased by the user, set the alias to
the replacing item.
*/
- if (*ref && !(*ref)->is_autogenerated_name)
- item->set_name(thd, (*ref)->name.str, (*ref)->name.length,
- system_charset_info);
+ if (*ref && !(*ref)->is_autogenerated_name())
+ item->set_name(thd, (*ref)->name);
if (register_tree_change)
thd->change_item_tree(ref, item);
else
@@ -5872,9 +5856,8 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, si
replace. If the item was aliased by the user, set the alias to
the replacing item.
*/
- if (*ref && !(*ref)->is_autogenerated_name)
- item->set_name(thd, (*ref)->name.str, (*ref)->name.length,
- system_charset_info);
+ if (*ref && !(*ref)->is_autogenerated_name())
+ item->set_name(thd, (*ref)->name);
if (register_tree_change && arena)
thd->restore_active_arena(arena, &backup);
@@ -6290,8 +6273,8 @@ find_field_in_tables(THD *thd, Item_ident *item,
bool check_privileges, bool register_tree_change)
{
Field *found=0;
- const char *db= item->db_name;
- const char *table_name= item->table_name;
+ const char *db= item->db_name.str;
+ const char *table_name= item->table_name.str;
const char *name= item->field_name.str;
size_t length= item->field_name.length;
char name_buff[SAFE_NAME_LEN+1];
@@ -6567,8 +6550,8 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
if (is_ref_by_name)
{
field_name= &((Item_ident*) find)->field_name;
- table_name= ((Item_ident*) find)->table_name;
- db_name= ((Item_ident*) find)->db_name;
+ table_name= ((Item_ident*) find)->table_name.str;
+ db_name= ((Item_ident*) find)->db_name.str;
}
for (uint i= 0; i < n_items; i++)
@@ -6608,13 +6591,13 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
item_field->field_name and item_field->table_name can be 0x0 if
item is not fix_field()'ed yet.
*/
- if (item_field->field_name.str && item_field->table_name &&
+ if (item_field->field_name.str && item_field->table_name.str &&
!lex_string_cmp(system_charset_info, &item_field->field_name,
field_name) &&
- !my_strcasecmp(table_alias_charset, item_field->table_name,
+ !my_strcasecmp(table_alias_charset, item_field->table_name.str,
table_name) &&
- (!db_name || (item_field->db_name &&
- !strcmp(item_field->db_name, db_name))))
+ (!db_name || (item_field->db_name.str &&
+ !strcmp(item_field->db_name.str, db_name))))
{
if (found_unaliased)
{
@@ -7472,17 +7455,16 @@ static bool setup_natural_join_row_types(THD *thd,
****************************************************************************/
int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
- List<Item> *sum_func_list,
- uint wild_num, uint *hidden_bit_fields)
+ List<Item> *sum_func_list, SELECT_LEX *select_lex)
{
- if (!wild_num)
- return(0);
-
Item *item;
List_iterator<Item> it(fields);
Query_arena *arena, backup;
DBUG_ENTER("setup_wild");
+ if (!select_lex->with_wild)
+ DBUG_RETURN(0);
+
/*
Don't use arena if we are not in prepared statements or stored procedures
For PS/SP we have to use arena to remember the changes
@@ -7490,7 +7472,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
arena= thd->activate_stmt_arena_if_needed(&backup);
thd->lex->current_select->cur_pos_in_select_list= 0;
- while (wild_num && (item= it++))
+ while (select_lex->with_wild && (item= it++))
{
if (item->type() == Item::FIELD_ITEM &&
((Item_field*) item)->field_name.str == star_clex_str.str &&
@@ -7511,9 +7493,9 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
MY_INT64_NUM_DECIMAL_DIGITS));
}
else if (insert_fields(thd, ((Item_field*) item)->context,
- ((Item_field*) item)->db_name,
- ((Item_field*) item)->table_name, &it,
- any_privileges, hidden_bit_fields))
+ ((Item_field*) item)->db_name.str,
+ ((Item_field*) item)->table_name.str, &it,
+ any_privileges, &select_lex->hidden_bit_fields))
{
if (arena)
thd->restore_active_arena(arena, &backup);
@@ -7528,30 +7510,15 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
*/
sum_func_list->elements+= fields.elements - elem;
}
- wild_num--;
+ select_lex->with_wild--;
}
else
thd->lex->current_select->cur_pos_in_select_list++;
}
+ DBUG_ASSERT(!select_lex->with_wild);
thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS;
if (arena)
- {
- /* make * substituting permanent */
- SELECT_LEX *select_lex= thd->lex->current_select;
- select_lex->with_wild= 0;
-#ifdef HAVE_valgrind
- if (&select_lex->item_list != &fields) // Avoid warning
-#endif
- /*
- The assignment below is translated to memcpy() call (at least on some
- platforms). memcpy() expects that source and destination areas do not
- overlap. That problem was detected by valgrind.
- */
- if (&select_lex->item_list != &fields)
- select_lex->item_list= fields;
-
thd->restore_active_arena(arena, &backup);
- }
DBUG_RETURN(0);
}
@@ -7661,6 +7628,26 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
/*
+ Perform checks like all given fields exists, if exists fill struct with
+ current data and expand all '*' in given fields for LEX::returning.
+
+ SYNOPSIS
+ thd Thread handler
+ table_list Global/local table list
+*/
+
+int setup_returning_fields(THD* thd, TABLE_LIST* table_list)
+{
+ if (!thd->lex->has_returning())
+ return 0;
+ return setup_wild(thd, table_list, thd->lex->returning()->item_list, NULL,
+ thd->lex->returning())
+ || setup_fields(thd, Ref_ptr_array(), thd->lex->returning()->item_list,
+ MARK_COLUMNS_READ, NULL, NULL, false);
+}
+
+
+/*
make list of leaves of join table tree
SYNOPSIS
@@ -7889,8 +7876,8 @@ bool setup_tables_and_check_access(THD *thd,
TABLE_LIST *tables,
List<TABLE_LIST> &leaves,
bool select_insert,
- ulong want_access_first,
- ulong want_access,
+ privilege_t want_access_first,
+ privilege_t want_access,
bool full_table_list)
{
DBUG_ENTER("setup_tables_and_check_access");
@@ -7901,7 +7888,7 @@ bool setup_tables_and_check_access(THD *thd,
List_iterator<TABLE_LIST> ti(leaves);
TABLE_LIST *table_list;
- ulong access= want_access_first;
+ privilege_t access= want_access_first;
while ((table_list= ti++))
{
if (table_list->belong_to_view && !table_list->view &&
diff --git a/sql/sql_base.h b/sql/sql_base.h
index 28a787c56dd..572dd487d4a 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -175,7 +175,8 @@ bool insert_fields(THD *thd, Name_resolution_context *context,
void make_leaves_list(THD *thd, List<TABLE_LIST> &list, TABLE_LIST *tables,
bool full_table_list, TABLE_LIST *boundary);
int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
- List<Item> *sum_func_list, uint wild_num, uint * hidden_bit_fields);
+ List<Item> *sum_func_list, SELECT_LEX *sl);
+int setup_returning_fields(THD* thd, TABLE_LIST* table_list);
bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &item, enum_column_usage column_usage,
List<Item> *sum_func_list, List<Item> *pre_fix,
@@ -217,8 +218,8 @@ bool setup_tables_and_check_access(THD *thd,
TABLE_LIST *tables,
List<TABLE_LIST> &leaves,
bool select_insert,
- ulong want_access_first,
- ulong want_access,
+ privilege_t want_access_first,
+ privilege_t want_access,
bool full_table_list);
bool wait_while_table_is_used(THD *thd, TABLE *table,
enum ha_extra_function function);
@@ -298,7 +299,7 @@ void close_log_table(THD *thd, Open_tables_backup *backup);
bool close_cached_tables(THD *thd, TABLE_LIST *tables,
bool wait_for_refresh, ulong timeout);
-void purge_tables(bool purge_flag);
+void purge_tables();
bool flush_tables(THD *thd, flush_tables_type flag);
bool close_cached_connection_tables(THD *thd, LEX_CSTRING *connect_string);
void close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
diff --git a/sql/sql_basic_types.h b/sql/sql_basic_types.h
index 170e93741ef..3200228618f 100644
--- a/sql/sql_basic_types.h
+++ b/sql/sql_basic_types.h
@@ -23,6 +23,8 @@
typedef ulonglong sql_mode_t;
typedef int64 query_id_t;
+enum enum_nullability { NOT_NULL, NULLABLE };
+
/*
"fuzzydate" with strict data type control.
diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc
index 44a885bf0eb..ea91f68f360 100644
--- a/sql/sql_binlog.cc
+++ b/sql/sql_binlog.cc
@@ -144,7 +144,7 @@ int binlog_defragment(THD *thd)
}
thd->lex->comment.str= // to be freed by the caller
- (char *) my_malloc(thd->lex->comment.length, MYF(MY_WME));
+ (char *) my_malloc(PSI_INSTRUMENT_ME, thd->lex->comment.length, MYF(MY_WME));
if (!thd->lex->comment.str)
{
my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), 1);
@@ -189,7 +189,7 @@ void mysql_client_binlog_statement(THD* thd)
thd->lex->comment.length : 2048),
thd->lex->comment.str));
- if (check_global_access(thd, SUPER_ACL))
+ if (check_global_access(thd, PRIV_STMT_BINLOG))
DBUG_VOID_RETURN;
/*
@@ -242,7 +242,8 @@ void mysql_client_binlog_statement(THD* thd)
}
decoded_len= my_base64_needed_decoded_length((int)coded_len);
- if (!(buf= (char *) my_malloc(decoded_len, MYF(MY_WME))))
+ if (!(buf= (char *) my_malloc(key_memory_binlog_statement_buffer,
+ decoded_len, MYF(MY_WME))))
{
my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), 1);
goto end;
diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h
index cce80ce2bc8..02dc8198c7c 100644
--- a/sql/sql_bitmap.h
+++ b/sql/sql_bitmap.h
@@ -28,9 +28,26 @@
#include <my_bit.h>
-template <uint width> class Bitmap
+/* An iterator to quickly walk over bits in ulonglong bitmap. */
+class Table_map_iterator
{
+ ulonglong bmp;
+public:
+ Table_map_iterator(ulonglong t): bmp(t){}
+ uint next_bit()
+ {
+ if (!bmp)
+ return BITMAP_END;
+ uint bit= my_find_first_bit(bmp);
+ bmp &= ~(1ULL << bit);
+ return bit;
+ }
+ int operator++(int) { return next_bit(); }
+ enum { BITMAP_END= 64 };
+};
+template <uint width> class Bitmap
+{
/*
Workaround GCC optimizer bug (generating SSE instuctions on unaligned data)
*/
@@ -43,12 +60,38 @@ template <uint width> class Bitmap
#pragma GCC target ("no-sse")
#endif
- uint32 buffer[(width + 31) / 32];
-public:
- Bitmap()
+private:
+ static const int BITS_PER_ELEMENT= sizeof(ulonglong) * 8;
+ static const int ARRAY_ELEMENTS= (width + BITS_PER_ELEMENT - 1) / BITS_PER_ELEMENT;
+ static const ulonglong ALL_BITS_SET= ULLONG_MAX;
+
+ ulonglong buffer[ARRAY_ELEMENTS];
+
+ uint bit_index(uint n) const
+ {
+ DBUG_ASSERT(n < width);
+ return ARRAY_ELEMENTS == 1 ? 0 : n / BITS_PER_ELEMENT;
+ }
+ ulonglong bit_mask(uint n) const
{
- clear_all();
+ DBUG_ASSERT(n < width);
+ return ARRAY_ELEMENTS == 1 ? 1ULL << n : 1ULL << (n % BITS_PER_ELEMENT);
+ }
+ ulonglong last_element_mask(int n) const
+ {
+ DBUG_ASSERT(n % BITS_PER_ELEMENT != 0);
+ return bit_mask(n) - 1;
}
+
+public:
+ /*
+ The default constructor does nothing.
+ The caller is supposed to either zero the memory
+ or to call set_all()/clear_all()/set_prefix()
+ to initialize bitmap.
+ */
+ Bitmap() { }
+
explicit Bitmap(uint prefix)
{
set_prefix(prefix);
@@ -57,50 +100,76 @@ public:
{
set_prefix(prefix);
}
-
uint length() const
{
return width;
}
void set_bit(uint n)
{
- DBUG_ASSERT(n < width);
- ((uchar*)buffer)[n / 8] |= (1 << (n & 7));
+ buffer[bit_index(n)] |= bit_mask(n);
}
void clear_bit(uint n)
{
- DBUG_ASSERT(n < width);
- ((uchar*)buffer)[n / 8] &= ~(1 << (n & 7));
+ buffer[bit_index(n)] &= ~bit_mask(n);
+ }
+ bool is_set(uint n) const
+ {
+ return buffer[bit_index(n)] & bit_mask(n);
}
void set_prefix(uint prefix_size)
{
set_if_smaller(prefix_size, width);
- uint prefix_bytes, prefix_bits, d;
- uchar* m = (uchar*)buffer;
- if ((prefix_bytes = prefix_size / 8))
- memset(m, 0xff, prefix_bytes);
- m += prefix_bytes;
- if ((prefix_bits = prefix_size & 7))
- {
- *(m++) = (1 << prefix_bits) - 1;
- // As the prefix bits are set, lets count this byte too as a prefix byte.
- prefix_bytes++;
- }
- if ((d = (width + 7) / 8 - prefix_bytes))
- memset(m, 0, d);
+ size_t idx= prefix_size / BITS_PER_ELEMENT;
+
+ for (size_t i= 0; i < idx; i++)
+ buffer[i]= ALL_BITS_SET;
+
+ if (prefix_size % BITS_PER_ELEMENT)
+ buffer[idx++]= last_element_mask(prefix_size);
+
+ for (size_t i= idx; i < ARRAY_ELEMENTS; i++)
+ buffer[i]= 0;
+ }
+ bool is_prefix(uint prefix_size) const
+ {
+ DBUG_ASSERT(prefix_size <= width);
+
+ size_t idx= prefix_size / BITS_PER_ELEMENT;
+
+ for (size_t i= 0; i < idx; i++)
+ if (buffer[i] != ALL_BITS_SET)
+ return false;
+
+ if (prefix_size % BITS_PER_ELEMENT)
+ if (buffer[idx++] != last_element_mask(prefix_size))
+ return false;
+
+ for (size_t i= idx; i < ARRAY_ELEMENTS; i++)
+ if (buffer[i] != 0)
+ return false;
+
+ return true;
}
void set_all()
{
- set_prefix(width);
+ if (width % BITS_PER_ELEMENT)
+ set_prefix(width);
+ else if (ARRAY_ELEMENTS > 1)
+ memset(buffer, 0xff, sizeof(buffer));
+ else
+ buffer[0] = ALL_BITS_SET;
}
void clear_all()
{
- memset(buffer, 0x00, sizeof(buffer));
+ if (ARRAY_ELEMENTS > 1)
+ memset(buffer, 0, sizeof(buffer));
+ else
+ buffer[0]= 0;
}
- void intersect(Bitmap & map2)
+ void intersect(const Bitmap& map2)
{
- for (uint i = 0; i < array_elements(buffer); i++)
+ for (size_t i= 0; i < ARRAY_ELEMENTS; i++)
buffer[i] &= map2.buffer[i];
}
@@ -112,27 +181,13 @@ private:
*/
void intersect_and_pad(ulonglong map2buff, bool pad_with_ones)
{
- compile_time_assert(sizeof(ulonglong) == 8);
- uint32 tmp[2];
- int8store(tmp, map2buff);
+ buffer[0] &= map2buff;
- buffer[0] &= tmp[0];
- if (array_elements(buffer) > 1)
- buffer[1] &= tmp[1];
-
- if (array_elements(buffer) <= 2)
- return;
- if (pad_with_ones)
- {
- memset((char*)buffer + 8, 0xff , sizeof(buffer) - 8);
- if (width != sizeof(buffer) * 8)
- {
- ((uchar*)buffer)[sizeof(buffer)-1] = last_byte_mask(width);
- }
- }
- else
- memset((char*)buffer + 8, 0 , sizeof(buffer) - 8);
+ for (size_t i= 1; i < ARRAY_ELEMENTS; i++)
+ buffer[i]= pad_with_ones ? ALL_BITS_SET : 0;
+ if (ARRAY_ELEMENTS > 1 && (width % BITS_PER_ELEMENT) && pad_with_ones)
+ buffer[ARRAY_ELEMENTS - 1]= last_element_mask(width);
}
public:
@@ -140,141 +195,110 @@ public:
{
intersect_and_pad(map2buff, 0);
}
- /* Use highest bit for all bits above sizeof(ulonglong)*8. */
+ /* Use highest bit for all bits above first element. */
void intersect_extended(ulonglong map2buff)
{
intersect_and_pad(map2buff, (map2buff & (1ULL << 63)));
}
- void subtract(Bitmap & map2)
+ void subtract(const Bitmap& map2)
{
- for (size_t i = 0; i < array_elements(buffer); i++)
+ for (size_t i= 0; i < ARRAY_ELEMENTS; i++)
buffer[i] &= ~(map2.buffer[i]);
}
- void merge(Bitmap & map2)
+ void merge(const Bitmap& map2)
{
- for (size_t i = 0; i < array_elements(buffer); i++)
+ for (size_t i= 0; i < ARRAY_ELEMENTS; i++)
buffer[i] |= map2.buffer[i];
}
- bool is_set(uint n) const
- {
- DBUG_ASSERT(n < width);
- return ((uchar*)buffer)[n / 8] & (1 << (n & 7));
- }
- bool is_prefix(uint prefix_size) const
- {
- uint prefix_mask = last_byte_mask(prefix_size);
- uchar* m = (uchar*)buffer;
- uchar* end_prefix = m + (prefix_size - 1) / 8;
- uchar* end;
- DBUG_ASSERT(prefix_size <= width);
-
- /* Empty prefix is always true */
- if (!prefix_size)
- return true;
-
- while (m < end_prefix)
- if (*m++ != 0xff)
- return false;
-
- end = ((uchar*)buffer) + (width + 7) / 8 - 1;
- if (m == end)
- return ((*m & last_byte_mask(width)) == prefix_mask);
-
- if (*m != prefix_mask)
- return false;
-
- while (++m < end)
- if (*m != 0)
- return false;
- return ((*m & last_byte_mask(width)) == 0);
- }
bool is_clear_all() const
{
- for (size_t i= 0; i < array_elements(buffer); i++)
+ for (size_t i= 0; i < ARRAY_ELEMENTS; i++)
if (buffer[i])
return false;
return true;
}
- bool is_set_all() const
- {
- if (width == sizeof(buffer) * 8)
- {
- for (size_t i = 0; i < array_elements(buffer); i++)
- if (buffer[i] != 0xFFFFFFFFU)
- return false;
- return true;
- }
- else
- return is_prefix(width);
- }
-
- bool is_subset(const Bitmap & map2) const
+ bool is_subset(const Bitmap& map2) const
{
- for (size_t i= 0; i < array_elements(buffer); i++)
+ for (size_t i= 0; i < ARRAY_ELEMENTS; i++)
if (buffer[i] & ~(map2.buffer[i]))
return false;
return true;
}
- bool is_overlapping(const Bitmap & map2) const
+ bool is_overlapping(const Bitmap& map2) const
{
- for (size_t i = 0; i < array_elements(buffer); i++)
+ for (size_t i= 0; i < ARRAY_ELEMENTS; i++)
if (buffer[i] & map2.buffer[i])
return true;
return false;
}
- bool operator==(const Bitmap & map2) const
+ bool operator==(const Bitmap& map2) const
{
- return memcmp(buffer, map2.buffer, sizeof(buffer)) == 0;
+ if (ARRAY_ELEMENTS > 1)
+ return !memcmp(buffer,map2.buffer,sizeof(buffer));
+ return buffer[0] == map2.buffer[0];
}
- bool operator!=(const Bitmap & map2) const
+ bool operator!=(const Bitmap& map2) const
{
return !(*this == map2);
}
+ /*
+ Print hexadecimal representation of bitmap.
+ Truncate trailing zeros.
+ */
char *print(char *buf) const
{
- char *s=buf;
- const uchar *e=(uchar *)buffer, *b=e+sizeof(buffer)-1;
- while (!*b && b>e)
- b--;
- if ((*s=_dig_vec_upper[*b >> 4]) != '0')
- s++;
- *s++=_dig_vec_upper[*b & 15];
- while (--b>=e)
+ size_t last; /*index of the last non-zero element, or 0. */
+
+ for (last= ARRAY_ELEMENTS - 1; last && !buffer[last]; last--){}
+
+ const int HEX_DIGITS_PER_ELEMENT= BITS_PER_ELEMENT / 4;
+ for (size_t i= 0; i < last; i++)
{
- *s++=_dig_vec_upper[*b >> 4];
- *s++=_dig_vec_upper[*b & 15];
+ ulonglong num = buffer[i];
+ uint shift = BITS_PER_ELEMENT - 4;
+ size_t pos= i * HEX_DIGITS_PER_ELEMENT;
+ for (size_t j= 0; j < HEX_DIGITS_PER_ELEMENT; j++)
+ {
+ buf[pos + j]= _dig_vec_upper[(num >> shift) & 0xf];
+ shift += 4;
+ }
}
- *s=0;
+ longlong2str(buffer[last], buf, 16);
return buf;
}
ulonglong to_ulonglong() const
{
- DBUG_ASSERT(sizeof(buffer) >= 4);
- uchar *b=(uchar *)buffer;
- if (sizeof(buffer) >= 8)
- return uint8korr(b);
- return (ulonglong) uint4korr(b);
+ return buffer[0];
}
uint bits_set()
{
- uint res = 0;
- for (size_t i = 0; i < array_elements(buffer); i++)
- res += my_count_bits_uint32(buffer[i]);
+ uint res= 0;
+ for (size_t i= 0; i < ARRAY_ELEMENTS; i++)
+ res += my_count_bits(buffer[i]);
return res;
}
class Iterator
{
- Bitmap &map;
- uint no;
+ const Bitmap& map;
+ uint offset;
+ Table_map_iterator tmi;
public:
- Iterator(Bitmap<width> &map2): map(map2), no(0) {}
- int operator++(int) {
- if (no == width) return BITMAP_END;
- while (!map.is_set(no))
+ Iterator(const Bitmap<width>& map2) : map(map2), offset(0), tmi(map2.buffer[0]) {}
+ int operator++(int)
+ {
+ for (;;)
{
- if ((++no) == width) return BITMAP_END;
+ int nextbit= tmi++;
+
+ if (nextbit != Table_map_iterator::BITMAP_END)
+ return offset + nextbit;
+
+ if (offset + BITS_PER_ELEMENT >= map.length())
+ return BITMAP_END;
+
+ offset += BITS_PER_ELEMENT;
+ tmi= Table_map_iterator(map.buffer[offset / BITS_PER_ELEMENT]);
}
- return no++;
}
enum { BITMAP_END = width };
};
@@ -283,98 +307,8 @@ public:
#pragma GCC pop_options
#undef NEED_GCC_NO_SSE_WORKAROUND
#endif
-
};
-
-/* An iterator to quickly walk over bits in ulonglong bitmap. */
-class Table_map_iterator
-{
- ulonglong bmp;
- uint no;
-public:
- Table_map_iterator(ulonglong t) : bmp(t), no(0) {}
- uint next_bit()
- {
- static const uchar last_bit[16]= {32, 0, 1, 0,
- 2, 0, 1, 0,
- 3, 0, 1, 0,
- 2, 0, 1, 0};
- uint bit;
- while ((bit= last_bit[bmp & 0xF]) == 32)
- {
- no += 4;
- bmp= bmp >> 4;
- if (!bmp)
- return BITMAP_END;
- }
- bmp &= ~(1ULL << bit);
- return no + bit;
- }
- uint operator++(int) { return next_bit(); }
- enum { BITMAP_END= 64 };
-};
-
-template <> class Bitmap<64>
-{
- ulonglong map;
-public:
- Bitmap<64>() { }
- explicit Bitmap<64>(uint prefix_to_set) { set_prefix(prefix_to_set); }
- void init(uint prefix_to_set) { set_prefix(prefix_to_set); }
- uint length() const { return 64; }
- void set_bit(uint n) { map|= ((ulonglong)1) << n; }
- void clear_bit(uint n) { map&= ~(((ulonglong)1) << n); }
- void set_prefix(uint n)
- {
- if (n >= length())
- set_all();
- else
- map= (((ulonglong)1) << n)-1;
- }
- void set_all() { map=~(ulonglong)0; }
- void clear_all() { map=(ulonglong)0; }
- void intersect(Bitmap<64>& map2) { map&= map2.map; }
- void intersect(ulonglong map2) { map&= map2; }
- void intersect_extended(ulonglong map2) { map&= map2; }
- void subtract(Bitmap<64>& map2) { map&= ~map2.map; }
- void merge(Bitmap<64>& map2) { map|= map2.map; }
- bool is_set(uint n) const { return MY_TEST(map & (((ulonglong) 1) << n)); }
- bool is_prefix(uint n) const { return map == (((ulonglong)1) << n)-1; }
- bool is_clear_all() const { return map == (ulonglong)0; }
- bool is_set_all() const { return map == ~(ulonglong)0; }
- bool is_subset(const Bitmap<64>& map2) const { return !(map & ~map2.map); }
- bool is_overlapping(const Bitmap<64>& map2) const { return (map & map2.map)!= 0; }
- bool operator==(const Bitmap<64>& map2) const { return map == map2.map; }
- char *print(char *buf) const {
- longlong2str(longlong(map), buf, 16);
- return buf;
- }
- ulonglong to_ulonglong() const { return map; }
- class Iterator : public Table_map_iterator
- {
- public:
- Iterator(Bitmap<64> &map2) : Table_map_iterator(map2.map) {}
- };
- uint bits_set()
- {
- //TODO: use my_count_bits()
- uint res= 0, i= 0;
- for (; i < 64 ; i++)
- {
- if (map & ((ulonglong)1<<i))
- res++;
- }
- return res;
- }
-};
-
-#if MAX_INDEXES <= 64
-typedef Bitmap<64> key_map; /* Used for finding keys */
-#elif MAX_INDEXES > 128
-#error "MAX_INDEXES values greater than 128 is not supported."
-#else
-typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */
-#endif
+typedef Bitmap<MAX_INDEXES> key_map; /* Used for finding keys */
#endif /* SQL_BITMAP_INCLUDED */
diff --git a/sql/sql_builtin.cc.in b/sql/sql_builtin.cc.in
index 5ac044afd5d..810f98a876c 100644
--- a/sql/sql_builtin.cc.in
+++ b/sql/sql_builtin.cc.in
@@ -32,9 +32,6 @@ extern
builtin_maria_plugin
@mysql_mandatory_plugins@ @mysql_optional_plugins@
builtin_maria_binlog_plugin,
-#ifdef WITH_WSREP
- builtin_maria_wsrep_plugin,
-#endif /* WITH_WSREP */
builtin_maria_mysql_password_plugin;
struct st_maria_plugin *mysql_optional_plugins[]=
@@ -45,8 +42,5 @@ struct st_maria_plugin *mysql_optional_plugins[]=
struct st_maria_plugin *mysql_mandatory_plugins[]=
{
builtin_maria_binlog_plugin, builtin_maria_mysql_password_plugin,
-#ifdef WITH_WSREP
- builtin_maria_wsrep_plugin,
-#endif /* WITH_WSREP */
@mysql_mandatory_plugins@ 0
};
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 5b649b739c6..00681ba8e2a 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -2727,8 +2727,8 @@ size_t Query_cache::init_cache()
DUMP(this);
- (void) my_hash_init(&queries, &my_charset_bin, def_query_hash_size, 0, 0,
- query_cache_query_get_key, 0, 0);
+ (void) my_hash_init(key_memory_Query_cache, &queries, &my_charset_bin,
+ def_query_hash_size, 0,0, query_cache_query_get_key,0,0);
#ifndef FN_NO_CASE_SENSE
/*
If lower_case_table_names!=0 then db and table names are already
@@ -2738,8 +2738,8 @@ size_t Query_cache::init_cache()
lower_case_table_names == 0 then we should distinguish my_table
and MY_TABLE cases and so again can use binary collation.
*/
- (void) my_hash_init(&tables, &my_charset_bin, def_table_hash_size, 0, 0,
- query_cache_table_get_key, 0, 0);
+ (void) my_hash_init(key_memory_Query_cache, &tables, &my_charset_bin,
+ def_table_hash_size, 0,0, query_cache_table_get_key, 0,0);
#else
/*
On windows, OS/2, MacOS X with HFS+ or any other case insensitive
@@ -2749,11 +2749,9 @@ size_t Query_cache::init_cache()
file system) and so should use case insensitive collation for
comparison.
*/
- (void) my_hash_init(&tables,
- lower_case_table_names ? &my_charset_bin :
- files_charset_info,
- def_table_hash_size, 0, 0,query_cache_table_get_key,
- 0, 0);
+ (void) my_hash_init(PSI_INSTRUMENT_ME, &tables, lower_case_table_names ?
+ &my_charset_bin : files_charset_info,
+ def_table_hash_size, 0,0, query_cache_table_get_key, 0,0);
#endif
queries_in_cache = 0;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 22690c7e432..f67b42230c3 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2008, 2019, MariaDB Corporation.
+ Copyright (c) 2008, 2020, 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
@@ -35,7 +35,7 @@
#include "sql_base.h" // close_thread_tables
#include "sql_time.h" // date_time_format_copy
#include "tztime.h" // MYSQL_TIME <-> my_time_t
-#include "sql_acl.h" // NO_ACCESS,
+#include "sql_acl.h" // NO_ACL,
// acl_getroot_no_password
#include "sql_base.h"
#include "sql_handler.h" // mysql_ha_cleanup
@@ -129,6 +129,39 @@ bool Key_part_spec::operator==(const Key_part_spec& other) const
&other.field_name);
}
+
+bool Key_part_spec::check_key_for_blob(const handler *file) const
+{
+ if (!(file->ha_table_flags() & HA_CAN_INDEX_BLOBS))
+ {
+ my_error(ER_BLOB_USED_AS_KEY, MYF(0), field_name.str, file->table_type());
+ return true;
+ }
+ return false;
+}
+
+
+bool Key_part_spec::check_key_length_for_blob() const
+{
+ if (!length)
+ {
+ my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), field_name.str);
+ return true;
+ }
+ return false;
+}
+
+
+bool Key_part_spec::init_multiple_key_for_blob(const handler *file)
+{
+ if (check_key_for_blob(file))
+ return true;
+ if (!length)
+ length= file->max_key_length() + 1;
+ return false;
+}
+
+
/**
Construct an (almost) deep copy of this key. Only those
elements that are known to never change are not copied.
@@ -156,6 +189,7 @@ Key::Key(const Key &rhs, MEM_ROOT *mem_root)
Foreign_key::Foreign_key(const Foreign_key &rhs, MEM_ROOT *mem_root)
:Key(rhs,mem_root),
+ constraint_name(rhs.constraint_name),
ref_db(rhs.ref_db),
ref_table(rhs.ref_table),
ref_columns(rhs.ref_columns,mem_root),
@@ -420,12 +454,6 @@ void thd_exit_cond(MYSQL_THD thd, const PSI_stage_info *stage,
}
extern "C"
-void **thd_ha_data(const THD *thd, const struct handlerton *hton)
-{
- return (void **) &thd->ha_data[hton->slot].ha_ptr;
-}
-
-extern "C"
void thd_storage_lock_wait(THD *thd, long long value)
{
thd->utime_after_lock+= value;
@@ -437,7 +465,7 @@ void thd_storage_lock_wait(THD *thd, long long value)
extern "C"
void *thd_get_ha_data(const THD *thd, const struct handlerton *hton)
{
- return *thd_ha_data(thd, hton);
+ return thd->ha_data[hton->slot].ha_ptr;
}
@@ -450,6 +478,7 @@ void thd_set_ha_data(THD *thd, const struct handlerton *hton,
const void *ha_data)
{
plugin_ref *lock= &thd->ha_data[hton->slot].lock;
+ thd->ha_data[hton->slot].ha_ptr= const_cast<void*>(ha_data);
if (ha_data && !*lock)
*lock= ha_lock_engine(NULL, (handlerton*) hton);
else if (!ha_data && *lock)
@@ -457,7 +486,6 @@ void thd_set_ha_data(THD *thd, const struct handlerton *hton,
plugin_unlock(NULL, *lock);
*lock= NULL;
}
- *thd_ha_data(thd, hton)= (void*) ha_data;
}
@@ -604,8 +632,8 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
:Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION,
/* statement id */ 0),
rli_fake(0), rgi_fake(0), rgi_slave(NULL),
- protocol_text(this), protocol_binary(this),
- m_current_stage_key(0),
+ protocol_text(this), protocol_binary(this), initial_status_var(0),
+ m_current_stage_key(0), m_psi(0),
in_sub_stmt(0), log_all_errors(0),
binlog_unsafe_warning_flags(0),
binlog_table_maps(0),
@@ -615,7 +643,9 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
accessed_rows_and_keys(0),
m_digest(NULL),
m_statement_psi(NULL),
+ m_transaction_psi(NULL),
m_idle_psi(NULL),
+ col_access(NO_ACL),
thread_id(id),
thread_dbug_id(id),
os_thread_id(0),
@@ -669,9 +699,10 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
wsrep_apply_format(0),
wsrep_rbr_buf(NULL),
wsrep_sync_wait_gtid(WSREP_GTID_UNDEFINED),
+ wsrep_last_written_gtid_seqno(0),
+ wsrep_current_gtid_seqno(0),
wsrep_affected_rows(0),
wsrep_has_ignored_error(false),
- wsrep_replicate_GTID(false),
wsrep_ignore_table(false),
/* wsrep-lib */
@@ -713,8 +744,9 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
the destructor works OK in case of an error. The main_mem_root
will be re-initialized in init_for_queries().
*/
- init_sql_alloc(&main_mem_root, "THD::main_mem_root",
- ALLOC_ROOT_MIN_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC));
+ init_sql_alloc(key_memory_thd_main_mem_root,
+ &main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0,
+ MYF(MY_THREAD_SPECIFIC));
/*
Allocation of user variables for binary logging is always done with main
@@ -726,9 +758,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
thread_stack= 0;
scheduler= thread_scheduler; // Will be fixed later
event_scheduler.data= 0;
- event_scheduler.m_psi= 0;
skip_wait_timeout= false;
- extra_port= 0;
catalog= (char*)"std"; // the only catalog we have for now
main_security_ctx.init();
security_ctx= &main_security_ctx;
@@ -738,7 +768,6 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
count_cuted_fields= CHECK_FIELD_IGNORE;
killed= NOT_KILLED;
killed_err= 0;
- col_access=0;
is_slave_error= thread_specific_used= FALSE;
my_hash_clear(&handler_tables_hash);
my_hash_clear(&ull_hash);
@@ -811,16 +840,18 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
reset_open_tables_state(this);
init();
+ debug_sync_init_thread(this);
#if defined(ENABLED_PROFILING)
profiling.set_thd(this);
#endif
user_connect=(USER_CONN *)0;
- my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
- (my_hash_get_key) get_var_key,
+ my_hash_init(key_memory_user_var_entry, &user_vars, system_charset_info,
+ USER_VARS_HASH_SIZE, 0, 0, (my_hash_get_key) get_var_key,
(my_hash_free_key) free_user_var, HASH_THREAD_SPECIFIC);
- my_hash_init(&sequences, system_charset_info, SEQUENCES_HASH_SIZE, 0, 0,
- (my_hash_get_key) get_sequence_last_key,
- (my_hash_free_key) free_sequence_last, HASH_THREAD_SPECIFIC);
+ my_hash_init(PSI_INSTRUMENT_ME, &sequences, system_charset_info,
+ SEQUENCES_HASH_SIZE, 0, 0, (my_hash_get_key)
+ get_sequence_last_key, (my_hash_free_key) free_sequence_last,
+ HASH_THREAD_SPECIFIC);
sp_proc_cache= NULL;
sp_func_cache= NULL;
@@ -829,7 +860,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
/* For user vars replication*/
if (opt_bin_log)
- my_init_dynamic_array(&user_var_events,
+ my_init_dynamic_array(key_memory_user_var_entry, &user_var_events,
sizeof(BINLOG_USER_VAR_EVENT *), 16, 16, MYF(0));
else
bzero((char*) &user_var_events, sizeof(user_var_events));
@@ -857,7 +888,8 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
m_token_array= NULL;
if (max_digest_length > 0)
{
- m_token_array= (unsigned char*) my_malloc(max_digest_length,
+ m_token_array= (unsigned char*) my_malloc(PSI_INSTRUMENT_ME,
+ max_digest_length,
MYF(MY_WME|MY_THREAD_SPECIFIC));
}
@@ -1157,19 +1189,9 @@ void *thd_memdup(MYSQL_THD thd, const void* str, size_t size)
extern "C"
void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid)
{
-#ifdef WITH_WSREP
- if (!thd->wsrep_xid.is_null())
- {
- *xid = *(MYSQL_XID *) &thd->wsrep_xid;
- return;
- }
-#endif /* WITH_WSREP */
- *xid= thd->transaction.xid_state.is_explicit_XA() ?
- *(MYSQL_XID *) thd->transaction.xid_state.get_xid() :
- *(MYSQL_XID *) &thd->transaction.implicit_xid;
+ *xid = *(MYSQL_XID *) thd->get_xid();
}
-
extern "C"
my_time_t thd_TIME_to_gmt_sec(MYSQL_THD thd, const MYSQL_TIME *ltime,
unsigned int *errcode)
@@ -1286,7 +1308,6 @@ void THD::init()
wsrep_rbr_buf = NULL;
wsrep_affected_rows = 0;
m_wsrep_next_trx_id = WSREP_UNDEFINED_TRX_ID;
- wsrep_replicate_GTID = false;
#endif /* WITH_WSREP */
if (variables.sql_log_bin)
@@ -1300,16 +1321,12 @@ void THD::init()
/* Set to handle counting of aborted connections */
userstat_running= opt_userstat_running;
last_global_update_time= current_connect_time= time(NULL);
-#if defined(ENABLED_DEBUG_SYNC)
- /* Initialize the Debug Sync Facility. See debug_sync.cc. */
- debug_sync_init_thread(this);
-#endif /* defined(ENABLED_DEBUG_SYNC) */
-
#ifndef EMBEDDED_LIBRARY
session_tracker.enable(this);
#endif //EMBEDDED_LIBRARY
apc_target.init(&LOCK_thd_kill);
+ gap_tracker_data.init();
DBUG_VOID_RETURN;
}
@@ -1420,12 +1437,13 @@ void THD::change_user(void)
init();
stmt_map.reset();
- my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
- (my_hash_get_key) get_var_key,
- (my_hash_free_key) free_user_var, 0);
- my_hash_init(&sequences, system_charset_info, SEQUENCES_HASH_SIZE, 0, 0,
- (my_hash_get_key) get_sequence_last_key,
- (my_hash_free_key) free_sequence_last, HASH_THREAD_SPECIFIC);
+ my_hash_init(key_memory_user_var_entry, &user_vars, system_charset_info,
+ USER_VARS_HASH_SIZE, 0, 0, (my_hash_get_key) get_var_key,
+ (my_hash_free_key) free_user_var, HASH_THREAD_SPECIFIC);
+ my_hash_init(key_memory_user_var_entry, &sequences, system_charset_info,
+ SEQUENCES_HASH_SIZE, 0, 0, (my_hash_get_key)
+ get_sequence_last_key, (my_hash_free_key) free_sequence_last,
+ HASH_THREAD_SPECIFIC);
sp_cache_clear(&sp_proc_cache);
sp_cache_clear(&sp_func_cache);
sp_cache_clear(&sp_package_spec_cache);
@@ -1462,7 +1480,8 @@ bool THD::set_db(const LEX_CSTRING *new_db)
const char *tmp= NULL;
if (new_db->str)
{
- if (!(tmp= my_strndup(new_db->str, new_db->length, MYF(MY_WME | ME_FATAL))))
+ if (!(tmp= my_strndup(key_memory_THD_db, new_db->str, new_db->length,
+ MYF(MY_WME | ME_FATAL))))
result= 1;
}
@@ -1553,11 +1572,6 @@ void THD::cleanup(void)
}
wt_thd_destroy(&transaction.wt);
-#if defined(ENABLED_DEBUG_SYNC)
- /* End the Debug Sync Facility. See debug_sync.cc. */
- debug_sync_end_thread(this);
-#endif /* defined(ENABLED_DEBUG_SYNC) */
-
my_hash_free(&user_vars);
my_hash_free(&sequences);
sp_cache_clear(&sp_proc_cache);
@@ -1611,6 +1625,7 @@ void THD::free_connection()
#if defined(ENABLED_PROFILING)
profiling.restart(); // Reset profiling
#endif
+ debug_sync_reset_thread(this);
}
/*
@@ -1654,6 +1669,8 @@ THD::~THD()
DBUG_ENTER("~THD()");
/* Make sure threads are not available via server_threads. */
assert_not_linked();
+ if (m_psi)
+ PSI_CALL_set_thread_THD(m_psi, 0);
/*
In error cases, thd may not be current thd. We have to fix this so
@@ -1717,12 +1734,14 @@ THD::~THD()
lf_hash_put_pins(tdc_hash_pins);
if (xid_hash_pins)
lf_hash_put_pins(xid_hash_pins);
+ debug_sync_end_thread(this);
/* Ensure everything is freed */
status_var.local_memory_used-= sizeof(THD);
/* trick to make happy memory accounting system */
#ifndef EMBEDDED_LIBRARY
session_tracker.sysvars.deinit();
+ session_tracker.user_variables.deinit();
#endif //EMBEDDED_LIBRARY
if (status_var.local_memory_used != 0)
@@ -2518,8 +2537,7 @@ THD::make_string_literal_charset(const Lex_string_with_metadata_st &str,
{
if (!str.length && (variables.sql_mode & MODE_EMPTY_STRING_IS_NULL))
return new (mem_root) Item_null(this, 0, cs);
- return new (mem_root) Item_string_with_introducer(this,
- str.str, (uint)str.length, cs);
+ return new (mem_root) Item_string_with_introducer(this, str, cs);
}
@@ -2984,15 +3002,6 @@ int select_send::send_data(List<Item> &items)
Protocol *protocol= thd->protocol;
DBUG_ENTER("select_send::send_data");
- /* unit is not set when using 'delete ... returning' */
- if (unit && unit->offset_limit_cnt)
- { // using limit offset,count
- unit->offset_limit_cnt--;
- DBUG_RETURN(FALSE);
- }
- if (thd->killed == ABORT_QUERY)
- DBUG_RETURN(FALSE);
-
protocol->prepare_for_resend();
if (protocol->send_result_set_row(&items))
{
@@ -3255,13 +3264,6 @@ int select_export::send_data(List<Item> &items)
String tmp(buff,sizeof(buff),&my_charset_bin),*res;
tmp.length(0);
- if (unit->offset_limit_cnt)
- { // using limit offset,count
- unit->offset_limit_cnt--;
- DBUG_RETURN(0);
- }
- if (thd->killed == ABORT_QUERY)
- DBUG_RETURN(0);
row_count++;
Item *item;
uint used_length=0,items_left=items.elements;
@@ -3379,7 +3381,7 @@ int select_export::send_data(List<Item> &items)
pos++)
{
#ifdef USE_MB
- if (use_mb(res_charset))
+ if (res_charset->use_mb())
{
int l;
if ((l=my_ismbchar(res_charset, pos, end)))
@@ -3515,14 +3517,6 @@ int select_dump::send_data(List<Item> &items)
Item *item;
DBUG_ENTER("select_dump::send_data");
- if (unit->offset_limit_cnt)
- { // using limit offset,count
- unit->offset_limit_cnt--;
- DBUG_RETURN(0);
- }
- if (thd->killed == ABORT_QUERY)
- DBUG_RETURN(0);
-
if (row_count++ > 1)
{
my_message(ER_TOO_MANY_ROWS, ER_THD(thd, ER_TOO_MANY_ROWS), MYF(0));
@@ -3558,13 +3552,6 @@ int select_singlerow_subselect::send_data(List<Item> &items)
MYF(current_thd->lex->ignore ? ME_WARNING : 0));
DBUG_RETURN(1);
}
- if (unit->offset_limit_cnt)
- { // Using limit offset,count
- unit->offset_limit_cnt--;
- DBUG_RETURN(0);
- }
- if (thd->killed == ABORT_QUERY)
- DBUG_RETURN(0);
List_iterator_fast<Item> li(items);
Item *val_item;
for (uint i= 0; (val_item= li++); i++)
@@ -3699,13 +3686,6 @@ int select_exists_subselect::send_data(List<Item> &items)
{
DBUG_ENTER("select_exists_subselect::send_data");
Item_exists_subselect *it= (Item_exists_subselect *)item;
- if (unit->offset_limit_cnt)
- { // Using limit offset,count
- unit->offset_limit_cnt--;
- DBUG_RETURN(0);
- }
- if (thd->killed == ABORT_QUERY)
- DBUG_RETURN(0);
it->value= 1;
it->assigned(1);
DBUG_RETURN(0);
@@ -3935,12 +3915,12 @@ Statement_map::Statement_map() :
START_STMT_HASH_SIZE = 16,
START_NAME_HASH_SIZE = 16
};
- my_hash_init(&st_hash, &my_charset_bin, START_STMT_HASH_SIZE, 0, 0,
- get_statement_id_as_hash_key,
+ my_hash_init(key_memory_prepared_statement_map, &st_hash, &my_charset_bin,
+ START_STMT_HASH_SIZE, 0, 0, get_statement_id_as_hash_key,
delete_statement_as_hash_key, MYF(0));
- my_hash_init(&names_hash, system_charset_info, START_NAME_HASH_SIZE, 0, 0,
+ my_hash_init(key_memory_prepared_statement_map, &names_hash, system_charset_info, START_NAME_HASH_SIZE, 0, 0,
(my_hash_get_key) get_stmt_name_hash_key,
- NULL,MYF(0));
+ NULL, MYF(0));
}
@@ -4108,12 +4088,7 @@ int select_dumpvar::send_data(List<Item> &items)
{
DBUG_ENTER("select_dumpvar::send_data");
- if (unit->offset_limit_cnt)
- { // using limit offset,count
- unit->offset_limit_cnt--;
- DBUG_RETURN(0);
- }
- if (row_count++)
+ if (row_count++)
{
my_message(ER_TOO_MANY_ROWS, ER_THD(thd, ER_TOO_MANY_ROWS), MYF(0));
DBUG_RETURN(1);
@@ -4303,10 +4278,10 @@ void Security_context::init()
host= user= ip= external_user= 0;
host_or_ip= "connecting host";
priv_user[0]= priv_host[0]= proxy_user[0]= priv_role[0]= '\0';
- master_access= 0;
+ master_access= NO_ACL;
password_expired= false;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- db_access= NO_ACCESS;
+ db_access= NO_ACL;
#endif
}
@@ -4341,7 +4316,7 @@ void Security_context::skip_grants()
{
/* privileges for the user are unknown everything is allowed */
host_or_ip= (char *)"";
- master_access= ~NO_ACCESS;
+ master_access= ALL_KNOWN_ACL;
*priv_user= *priv_host= '\0';
password_expired= false;
}
@@ -4349,15 +4324,16 @@ void Security_context::skip_grants()
bool Security_context::set_user(char *user_arg)
{
- my_free((char*) user);
- user= my_strdup(user_arg, MYF(0));
+ my_free(const_cast<char*>(user));
+ user= my_strdup(key_memory_MPVIO_EXT_auth_info, user_arg, MYF(0));
return user == 0;
}
-bool Security_context::check_access(ulong want_access, bool match_any)
+bool Security_context::check_access(const privilege_t want_access,
+ bool match_any)
{
DBUG_ENTER("Security_context::check_access");
- DBUG_RETURN((match_any ? (master_access & want_access)
+ DBUG_RETURN((match_any ? (master_access & want_access) != NO_ACL
: ((master_access & want_access) == want_access)));
}
@@ -4763,6 +4739,12 @@ TABLE *open_purge_table(THD *thd, const char *db, size_t dblen,
DBUG_RETURN(error ? NULL : tl->table);
}
+TABLE *get_purge_table(THD *thd)
+{
+ /* see above, at most one table can be opened */
+ DBUG_ASSERT(thd->open_tables == NULL || thd->open_tables->next == NULL);
+ return thd->open_tables;
+}
/** Find an open table in the list of prelocked tabled
@@ -4806,6 +4788,115 @@ void destroy_thd(MYSQL_THD thd)
delete thd;
}
+/**
+ Create a THD that only has auxilliary functions
+ It will never be added to the global connection list
+ server_threads. It does not represent any client connection.
+
+ It should never be counted, because it will stall the
+ shutdown. It is solely for engine's internal use,
+ like for example, evaluation of virtual function in innodb
+ purge.
+*/
+extern "C" pthread_key(struct st_my_thread_var *, THR_KEY_mysys);
+MYSQL_THD create_background_thd()
+{
+ DBUG_ASSERT(!current_thd);
+ auto save_mysysvar= pthread_getspecific(THR_KEY_mysys);
+
+ /*
+ Allocate new mysys_var specifically this THD,
+ so that e.g safemalloc, DBUG etc are happy.
+ */
+ pthread_setspecific(THR_KEY_mysys, 0);
+ my_thread_init();
+ auto thd_mysysvar= pthread_getspecific(THR_KEY_mysys);
+ auto thd= new THD(0);
+ pthread_setspecific(THR_KEY_mysys, save_mysysvar);
+ thd->set_psi(PSI_CALL_get_thread());
+
+ /*
+ Workaround the adverse effect of incrementing thread_count
+ in THD constructor. We do not want these THDs to be counted,
+ or waited for on shutdown.
+ */
+ thread_count--;
+
+ thd->mysys_var= (st_my_thread_var *) thd_mysysvar;
+ thd->set_command(COM_DAEMON);
+ thd->system_thread= SYSTEM_THREAD_GENERIC;
+ thd->security_ctx->host_or_ip= "";
+ return thd;
+}
+
+
+/*
+ Attach a background THD.
+
+ Changes current value THR_KEY_mysys TLS variable,
+ and returns the original value.
+*/
+void *thd_attach_thd(MYSQL_THD thd)
+{
+ DBUG_ASSERT(!current_thd);
+ DBUG_ASSERT(thd && thd->mysys_var);
+
+ auto save_mysysvar= pthread_getspecific(THR_KEY_mysys);
+ pthread_setspecific(THR_KEY_mysys, thd->mysys_var);
+ thd->thread_stack= (char *) &thd;
+ thd->store_globals();
+ return save_mysysvar;
+}
+
+/*
+ Restore THR_KEY_mysys TLS variable,
+ which was changed thd_attach_thd().
+*/
+void thd_detach_thd(void *mysysvar)
+{
+ /* Restore mysys_var that is changed when THD was attached.*/
+ pthread_setspecific(THR_KEY_mysys, mysysvar);
+ /* Restore the THD (we assume it was NULL during attach).*/
+ set_current_thd(0);
+}
+
+/*
+ Destroy a THD that was previously created by
+ create_background_thd()
+*/
+void destroy_background_thd(MYSQL_THD thd)
+{
+ DBUG_ASSERT(!current_thd);
+ auto thd_mysys_var= thd->mysys_var;
+ auto save_mysys_var= thd_attach_thd(thd);
+ DBUG_ASSERT(thd_mysys_var != save_mysys_var);
+ /*
+ Workaround the adverse effect decrementing thread_count on THD()
+ destructor.
+ As we decremented it in create_background_thd(), in order for it
+ not to go negative, we have to increment it before destructor.
+ */
+ thread_count++;
+ delete thd;
+
+ thd_detach_thd(save_mysys_var);
+ /*
+ Delete THD-specific my_thread_var, that was
+ allocated in create_background_thd().
+ Also preserve current PSI context, since my_thread_end()
+ would kill it, if we're not careful.
+ */
+#ifdef HAVE_PSI_THREAD_INTERFACE
+ auto save_psi_thread= PSI_CALL_get_thread();
+#endif
+ PSI_CALL_set_thread(0);
+ pthread_setspecific(THR_KEY_mysys, thd_mysys_var);
+ my_thread_end();
+ pthread_setspecific(THR_KEY_mysys, save_mysys_var);
+ PSI_CALL_set_thread(save_psi_thread);
+}
+
+
void reset_thd(MYSQL_THD thd)
{
close_thread_tables(thd);
@@ -5206,6 +5297,18 @@ extern "C" void thd_wait_end(MYSQL_THD thd)
#endif // INNODB_COMPATIBILITY_HOOKS */
+
+/**
+ MDL_context accessor
+ @param thd the current session
+ @return pointer to thd->mdl_context
+*/
+extern "C" void *thd_mdl_context(MYSQL_THD thd)
+{
+ return &thd->mdl_context;
+}
+
+
/****************************************************************************
Handling of statement states in functions and triggers.
@@ -6486,7 +6589,8 @@ CPP_UNNAMED_NS_START
}
else
{
- m_memory= (uchar *) my_malloc(total_length, MYF(MY_WME));
+ m_memory= (uchar *) my_malloc(key_memory_Row_data_memory_memory,
+ total_length, MYF(MY_WME));
m_release_memory_on_destruction= TRUE;
}
}
@@ -6705,7 +6809,7 @@ void THD::binlog_prepare_row_images(TABLE *table)
/**
if there is a primary key in the table (ie, user declared PK or a
- non-null unique index) and we dont want to ship the entire image,
+ non-null unique index) and we don't want to ship the entire image,
and the handler involved supports this.
*/
if (table->s->primary_key < MAX_KEY &&
@@ -7211,11 +7315,10 @@ void THD::set_last_commit_gtid(rpl_gtid &gtid)
#endif
m_last_commit_gtid= gtid;
#ifndef EMBEDDED_LIBRARY
- if (changed_gtid && session_tracker.sysvars.is_enabled())
+ if (changed_gtid)
{
DBUG_ASSERT(current_thd == this);
- session_tracker.sysvars.
- mark_as_changed(this, (LEX_CSTRING*)Sys_last_gtid_ptr);
+ session_tracker.sysvars.mark_as_changed(this, Sys_last_gtid_ptr);
}
#endif
}
@@ -7671,3 +7774,8 @@ bool THD::timestamp_to_TIME(MYSQL_TIME *ltime, my_time_t ts,
}
return 0;
}
+
+THD_list_iterator *THD_list_iterator::iterator()
+{
+ return &server_threads;
+}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 8e703dcf26f..6d3a18259a0 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2009, 2019, MariaDB Corporation.
+ Copyright (c) 2009, 2020, 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
@@ -106,7 +106,8 @@ enum enum_slave_exec_mode { SLAVE_EXEC_MODE_STRICT,
SLAVE_EXEC_MODE_LAST_BIT };
enum enum_slave_run_triggers_for_rbr { SLAVE_RUN_TRIGGERS_FOR_RBR_NO,
SLAVE_RUN_TRIGGERS_FOR_RBR_YES,
- SLAVE_RUN_TRIGGERS_FOR_RBR_LOGGING};
+ SLAVE_RUN_TRIGGERS_FOR_RBR_LOGGING,
+ SLAVE_RUN_TRIGGERS_FOR_RBR_ENFORCE};
enum enum_slave_type_conversions { SLAVE_TYPE_CONVERSIONS_ALL_LOSSY,
SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY};
@@ -290,6 +291,17 @@ public:
*/
Key_part_spec *clone(MEM_ROOT *mem_root) const
{ return new (mem_root) Key_part_spec(*this); }
+ bool check_key_for_blob(const class handler *file) const;
+ bool check_key_length_for_blob() const;
+ bool check_primary_key_for_blob(const class handler *file) const
+ {
+ return check_key_for_blob(file) || check_key_length_for_blob();
+ }
+ bool check_foreign_key_for_blob(const class handler *file) const
+ {
+ return check_key_for_blob(file) || check_key_length_for_blob();
+ }
+ bool init_multiple_key_for_blob(const class handler *file);
};
@@ -322,17 +334,40 @@ public:
class Alter_column :public Sql_alloc {
public:
- const char *name;
+ LEX_CSTRING name;
+ LEX_CSTRING new_name;
Virtual_column_info *default_value;
bool alter_if_exists;
- Alter_column(const char *par_name, Virtual_column_info *expr, bool par_exists)
- :name(par_name), default_value(expr), alter_if_exists(par_exists) {}
+ Alter_column(LEX_CSTRING par_name, Virtual_column_info *expr, bool par_exists)
+ :name(par_name), new_name{NULL, 0}, default_value(expr), alter_if_exists(par_exists) {}
+ Alter_column(LEX_CSTRING par_name, LEX_CSTRING _new_name)
+ :name(par_name), new_name(_new_name), default_value(NULL), alter_if_exists(false) {}
/**
Used to make a clone of this object for ALTER/CREATE TABLE
@sa comment for Key_part_spec::clone
*/
Alter_column *clone(MEM_ROOT *mem_root) const
{ return new (mem_root) Alter_column(*this); }
+ bool is_rename()
+ {
+ DBUG_ASSERT(!new_name.str || !default_value);
+ return new_name.str;
+ }
+};
+
+
+class Alter_rename_key : public Sql_alloc
+{
+public:
+ LEX_CSTRING old_name;
+ LEX_CSTRING new_name;
+
+ Alter_rename_key(LEX_CSTRING old_name_arg, LEX_CSTRING new_name_arg)
+ : old_name(old_name_arg), new_name(new_name_arg) {}
+
+ Alter_rename_key *clone(MEM_ROOT *mem_root) const
+ { return new (mem_root) Alter_rename_key(*this); }
+
};
@@ -382,12 +417,14 @@ class Foreign_key: public Key {
public:
enum fk_match_opt { FK_MATCH_UNDEF, FK_MATCH_FULL,
FK_MATCH_PARTIAL, FK_MATCH_SIMPLE};
+ LEX_CSTRING constraint_name;
LEX_CSTRING ref_db;
LEX_CSTRING ref_table;
List<Key_part_spec> ref_columns;
enum enum_fk_option delete_opt, update_opt;
enum fk_match_opt match_opt;
Foreign_key(const LEX_CSTRING *name_arg, List<Key_part_spec> *cols,
+ const LEX_CSTRING *constraint_name_arg,
const LEX_CSTRING *ref_db_arg, const LEX_CSTRING *ref_table_arg,
List<Key_part_spec> *ref_cols,
enum_fk_option delete_opt_arg, enum_fk_option update_opt_arg,
@@ -395,6 +432,7 @@ public:
DDL_options ddl_options)
:Key(FOREIGN_KEY, name_arg, &default_key_create_info, 0, cols, NULL,
ddl_options),
+ constraint_name(*constraint_name_arg),
ref_db(*ref_db_arg), ref_table(*ref_table_arg), ref_columns(*ref_cols),
delete_opt(delete_opt_arg), update_opt(update_opt_arg),
match_opt(match_opt_arg)
@@ -426,8 +464,8 @@ class LEX_COLUMN : public Sql_alloc
{
public:
String column;
- uint rights;
- LEX_COLUMN (const String& x,const uint& y ): column (x),rights (y) {}
+ privilege_t rights;
+ LEX_COLUMN (const String& x,const privilege_t & y ): column (x),rights (y) {}
};
class MY_LOCALE;
@@ -615,6 +653,7 @@ typedef struct system_variables
are based on the cluster size):
*/
ulong saved_auto_increment_increment, saved_auto_increment_offset;
+ ulonglong wsrep_gtid_seq_no;
#endif /* WITH_WSREP */
uint eq_range_index_dive_limit;
ulong column_compression_zlib_strategy;
@@ -628,7 +667,6 @@ typedef struct system_variables
ulong max_tmp_tables;
ulong max_insert_delayed_threads;
ulong min_examined_row_limit;
- ulong multi_range_count;
ulong net_buffer_length;
ulong net_interactive_timeout;
ulong net_read_timeout;
@@ -756,6 +794,7 @@ typedef struct system_variables
ulong session_track_transaction_info;
my_bool session_track_schema;
my_bool session_track_state_change;
+ my_bool session_track_user_variables;
my_bool tcp_nodelay;
ulong threadpool_priority;
@@ -867,6 +906,7 @@ typedef struct system_status_var
ulong feature_system_versioning; /* +1 opening a table WITH SYSTEM VERSIONING */
ulong feature_application_time_periods;
/* +1 opening a table with application-time period */
+ ulong feature_insert_returning; /* +1 when INSERT...RETURNING is used */
ulong feature_timezone; /* +1 when XPATH is used */
ulong feature_trigger; /* +1 opening a table with triggers */
ulong feature_xml; /* +1 when XPATH is used */
@@ -920,6 +960,11 @@ typedef struct system_status_var
#define last_system_status_var questions
#define last_cleared_system_status_var local_memory_used
+/** Number of contiguous global status variables */
+constexpr int COUNT_GLOBAL_STATUS_VARS= int(offsetof(STATUS_VAR,
+ last_system_status_var) /
+ sizeof(ulong)) + 1;
+
/*
Global status variables
*/
@@ -977,6 +1022,39 @@ inline bool is_supported_parser_charset(CHARSET_INFO *cs)
return MY_TEST(cs->mbminlen == 1);
}
+/** THD registry */
+class THD_list_iterator
+{
+protected:
+ I_List<THD> threads;
+ mutable mysql_rwlock_t lock;
+
+public:
+
+ /**
+ Iterates registered threads.
+
+ @param action called for every element
+ @param argument opque argument passed to action
+
+ @return
+ @retval 0 iteration completed successfully
+ @retval 1 iteration was interrupted (action returned 1)
+ */
+ template <typename T> int iterate(my_bool (*action)(THD *thd, T *arg), T *arg= 0)
+ {
+ int res= 0;
+ mysql_rwlock_rdlock(&lock);
+ I_List_iterator<THD> it(threads);
+ while (auto tmp= it++)
+ if ((res= action(tmp, arg)))
+ break;
+ mysql_rwlock_unlock(&lock);
+ return res;
+ }
+ static THD_list_iterator *iterator();
+};
+
#ifdef MYSQL_SERVER
void free_tmp_table(THD *thd, TABLE *entry);
@@ -1286,7 +1364,10 @@ struct st_savepoint {
class Security_context {
public:
- Security_context() {} /* Remove gcc warning */
+ Security_context()
+ :master_access(NO_ACL),
+ db_access(NO_ACL)
+ {} /* Remove gcc warning */
/*
host - host of the client
user - user of the client, set to NULL until the user has been read from
@@ -1306,8 +1387,8 @@ public:
char *external_user;
/* points to host if host is available, otherwise points to ip */
const char *host_or_ip;
- ulong master_access; /* Global privileges from mysql.user */
- ulong db_access; /* Privileges for current db */
+ privilege_t master_access; /* Global privileges from mysql.user */
+ privilege_t db_access; /* Privileges for current db */
bool password_expired;
@@ -1340,7 +1421,7 @@ public:
* privileges.
@return True if the security context fulfills the access requirements.
*/
- bool check_access(ulong want_access, bool match_any = false);
+ bool check_access(const privilege_t want_access, bool match_any = false);
bool is_priv_user(const char *user, const char *host);
};
@@ -1886,9 +1967,8 @@ public:
m_reopen_array(NULL),
m_locked_tables_count(0)
{
- init_sql_alloc(&m_locked_tables_root, "Locked_tables_list",
- MEM_ROOT_BLOCK_SIZE, 0,
- MYF(MY_THREAD_SPECIFIC));
+ init_sql_alloc(key_memory_locked_table_list, &m_locked_tables_root,
+ MEM_ROOT_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC));
}
void unlock_locked_tables(THD *thd);
void unlock_locked_table(THD *thd, MDL_ticket *mdl_ticket);
@@ -2135,6 +2215,22 @@ struct wait_for_commit
extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
+class Gap_time_tracker;
+
+/*
+ Thread context for Gap_time_tracker class.
+*/
+class Gap_time_tracker_data
+{
+public:
+ Gap_time_tracker_data(): bill_to(NULL) {}
+
+ Gap_time_tracker *bill_to;
+ ulonglong start_time;
+
+ void init() { bill_to = NULL; }
+};
+
/**
A wrapper around thread_count.
@@ -2313,9 +2409,22 @@ public:
*/
const char *proc_info;
+ void set_psi(PSI_thread *psi)
+ {
+ my_atomic_storeptr((void*volatile*)&m_psi, psi);
+ }
+
+ PSI_thread* get_psi()
+ {
+ return static_cast<PSI_thread*>(my_atomic_loadptr((void*volatile*)&m_psi));
+ }
+
private:
unsigned int m_current_stage_key;
+ /** Performance schema thread instrumentation for this session. */
+ PSI_thread *m_psi;
+
public:
void enter_stage(const PSI_stage_info *stage,
const char *calling_func,
@@ -2332,7 +2441,7 @@ public:
calling_line);
#endif
#ifdef HAVE_PSI_THREAD_INTERFACE
- MYSQL_SET_STAGE(m_current_stage_key, calling_file, calling_line);
+ m_stage_progress_psi= MYSQL_SET_STAGE(m_current_stage_key, calling_file, calling_line);
#endif
}
@@ -2631,9 +2740,8 @@ public:
{
bzero((char*)this, sizeof(*this));
implicit_xid.null();
- init_sql_alloc(&mem_root, "THD::transactions",
- ALLOC_ROOT_MIN_BLOCK_SIZE, 0,
- MYF(MY_THREAD_SPECIFIC));
+ init_sql_alloc(key_memory_thd_transactions, &mem_root,
+ ALLOC_ROOT_MIN_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC));
}
} transaction;
Global_read_lock global_read_lock;
@@ -2931,6 +3039,8 @@ public:
PROFILING profiling;
#endif
+ /** Current stage progress instrumentation. */
+ PSI_stage_progress *m_stage_progress_psi;
/** Current statement digest. */
sql_digest_state *m_digest;
/** Current statement digest token array. */
@@ -2944,6 +3054,14 @@ public:
/** Current statement instrumentation state. */
PSI_statement_locker_state m_statement_state;
#endif /* HAVE_PSI_STATEMENT_INTERFACE */
+
+ /** Current transaction instrumentation. */
+ PSI_transaction_locker *m_transaction_psi;
+#ifdef HAVE_PSI_TRANSACTION_INTERFACE
+ /** Current transaction instrumentation state. */
+ PSI_transaction_locker_state m_transaction_state;
+#endif /* HAVE_PSI_TRANSACTION_INTERFACE */
+
/** Idle instrumentation. */
PSI_idle_locker *m_idle_psi;
#ifdef HAVE_PSI_IDLE_INTERFACE
@@ -2960,7 +3078,7 @@ public:
update auto-updatable fields (like auto_increment and timestamp).
*/
query_id_t query_id;
- ulong col_access;
+ privilege_t col_access;
/* Statement id is thread-wide. This counter is used to generate ids */
ulong statement_id_counter;
@@ -3068,7 +3186,6 @@ public:
uint8 password; /* 0, 1 or 2 */
uint8 failed_com_change_user;
bool slave_thread;
- bool extra_port; /* If extra connection */
bool no_errors;
/**
@@ -3324,6 +3441,7 @@ public:
*/
Apc_target apc_target;
+ Gap_time_tracker_data gap_tracker_data;
#ifndef MYSQL_CLIENT
enum enum_binlog_query_type {
/* The query can be logged in row format or in statement format. */
@@ -3640,6 +3758,18 @@ public:
return alloc_root(&transaction.mem_root,size);
}
+ LEX_CSTRING strmake_lex_cstring(const char *str, size_t length)
+ {
+ const char *tmp= strmake_root(mem_root, str, length);
+ if (!tmp)
+ return {0,0};
+ return {tmp, length};
+ }
+ LEX_CSTRING strmake_lex_cstring(const LEX_CSTRING &from)
+ {
+ return strmake_lex_cstring(from.str, from.length);
+ }
+
LEX_STRING *make_lex_string(LEX_STRING *lex_str, const char* str, size_t length)
{
if (!(lex_str->str= strmake_root(mem_root, str, length)))
@@ -3749,7 +3879,7 @@ public:
const char *src, size_t src_length);
/*
If either "dstcs" or "srccs" is &my_charset_bin,
- then performs native copying using cs->cset->copy_fix().
+ then performs native copying using copy_fix().
Otherwise, performs Unicode conversion using convert_fix().
*/
bool copy_fix(CHARSET_INFO *dstcs, LEX_STRING *dst,
@@ -4553,7 +4683,7 @@ public:
information to decide the logging format. So that cases we call decide_logging_format_2
at later stages in execution.
One example would be binlog format for IODKU but column with unique key is not inserted.
- We dont have inserted columns info when we call decide_logging_format so on later stage we call
+ We don't have inserted columns info when we call decide_logging_format so on later stage we call
decide_logging_format_low
@returns 0 if no format is changed
@@ -4674,9 +4804,7 @@ private:
AUTHID invoker;
public:
-#ifndef EMBEDDED_LIBRARY
Session_tracker session_tracker;
-#endif //EMBEDDED_LIBRARY
/*
Flag, mutex and condition for a thread to wait for a signal from another
thread.
@@ -4703,6 +4831,17 @@ public:
LF_PINS *xid_hash_pins;
bool fix_xid_hash_pins();
+ const XID *get_xid() const
+ {
+#ifdef WITH_WSREP
+ if (!wsrep_xid.is_null())
+ return &wsrep_xid;
+#endif /* WITH_WSREP */
+ return transaction.xid_state.is_explicit_XA() ?
+ transaction.xid_state.get_xid() :
+ &transaction.implicit_xid;
+ }
+
/* Members related to temporary tables. */
public:
/* Opened table states. */
@@ -4836,17 +4975,13 @@ public:
size_t wsrep_TOI_pre_query_len;
wsrep_po_handle_t wsrep_po_handle;
size_t wsrep_po_cnt;
-#ifdef GTID_SUPPORT
- my_bool wsrep_po_in_trans;
- rpl_sid wsrep_po_sid;
-#endif /* GTID_SUPPORT */
void *wsrep_apply_format;
uchar* wsrep_rbr_buf;
wsrep_gtid_t wsrep_sync_wait_gtid;
- // wsrep_gtid_t wsrep_last_written_gtid;
+ uint64 wsrep_last_written_gtid_seqno;
+ uint64 wsrep_current_gtid_seqno;
ulong wsrep_affected_rows;
bool wsrep_has_ignored_error;
- bool wsrep_replicate_GTID;
/*
When enabled, do not replicate/binlog updates from the current table that's
@@ -5089,6 +5224,18 @@ class select_result_sink: public Sql_alloc
public:
THD *thd;
select_result_sink(THD *thd_arg): thd(thd_arg) {}
+ inline int send_data_with_check(List<Item> &items,
+ SELECT_LEX_UNIT *u,
+ ha_rows sent)
+ {
+ if (u->lim.check_offset(sent))
+ return 0;
+
+ if (u->thd->killed == ABORT_QUERY)
+ return 0;
+
+ return send_data(items);
+ }
/*
send_data returns 0 on ok, 1 on error and -1 if data was ignored, for
example for a duplicate row entry written to a temp table.
@@ -5124,7 +5271,7 @@ protected:
/* Something used only by the parser: */
public:
ha_rows est_records; /* estimated number of records in the result */
- select_result(THD *thd_arg): select_result_sink(thd_arg), est_records(0) {}
+ 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() {};
/**
@@ -5190,9 +5337,9 @@ public:
/* this method is called just before the first row of the table can be read */
virtual void prepare_to_read_rows() {}
- void reset_offset_limit()
+ void remove_offset_limit()
{
- unit->offset_limit_cnt= 0;
+ unit->lim.remove_offset();
}
/*
@@ -5218,7 +5365,7 @@ public:
It is aimed at capturing SHOW EXPLAIN output, so:
- Unlike select_result class, we don't assume that the sent data is an
- output of a SELECT_LEX_UNIT (and so we dont apply "LIMIT x,y" from the
+ output of a SELECT_LEX_UNIT (and so we don't apply "LIMIT x,y" from the
unit)
- We don't try to convert the target table to MyISAM
*/
@@ -5499,16 +5646,17 @@ public:
class select_insert :public select_result_interceptor {
public:
+ select_result *sel_result;
TABLE_LIST *table_list;
TABLE *table;
List<Item> *fields;
ulonglong autoinc_value_of_last_inserted_row; // autogenerated or not
COPY_INFO info;
bool insert_into_view;
- select_insert(THD *thd_arg, TABLE_LIST *table_list_par,
- TABLE *table_par, List<Item> *fields_par,
- List<Item> *update_fields, List<Item> *update_values,
- enum_duplicates duplic, bool ignore);
+ select_insert(THD *thd_arg, TABLE_LIST *table_list_par, TABLE *table_par,
+ List<Item> *fields_par, List<Item> *update_fields,
+ List<Item> *update_values, enum_duplicates duplic,
+ bool ignore, select_result *sel_ret_list);
~select_insert();
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
virtual int prepare2(JOIN *join);
@@ -5544,7 +5692,7 @@ public:
List<Item> &select_fields,enum_duplicates duplic, bool ignore,
TABLE_LIST *select_tables_arg):
select_insert(thd_arg, table_arg, NULL, &select_fields, 0, 0, duplic,
- ignore),
+ ignore, NULL),
create_table(table_arg),
create_info(create_info_par),
select_tables(select_tables_arg),
@@ -5699,17 +5847,18 @@ public:
class select_unit :public select_result_interceptor
{
+protected:
uint curr_step, prev_step, curr_sel;
enum sub_select_type step;
public:
- Item_int *intersect_mark;
TMP_TABLE_PARAM tmp_table_param;
+ /* Number of additional (hidden) field of the used temporary table */
+ int addon_cnt;
int write_err; /* Error code from the last send_data->ha_write_row call. */
TABLE *table;
select_unit(THD *thd_arg):
- select_result_interceptor(thd_arg),
- intersect_mark(0), table(0)
+ select_result_interceptor(thd_arg), addon_cnt(0), table(0)
{
init();
tmp_table_param.init();
@@ -5726,6 +5875,9 @@ public:
virtual bool postponed_prepare(List<Item> &types)
{ return false; }
int send_data(List<Item> &items);
+ int write_record();
+ int update_counter(Field *counter, longlong value);
+ int delete_record();
bool send_eof();
virtual bool flush();
void cleanup();
@@ -5744,7 +5896,148 @@ public:
step= UNION_TYPE;
write_err= 0;
}
+ virtual void change_select();
+ virtual bool force_enable_index_if_needed() { return false; }
+};
+
+
+/**
+ @class select_unit_ext
+
+ The class used when processing rows produced by operands of query expressions
+ containing INTERSECT ALL and/or EXCEPT all operations. One or two extra fields
+ of the temporary to store the rows of the partial and final result can be employed.
+ Both of them contain counters. The second additional field is used only when
+ the processed query expression contains INTERSECT ALL.
+
+ Consider how these extra fields are used.
+
+ Let
+ table t1 (f char(8))
+ table t2 (f char(8))
+ table t3 (f char(8))
+ contain the following sets:
+ ("b"),("a"),("d"),("c"),("b"),("a"),("c"),("a")
+ ("c"),("b"),("c"),("c"),("a"),("b"),("g")
+ ("c"),("a"),("b"),("d"),("b"),("e")
+
+ - Let's demonstrate how the the set operation INTERSECT ALL is proceesed
+ for the query
+ SELECT f FROM t1 INTERSECT ALL SELECT f FROM t2
+
+ When send_data() is called for the rows of the first operand we put
+ the processed record into the temporary table if there was no such record
+ setting dup_cnt field to 1 and add_cnt field to 0 and increment the
+ counter in the dup_cnt field by one otherwise. We get
+
+ |add_cnt|dup_cnt| f |
+ |0 |2 |b |
+ |0 |3 |a |
+ |0 |1 |d |
+ |0 |2 |c |
+
+ The call of send_eof() for the first operand swaps the values stored in
+ dup_cnt and add_cnt. After this, we'll see the following rows in the
+ temporary table
+
+ |add_cnt|dup_cnt| f |
+ |2 |0 |b |
+ |3 |0 |a |
+ |1 |0 |d |
+ |2 |0 |c |
+
+ When send_data() is called for the rows of the second operand we increment
+ the counter in dup_cnt if the processed row is found in the table and do
+ nothing otherwise. As a result we get
+
+ |add_cnt|dup_cnt| f |
+ |2 |2 |b |
+ |3 |1 |a |
+ |1 |0 |d |
+ |2 |3 |c |
+
+ At the call of send_eof() for the second operand first we disable index.
+ Then for each record, the minimum of counters from dup_cnt and add_cnt m is
+ taken. If m == 0 then the record is deleted. Otherwise record is replaced
+ with m copies of it. Yet the counter in this copies are set to 1 for
+ dup_cnt and to 0 for add_cnt
+
+ |add_cnt|dup_cnt| f |
+ |0 |1 |b |
+ |0 |1 |b |
+ |0 |1 |a |
+ |0 |1 |c |
+ |0 |1 |c |
+
+ - Let's demonstrate how the the set operation EXCEPT ALL is proceesed
+ for the query
+ SELECT f FROM t1 EXCEPT ALL SELECT f FROM t3
+
+ Only one additional counter field dup_cnt is used for EXCEPT ALL.
+ After the first operand has been processed we have in the temporary table
+
+ |dup_cnt| f |
+ |2 |b |
+ |3 |a |
+ |1 |d |
+ |2 |c |
+
+ When send_data() is called for the rows of the second operand we decrement
+ the counter in dup_cnt if the processed row is found in the table and do
+ nothing otherwise. If the counter becomes 0 we delete the record
+
+ |dup_cnt| f |
+ |2 |a |
+ |1 |c |
+
+ Finally at the call of send_eof() for the second operand we disable index
+ unfold rows adding duplicates
+
+ |dup_cnt| f |
+ |1 |a |
+ |1 |a |
+ |1 |c |
+ */
+
+class select_unit_ext :public select_unit
+{
+public:
+ select_unit_ext(THD *thd_arg):
+ select_unit(thd_arg), increment(0), is_index_enabled(TRUE),
+ curr_op_type(UNSPECIFIED)
+ {
+ };
+ int send_data(List<Item> &items);
void change_select();
+ int unfold_record(ha_rows cnt);
+ bool send_eof();
+ bool force_enable_index_if_needed()
+ {
+ is_index_enabled= true;
+ return true;
+ }
+ bool disable_index_if_needed(SELECT_LEX *curr_sl);
+
+ /*
+ How to change increment/decrement the counter in duplicate_cnt field
+ when processing a record produced by the current operand in send_data().
+ The value can be 1 or -1
+ */
+ int increment;
+ /* TRUE <=> the index of the result temporary table is enabled */
+ bool is_index_enabled;
+ /* The type of the set operation currently executed */
+ enum set_op_type curr_op_type;
+ /*
+ Points to the extra field of the temporary table where
+ duplicate counters are stored
+ */
+ Field *duplicate_cnt;
+ /*
+ Points to the extra field of the temporary table where additional
+ counters used only for INTERSECT ALL operations are stored
+ */
+ Field *additional_cnt;
};
class select_union_recursive :public select_unit
@@ -5858,7 +6151,7 @@ public:
*/
DBUG_ASSERT(false); /* purecov: inspected */
}
- void reset_offset_limit_cnt()
+ void remove_offset_limit()
{
// EXPLAIN should never output to a select_union_direct
DBUG_ASSERT(false); /* purecov: inspected */
@@ -6058,8 +6351,52 @@ public:
/* Structs used when sorting */
struct SORT_FIELD_ATTR
{
- uint length; /* Length of sort field */
- uint suffix_length; /* Length suffix (0-4) */
+ /*
+ If using mem-comparable fixed-size keys:
+ length of the mem-comparable image of the field, in bytes.
+
+ If using packed keys: still the same? Not clear what is the use of it.
+ */
+ uint length;
+
+ /*
+ For most datatypes, this is 0.
+ The exception are the VARBINARY columns.
+ For those columns, the comparison actually compares
+
+ (value_prefix(N), suffix=length(value))
+
+ Here value_prefix is either the whole value or its prefix if it was too
+ long, and the suffix is the length of the original value.
+ (this way, for values X and Y: if X=prefix(Y) then X compares as less
+ than Y
+ */
+ uint suffix_length;
+
+ /*
+ If using packed keys, number of bytes that are used to store the length
+ of the packed key.
+
+ */
+ uint length_bytes;
+
+ /* Max. length of the original value, in bytes */
+ uint original_length;
+ enum Type { FIXED_SIZE, VARIABLE_SIZE } type;
+ /*
+ TRUE : if the item or field is NULLABLE
+ FALSE : otherwise
+ */
+ bool maybe_null;
+ CHARSET_INFO *cs;
+ uint pack_sort_string(uchar *to, const LEX_CSTRING &str,
+ CHARSET_INFO *cs) const;
+ int compare_packed_fixed_size_vals(uchar *a, size_t *a_len,
+ uchar *b, size_t *b_len);
+ int compare_packed_varstrings(uchar *a, size_t *a_len,
+ uchar *b, size_t *b_len);
+ bool check_if_packing_possible(THD *thd) const;
+ bool is_variable_sized() { return type == VARIABLE_SIZE; }
};
@@ -6166,7 +6503,7 @@ class user_var_entry
double val_real(bool *null_value);
longlong val_int(bool *null_value) const;
- String *val_str(bool *null_value, String *str, uint decimals);
+ String *val_str(bool *null_value, String *str, uint decimals) const;
my_decimal *val_decimal(bool *null_value, my_decimal *result);
CHARSET_INFO *charset() const { return m_charset; }
void set_charset(CHARSET_INFO *cs) { m_charset= cs; }
@@ -6600,8 +6937,8 @@ inline int handler::ha_write_tmp_row(uchar *buf)
int error;
MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str);
increment_statistics(&SSV::ha_tmp_write_count);
- TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0,
- { error= write_row(buf); })
+ TABLE_IO_WAIT(tracker, PSI_TABLE_WRITE_ROW, MAX_KEY, error,
+ { error= write_row(buf); })
MYSQL_INSERT_ROW_DONE(error);
return error;
}
@@ -6611,7 +6948,7 @@ inline int handler::ha_delete_tmp_row(uchar *buf)
int error;
MYSQL_DELETE_ROW_START(table_share->db.str, table_share->table_name.str);
increment_statistics(&SSV::ha_tmp_delete_count);
- TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_DELETE_ROW, MAX_KEY, 0,
+ TABLE_IO_WAIT(tracker, PSI_TABLE_DELETE_ROW, MAX_KEY, error,
{ error= delete_row(buf); })
MYSQL_DELETE_ROW_DONE(error);
return error;
@@ -6622,13 +6959,12 @@ inline int handler::ha_update_tmp_row(const uchar *old_data, uchar *new_data)
int error;
MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str);
increment_statistics(&SSV::ha_tmp_update_count);
- TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_UPDATE_ROW, active_index, 0,
- { error= update_row(old_data, new_data);})
+ TABLE_IO_WAIT(tracker, PSI_TABLE_UPDATE_ROW, active_index, error,
+ { error= update_row(old_data, new_data);})
MYSQL_UPDATE_ROW_DONE(error);
return error;
}
-
extern pthread_attr_t *get_connection_attrib(void);
/**
@@ -6715,6 +7051,62 @@ class Switch_to_definer_security_ctx
};
+class Sql_mode_instant_set: public Sql_mode_save
+{
+public:
+ Sql_mode_instant_set(THD *thd, sql_mode_t temporary_value)
+ :Sql_mode_save(thd)
+ {
+ thd->variables.sql_mode= temporary_value;
+ }
+};
+
+
+class Sql_mode_instant_remove: public Sql_mode_save
+{
+public:
+ Sql_mode_instant_remove(THD *thd, sql_mode_t temporary_remove_flags)
+ :Sql_mode_save(thd)
+ {
+ thd->variables.sql_mode&= ~temporary_remove_flags;
+ }
+};
+
+
+class Abort_on_warning_instant_set
+{
+ THD *m_thd;
+ bool m_save_abort_on_warning;
+public:
+ Abort_on_warning_instant_set(THD *thd, bool temporary_value)
+ :m_thd(thd), m_save_abort_on_warning(thd->abort_on_warning)
+ {
+ thd->abort_on_warning= temporary_value;
+ }
+ ~Abort_on_warning_instant_set()
+ {
+ m_thd->abort_on_warning= m_save_abort_on_warning;
+ }
+};
+
+
+class Check_level_instant_set
+{
+ THD *m_thd;
+ enum_check_fields m_check_level;
+public:
+ Check_level_instant_set(THD *thd, enum_check_fields temporary_value)
+ :m_thd(thd), m_check_level(thd->count_cuted_fields)
+ {
+ thd->count_cuted_fields= temporary_value;
+ }
+ ~Check_level_instant_set()
+ {
+ m_thd->count_cuted_fields= m_check_level;
+ }
+};
+
+
/**
This class resembles the SQL Standard schema qualified object name:
<schema qualified name> ::= [ <schema name> <period> ] <qualified identifier>
@@ -6742,17 +7134,15 @@ public:
bool eq(const Database_qualified_name *other) const
{
CHARSET_INFO *cs= lower_case_table_names ?
- &my_charset_utf8_general_ci :
- &my_charset_utf8_bin;
+ &my_charset_utf8mb3_general_ci :
+ &my_charset_utf8mb3_bin;
return
m_db.length == other->m_db.length &&
m_name.length == other->m_name.length &&
- !my_strnncoll(cs,
- (const uchar *) m_db.str, m_db.length,
- (const uchar *) other->m_db.str, other->m_db.length) &&
- !my_strnncoll(cs,
- (const uchar *) m_name.str, m_name.length,
- (const uchar *) other->m_name.str, other->m_name.length);
+ !cs->strnncoll(m_db.str, m_db.length,
+ other->m_db.str, other->m_db.length) &&
+ !cs->strnncoll(m_name.str, m_name.length,
+ other->m_name.str, other->m_name.length);
}
void copy(MEM_ROOT *mem_root, const LEX_CSTRING &db,
const LEX_CSTRING &name);
@@ -6828,10 +7218,9 @@ public:
class Type_holder: public Sql_alloc,
public Item_args,
public Type_handler_hybrid_field_type,
- public Type_all_attributes,
- public Type_geometry_attributes
+ public Type_all_attributes
{
- TYPELIB *m_typelib;
+ const TYPELIB *m_typelib;
bool m_maybe_null;
public:
Type_holder()
@@ -6854,19 +7243,11 @@ public:
DBUG_ASSERT(0);
return 0;
}
- void set_geometry_type(uint type)
- {
- Type_geometry_attributes::set_geometry_type(type);
- }
- uint uint_geometry_type() const
- {
- return Type_geometry_attributes::get_geometry_type();
- }
- void set_typelib(TYPELIB *typelib)
+ void set_typelib(const TYPELIB *typelib)
{
m_typelib= typelib;
}
- TYPELIB *get_typelib() const
+ const TYPELIB *get_typelib() const
{
return m_typelib;
}
@@ -6951,11 +7332,8 @@ private:
/** THD registry */
-class THD_list
+class THD_list: public THD_list_iterator
{
- I_List<THD> threads;
- mutable mysql_rwlock_t lock;
-
public:
/**
Constructor replacement.
@@ -7003,28 +7381,6 @@ public:
thd->unlink();
mysql_rwlock_unlock(&lock);
}
-
- /**
- Iterates registered threads.
-
- @param action called for every element
- @param argument opque argument passed to action
-
- @return
- @retval 0 iteration completed successfully
- @retval 1 iteration was interrupted (action returned 1)
- */
- template <typename T> int iterate(my_bool (*action)(THD *thd, T *arg), T *arg= 0)
- {
- int res= 0;
- mysql_rwlock_rdlock(&lock);
- I_List_iterator<THD> it(threads);
- while (auto tmp= it++)
- if ((res= action(tmp, arg)))
- break;
- mysql_rwlock_unlock(&lock);
- return res;
- }
};
extern THD_list server_threads;
diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h
index 7f1fd06aa46..ce34852117f 100644
--- a/sql/sql_cmd.h
+++ b/sql/sql_cmd.h
@@ -38,7 +38,7 @@ enum enum_sql_command {
SQLCOM_SHOW_DATABASES, SQLCOM_SHOW_TABLES, SQLCOM_SHOW_FIELDS,
SQLCOM_SHOW_KEYS, SQLCOM_SHOW_VARIABLES, SQLCOM_SHOW_STATUS,
SQLCOM_SHOW_ENGINE_LOGS, SQLCOM_SHOW_ENGINE_STATUS, SQLCOM_SHOW_ENGINE_MUTEX,
- SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT,
+ SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_BINLOG_STAT, SQLCOM_SHOW_SLAVE_STAT,
SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS,
SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_SHOW_TABLE_STATUS,
SQLCOM_SHOW_TRIGGERS,
@@ -208,6 +208,26 @@ protected:
}
};
+class Sql_cmd_show_slave_status: public Sql_cmd
+{
+protected:
+ bool show_all_slaves_status;
+public:
+ Sql_cmd_show_slave_status()
+ :show_all_slaves_status(false)
+ {}
+
+ Sql_cmd_show_slave_status(bool status_all)
+ :show_all_slaves_status(status_all)
+ {}
+
+ enum_sql_command sql_command_code() const { return SQLCOM_SHOW_SLAVE_STAT; }
+
+ bool execute(THD *thd);
+ bool is_show_all_slaves_stat() { return show_all_slaves_status; }
+};
+
+
class Sql_cmd_create_table_like: public Sql_cmd,
public Storage_engine_name
{
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 6bf43d3df5e..d5a90089da4 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -35,7 +35,6 @@
#include "sql_db.h" // mysql_change_db
#include "hostname.h" // inc_host_errors, ip_to_hostname,
// reset_host_errors
-#include "sql_acl.h" // acl_getroot, NO_ACCESS, SUPER_ACL
#include "sql_callback.h"
#ifdef WITH_WSREP
@@ -43,6 +42,7 @@
#include "wsrep_mysqld.h"
#endif /* WITH_WSREP */
#include "proxy_protocol.h"
+#include <ssl_compat.h>
HASH global_user_stats, global_client_stats, global_table_stats;
HASH global_index_stats;
@@ -80,8 +80,8 @@ int get_or_create_user_conn(THD *thd, const char *user,
{
/* First connection for user; Create a user connection object */
if (!(uc= ((struct user_conn*)
- my_malloc(sizeof(struct user_conn) + temp_len+1,
- MYF(MY_WME)))))
+ my_malloc(key_memory_user_conn,
+ sizeof(struct user_conn) + temp_len+1, MYF(MY_WME)))))
{
/* MY_WME ensures an error is set in THD. */
return_val= 1;
@@ -139,7 +139,7 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc)
if (global_system_variables.max_user_connections &&
!uc->user_resources.user_conn &&
global_system_variables.max_user_connections < uc->connections &&
- !(thd->security_ctx->master_access & SUPER_ACL))
+ !(thd->security_ctx->master_access & PRIV_IGNORE_MAX_USER_CONNECTIONS))
{
my_error(ER_TOO_MANY_USER_CONNECTIONS, MYF(0), uc->user);
error=1;
@@ -321,9 +321,9 @@ extern "C" void free_user(struct user_conn *uc)
void init_max_user_conn(void)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- my_hash_init(&hash_user_connections, system_charset_info, max_connections,
- 0, 0, (my_hash_get_key) get_key_conn,
- (my_hash_free_key) free_user, 0);
+ my_hash_init(key_memory_user_conn, &hash_user_connections,
+ system_charset_info, max_connections, 0, 0, (my_hash_get_key)
+ get_key_conn, (my_hash_free_key) free_user, 0);
#endif
}
@@ -482,14 +482,14 @@ void init_user_stats(USER_STATS *user_stats,
void init_global_user_stats(void)
{
- my_hash_init(&global_user_stats, system_charset_info, max_connections,
+ my_hash_init(PSI_INSTRUMENT_ME, &global_user_stats, system_charset_info, max_connections,
0, 0, (my_hash_get_key) get_key_user_stats,
(my_hash_free_key) free_user_stats, 0);
}
void init_global_client_stats(void)
{
- my_hash_init(&global_client_stats, system_charset_info, max_connections,
+ my_hash_init(PSI_INSTRUMENT_ME, &global_client_stats, system_charset_info, max_connections,
0, 0, (my_hash_get_key) get_key_user_stats,
(my_hash_free_key) free_user_stats, 0);
}
@@ -508,8 +508,8 @@ extern "C" void free_table_stats(TABLE_STATS* table_stats)
void init_global_table_stats(void)
{
- my_hash_init(&global_table_stats, system_charset_info, max_connections,
- 0, 0, (my_hash_get_key) get_key_table_stats,
+ my_hash_init(PSI_INSTRUMENT_ME, &global_table_stats, system_charset_info,
+ max_connections, 0, 0, (my_hash_get_key) get_key_table_stats,
(my_hash_free_key) free_table_stats, 0);
}
@@ -527,8 +527,8 @@ extern "C" void free_index_stats(INDEX_STATS* index_stats)
void init_global_index_stats(void)
{
- my_hash_init(&global_index_stats, system_charset_info, max_connections,
- 0, 0, (my_hash_get_key) get_key_index_stats,
+ my_hash_init(PSI_INSTRUMENT_ME, &global_index_stats, system_charset_info,
+ max_connections, 0, 0, (my_hash_get_key) get_key_index_stats,
(my_hash_free_key) free_index_stats, 0);
}
@@ -570,7 +570,7 @@ static bool increment_count_by_name(const char *name, size_t name_length,
{
/* First connection for this user or client */
if (!(user_stats= ((USER_STATS*)
- my_malloc(sizeof(USER_STATS),
+ my_malloc(PSI_INSTRUMENT_ME, sizeof(USER_STATS),
MYF(MY_WME | MY_ZEROFILL)))))
return TRUE; // Out of memory
@@ -879,7 +879,7 @@ int thd_set_peer_addr(THD *thd,
}
my_free((void *)thd->main_security_ctx.ip);
- if (!(thd->main_security_ctx.ip = my_strdup(ip, MYF(MY_WME))))
+ if (!(thd->main_security_ctx.ip = my_strdup(PSI_INSTRUMENT_ME, ip, MYF(MY_WME))))
{
/*
No error accounting per IP in host_cache,
@@ -1112,7 +1112,6 @@ bool setup_connection_thread_globals(THD *thd)
close_connection(thd, ER_OUT_OF_RESOURCES);
statistic_increment(aborted_connects,&LOCK_status);
statistic_increment(connection_errors_internal, &LOCK_status);
- thd->scheduler->end_thread(thd, 0);
return 1; // Error
}
return 0;
@@ -1246,7 +1245,8 @@ void prepare_new_connection_state(THD* thd)
thd->set_command(COM_SLEEP);
thd->init_for_queries();
- if (opt_init_connect.length && !(sctx->master_access & SUPER_ACL))
+ if (opt_init_connect.length &&
+ !(sctx->master_access & PRIV_IGNORE_INIT_CONNECT))
{
execute_init_command(thd, &opt_init_connect, &LOCK_sys_init_connect);
if (unlikely(thd->is_error()))
@@ -1313,7 +1313,16 @@ pthread_handler_t handle_one_connection(void *arg)
mysql_thread_set_psi_id(connect->thread_id);
- do_handle_one_connection(connect);
+ if (init_new_connection_handler_thread())
+ connect->close_with_error(0, 0, ER_OUT_OF_RESOURCES);
+ else
+ do_handle_one_connection(connect, true);
+
+ DBUG_PRINT("info", ("killing thread"));
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
+ ERR_remove_state(0);
+#endif
+ my_thread_end();
return 0;
}
@@ -1347,16 +1356,13 @@ bool thd_is_connection_alive(THD *thd)
}
-void do_handle_one_connection(CONNECT *connect)
+void do_handle_one_connection(CONNECT *connect, bool put_in_cache)
{
ulonglong thr_create_utime= microsecond_interval_timer();
THD *thd;
- if (connect->scheduler->init_new_connection_thread() ||
- !(thd= connect->create_thd(NULL)))
+ if (!(thd= connect->create_thd(NULL)))
{
- scheduler_functions *scheduler= connect->scheduler;
- connect->close_with_error(0, 0, ER_OUT_OF_RESOURCES);
- scheduler->end_thread(0, 0);
+ connect->close_and_delete();
return;
}
@@ -1392,7 +1398,11 @@ void do_handle_one_connection(CONNECT *connect)
*/
thd->thread_stack= (char*) &thd;
if (setup_connection_thread_globals(thd))
+ {
+ unlink_thd(thd);
+ delete thd;
return;
+ }
for (;;)
{
@@ -1420,16 +1430,37 @@ end_thread:
if (thd->userstat_running)
update_global_user_stats(thd, create_user, time(NULL));
- if (thd->scheduler->end_thread(thd, 1))
- return; // Probably no-threads
+ unlink_thd(thd);
+ if (IF_WSREP(thd->wsrep_applier, false) || !put_in_cache ||
+ !(connect= cache_thread(thd)))
+ break;
+
+ /* Create new instrumentation for the new THD job */
+ PSI_CALL_set_thread(PSI_CALL_new_thread(key_thread_one_connection, thd,
+ thd->thread_id));
+
+ if (!(connect->create_thd(thd)))
+ {
+ /* Out of resources. Free thread to get more resources */
+ connect->close_and_delete();
+ break;
+ }
+ delete connect;
/*
- If end_thread() returns, this thread has been schedule to
- handle the next connection.
+ We have to call store_globals to update mysys_var->id and lock_info
+ with the new thread_id
*/
- thd= current_thd;
- thd->thread_stack= (char*) &thd;
+ thd->store_globals();
+
+ /* reset abort flag for the thread */
+ thd->mysys_var->abort= 0;
+ thd->thr_create_utime= microsecond_interval_timer();
+ thd->start_utime= thd->thr_create_utime;
+
+ server_threads.insert(thd);
}
+ delete thd;
}
#endif /* EMBEDDED_LIBRARY */
@@ -1446,10 +1477,16 @@ void CONNECT::close_and_delete()
{
DBUG_ENTER("close_and_delete");
- if (vio)
- vio_close(vio);
- if (thread_count_incremented)
- dec_connection_count(scheduler);
+#if _WIN32
+ if (vio_type == VIO_TYPE_NAMEDPIPE)
+ CloseHandle(pipe);
+ else
+#endif
+ if (vio_type != VIO_CLOSED)
+ mysql_socket_close(sock);
+ vio_type= VIO_CLOSED;
+
+ --*scheduler->connection_count;
statistic_increment(connection_errors_internal, &LOCK_status);
statistic_increment(aborted_connects,&LOCK_status);
@@ -1478,18 +1515,12 @@ void CONNECT::close_with_error(uint sql_errno,
}
-CONNECT::~CONNECT()
-{
- if (vio)
- vio_delete(vio);
-}
-
-
/* Reuse or create a THD based on a CONNECT object */
THD *CONNECT::create_thd(THD *thd)
{
bool res, thd_reused= thd != 0;
+ Vio *vio;
DBUG_ENTER("create_thd");
DBUG_EXECUTE_IF("simulate_failed_connection_2", DBUG_RETURN(0); );
@@ -1508,9 +1539,23 @@ THD *CONNECT::create_thd(THD *thd)
else if (!(thd= new THD(thread_id)))
DBUG_RETURN(0);
+#if _WIN32
+ if (vio_type == VIO_TYPE_NAMEDPIPE)
+ vio= vio_new_win32pipe(pipe);
+ else
+#endif
+ vio= mysql_socket_vio_new(sock, vio_type, vio_type == VIO_TYPE_SOCKET ?
+ VIO_LOCALHOST : 0);
+ if (!vio)
+ {
+ if (!thd_reused)
+ delete thd;
+ DBUG_RETURN(0);
+ }
+
set_current_thd(thd);
res= my_net_init(&thd->net, vio, thd, MYF(MY_THREAD_SPECIFIC));
- vio= 0; // Vio now handled by thd
+ vio_type= VIO_CLOSED; // Vio now handled by thd
if (unlikely(res || thd->is_error()))
{
@@ -1522,9 +1567,20 @@ THD *CONNECT::create_thd(THD *thd)
init_net_server_extension(thd);
- thd->security_ctx->host= host;
- thd->extra_port= extra_port;
+ thd->security_ctx->host= thd->net.vio->type == VIO_TYPE_NAMEDPIPE ||
+ thd->net.vio->type == VIO_TYPE_SOCKET ?
+ my_localhost : 0;
+
thd->scheduler= scheduler;
- thd->real_id= real_id;
+ thd->real_id= pthread_self(); /* Duplicates THD::store_globals() setting. */
+
+ /* Attach PSI instrumentation to the new THD */
+
+ PSI_thread *psi= PSI_CALL_get_thread();
+ PSI_CALL_set_thread_os_id(psi);
+ PSI_CALL_set_thread_THD(psi, thd);
+ PSI_CALL_set_thread_id(psi, thd->thread_id);
+ thd->set_psi(psi);
+
DBUG_RETURN(thd);
}
diff --git a/sql/sql_connect.h b/sql/sql_connect.h
index 82ab4423b37..4d62834a6f9 100644
--- a/sql/sql_connect.h
+++ b/sql/sql_connect.h
@@ -21,6 +21,7 @@
#include "structs.h"
#include <mysql/psi/mysql_socket.h>
#include <hash.h>
+#include "violite.h"
/*
Object to hold connect information to be given to the newly created thread
@@ -30,25 +31,24 @@ struct scheduler_functions;
class CONNECT : public ilink {
public:
- /* To be copied to THD */
- Vio *vio; /* Copied to THD with my_net_init() */
- const char *host;
+ MYSQL_SOCKET sock;
+#ifdef _WIN32
+ HANDLE pipe;
+ CONNECT(HANDLE pipe_arg): pipe(pipe_arg), vio_type(VIO_TYPE_NAMEDPIPE),
+ scheduler(thread_scheduler), thread_id(0), prior_thr_create_utime(0) {}
+#endif
+ enum enum_vio_type vio_type;
scheduler_functions *scheduler;
my_thread_id thread_id;
- pthread_t real_id;
- bool extra_port;
/* Own variables */
- bool thread_count_incremented;
ulonglong prior_thr_create_utime;
- CONNECT()
- :vio(0), host(0), scheduler(thread_scheduler), thread_id(0), real_id(0),
- extra_port(0),
- thread_count_incremented(0), prior_thr_create_utime(0)
- {
- };
- ~CONNECT();
+ CONNECT(MYSQL_SOCKET sock_arg, enum enum_vio_type vio_type_arg,
+ scheduler_functions *scheduler_arg): sock(sock_arg),
+ vio_type(vio_type_arg), scheduler(scheduler_arg), thread_id(0),
+ prior_thr_create_utime(0) {}
+ ~CONNECT() { DBUG_ASSERT(vio_type == VIO_CLOSED); }
void close_and_delete();
void close_with_error(uint sql_errno,
const char *message, uint close_error);
@@ -71,7 +71,7 @@ void free_global_index_stats(void);
void free_global_client_stats(void);
pthread_handler_t handle_one_connection(void *arg);
-void do_handle_one_connection(CONNECT *connect);
+void do_handle_one_connection(CONNECT *connect, bool put_in_cache);
bool init_new_connection_handler_thread();
void reset_mqh(LEX_USER *lu, bool get_them);
bool check_mqh(THD *thd, uint check_command);
diff --git a/sql/sql_const.h b/sql/sql_const.h
index f7c820c727b..a3f0e35ac47 100644
--- a/sql/sql_const.h
+++ b/sql/sql_const.h
@@ -309,4 +309,6 @@
#define QUERY_PRIOR 6
#endif /* __WIN92__ */
+#define SP_PSI_STATEMENT_INFO_COUNT 19
+
#endif /* SQL_CONST_INCLUDED */
diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc
index e452196a271..93344956468 100644
--- a/sql/sql_cte.cc
+++ b/sql/sql_cte.cc
@@ -21,6 +21,7 @@
#include "sql_view.h" // for make_valid_column_names
#include "sql_parse.h"
#include "sql_select.h"
+#include "sql_show.h" // append_definer, append_identifier
/**
@@ -944,9 +945,9 @@ err:
false otherwise
*/
-bool
-With_element::rename_columns_of_derived_unit(THD *thd,
- st_select_lex_unit *unit)
+bool
+With_element::process_columns_of_derived_unit(THD *thd,
+ st_select_lex_unit *unit)
{
if (unit->columns_are_renamed)
return false;
@@ -956,7 +957,7 @@ With_element::rename_columns_of_derived_unit(THD *thd,
if (column_list.elements) // The column list is optional
{
List_iterator_fast<Item> it(select->item_list);
- List_iterator_fast<LEX_CSTRING> nm(column_list);
+ List_iterator_fast<Lex_ident_sys> nm(column_list);
Item *item;
LEX_CSTRING *name;
@@ -972,8 +973,8 @@ With_element::rename_columns_of_derived_unit(THD *thd,
/* Rename the columns of the first select in the unit */
while ((item= it++, name= nm++))
{
- item->set_name(thd, name->str, (uint) name->length, system_charset_info);
- item->is_autogenerated_name= false;
+ item->set_name(thd, *name);
+ item->common_flags&= ~IS_AUTO_GENERATED_NAME;
}
if (arena)
@@ -982,6 +983,43 @@ With_element::rename_columns_of_derived_unit(THD *thd,
else
make_valid_column_names(thd, select->item_list);
+ if (cycle_list)
+ {
+ List_iterator_fast<Item> it(select->item_list);
+ List_iterator_fast<Lex_ident_sys> nm(*cycle_list);
+ List_iterator_fast<Lex_ident_sys> nm_check(*cycle_list);
+ DBUG_ASSERT(cycle_list->elements != 0);
+ while (LEX_CSTRING *name= nm++)
+ {
+ Item *item;
+ /*
+ Check for uniqueness of each element in the cycle list:
+ It's sufficient to check that there is no duplicate of 'name'
+ among the elements that precede it.
+ */
+ LEX_CSTRING *check;
+ nm_check.rewind();
+ while ((check= nm_check++) && check != name)
+ {
+ if (check->length == name->length &&
+ strncmp(check->str, name->str, name->length) == 0)
+ {
+ my_error(ER_DUP_FIELDNAME, MYF(0), check->str);
+ return true;
+ }
+ }
+ /* Check that 'name' is the name of a column of the processed CTE */
+ while ((item= it++) &&
+ (item->name.length != name->length ||
+ strncmp(item->name.str, name->str, name->length) != 0));
+ if (item == NULL)
+ {
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), name->str, "CYCLE clause");
+ return true;
+ }
+ item->common_flags|= IS_IN_WITH_CYCLE;
+ }
+ }
unit->columns_are_renamed= true;
return false;
@@ -1018,7 +1056,7 @@ bool With_element::prepare_unreferenced(THD *thd)
thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED;
if (!spec->prepared &&
(spec->prepare(spec->derived, 0, 0) ||
- rename_columns_of_derived_unit(thd, spec) ||
+ process_columns_of_derived_unit(thd, spec) ||
check_duplicate_names(thd, first_sl->item_list, 1)))
rc= true;
@@ -1394,16 +1432,17 @@ bool st_select_lex::check_subqueries_with_recursive_references()
/**
@brief
Print this with clause
-
+
+ @param thd Thread handle
@param str Where to print to
- @param query_type The mode of printing
-
+ @param query_type The mode of printing
+
@details
- The method prints a string representation of this clause in the
+ The method prints a string representation of this clause in the
string str. The parameter query_type specifies the mode of printing.
-*/
+*/
-void With_clause::print(String *str, enum_query_type query_type)
+void With_clause::print(THD *thd, String *str, enum_query_type query_type)
{
/*
Any with clause contains just definitions of CTE tables.
@@ -1420,7 +1459,22 @@ void With_clause::print(String *str, enum_query_type query_type)
{
if (with_elem != with_list.first)
str->append(", ");
- with_elem->print(str, query_type);
+ with_elem->print(thd, str, query_type);
+ }
+}
+
+
+static void list_strlex_print(THD *thd, String *str, List<Lex_ident_sys> *list)
+{
+ List_iterator_fast<Lex_ident_sys> li(*list);
+ bool first= TRUE;
+ while(Lex_ident_sys *col_name= li++)
+ {
+ if (first)
+ first= FALSE;
+ else
+ str->append(',');
+ append_identifier(thd, str, col_name);
}
}
@@ -1428,38 +1482,37 @@ void With_clause::print(String *str, enum_query_type query_type)
/**
@brief
Print this with element
-
+
+ @param thd Thread handle
@param str Where to print to
- @param query_type The mode of printing
-
+ @param query_type The mode of printing
+
@details
- The method prints a string representation of this with element in the
+ The method prints a string representation of this with element in the
string str. The parameter query_type specifies the mode of printing.
*/
-void With_element::print(String *str, enum_query_type query_type)
+void With_element::print(THD *thd, String *str, enum_query_type query_type)
{
str->append(query_name);
if (column_list.elements)
{
- List_iterator_fast<LEX_CSTRING> li(column_list);
+ List_iterator_fast<Lex_ident_sys> li(column_list);
str->append('(');
- for (LEX_CSTRING *col_name= li++; ; )
- {
- str->append(col_name);
- col_name= li++;
- if (!col_name)
- {
- str->append(')');
- break;
- }
- str->append(',');
- }
+ list_strlex_print(thd, str, &column_list);
+ str->append(')');
}
- str->append(STRING_WITH_LEN(" as "));
- str->append('(');
+ str->append(STRING_WITH_LEN(" as ("));
spec->print(str, query_type);
str->append(')');
+
+ if (cycle_list)
+ {
+ DBUG_ASSERT(cycle_list->elements != 0);
+ str->append(STRING_WITH_LEN(" CYCLE "));
+ list_strlex_print(thd, str, cycle_list);
+ str->append(STRING_WITH_LEN(" RESTRICT "));
+ }
}
@@ -1483,3 +1536,26 @@ bool With_element::instantiate_tmp_tables()
return false;
}
+void With_element::set_cycle_list(List<Lex_ident_sys> *cycle_list_arg)
+{
+ cycle_list= cycle_list_arg;
+
+ /*
+ If a CTE table with columns c1,...,cn is defined with a cycle
+ clause CYCLE(ci1,...,cik) then no two rows r1 and r2 from the
+ table shall have r1.ci1=r2.ci1 && ... && r1.cik=r2.cik.
+
+ If a cycle clause is used in the specification of a CTE then
+ each UNION ALL at the top level of the specification is interpreted
+ as a UNION DISTINCT over the cycle columns.
+ */
+ for (st_select_lex *sl= spec->first_select(); sl; sl= sl->next_select())
+ {
+ spec->union_distinct= sl;
+ if (sl != spec->first_select())
+ {
+ sl->distinct= TRUE;
+ sl->with_all_modifier= FALSE;
+ }
+ }
+}
diff --git a/sql/sql_cte.h b/sql/sql_cte.h
index 80d56644d7e..4c42dd23614 100644
--- a/sql/sql_cte.h
+++ b/sql/sql_cte.h
@@ -111,7 +111,8 @@ public:
inherited from the query that specified the table. Otherwise the list is
always empty.
*/
- List <LEX_CSTRING> column_list;
+ List <Lex_ident_sys> column_list;
+ List <Lex_ident_sys> *cycle_list;
/* The query that specifies the table introduced by this with element */
st_select_lex_unit *spec;
/*
@@ -163,13 +164,13 @@ public:
SQL_I_List<TABLE_LIST> derived_with_rec_ref;
With_element(LEX_CSTRING *name,
- List <LEX_CSTRING> list,
+ List <Lex_ident_sys> list,
st_select_lex_unit *unit)
: next(NULL), base_dep_map(0), derived_dep_map(0),
sq_dep_map(0), work_dep_map(0), mutually_recursive(0),
top_level_dep_map(0), sq_rec_ref(NULL),
next_mutually_recursive(NULL), references(0),
- query_name(name), column_list(list), spec(unit),
+ query_name(name), column_list(list), cycle_list(0), spec(unit),
is_recursive(false), rec_outer_references(0), with_anchor(false),
level(0), rec_result(NULL)
{ unit->with_element= this; }
@@ -206,7 +207,7 @@ public:
void inc_references() { references++; }
- bool rename_columns_of_derived_unit(THD *thd, st_select_lex_unit *unit);
+ bool process_columns_of_derived_unit(THD *thd, st_select_lex_unit *unit);
bool prepare_unreferenced(THD *thd);
@@ -214,7 +215,7 @@ public:
table_map &unrestricted,
table_map &encountered);
- void print(String *str, enum_query_type query_type);
+ void print(THD *thd, String *str, enum_query_type query_type);
With_clause *get_owner() { return owner; }
@@ -259,6 +260,8 @@ public:
void prepare_for_next_iteration();
+ void set_cycle_list(List<Lex_ident_sys> *cycle_list_arg);
+
friend class With_clause;
};
@@ -353,7 +356,7 @@ public:
void add_unrestricted(table_map map) { unrestricted|= map; }
- void print(String *str, enum_query_type query_type);
+ void print(THD *thd, String *str, enum_query_type query_type);
friend class With_element;
diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc
index 8f41fe7c70d..b995a841a74 100644
--- a/sql/sql_cursor.cc
+++ b/sql/sql_cursor.cc
@@ -284,12 +284,11 @@ int Materialized_cursor::send_result_set_metadata(
*/
while ((item_dst= it_dst++, item_org= it_org++))
{
- Send_field send_field;
Item_ident *ident= static_cast<Item_ident *>(item_dst);
- item_org->make_send_field(thd, &send_field);
+ Send_field send_field(thd, item_org);
- ident->db_name= thd->strdup(send_field.db_name);
- ident->table_name= thd->strdup(send_field.table_name);
+ ident->db_name= thd->strmake_lex_cstring(send_field.db_name);
+ ident->table_name= thd->strmake_lex_cstring(send_field.table_name);
}
/*
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index b2b591464f7..3ad7bea5661 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -26,11 +26,12 @@
#include "lock.h" // lock_schema_name
#include "sql_table.h" // build_table_filename,
// filename_to_tablename
+ // validate_comment_length
#include "sql_rename.h" // mysql_rename_tables
#include "sql_acl.h" // SELECT_ACL, DB_ACLS,
// acl_get, check_grant_db
#include "log_event.h" // Query_log_event
-#include "sql_base.h" // lock_table_names, tdc_remove_table
+#include "sql_base.h" // lock_table_names
#include "sql_handler.h" // mysql_ha_rm_tables
#include "sql_class.h"
#include <mysys_err.h>
@@ -60,7 +61,7 @@ long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path);
static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error);
static void mysql_change_db_impl(THD *thd,
LEX_CSTRING *new_db_name,
- ulong new_db_access,
+ privilege_t new_db_access,
CHARSET_INFO *new_db_charset);
static bool mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db,
bool if_exists, bool silent);
@@ -77,6 +78,7 @@ typedef struct my_dbopt_st
char *name; /* Database name */
uint name_length; /* Database length name */
CHARSET_INFO *charset; /* Database default character set */
+ LEX_STRING comment; /* Database comment */
} my_dbopt_t;
@@ -184,9 +186,9 @@ bool my_dboptions_cache_init(void)
if (!dboptions_init)
{
dboptions_init= 1;
- error= my_hash_init(&dboptions, table_alias_charset,
- 32, 0, 0, (my_hash_get_key) dboptions_get_key,
- free_dbopt,0);
+ error= my_hash_init(key_memory_dboptions_hash, &dboptions,
+ table_alias_charset, 32, 0, 0, (my_hash_get_key)
+ dboptions_get_key, free_dbopt, 0);
}
return error;
}
@@ -216,9 +218,8 @@ void my_dbopt_cleanup(void)
{
mysql_rwlock_wrlock(&LOCK_dboptions);
my_hash_free(&dboptions);
- my_hash_init(&dboptions, table_alias_charset,
- 32, 0, 0, (my_hash_get_key) dboptions_get_key,
- free_dbopt,0);
+ my_hash_init(key_memory_dboptions_hash, &dboptions, table_alias_charset, 32,
+ 0, 0, (my_hash_get_key) dboptions_get_key, free_dbopt, 0);
mysql_rwlock_unlock(&LOCK_dboptions);
}
@@ -235,7 +236,8 @@ void my_dbopt_cleanup(void)
1 on error.
*/
-static my_bool get_dbopt(const char *dbname, Schema_specification_st *create)
+static my_bool get_dbopt(THD *thd, const char *dbname,
+ Schema_specification_st *create)
{
my_dbopt_t *opt;
uint length;
@@ -247,6 +249,11 @@ static my_bool get_dbopt(const char *dbname, Schema_specification_st *create)
if ((opt= (my_dbopt_t*) my_hash_search(&dboptions, (uchar*) dbname, length)))
{
create->default_table_charset= opt->charset;
+ if (opt->comment.length)
+ {
+ create->schema_comment= thd->make_clex_string(opt->comment.str,
+ opt->comment.length);
+ }
error= 0;
}
mysql_rwlock_unlock(&LOCK_dboptions);
@@ -274,15 +281,17 @@ static my_bool put_dbopt(const char *dbname, Schema_specification_st *create)
DBUG_ENTER("put_dbopt");
length= (uint) strlen(dbname);
-
+
mysql_rwlock_wrlock(&LOCK_dboptions);
if (!(opt= (my_dbopt_t*) my_hash_search(&dboptions, (uchar*) dbname,
length)))
{
/* Options are not in the hash, insert them */
char *tmp_name;
- if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
+ char *tmp_comment= NULL;
+ if (!my_multi_malloc(key_memory_dboptions_hash, MYF(MY_WME | MY_ZEROFILL),
&opt, (uint) sizeof(*opt), &tmp_name, (uint) length+1,
+ &tmp_comment, (uint) DATABASE_COMMENT_MAXLEN+1,
NullS))
{
error= 1;
@@ -292,7 +301,7 @@ static my_bool put_dbopt(const char *dbname, Schema_specification_st *create)
opt->name= tmp_name;
strmov(opt->name, dbname);
opt->name_length= length;
-
+ opt->comment.str= tmp_comment;
if (unlikely((error= my_hash_insert(&dboptions, (uchar*) opt))))
{
my_free(opt);
@@ -303,6 +312,12 @@ static my_bool put_dbopt(const char *dbname, Schema_specification_st *create)
/* Update / write options in hash */
opt->charset= create->default_table_charset;
+ if (create->schema_comment)
+ {
+ strmov(opt->comment.str, create->schema_comment->str);
+ opt->comment.length= create->schema_comment->length;
+ }
+
end:
mysql_rwlock_unlock(&LOCK_dboptions);
DBUG_RETURN(error);
@@ -328,7 +343,8 @@ static void del_dbopt(const char *path)
Create database options file:
DESCRIPTION
- Currently database default charset is only stored there.
+ Currently database default charset, default collation
+ and comment are stored there.
RETURN VALUES
0 ok
@@ -339,9 +355,34 @@ static bool write_db_opt(THD *thd, const char *path,
Schema_specification_st *create)
{
File file;
- char buf[256]; // Should be enough for one option
+ char buf[256+DATABASE_COMMENT_MAXLEN];
bool error=1;
+ if (create->schema_comment)
+ {
+ if (validate_comment_length(thd, create->schema_comment,
+ DATABASE_COMMENT_MAXLEN,
+ ER_TOO_LONG_DATABASE_COMMENT,
+ thd->lex->name.str))
+ return error;
+ }
+
+ if (thd->lex->sql_command == SQLCOM_ALTER_DB &&
+ (!create->schema_comment || !create->default_table_charset))
+ {
+ /* Use existing values of schema_comment and charset for
+ ALTER DATABASE queries */
+ Schema_specification_st tmp;
+ tmp.init();
+ load_db_opt(thd, path, &tmp);
+
+ if (!create->schema_comment)
+ create->schema_comment= tmp.schema_comment;
+
+ if (!create->default_table_charset)
+ create->default_table_charset= tmp.default_table_charset;
+ }
+
if (!create->default_table_charset)
create->default_table_charset= thd->variables.collation_server;
@@ -358,6 +399,11 @@ static bool write_db_opt(THD *thd, const char *path,
create->default_table_charset->name,
"\n", NullS) - buf);
+ if (create->schema_comment)
+ length= (ulong) (strxnmov(buf+length, sizeof(buf)-1-length,
+ "comment=", create->schema_comment->str,
+ "\n", NullS) - buf);
+
/* Error is written by mysql_file_write */
if (!mysql_file_write(file, (uchar*) buf, length, MYF(MY_NABP+MY_WME)))
error=0;
@@ -385,7 +431,7 @@ static bool write_db_opt(THD *thd, const char *path,
bool load_db_opt(THD *thd, const char *path, Schema_specification_st *create)
{
File file;
- char buf[256];
+ char buf[256+DATABASE_COMMENT_MAXLEN];
DBUG_ENTER("load_db_opt");
bool error=1;
size_t nbytes;
@@ -394,7 +440,7 @@ bool load_db_opt(THD *thd, const char *path, Schema_specification_st *create)
create->default_table_charset= thd->variables.collation_server;
/* Check if options for this database are already in the hash */
- if (!get_dbopt(path, create))
+ if (!get_dbopt(thd, path, create))
DBUG_RETURN(0);
/* Otherwise, load options from the .opt file */
@@ -444,6 +490,8 @@ bool load_db_opt(THD *thd, const char *path, Schema_specification_st *create)
create->default_table_charset= default_charset_info;
}
}
+ else if (!strncmp(buf, "comment", (pos-buf)))
+ create->schema_comment= thd->make_clex_string(pos+1, strlen(pos+1));
}
}
/*
@@ -544,7 +592,7 @@ CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name)
Create a database
SYNOPSIS
- mysql_create_db_iternal()
+ mysql_create_db_internal()
thd Thread handler
db Name of database to create
Function assumes that this is already validated.
@@ -1039,8 +1087,8 @@ exit:
*/
if (unlikely(thd->db.str && cmp_db_names(&thd->db, db) && !error))
{
- mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
- SESSION_TRACKER_CHANGED(thd, CURRENT_SCHEMA_TRACKER, NULL);
+ mysql_change_db_impl(thd, NULL, NO_ACL, thd->variables.collation_server);
+ thd->session_tracker.current_schema.mark_as_changed(thd);
}
my_dirend(dirp);
DBUG_RETURN(error);
@@ -1099,9 +1147,9 @@ static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp,
(char*) table_list->table_name.str);
table_list->alias= table_list->table_name; // If lower_case_table_names=2
- table_list->mdl_request.init(MDL_key::TABLE, table_list->db.str,
- table_list->table_name.str, MDL_EXCLUSIVE,
- MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&table_list->mdl_request, MDL_key::TABLE,
+ table_list->db.str, table_list->table_name.str,
+ MDL_EXCLUSIVE, MDL_TRANSACTION);
/* Link into list */
(*tot_list_next_local)= table_list;
(*tot_list_next_global)= table_list;
@@ -1303,7 +1351,7 @@ err:
static void mysql_change_db_impl(THD *thd,
LEX_CSTRING *new_db_name,
- ulong new_db_access,
+ privilege_t new_db_access,
CHARSET_INFO *new_db_charset)
{
/* 1. Change current database in THD. */
@@ -1452,7 +1500,7 @@ uint mysql_change_db(THD *thd, const LEX_CSTRING *new_db_name,
LEX_CSTRING new_db_file_name;
Security_context *sctx= thd->security_ctx;
- ulong db_access= sctx->db_access;
+ privilege_t db_access(sctx->db_access);
CHARSET_INFO *db_default_cl;
DBUG_ENTER("mysql_change_db");
@@ -1469,7 +1517,7 @@ uint mysql_change_db(THD *thd, const LEX_CSTRING *new_db_name,
new_db_name->length == 0.
*/
- mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
+ mysql_change_db_impl(thd, NULL, NO_ACL, thd->variables.collation_server);
goto done;
}
@@ -1498,8 +1546,8 @@ uint mysql_change_db(THD *thd, const LEX_CSTRING *new_db_name,
TODO: fix check_db_name().
*/
- new_db_file_name.str= my_strndup(new_db_name->str, new_db_name->length,
- MYF(MY_WME));
+ new_db_file_name.str= my_strndup(key_memory_THD_db, new_db_name->str,
+ new_db_name->length, MYF(MY_WME));
new_db_file_name.length= new_db_name->length;
if (new_db_file_name.str == NULL)
@@ -1521,7 +1569,7 @@ uint mysql_change_db(THD *thd, const LEX_CSTRING *new_db_name,
my_free(const_cast<char*>(new_db_file_name.str));
if (force_switch)
- mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
+ mysql_change_db_impl(thd, NULL, NO_ACL, thd->variables.collation_server);
DBUG_RETURN(ER_WRONG_DB_NAME);
}
@@ -1573,7 +1621,7 @@ uint mysql_change_db(THD *thd, const LEX_CSTRING *new_db_name,
/* Change db to NULL. */
- mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
+ mysql_change_db_impl(thd, NULL, NO_ACL, thd->variables.collation_server);
/* The operation succeed. */
goto done;
@@ -1601,8 +1649,8 @@ uint mysql_change_db(THD *thd, const LEX_CSTRING *new_db_name,
mysql_change_db_impl(thd, &new_db_file_name, db_access, db_default_cl);
done:
- SESSION_TRACKER_CHANGED(thd, CURRENT_SCHEMA_TRACKER, NULL);
- SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
+ thd->session_tracker.current_schema.mark_as_changed(thd);
+ thd->session_tracker.state_change.mark_as_changed(thd);
DBUG_RETURN(0);
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index f4cad88124f..bef77e1a2e9 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -30,7 +30,6 @@
#include "lock.h" // unlock_table_name
#include "sql_view.h" // check_key_in_view, mysql_frm_type
#include "sql_parse.h" // mysql_init_select
-#include "sql_acl.h" // *_ACL
#include "filesort.h" // filesort
#include "sql_handler.h" // mysql_ha_rm_tables
#include "sql_select.h"
@@ -199,23 +198,12 @@ bool Update_plan::save_explain_data_intern(MEM_ROOT *mem_root,
&explain->mrr_type);
}
- bool skip= updating_a_view;
-
/* Save subquery children */
for (SELECT_LEX_UNIT *unit= select_lex->first_inner_unit();
unit;
unit= unit->next_unit())
{
- if (skip)
- {
- skip= false;
- continue;
- }
- /*
- Display subqueries only if they are not parts of eliminated WHERE/ON
- clauses.
- */
- if (!(unit->item && unit->item->eliminated))
+ if (unit->explainable())
explain->add_child(unit->first_select()->select_number);
}
return 0;
@@ -322,10 +310,10 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
ORDER *order= (ORDER *) ((order_list && order_list->elements) ?
order_list->first : NULL);
SELECT_LEX *select_lex= thd->lex->first_select_lex();
+ SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0;
killed_state killed_status= NOT_KILLED;
THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE;
bool binlog_is_row;
- bool with_select= !select_lex->item_list.is_empty();
Explain_delete *explain;
Delete_plan query_plan(thd->mem_root);
Unique * deltempfile= NULL;
@@ -365,18 +353,15 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
table->map=1;
query_plan.select_lex= thd->lex->first_select_lex();
query_plan.table= table;
- query_plan.updating_a_view= MY_TEST(table_list->view);
- if (mysql_prepare_delete(thd, table_list, select_lex->with_wild,
- select_lex->item_list, &conds,
- &delete_while_scanning))
+ if (mysql_prepare_delete(thd, table_list, &conds, &delete_while_scanning))
DBUG_RETURN(TRUE);
if (delete_history)
table->vers_write= false;
- if (with_select)
- (void) result->prepare(select_lex->item_list, NULL);
+ if (returning)
+ (void) result->prepare(returning->item_list, NULL);
if (thd->lex->current_select->first_cond_optimization)
{
@@ -441,9 +426,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
has_triggers= table->triggers && table->triggers->has_delete_triggers();
- if (!with_select && !using_limit && const_cond_result &&
- (!thd->is_current_stmt_binlog_format_row() &&
- !has_triggers)
+ if (!returning && !using_limit && const_cond_result &&
+ (!thd->is_current_stmt_binlog_format_row() && !has_triggers)
&& !table->versioned(VERS_TIMESTAMP) && !table_list->has_period())
{
/* Update the table->file->stats.records number */
@@ -585,7 +569,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (!(explain= query_plan.save_explain_delete_data(thd->mem_root, thd)))
goto got_error;
- ANALYZE_START_TRACKING(&explain->command_tracker);
+ ANALYZE_START_TRACKING(thd, &explain->command_tracker);
DBUG_EXECUTE_IF("show_explain_probe_delete_exec_start",
dbug_serve_apcs(thd, 1););
@@ -614,7 +598,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
*/
if ((table->file->ha_table_flags() & HA_CAN_DIRECT_UPDATE_AND_DELETE) &&
- !has_triggers && !binlog_is_row && !with_select &&
+ !has_triggers && !binlog_is_row && !returning &&
!table_list->has_period())
{
table->mark_columns_needed_for_delete();
@@ -664,7 +648,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
DELETE ... RETURNING we can't, because the RETURNING part may have
a subquery in it)
*/
- if (!with_select)
+ if (!returning)
free_underlaid_joins(thd, select_lex);
select= 0;
}
@@ -699,11 +683,10 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
!table->prepare_triggers_for_delete_stmt_or_event())
will_batch= !table->file->start_bulk_delete();
- if (with_select)
+ if (returning)
{
- if (unlikely(result->send_result_set_metadata(select_lex->item_list,
- Protocol::SEND_NUM_ROWS |
- Protocol::SEND_EOF)))
+ if (result->send_result_set_metadata(returning->item_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
goto cleanup;
}
@@ -785,7 +768,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
break;
}
- if (with_select && result->send_data(select_lex->item_list) < 0)
+ // no LIMIT / OFFSET
+ if (returning && result->send_data(returning->item_list) < 0)
{
error=1;
break;
@@ -863,7 +847,7 @@ terminate_delete:
table->file->ha_release_auto_increment();
if (options & OPTION_QUICK)
(void) table->file->extra(HA_EXTRA_NORMAL);
- ANALYZE_STOP_TRACKING(&explain->command_tracker);
+ ANALYZE_STOP_TRACKING(thd, &explain->command_tracker);
cleanup:
/*
@@ -929,7 +913,7 @@ cleanup:
if (thd->lex->analyze_stmt)
goto send_nothing_and_leave;
- if (with_select)
+ if (returning)
result->send_eof();
else
my_ok(thd, deleted);
@@ -979,16 +963,13 @@ got_error:
mysql_prepare_delete()
thd - thread handler
table_list - global/local table list
- wild_num - number of wildcards used in optional SELECT clause
- field_list - list of items in optional SELECT clause
conds - conditions
RETURN VALUE
FALSE OK
TRUE error
*/
-int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list,
- uint wild_num, List<Item> &field_list, Item **conds,
+int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds,
bool *delete_while_scanning)
{
Item *fake_conds= 0;
@@ -998,12 +979,9 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list,
*delete_while_scanning= true;
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()->
- top_join_list,
- table_list,
- select_lex->leaf_tables, FALSE,
+ if (setup_tables_and_check_access(thd, &select_lex->context,
+ &select_lex->top_join_list, table_list,
+ select_lex->leaf_tables, FALSE,
DELETE_ACL, SELECT_ACL, TRUE))
DBUG_RETURN(TRUE);
@@ -1034,10 +1012,7 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list,
*conds= select_lex->where;
- if ((wild_num && setup_wild(thd, table_list, field_list, NULL, wild_num,
- &select_lex->hidden_bit_fields)) ||
- setup_fields(thd, Ref_ptr_array(),
- field_list, MARK_COLUMNS_READ, NULL, NULL, 0) ||
+ if (setup_returning_fields(thd, table_list) ||
setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
setup_ftfuncs(select_lex))
DBUG_RETURN(TRUE);
@@ -1061,7 +1036,7 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list,
fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array))
DBUG_RETURN(TRUE);
- select_lex->fix_prepare_information(thd, conds, &fake_conds);
+ select_lex->fix_prepare_information(thd, conds, &fake_conds);
DBUG_RETURN(FALSE);
}
diff --git a/sql/sql_delete.h b/sql/sql_delete.h
index 7af8564abf9..520524c72cc 100644
--- a/sql/sql_delete.h
+++ b/sql/sql_delete.h
@@ -26,8 +26,7 @@ class select_result;
typedef class Item COND;
template <typename T> class SQL_I_List;
-int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list,
- uint wild_num, List<Item> &field_list, Item **conds,
+int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds,
bool *delete_while_scanning);
bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
SQL_I_List<ORDER> *order, ha_rows rows,
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 8396fd89433..7d09c85a7c7 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -816,8 +816,8 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
if ((res= unit->prepare(derived, derived->derived_result, 0)))
goto exit;
if (derived->with &&
- (res= derived->with->rename_columns_of_derived_unit(thd, unit)))
- goto exit;
+ (res= derived->with->process_columns_of_derived_unit(thd, unit)))
+ goto exit;
lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_DERIVED;
if ((res= check_duplicate_names(thd, unit->types, 0)))
goto exit;
@@ -1250,13 +1250,12 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
{
SELECT_LEX *first_select= unit->first_select();
unit->set_limit(unit->global_parameters());
- if (unit->select_limit_cnt == HA_POS_ERROR)
+ if (unit->lim.is_unlimited())
first_select->options&= ~OPTION_FOUND_ROWS;
lex->current_select= first_select;
res= mysql_select(thd,
first_select->table_list.first,
- first_select->with_wild,
first_select->item_list, first_select->where,
(first_select->order_list.elements+
first_select->group_list.elements),
diff --git a/sql/sql_digest.cc b/sql/sql_digest.cc
index 10a9547d80f..5ca855c9608 100644
--- a/sql/sql_digest.cc
+++ b/sql/sql_digest.cc
@@ -188,7 +188,7 @@ void compute_digest_text(const sql_digest_storage* digest_storage,
/* Convert text to utf8 */
const CHARSET_INFO *from_cs= get_charset(digest_storage->m_charset_number, MYF(0));
- const CHARSET_INFO *to_cs= &my_charset_utf8_bin;
+ const CHARSET_INFO *to_cs= &my_charset_utf8mb3_bin;
if (from_cs == NULL)
{
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index a11a0f454a2..e5dda9904d2 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -506,7 +506,7 @@ void Warning_info::init()
{
/* Initialize sub structures */
DBUG_ASSERT(initialized == 0);
- init_sql_alloc(&m_warn_root, "Warning_info", WARN_ALLOC_BLOCK_SIZE,
+ init_sql_alloc(PSI_INSTRUMENT_ME, &m_warn_root, WARN_ALLOC_BLOCK_SIZE,
WARN_ALLOC_PREALLOC_SIZE, MYF(MY_THREAD_SPECIFIC));
initialized= 1;
}
@@ -744,7 +744,7 @@ void push_warning_printf(THD *thd, Sql_condition::enum_warning_level level,
DBUG_ASSERT(format != NULL);
va_start(args,format);
- my_vsnprintf_ex(&my_charset_utf8_general_ci, warning,
+ my_vsnprintf_ex(&my_charset_utf8mb3_general_ci, warning,
sizeof(warning), format, args);
va_end(args);
push_warning(thd, level, code, warning);
@@ -783,7 +783,7 @@ bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
const Sql_condition *err;
SELECT_LEX *sel= thd->lex->first_select_lex();
SELECT_LEX_UNIT *unit= &thd->lex->unit;
- ulonglong idx= 0;
+ ha_rows idx;
Protocol *protocol=thd->protocol;
DBUG_ENTER("mysqld_show_warnings");
@@ -808,23 +808,22 @@ bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
Diagnostics_area::Sql_condition_iterator it=
thd->get_stmt_da()->sql_conditions();
- while ((err= it++))
+ for (idx= 0; (err= it++) ; idx++)
{
/* Skip levels that the user is not interested in */
if (!(levels_to_show & ((ulong) 1 << err->get_level())))
continue;
- if (++idx <= unit->offset_limit_cnt)
- continue;
- if (idx > unit->select_limit_cnt)
+ if (unit->lim.check_offset(idx))
+ continue; // using limit offset,count
+ if (idx >= unit->lim.get_select_limit())
break;
protocol->prepare_for_resend();
protocol->store(warning_level_names[err->get_level()].str,
warning_level_names[err->get_level()].length,
system_charset_info);
protocol->store((uint32) err->get_sql_errno());
- protocol->store(err->get_message_text(),
- err->get_message_octet_length(),
- system_charset_info);
+ protocol->store_warning(err->get_message_text(),
+ err->get_message_octet_length());
if (protocol->write())
DBUG_RETURN(TRUE);
}
@@ -837,6 +836,26 @@ bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
/**
+ This replaces U+0000 to '\0000', so the result error message string:
+ - is a good null-terminated string
+ - presents the entire data
+ For example:
+ SELECT CAST(_latin1 0x610062 AS SIGNED);
+ returns a warning:
+ Truncated incorrect INTEGER value: 'a\0000b'
+ Notice, the 0x00 byte is replaced to a 5-byte long string '\0000',
+ while 'a' and 'b' are printed as is.
+*/
+extern "C" int my_wc_mb_utf8_null_terminated(CHARSET_INFO *cs,
+ my_wc_t wc, uchar *r, uchar *e)
+{
+ return wc == '\0' ?
+ my_wc_to_printable_generic(cs, wc, r, e) :
+ my_charset_utf8mb3_handler.wc_mb(cs, wc, r, e);
+}
+
+
+/**
Convert value for dispatch to error message(see WL#751).
@param to buffer for converted string
@@ -894,8 +913,11 @@ char *err_conv(char *buff, uint to_length, const char *from,
else
{
uint errors;
- res= copy_and_convert(to, to_length, system_charset_info,
- from, from_length, from_cs, &errors);
+ res= my_convert_using_func(to, to_length, system_charset_info,
+ my_wc_mb_utf8_null_terminated,
+ from, from_length, from_cs,
+ from_cs->cset->mb_wc,
+ &errors);
to[res]= 0;
}
return buff;
@@ -921,64 +943,21 @@ size_t convert_error_message(char *to, size_t to_length, CHARSET_INFO *to_cs,
const char *from, size_t from_length,
CHARSET_INFO *from_cs, uint *errors)
{
- int cnvres;
- my_wc_t wc;
- const uchar *from_end= (const uchar*) from+from_length;
- char *to_start= to;
- uchar *to_end;
- my_charset_conv_mb_wc mb_wc= from_cs->cset->mb_wc;
- my_charset_conv_wc_mb wc_mb;
- uint error_count= 0;
- size_t length;
-
DBUG_ASSERT(to_length > 0);
/* Make room for the null terminator. */
to_length--;
- to_end= (uchar*) (to + to_length);
-
- if (!to_cs || from_cs == to_cs || to_cs == &my_charset_bin)
- {
- length= MY_MIN(to_length, from_length);
- memmove(to, from, length);
- to[length]= 0;
- return length;
- }
- wc_mb= to_cs->cset->wc_mb;
- while (1)
- {
- if ((cnvres= (*mb_wc)(from_cs, &wc, (uchar*) from, from_end)) > 0)
- {
- if (!wc)
- break;
- from+= cnvres;
- }
- else if (cnvres == MY_CS_ILSEQ)
- {
- wc= (ulong) (uchar) *from;
- from+=1;
- }
- else
- break;
-
- if ((cnvres= (*wc_mb)(to_cs, wc, (uchar*) to, to_end)) > 0)
- to+= cnvres;
- else if (cnvres == MY_CS_ILUNI)
- {
- length= (wc <= 0xFFFF) ? 6/* '\1234' format*/ : 9 /* '\+123456' format*/;
- if ((uchar*)(to + length) >= to_end)
- break;
- cnvres= (int)my_snprintf(to, 9,
- (wc <= 0xFFFF) ? "\\%04X" : "\\+%06X", (uint) wc);
- to+= cnvres;
- }
- else
- break;
- }
-
- *to= 0;
- *errors= error_count;
- return (size_t) (to - to_start);
+ if (!to_cs || to_cs == &my_charset_bin)
+ to_cs= system_charset_info;
+ uint32 cnv_length= my_convert_using_func(to, to_length,
+ to_cs,
+ my_wc_to_printable_generic,
+ from, from_length,
+ from_cs, from_cs->cset->mb_wc,
+ errors);
+ DBUG_ASSERT(to_length >= cnv_length);
+ to[cnv_length]= '\0';
+ return cnv_length;
}
@@ -1009,3 +988,13 @@ bool is_sqlstate_valid(const LEX_CSTRING *sqlstate)
return true;
}
+
+
+void convert_error_to_warning(THD *thd)
+{
+ DBUG_ASSERT(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();
+}
diff --git a/sql/sql_error.h b/sql/sql_error.h
index bb83d8af800..a0497af78cb 100644
--- a/sql/sql_error.h
+++ b/sql/sql_error.h
@@ -307,16 +307,16 @@ protected:
String m_cursor_name;
Sql_condition_items()
- :m_class_origin((const char*) NULL, 0, & my_charset_utf8_bin),
- m_subclass_origin((const char*) NULL, 0, & my_charset_utf8_bin),
- m_constraint_catalog((const char*) NULL, 0, & my_charset_utf8_bin),
- m_constraint_schema((const char*) NULL, 0, & my_charset_utf8_bin),
- m_constraint_name((const char*) NULL, 0, & my_charset_utf8_bin),
- m_catalog_name((const char*) NULL, 0, & my_charset_utf8_bin),
- m_schema_name((const char*) NULL, 0, & my_charset_utf8_bin),
- m_table_name((const char*) NULL, 0, & my_charset_utf8_bin),
- m_column_name((const char*) NULL, 0, & my_charset_utf8_bin),
- m_cursor_name((const char*) NULL, 0, & my_charset_utf8_bin)
+ :m_class_origin((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_subclass_origin((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_constraint_catalog((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_constraint_schema((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_constraint_name((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_catalog_name((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_schema_name((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_table_name((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_column_name((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_cursor_name((const char*) NULL, 0, & my_charset_utf8mb3_bin)
{ }
void clear()
@@ -1260,6 +1260,7 @@ private:
///////////////////////////////////////////////////////////////////////////
+void convert_error_to_warning(THD *thd);
void push_warning(THD *thd, Sql_condition::enum_warning_level level,
uint code, const char *msg);
diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc
index d3b85638898..da727ba54fc 100644
--- a/sql/sql_explain.cc
+++ b/sql/sql_explain.cc
@@ -1811,10 +1811,11 @@ void Explain_table_access::print_explain_json(Explain_query *query,
double total_time= op_tracker.get_time_ms();
if (rowid_filter)
total_time+= rowid_filter->tracker->get_time_fill_container_ms();
- writer->add_member("r_total_time_ms").add_double(total_time);
+ writer->add_member("r_table_time_ms").add_double(total_time);
+ writer->add_member("r_other_time_ms").add_double(extra_time_tracker.get_time_ms());
}
}
-
+
/* `filtered` */
if (filtered_set)
writer->add_member("filtered").add_double(filtered);
diff --git a/sql/sql_explain.h b/sql/sql_explain.h
index 3896636f9fd..041f77b6f42 100644
--- a/sql/sql_explain.h
+++ b/sql/sql_explain.h
@@ -342,7 +342,7 @@ class Explain_union : public Explain_node
{
public:
Explain_union(MEM_ROOT *root, bool is_analyze) :
- Explain_node(root),
+ Explain_node(root), union_members(PSI_INSTRUMENT_MEM),
is_recursive_cte(false),
fake_select_lex_explain(root, is_analyze)
{}
@@ -835,6 +835,8 @@ public:
/* Tracker for reading the table */
Table_access_tracker tracker;
Exec_time_tracker op_tracker;
+ Gap_time_tracker extra_time_tracker;
+
Table_access_tracker jbuf_tracker;
Explain_rowid_filter *rowid_filter;
diff --git a/sql/sql_expression_cache.h b/sql/sql_expression_cache.h
index 61e0c4c69b3..031773adb9f 100644
--- a/sql/sql_expression_cache.h
+++ b/sql/sql_expression_cache.h
@@ -152,7 +152,7 @@ private:
Item *val;
/* hit/miss counters */
ulong hit, miss;
- /* Set on if the object has been succesfully initialized with init() */
+ /* Set on if the object has been successfully initialized with init() */
bool inited;
};
diff --git a/sql/sql_get_diagnostics.cc b/sql/sql_get_diagnostics.cc
index b3ae423b914..197bf5e7a00 100644
--- a/sql/sql_get_diagnostics.cc
+++ b/sql/sql_get_diagnostics.cc
@@ -266,8 +266,8 @@ Condition_information::aggregate(THD *thd, const Diagnostics_area *da)
Item *
Condition_information_item::make_utf8_string_item(THD *thd, const String *str)
{
- /* Default is utf8 character set and utf8_general_ci collation. */
- CHARSET_INFO *to_cs= &my_charset_utf8_general_ci;
+ /* Default is utf8 character set and utf8mb3_general_ci collation. */
+ CHARSET_INFO *to_cs= &my_charset_utf8mb3_general_ci;
/* If a charset was not set, assume that no conversion is needed. */
CHARSET_INFO *from_cs= str->charset() ? str->charset() : to_cs;
String tmp(str->ptr(), str->length(), from_cs);
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 12119997430..d7adc35c5c9 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -289,10 +289,11 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen)
/*
HASH entries are of type SQL_HANDLER
*/
- if (my_hash_init(&thd->handler_tables_hash, &my_charset_latin1,
- HANDLER_TABLES_HASH_SIZE, 0, 0,
- (my_hash_get_key) mysql_ha_hash_get_key,
- (my_hash_free_key) mysql_ha_hash_free, 0))
+ if (my_hash_init(key_memory_THD_handler_tables_hash,
+ &thd->handler_tables_hash, &my_charset_latin1,
+ HANDLER_TABLES_HASH_SIZE, 0, 0, (my_hash_get_key)
+ mysql_ha_hash_get_key, (my_hash_free_key)
+ mysql_ha_hash_free, 0))
{
DBUG_PRINT("exit",("ERROR"));
DBUG_RETURN(TRUE);
@@ -332,8 +333,8 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen)
right from the start as open_tables() can't handle properly
back-off for such locks.
*/
- tables->mdl_request.init(MDL_key::TABLE, tables->db.str, tables->table_name.str,
- MDL_SHARED_READ, MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&tables->mdl_request, MDL_key::TABLE, tables->db.str,
+ tables->table_name.str, MDL_SHARED_READ, MDL_TRANSACTION);
mdl_savepoint= thd->mdl_context.mdl_savepoint();
/* for now HANDLER can be used only for real TABLES */
@@ -384,14 +385,14 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen)
/* copy data to sql_handler */
if (!(sql_handler= new SQL_HANDLER(thd)))
goto err;
- init_alloc_root(&sql_handler->mem_root, "sql_handler", 1024, 0,
+ init_alloc_root(PSI_INSTRUMENT_ME, &sql_handler->mem_root, 1024, 0,
MYF(MY_THREAD_SPECIFIC));
sql_handler->db.length= tables->db.length;
sql_handler->table_name.length= tables->table_name.length;
sql_handler->handler_name.length= tables->alias.length;
- if (!(my_multi_malloc(MY_WME,
+ if (!(my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME),
&sql_handler->base_data,
(uint) sql_handler->db.length + 1,
&sql_handler->table_name.str,
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index e5f1e958d99..c9307b578fc 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -92,14 +92,12 @@ static bool init_fields(THD *thd, TABLE_LIST *tables,
context->resolve_in_table_list_only(tables);
for (; count-- ; find_fields++)
{
- LEX_CSTRING field_name= {find_fields->field_name,
- strlen(find_fields->field_name) };
/* We have to use 'new' here as field will be re_linked on free */
Item_field *field= (new (thd->mem_root)
Item_field(thd, context,
- "mysql",
- find_fields->table_name,
- &field_name));
+ {STRING_WITH_LEN("mysql")},
+ Lex_cstring_strlen(find_fields->table_name),
+ Lex_cstring_strlen(find_fields->field_name)));
if (!(find_fields->field= find_field_in_tables(thd, field, tables, NULL,
0, REPORT_ALL_ERRORS, 1,
TRUE)))
@@ -858,9 +856,7 @@ error2:
bool mysqld_help(THD *thd, const char *mask)
{
- sql_mode_t sql_mode_backup= thd->variables.sql_mode;
- thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
+ Sql_mode_instant_remove sms(thd, MODE_PAD_CHAR_TO_FULL_LENGTH);
bool rc= mysqld_help_internal(thd, mask);
- thd->variables.sql_mode= sql_mode_backup;
return rc;
}
diff --git a/sql/sql_hset.h b/sql/sql_hset.h
index 7834349a2f7..b3d8165f6f6 100644
--- a/sql/sql_hset.h
+++ b/sql/sql_hset.h
@@ -31,12 +31,20 @@ public:
Constructs an empty hash. Does not allocate memory, it is done upon
the first insert. Thus does not cause or return errors.
*/
- Hash_set(uchar *(*K)(const T *, size_t *, my_bool),
+ Hash_set(PSI_memory_key psi_key, uchar *(*K)(const T *, size_t *, my_bool),
CHARSET_INFO *cs= &my_charset_bin)
{
my_hash_clear(&m_hash);
m_hash.get_key= (my_hash_get_key)K;
m_hash.charset= cs;
+ m_hash.array.m_psi_key= psi_key;
+ }
+ Hash_set(PSI_memory_key psi_key, CHARSET_INFO *charset, ulong default_array_elements,
+ size_t key_offset, size_t key_length, my_hash_get_key get_key,
+ void (*free_element)(void*), uint flags)
+ {
+ my_hash_init(psi_key, &m_hash, charset, default_array_elements, key_offset,
+ key_length, get_key, free_element, flags);
}
/**
Destroy the hash by freeing the buckets table. Does
@@ -57,14 +65,9 @@ public:
*/
bool insert(T *value)
{
- my_hash_init_opt(&m_hash, m_hash.charset, START_SIZE, 0, 0,
- m_hash.get_key, 0, MYF(0));
- size_t key_len;
- uchar *v= reinterpret_cast<uchar *>(value);
- const uchar *key= m_hash.get_key(v, &key_len, FALSE);
- if (find(key, key_len) == NULL)
- return my_hash_insert(&m_hash, v);
- return FALSE;
+ my_hash_init_opt(m_hash.array.m_psi_key, &m_hash, m_hash.charset,
+ START_SIZE, 0, 0, m_hash.get_key, 0, HASH_UNIQUE);
+ return my_hash_insert(&m_hash, reinterpret_cast<const uchar*>(value));
}
bool remove(T *value)
{
@@ -78,6 +81,8 @@ public:
bool is_empty() const { return m_hash.records == 0; }
/** Returns the number of unique elements. */
size_t size() const { return static_cast<size_t>(m_hash.records); }
+ /** Erases all elements from the container */
+ void clear() { my_hash_reset(&m_hash); }
const T* at(size_t i) const
{
return reinterpret_cast<T*>(my_hash_element(const_cast<HASH*>(&m_hash), i));
diff --git a/sql/sql_i_s.h b/sql/sql_i_s.h
new file mode 100644
index 00000000000..b9a768f1452
--- /dev/null
+++ b/sql/sql_i_s.h
@@ -0,0 +1,360 @@
+#ifndef SQL_I_S_INCLUDED
+#define SQL_I_S_INCLUDED
+/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2019, 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-1335 USA */
+
+#include "sql_const.h" // MAX_FIELD_VARCHARLENGTH
+#include "sql_basic_types.h" // enum_nullability
+#include "sql_string.h" // strlen, MY_CS_NAME_SIZE
+#include "lex_string.h" // LEX_CSTRING
+#include "mysql_com.h" // enum_field_types
+#include "my_time.h" // TIME_SECOND_PART_DIGITS
+#include "sql_type.h" // Type_handler_xxx
+
+struct TABLE_LIST;
+struct TABLE;
+typedef class Item COND;
+
+#ifdef MYSQL_CLIENT
+#error MYSQL_CLIENT must not be defined
+#endif // MYSQL_CLIENT
+
+
+bool schema_table_store_record(THD *thd, TABLE *table);
+COND *make_cond_for_info_schema(THD *thd, COND *cond, TABLE_LIST *table);
+
+
+enum enum_show_open_table
+{
+ SKIP_OPEN_TABLE= 0U, // do not open table
+ OPEN_FRM_ONLY= 1U, // open FRM file only
+ OPEN_FULL_TABLE= 2U // open FRM,MYD, MYI files
+};
+
+
+enum enum_show_default
+{
+ DEFAULT_TYPE_IMPLICIT= 0,
+ DEFAULT_NONE
+};
+
+
+namespace Show {
+class Type
+{
+ /**
+ This denotes data type for the column. For the most part, there seems to
+ be one entry in the enum for each SQL data type, although there seem to
+ be a number of additional entries in the enum.
+ */
+ const Type_handler *m_type_handler;
+ /**
+ For string-type columns, this is the maximum number of
+ characters. Otherwise, it is the 'display-length' for the column.
+ */
+ uint m_char_length;
+ uint m_unsigned_flag;
+ const Typelib *m_typelib;
+public:
+ Type(const Type_handler *th, uint length, uint unsigned_flag,
+ const Typelib *typelib= NULL)
+ :m_type_handler(th), m_char_length(length), m_unsigned_flag(unsigned_flag),
+ m_typelib(typelib)
+ { }
+ const Type_handler *type_handler() const { return m_type_handler; }
+ uint char_length() const { return m_char_length; }
+ uint decimal_precision() const { return (m_char_length / 100) % 100; }
+ uint decimal_scale() const { return m_char_length % 10; }
+ uint fsp() const
+ {
+ DBUG_ASSERT(m_char_length <= TIME_SECOND_PART_DIGITS);
+ return m_char_length;
+ }
+ uint unsigned_flag() const { return m_unsigned_flag; }
+ const Typelib *typelib() const { return m_typelib; }
+};
+} // namespace Show
+
+
+
+class ST_FIELD_INFO: public Show::Type
+{
+protected:
+ LEX_CSTRING m_name; // I_S column name
+ enum_nullability m_nullability; // NULLABLE or NOT NULL
+ enum_show_default m_def; // Whether has a DEFAULT value
+ LEX_CSTRING m_old_name; // SHOW column name
+ enum_show_open_table m_open_method;
+public:
+ ST_FIELD_INFO(const LEX_CSTRING &name, const Type &type,
+ enum_nullability nullability,
+ enum_show_default def,
+ LEX_CSTRING &old_name,
+ enum_show_open_table open_method)
+ :Type(type), m_name(name),
+ m_nullability(nullability),
+ m_def(def),
+ m_old_name(old_name),
+ m_open_method(open_method)
+ { }
+ ST_FIELD_INFO(const char *name, const Type &type,
+ enum_nullability nullability,
+ enum_show_default def,
+ const char *old_name,
+ enum_show_open_table open_method)
+ :Type(type),
+ m_nullability(nullability),
+ m_def(def),
+ m_open_method(open_method)
+ {
+ m_name.str= name;
+ m_name.length= safe_strlen(name);
+ m_old_name.str= old_name;
+ m_old_name.length= safe_strlen(old_name);
+ }
+ const LEX_CSTRING &name() const { return m_name; }
+ bool nullable() const { return m_nullability == NULLABLE; }
+ enum_show_default def() const { return m_def; }
+ const LEX_CSTRING &old_name() const { return m_old_name; }
+ enum_show_open_table open_method() const { return m_open_method; }
+ bool end_marker() const { return m_name.str == NULL; }
+};
+
+
+namespace Show
+{
+
+
+class Enum: public Type
+{
+public:
+ Enum(const Typelib *typelib) :Type(&type_handler_enum, 0, false, typelib) { }
+};
+
+
+class Blob: public Type
+{
+public:
+ Blob(uint length) :Type(&type_handler_blob, length, false) { }
+};
+
+
+class Varchar: public Type
+{
+public:
+ Varchar(uint length) :Type(&type_handler_varchar, length, false)
+ {
+ DBUG_ASSERT(length * 3 <= MAX_FIELD_VARCHARLENGTH);
+ }
+};
+
+
+class Longtext: public Type
+{
+public:
+ Longtext(uint length) :Type(&type_handler_varchar, length, false) { }
+};
+
+
+class Yesno: public Varchar
+{
+public:
+ Yesno(): Varchar(3) { }
+};
+
+
+class Catalog: public Varchar
+{
+public:
+ Catalog(): Varchar(FN_REFLEN) { }
+};
+
+
+class Name: public Varchar
+{
+public:
+ Name(): Varchar(NAME_CHAR_LEN) { }
+};
+
+
+class Definer: public Varchar
+{
+public:
+ Definer(): Varchar(DEFINER_CHAR_LENGTH) { }
+};
+
+
+class Userhost: public Varchar
+{
+public:
+ Userhost(): Varchar(USERNAME_CHAR_LENGTH + HOSTNAME_LENGTH + 2) { }
+};
+
+
+class CSName: public Varchar
+{
+public:
+ CSName(): Varchar(MY_CS_NAME_SIZE) { }
+};
+
+
+class SQLMode: public Varchar
+{
+public:
+ SQLMode(): Varchar(32*256) { }
+};
+
+
+class Datetime: public Type
+{
+public:
+ Datetime(uint dec) :Type(&type_handler_datetime2, dec, false) { }
+};
+
+
+class Decimal: public Type
+{
+public:
+ Decimal(uint length) :Type(&type_handler_newdecimal, length, false) { }
+};
+
+
+class ULonglong: public Type
+{
+public:
+ ULonglong(uint length) :Type(&type_handler_ulonglong, length, true) { }
+ ULonglong() :ULonglong(MY_INT64_NUM_DECIMAL_DIGITS) { }
+};
+
+
+class ULong: public Type
+{
+public:
+ ULong(uint length) :Type(&type_handler_ulong, length, true) { }
+ ULong() :ULong(MY_INT32_NUM_DECIMAL_DIGITS) { }
+};
+
+
+class SLonglong: public Type
+{
+public:
+ SLonglong(uint length) :Type(&type_handler_slonglong, length, false) { }
+ SLonglong() :SLonglong(MY_INT64_NUM_DECIMAL_DIGITS) { }
+};
+
+
+class SLong: public Type
+{
+public:
+ SLong(uint length) :Type(&type_handler_slong, length, false) { }
+ SLong() :SLong(MY_INT32_NUM_DECIMAL_DIGITS) { }
+};
+
+
+class SShort: public Type
+{
+public:
+ SShort(uint length) :Type(&type_handler_sshort, length, false) { }
+};
+
+
+class STiny: public Type
+{
+public:
+ STiny(uint length) :Type(&type_handler_stiny, length, false) { }
+};
+
+
+class Double: public Type
+{
+public:
+ Double(uint length) :Type(&type_handler_double, length, false) { }
+};
+
+
+class Float: public Type
+{
+public:
+ Float(uint length) :Type(&type_handler_float, length, false) { }
+};
+
+
+
+class Column: public ST_FIELD_INFO
+{
+public:
+ Column(const char *name, const Type &type,
+ enum_nullability nullability,
+ enum_show_default def,
+ const char *old_name,
+ enum_show_open_table open_method= SKIP_OPEN_TABLE)
+ :ST_FIELD_INFO(name, type, nullability, def, old_name, open_method)
+ { }
+ Column(const char *name, const Type &type, enum_nullability nullability,
+ enum_show_default def,
+ enum_show_open_table open_method= SKIP_OPEN_TABLE)
+ :ST_FIELD_INFO(name, type, nullability, def, NullS, open_method)
+ { }
+ Column(const char *name, const Type &type,
+ enum_nullability nullability,
+ const char *old_name,
+ enum_show_open_table open_method= SKIP_OPEN_TABLE)
+ :ST_FIELD_INFO(name, type, nullability, DEFAULT_TYPE_IMPLICIT,
+ old_name, open_method)
+ { }
+ Column(const char *name, const Type &type,
+ enum_nullability nullability,
+ enum_show_open_table open_method= SKIP_OPEN_TABLE)
+ :ST_FIELD_INFO(name, type, nullability, DEFAULT_TYPE_IMPLICIT,
+ NullS, open_method)
+ { }
+};
+
+
+// End marker
+class CEnd: public Column
+{
+public:
+ CEnd() :Column(NullS, Varchar(0), NOT_NULL, NullS, SKIP_OPEN_TABLE) { }
+};
+
+
+} // namespace Show
+
+
+struct TABLE_LIST;
+typedef class Item COND;
+
+typedef struct st_schema_table
+{
+ const char *table_name;
+ ST_FIELD_INFO *fields_info;
+ /* for FLUSH table_name */
+ int (*reset_table) ();
+ /* Fill table with data */
+ int (*fill_table) (THD *thd, TABLE_LIST *tables, COND *cond);
+ /* Handle fileds for old SHOW */
+ int (*old_format) (THD *thd, struct st_schema_table *schema_table);
+ int (*process_table) (THD *thd, TABLE_LIST *tables, TABLE *table,
+ bool res, const LEX_CSTRING *db_name,
+ const LEX_CSTRING *table_name);
+ int idx_field1, idx_field2;
+ bool hidden;
+ uint i_s_requested_object; /* the object we need to open(TABLE | VIEW) */
+} ST_SCHEMA_TABLE;
+
+
+#endif // SQL_I_S_INCLUDED
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 807dd94c6f0..708423c6214 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -67,7 +67,6 @@
#include "sp_head.h"
#include "sql_view.h" // check_key_in_view, insert_view_fields
#include "sql_table.h" // mysql_create_table_no_lock
-#include "sql_acl.h" // *_ACL, check_grant_all_columns
#include "sql_trigger.h"
#include "sql_select.h"
#include "sql_show.h"
@@ -554,8 +553,8 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list)
if (thd->has_read_only_protection())
DBUG_RETURN(TRUE);
- protection_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_DML,
- MDL_STATEMENT);
+ MDL_REQUEST_INIT(&protection_request, MDL_key::BACKUP, "", "",
+ MDL_BACKUP_DML, MDL_STATEMENT);
if (thd->mdl_context.acquire_lock(&protection_request,
thd->variables.lock_wait_timeout))
@@ -657,24 +656,12 @@ static void save_insert_query_plan(THD* thd, TABLE_LIST *table_list)
thd->lex->explain->add_insert_plan(explain);
- /* See Update_plan::updating_a_view for details */
- bool skip= MY_TEST(table_list->view);
-
/* Save subquery children */
for (SELECT_LEX_UNIT *unit= thd->lex->first_select_lex()->first_inner_unit();
unit;
unit= unit->next_unit())
{
- if (skip)
- {
- skip= false;
- continue;
- }
- /*
- Table elimination doesn't work for INSERTS, but let's still have this
- here for consistency
- */
- if (!(unit->item && unit->item->eliminated))
+ if (unit->explainable())
explain->add_child(unit->first_select()->select_number);
}
}
@@ -689,18 +676,19 @@ Field **TABLE::field_to_fill()
/**
INSERT statement implementation
+ SYNOPSIS
+ mysql_insert()
+ result NULL if the insert is not outputing results
+ via 'RETURNING' clause.
+
@note Like implementations of other DDL/DML in MySQL, this function
relies on the caller to close the thread tables. This is done in the
end of dispatch_command().
*/
-
-bool mysql_insert(THD *thd,TABLE_LIST *table_list,
- List<Item> &fields,
- List<List_item> &values_list,
- List<Item> &update_fields,
- List<Item> &update_values,
- enum_duplicates duplic,
- bool ignore)
+bool mysql_insert(THD *thd, TABLE_LIST *table_list,
+ List<Item> &fields, List<List_item> &values_list,
+ List<Item> &update_fields, List<Item> &update_values,
+ enum_duplicates duplic, bool ignore, select_result *result)
{
bool retval= true;
int error, res;
@@ -719,6 +707,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
List_item *values;
Name_resolution_context *context;
Name_resolution_context_state ctx_state;
+ SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0;
+
#ifndef EMBEDDED_LIBRARY
char *query= thd->query();
/*
@@ -744,8 +734,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
this will lead to a deadlock, since the delayed thread will
never be able to get a lock on the table.
*/
- if (table_list->lock_type == TL_WRITE_DELAYED &&
- thd->locked_tables_mode &&
+ if (table_list->lock_type == TL_WRITE_DELAYED && thd->locked_tables_mode &&
find_locked_table(thd->open_tables, table_list->db.str,
table_list->table_name.str))
{
@@ -774,10 +763,13 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
value_count= values->elements;
if (mysql_prepare_insert(thd, table_list, table, fields, values,
- update_fields, update_values, duplic, &unused_conds,
- FALSE))
+ update_fields, update_values, duplic,
+ &unused_conds, FALSE))
goto abort;
+ /* Prepares LEX::returing_list if it is not empty */
+ if (returning)
+ result->prepare(returning->item_list, NULL);
/* mysql_prepare_insert sets table_list->table if it was not set */
table= table_list->table;
@@ -949,6 +941,16 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
goto values_loop_end;
}
}
+ /*
+ If statement returns result set, we need to send the result set metadata
+ to the client so that it knows that it has to expect an EOF or ERROR.
+ At this point we have all the required information to send the result set
+ metadata.
+ */
+ if (returning &&
+ result->send_result_set_metadata(returning->item_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ goto values_loop_end;
THD_STAGE_INFO(thd, stage_update);
do
@@ -1075,7 +1077,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
}
else
#endif
- error=write_record(thd, table ,&info);
+ error= write_record(thd, table, &info, result);
if (unlikely(error))
break;
thd->get_stmt_da()->inc_current_row_for_warning();
@@ -1089,7 +1091,7 @@ values_loop_end:
joins_freed= TRUE;
/*
- Now all rows are inserted. Time to update logs and sends response to
+ Now all rows are inserted. Time to update logs and sends response to
user
*/
#ifndef EMBEDDED_LIBRARY
@@ -1245,7 +1247,7 @@ values_loop_end:
goto abort;
if (thd->lex->analyze_stmt)
{
- retval= thd->lex->explain->send_explain(thd);
+ retval= 0;
goto abort;
}
DBUG_PRINT("info", ("touched: %llu copied: %llu updated: %llu deleted: %llu",
@@ -1255,26 +1257,39 @@ values_loop_end:
if ((iteration * values_list.elements) == 1 &&
(!(thd->variables.option_bits & OPTION_WARNINGS) || !thd->cuted_fields))
{
- my_ok(thd, info.copied + info.deleted +
+ /*
+ Client expects an EOF/OK packet if result set metadata was sent. If
+ LEX::has_returning and the statement returns result set
+ we send EOF which is the indicator of the end of the row stream.
+ Oherwise we send an OK packet i.e when the statement returns only the
+ status information
+ */
+ if (returning)
+ result->send_eof();
+ else
+ my_ok(thd, info.copied + info.deleted +
((thd->client_capabilities & CLIENT_FOUND_ROWS) ?
- info.touched : info.updated),
- id);
+ info.touched : info.updated), id);
}
else
{
char buff[160];
ha_rows updated=((thd->client_capabilities & CLIENT_FOUND_ROWS) ?
info.touched : info.updated);
+
if (ignore)
sprintf(buff, ER_THD(thd, ER_INSERT_INFO), (ulong) info.records,
- (lock_type == TL_WRITE_DELAYED) ? (ulong) 0 :
- (ulong) (info.records - info.copied),
+ (lock_type == TL_WRITE_DELAYED) ? (ulong) 0 :
+ (ulong) (info.records - info.copied),
(long) thd->get_stmt_da()->current_statement_warn_count());
else
sprintf(buff, ER_THD(thd, ER_INSERT_INFO), (ulong) info.records,
- (ulong) (info.deleted + updated),
+ (ulong) (info.deleted + updated),
(long) thd->get_stmt_da()->current_statement_warn_count());
- ::my_ok(thd, info.copied + info.deleted + updated, id, buff);
+ if (returning)
+ result->send_eof();
+ else
+ ::my_ok(thd, info.copied + info.deleted + updated, id, buff);
}
thd->abort_on_warning= 0;
if (thd->lex->current_select->first_cond_optimization)
@@ -1282,7 +1297,7 @@ values_loop_end:
thd->lex->current_select->save_leaf_tables(thd);
thd->lex->current_select->first_cond_optimization= 0;
}
-
+
DBUG_RETURN(FALSE);
abort:
@@ -1483,12 +1498,13 @@ static void prepare_for_positional_update(TABLE *table, TABLE_LIST *tables)
SYNOPSIS
mysql_prepare_insert()
- thd Thread handler
- table_list Global/local table list
- table Table to insert into (can be NULL if table should
- be taken from table_list->table)
- where Where clause (for insert ... select)
- select_insert TRUE if INSERT ... SELECT statement
+ thd Thread handler
+ table_list Global/local table list
+ table Table to insert into
+ (can be NULL if table should
+ be taken from table_list->table)
+ where Where clause (for insert ... select)
+ select_insert TRUE if INSERT ... SELECT statement
TODO (in far future)
In cases of:
@@ -1499,7 +1515,7 @@ static void prepare_for_positional_update(TABLE *table, TABLE_LIST *tables)
WARNING
You MUST set table->insert_values to 0 after calling this function
before releasing the table object.
-
+
RETURN VALUE
FALSE OK
TRUE error
@@ -1530,25 +1546,6 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(TRUE);
if (thd->lex->handle_list_of_derived(table_list, DT_PREPARE))
DBUG_RETURN(TRUE);
- /*
- For subqueries in VALUES() we should not see the table in which we are
- inserting (for INSERT ... SELECT this is done by changing table_list,
- because INSERT ... SELECT share SELECT_LEX it with SELECT.
- */
- if (!select_insert)
- {
- for (SELECT_LEX_UNIT *un= select_lex->first_inner_unit();
- un;
- un= un->next_unit())
- {
- for (SELECT_LEX *sl= un->first_select();
- sl;
- sl= sl->next_select())
- {
- sl->context.outer_context= 0;
- }
- }
- }
if (duplic == DUP_UPDATE)
{
@@ -1576,10 +1573,11 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
table_list->next_local= 0;
context->resolve_in_table_list_only(table_list);
- res= (setup_fields(thd, Ref_ptr_array(),
- *values, MARK_COLUMNS_READ, 0, NULL, 0) ||
+ res= setup_returning_fields(thd, table_list) ||
+ setup_fields(thd, Ref_ptr_array(),
+ *values, MARK_COLUMNS_READ, 0, NULL, 0) ||
check_insert_fields(thd, context->table_list, fields, *values,
- !insert_into_view, 0, &map));
+ !insert_into_view, 0, &map);
if (!res)
res= setup_fields(thd, Ref_ptr_array(),
@@ -1696,6 +1694,7 @@ int vers_insert_history_row(TABLE *table)
info - COPY_INFO structure describing handling of duplicates
and which is used for counting number of records inserted
and deleted.
+ sink - result sink for the RETURNING clause
NOTE
Once this record will be written to table after insert trigger will
@@ -1703,8 +1702,8 @@ int vers_insert_history_row(TABLE *table)
then both on update triggers will work instead. Similarly both on
delete triggers will be invoked if we will delete conflicting records.
- Sets thd->transaction.stmt.modified_non_trans_table to TRUE if table which is updated didn't have
- transactions.
+ Sets thd->transaction.stmt.modified_non_trans_table to TRUE if table which
+ is updated didn't have transactions.
RETURN VALUE
0 - success
@@ -1712,7 +1711,7 @@ int vers_insert_history_row(TABLE *table)
*/
-int write_record(THD *thd, TABLE *table,COPY_INFO *info)
+int write_record(THD *thd, TABLE *table, COPY_INFO *info, select_result *sink)
{
int error, trg_error= 0;
char *key=0;
@@ -1723,7 +1722,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
DBUG_ENTER("write_record");
info->records++;
- save_read_set= table->read_set;
+ save_read_set= table->read_set;
save_write_set= table->write_set;
if (info->handle_duplicates == DUP_REPLACE ||
@@ -1745,7 +1744,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
table->file->insert_id_for_cur_row= insert_id_for_cur_row;
bool is_duplicate_key_error;
if (table->file->is_fatal_error(error, HA_CHECK_ALL))
- goto err;
+ goto err;
is_duplicate_key_error=
table->file->is_fatal_error(error, HA_CHECK_ALL & ~HA_CHECK_DUP);
if (!is_duplicate_key_error)
@@ -1758,7 +1757,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
if (info->ignore)
{
table->file->print_error(error, MYF(ME_WARNING));
- goto ok_or_after_trg_err; /* Ignoring a not fatal error, return 0 */
+ goto after_trg_or_ignored_err; /* Ignoring a not fatal error */
}
goto err;
}
@@ -1864,7 +1863,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
/* CHECK OPTION for VIEW ... ON DUPLICATE KEY UPDATE ... */
res= info->table_list->view_check_option(table->in_use, info->ignore);
if (res == VIEW_CHECK_SKIP)
- goto ok_or_after_trg_err;
+ goto after_trg_or_ignored_err;
if (res == VIEW_CHECK_ERROR)
goto before_trg_err;
@@ -1882,7 +1881,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
if (!(thd->variables.old_behavior &
OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE))
table->file->print_error(error, MYF(ME_WARNING));
- goto ok_or_after_trg_err;
+ goto after_trg_or_ignored_err;
}
goto err;
}
@@ -1901,7 +1900,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
table->file->print_error(error, MYF(0));
trg_error= 1;
restore_record(table, record[2]);
- goto ok_or_after_trg_err;
+ goto after_trg_or_ignored_err;
}
restore_record(table, record[2]);
}
@@ -1942,7 +1941,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
{
table->file->restore_auto_increment(prev_insert_id_for_cur_row);
}
- goto ok_or_after_trg_err;
+ goto ok;
}
else /* DUP_REPLACE */
{
@@ -2027,7 +2026,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
TRG_ACTION_AFTER, TRUE))
{
trg_error= 1;
- goto ok_or_after_trg_err;
+ goto after_trg_or_ignored_err;
}
/* Let us attempt do write_row() once more */
}
@@ -2063,7 +2062,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE))
table->file->print_error(error, MYF(ME_WARNING));
table->file->restore_auto_increment();
- goto ok_or_after_trg_err;
+ goto after_trg_or_ignored_err;
}
after_trg_n_copied_inc:
@@ -2073,7 +2072,17 @@ after_trg_n_copied_inc:
table->triggers->process_triggers(thd, TRG_EVENT_INSERT,
TRG_ACTION_AFTER, TRUE));
-ok_or_after_trg_err:
+ok:
+ /*
+ We send the row after writing it to the table so that the
+ correct values are sent to the client. Otherwise it won't show
+ autoinc values (generated inside the handler::ha_write()) and
+ values updated in ON DUPLICATE KEY UPDATE.
+ */
+ if (sink && sink->send_data(thd->lex->returning()->item_list) < 0)
+ trg_error= 1;
+
+after_trg_or_ignored_err:
if (key)
my_safe_afree(key,table->s->max_unique_length);
if (!table->file->has_transactions())
@@ -2392,7 +2401,8 @@ bool delayed_get_table(THD *thd, MDL_request *grl_protection_request,
di->thd.variables.binlog_annotate_row_events= 0;
di->thd.set_db(&table_list->db);
- di->thd.set_query(my_strndup(table_list->table_name.str,
+ di->thd.set_query(my_strndup(PSI_INSTRUMENT_ME,
+ table_list->table_name.str,
table_list->table_name.length,
MYF(MY_WME | ME_FATAL)),
table_list->table_name.length, system_charset_info);
@@ -2411,8 +2421,8 @@ bool delayed_get_table(THD *thd, MDL_request *grl_protection_request,
We need the tickets so that they can be cloned in
handle_delayed_insert
*/
- di->grl_protection.init(MDL_key::BACKUP, "", "",
- MDL_BACKUP_DML, MDL_STATEMENT);
+ MDL_REQUEST_INIT(&di->grl_protection, MDL_key::BACKUP, "", "",
+ MDL_BACKUP_DML, MDL_STATEMENT);
di->grl_protection.ticket= grl_protection_request->ticket;
init_mdl_requests(&di->table_list);
di->table_list.mdl_request.ticket= table_list->mdl_request.ticket;
@@ -2721,7 +2731,8 @@ int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic,
if (query.str)
{
char *str;
- if (!(str= my_strndup(query.str, query.length, MYF(MY_WME))))
+ if (!(str= my_strndup(PSI_INSTRUMENT_ME, query.str, query.length,
+ MYF(MY_WME))))
goto err;
query.str= str;
}
@@ -2744,7 +2755,8 @@ int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic,
ip_len= strlen(thd->security_ctx->ip) + 1;
}
/* This can't be THREAD_SPECIFIC as it's freed in delayed thread */
- if (!(row->record= (char*) my_malloc(table->s->reclength +
+ if (!(row->record= (char*) my_malloc(PSI_INSTRUMENT_ME,
+ table->s->reclength +
user_len + host_len + ip_len,
MYF(MY_WME))))
goto err;
@@ -3475,7 +3487,7 @@ bool Delayed_insert::handle_inserts(void)
VCOL_UPDATE_FOR_WRITE);
}
- if (unlikely(tmp_error) || unlikely(write_record(&thd, table, &info)))
+ if (unlikely(tmp_error || write_record(&thd, table, &info, NULL)))
{
info.error_count++; // Ignore errors
thread_safe_increment(delayed_insert_errors,&LOCK_delayed_status);
@@ -3631,24 +3643,30 @@ bool Delayed_insert::handle_inserts(void)
TRUE Error
*/
-bool mysql_insert_select_prepare(THD *thd)
+bool mysql_insert_select_prepare(THD *thd, select_result *sel_res)
{
LEX *lex= thd->lex;
SELECT_LEX *select_lex= lex->first_select_lex();
DBUG_ENTER("mysql_insert_select_prepare");
-
/*
SELECT_LEX do not belong to INSERT statement, so we can't add WHERE
clause if table is VIEW
*/
-
+
if (mysql_prepare_insert(thd, lex->query_tables,
lex->query_tables->table, lex->field_list, 0,
lex->update_list, lex->value_list, lex->duplicates,
&select_lex->where, TRUE))
DBUG_RETURN(TRUE);
+ /*
+ If sel_res is not empty, it means we have items in returing_list.
+ So we prepare the list now
+ */
+ if (sel_res)
+ sel_res->prepare(lex->returning()->item_list, NULL);
+
DBUG_ASSERT(select_lex->leaf_tables.elements != 0);
List_iterator<TABLE_LIST> ti(select_lex->leaf_tables);
TABLE_LIST *table;
@@ -3691,8 +3709,10 @@ select_insert::select_insert(THD *thd_arg, TABLE_LIST *table_list_par,
List<Item> *update_fields,
List<Item> *update_values,
enum_duplicates duplic,
- bool ignore_check_option_errors):
+ bool ignore_check_option_errors,
+ select_result *result):
select_result_interceptor(thd_arg),
+ sel_result(result),
table_list(table_list_par), table(table_par), fields(fields_par),
autoinc_value_of_last_inserted_row(0),
insert_into_view(table_list_par && table_list_par->view != 0)
@@ -3711,7 +3731,7 @@ int
select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
LEX *lex= thd->lex;
- int res;
+ int res= 0;
table_map map= 0;
SELECT_LEX *lex_current_select_save= lex->current_select;
DBUG_ENTER("select_insert::prepare");
@@ -3725,17 +3745,15 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
*/
lex->current_select= lex->first_select_lex();
- res= (setup_fields(thd, Ref_ptr_array(),
- values, MARK_COLUMNS_READ, 0, NULL, 0) ||
- check_insert_fields(thd, table_list, *fields, values,
- !insert_into_view, 1, &map));
+ res= setup_returning_fields(thd, table_list) ||
+ setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, 0, 0) ||
+ check_insert_fields(thd, table_list, *fields, values,
+ !insert_into_view, 1, &map);
if (!res && fields->elements)
{
- bool saved_abort_on_warning= thd->abort_on_warning;
- thd->abort_on_warning= !info.ignore && thd->is_strict_mode();
+ Abort_on_warning_instant_set aws(thd, !info.ignore && thd->is_strict_mode());
res= check_that_all_fields_are_given_values(thd, table_list->table, table_list);
- thd->abort_on_warning= saved_abort_on_warning;
}
if (info.handle_duplicates == DUP_UPDATE && !res)
@@ -3889,7 +3907,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
If the result table is the same as one of the source tables
(INSERT SELECT), the result table is not finally prepared at the
join prepair phase. Do the final preparation now.
-
+
RETURN
0 OK
*/
@@ -3897,11 +3915,18 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
int select_insert::prepare2(JOIN *)
{
DBUG_ENTER("select_insert::prepare2");
+ if (table->validate_default_values_of_unset_fields(thd))
+ DBUG_RETURN(1);
+ if (thd->lex->describe)
+ DBUG_RETURN(0);
if (thd->lex->current_select->options & OPTION_BUFFER_RESULT &&
- thd->locked_tables_mode <= LTM_LOCK_TABLES &&
- !thd->lex->describe)
+ thd->locked_tables_mode <= LTM_LOCK_TABLES)
table->file->ha_start_bulk_insert((ha_rows) 0);
- if (table->validate_default_values_of_unset_fields(thd))
+
+ /* Same as the other variants of INSERT */
+ if (sel_result &&
+ sel_result->send_result_set_metadata(thd->lex->returning()->item_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(1);
DBUG_RETURN(0);
}
@@ -3916,6 +3941,7 @@ void select_insert::cleanup()
select_insert::~select_insert()
{
DBUG_ENTER("~select_insert");
+ sel_result= NULL;
if (table && table->is_created())
{
table->next_number_field=0;
@@ -3933,14 +3959,6 @@ int select_insert::send_data(List<Item> &values)
DBUG_ENTER("select_insert::send_data");
bool error=0;
- if (unit->offset_limit_cnt)
- { // using limit offset,count
- unit->offset_limit_cnt--;
- DBUG_RETURN(0);
- }
- if (unlikely(thd->killed == ABORT_QUERY))
- DBUG_RETURN(0);
-
thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields
store_values(values);
if (table->default_field &&
@@ -3964,10 +3982,10 @@ int select_insert::send_data(List<Item> &values)
}
}
- error= write_record(thd, table, &info);
+ error= write_record(thd, table, &info, sel_result);
table->vers_write= table->versioned();
table->auto_increment_field_not_null= FALSE;
-
+
if (likely(!error))
{
if (table->triggers || info.handle_duplicates == DUP_UPDATE)
@@ -4103,7 +4121,6 @@ bool select_insert::send_ok_packet() {
char message[160]; /* status message */
ulonglong row_count; /* rows affected */
ulonglong id; /* last insert-id */
-
DBUG_ENTER("select_insert::send_ok_packet");
if (info.ignore)
@@ -4125,7 +4142,14 @@ bool select_insert::send_ok_packet() {
thd->first_successful_insert_id_in_prev_stmt :
(info.copied ? autoinc_value_of_last_inserted_row : 0));
- ::my_ok(thd, row_count, id, message);
+ /*
+ Client expects an EOF/OK packet If LEX::has_returning and if result set
+ meta was sent. See explanation for other variants of INSERT.
+ */
+ if (sel_result)
+ sel_result->send_eof();
+ else
+ ::my_ok(thd, row_count, id, message);
DBUG_RETURN(false);
}
@@ -4217,11 +4241,11 @@ void select_insert::abort_result_set()
CREATE TABLE (SELECT) ...
***************************************************************************/
-Field *Item::create_field_for_create_select(TABLE *table)
+Field *Item::create_field_for_create_select(MEM_ROOT *root, TABLE *table)
{
static Tmp_field_param param(false, false, false, false);
Tmp_field_src src;
- return create_tmp_field_ex(table, &src, &param);
+ return create_tmp_field_ex(root, table, &src, &param);
}
@@ -4293,7 +4317,8 @@ TABLE *select_create::create_table_from_items(THD *thd, List<Item> *items,
while ((item=it++))
{
- Field *tmp_field= item->create_field_for_create_select(&tmp_table);
+ Field *tmp_field= item->create_field_for_create_select(thd->mem_root,
+ &tmp_table);
if (!tmp_field)
DBUG_RETURN(NULL);
diff --git a/sql/sql_insert.h b/sql/sql_insert.h
index a37ed1f31e5..977a0eb23c8 100644
--- a/sql/sql_insert.h
+++ b/sql/sql_insert.h
@@ -31,14 +31,15 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
bool mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
List<List_item> &values, List<Item> &update_fields,
List<Item> &update_values, enum_duplicates flag,
- bool ignore);
+ bool ignore, select_result* result);
void upgrade_lock_type_for_insert(THD *thd, thr_lock_type *lock_type,
enum_duplicates duplic,
bool is_multi_insert);
int check_that_all_fields_are_given_values(THD *thd, TABLE *entry,
TABLE_LIST *table_list);
int vers_insert_history_row(TABLE *table);
-int write_record(THD *thd, TABLE *table, COPY_INFO *info);
+int write_record(THD *thd, TABLE *table, COPY_INFO *info,
+ select_result *returning= NULL);
void kill_delayed_threads(void);
#ifdef EMBEDDED_LIBRARY
diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc
index e9ad53850dd..5a243cd0a6d 100644
--- a/sql/sql_join_cache.cc
+++ b/sql/sql_join_cache.cc
@@ -937,7 +937,8 @@ int JOIN_CACHE::alloc_buffer()
{
size_t next_buff_size;
- if ((buff= (uchar*) my_malloc(buff_size, MYF(MY_THREAD_SPECIFIC))))
+ if ((buff= (uchar*) my_malloc(key_memory_JOIN_CACHE, buff_size,
+ MYF(MY_THREAD_SPECIFIC))))
break;
next_buff_size= buff_size > buff_size_decr ? buff_size-buff_size_decr : 0;
@@ -1013,11 +1014,11 @@ bool JOIN_CACHE::shrink_join_buffer_in_ratio(ulonglong n, ulonglong d)
int JOIN_CACHE::realloc_buffer()
{
- int rc;
free();
- rc= MY_TEST(!(buff= (uchar*) my_malloc(buff_size, MYF(MY_THREAD_SPECIFIC))));
+ buff= (uchar*) my_malloc(key_memory_JOIN_CACHE, buff_size,
+ MYF(MY_THREAD_SPECIFIC));
reset(TRUE);
- return rc;
+ return buff == NULL;
}
@@ -2084,8 +2085,13 @@ enum_nested_loop_state JOIN_CACHE::join_records(bool skip_last)
if (!join_tab->first_unmatched)
{
+ bool pfs_batch_update= join_tab->pfs_batch_update(join);
+ if (pfs_batch_update)
+ join_tab->table->file->start_psi_batch_mode();
/* Find all records from join_tab that match records from join buffer */
rc= join_matching_records(skip_last);
+ if (pfs_batch_update)
+ join_tab->table->file->end_psi_batch_mode();
if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS)
goto finish;
if (outer_join_first_inner)
@@ -2811,12 +2817,12 @@ int JOIN_CACHE_HASHED::init_hash_table()
int JOIN_CACHE_HASHED::realloc_buffer()
{
- int rc;
free();
- rc= MY_TEST(!(buff= (uchar*) my_malloc(buff_size, MYF(MY_THREAD_SPECIFIC))));
+ buff= (uchar*) my_malloc(key_memory_JOIN_CACHE, buff_size,
+ MYF(MY_THREAD_SPECIFIC));
init_hash_table();
reset(TRUE);
- return rc;
+ return buff == NULL;
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 39e8f42b409..ade7434803c 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
- Copyright (c) 2009, 2019, MariaDB Corporation
+ Copyright (c) 2009, 2020, 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
@@ -52,6 +52,535 @@ const LEX_CSTRING empty_clex_str= {"", 0};
const LEX_CSTRING star_clex_str= {"*", 1};
const LEX_CSTRING param_clex_str= {"?", 1};
+
+/**
+ Helper action for a case expression statement (the expr in 'CASE expr').
+ This helper is used for 'searched' cases only.
+ @param lex the parser lex context
+ @param expr the parsed expression
+ @return 0 on success
+*/
+
+int sp_expr_lex::case_stmt_action_expr()
+{
+ int case_expr_id= spcont->register_case_expr();
+ sp_instr_set_case_expr *i;
+
+ if (spcont->push_case_expr_id(case_expr_id))
+ return 1;
+
+ i= new (thd->mem_root)
+ sp_instr_set_case_expr(sphead->instructions(), spcont, case_expr_id,
+ get_item(), this);
+
+ sphead->add_cont_backpatch(i);
+ return sphead->add_instr(i);
+}
+
+/**
+ Helper action for a case when condition.
+ This helper is used for both 'simple' and 'searched' cases.
+ @param lex the parser lex context
+ @param when the parsed expression for the WHEN clause
+ @param simple true for simple cases, false for searched cases
+*/
+
+int sp_expr_lex::case_stmt_action_when(bool simple)
+{
+ uint ip= sphead->instructions();
+ sp_instr_jump_if_not *i;
+ Item_case_expr *var;
+ Item *expr;
+
+ if (simple)
+ {
+ var= new (thd->mem_root)
+ Item_case_expr(thd, spcont->get_current_case_expr_id());
+
+#ifdef DBUG_ASSERT_EXISTS
+ if (var)
+ {
+ var->m_sp= sphead;
+ }
+#endif
+
+ expr= new (thd->mem_root) Item_func_eq(thd, var, get_item());
+ i= new (thd->mem_root) sp_instr_jump_if_not(ip, spcont, expr, this);
+ }
+ else
+ i= new (thd->mem_root) sp_instr_jump_if_not(ip, spcont, get_item(), this);
+
+ /*
+ BACKPATCH: Registering forward jump from
+ "case_stmt_action_when" to "case_stmt_action_then"
+ (jump_if_not from instruction 2 to 5, 5 to 8 ... in the example)
+ */
+
+ return
+ !MY_TEST(i) ||
+ sphead->push_backpatch(thd, i, spcont->push_label(thd, &empty_clex_str, 0)) ||
+ sphead->add_cont_backpatch(i) ||
+ sphead->add_instr(i);
+}
+
+/**
+ Helper action for a case then statements.
+ This helper is used for both 'simple' and 'searched' cases.
+ @param lex the parser lex context
+*/
+
+int LEX::case_stmt_action_then()
+{
+ uint ip= sphead->instructions();
+ sp_instr_jump *i= new (thd->mem_root) sp_instr_jump(ip, spcont);
+ if (!MY_TEST(i) || sphead->add_instr(i))
+ return 1;
+
+ /*
+ BACKPATCH: Resolving forward jump from
+ "case_stmt_action_when" to "case_stmt_action_then"
+ (jump_if_not from instruction 2 to 5, 5 to 8 ... in the example)
+ */
+
+ sphead->backpatch(spcont->pop_label());
+
+ /*
+ BACKPATCH: Registering forward jump from
+ "case_stmt_action_then" to after END CASE
+ (jump from instruction 4 to 12, 7 to 12 ... in the example)
+ */
+
+ return sphead->push_backpatch(thd, i, spcont->last_label());
+}
+
+
+/**
+ Helper action for a SET statement.
+ Used to push a system variable into the assignment list.
+
+ @param tmp the system variable with base name
+ @param var_type the scope of the variable
+ @param val the value being assigned to the variable
+
+ @return TRUE if error, FALSE otherwise.
+*/
+
+bool
+LEX::set_system_variable(enum enum_var_type var_type,
+ sys_var *sysvar, const Lex_ident_sys_st *base_name,
+ Item *val)
+{
+ set_var *setvar;
+
+ /* No AUTOCOMMIT from a stored function or trigger. */
+ if (spcont && sysvar == Sys_autocommit_ptr)
+ sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
+
+ if (val && val->type() == Item::FIELD_ITEM &&
+ ((Item_field*)val)->table_name.str)
+ {
+ my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), sysvar->name.str);
+ return TRUE;
+ }
+
+ if (!(setvar= new (thd->mem_root) set_var(thd, var_type, sysvar,
+ base_name, val)))
+ return TRUE;
+
+ return var_list.push_back(setvar, thd->mem_root);
+}
+
+
+/**
+ Helper action for a SET statement.
+ Used to SET a field of NEW row.
+
+ @param name the field name
+ @param val the value being assigned to the row
+
+ @return TRUE if error, FALSE otherwise.
+*/
+
+bool LEX::set_trigger_new_row(const LEX_CSTRING *name, Item *val)
+{
+ Item_trigger_field *trg_fld;
+ sp_instr_set_trigger_field *sp_fld;
+
+ /* QQ: Shouldn't this be field's default value ? */
+ if (! val)
+ val= new (thd->mem_root) Item_null(thd);
+
+ DBUG_ASSERT(trg_chistics.action_time == TRG_ACTION_BEFORE &&
+ (trg_chistics.event == TRG_EVENT_INSERT ||
+ trg_chistics.event == TRG_EVENT_UPDATE));
+
+ trg_fld= new (thd->mem_root)
+ Item_trigger_field(thd, current_context(),
+ Item_trigger_field::NEW_ROW,
+ *name, UPDATE_ACL, FALSE);
+
+ if (unlikely(trg_fld == NULL))
+ return TRUE;
+
+ sp_fld= new (thd->mem_root)
+ sp_instr_set_trigger_field(sphead->instructions(),
+ spcont, trg_fld, val, this);
+
+ if (unlikely(sp_fld == NULL))
+ return TRUE;
+
+ /*
+ Let us add this item to list of all Item_trigger_field
+ objects in trigger.
+ */
+ trg_table_fields.link_in_list(trg_fld, &trg_fld->next_trg_field);
+
+ return sphead->add_instr(sp_fld);
+}
+
+
+/**
+ Create an object to represent a SP variable in the Item-hierarchy.
+
+ @param name The SP variable name.
+ @param spvar The SP variable (optional).
+ @param start_in_q Start position of the SP variable name in the query.
+ @param end_in_q End position of the SP variable name in the query.
+
+ @remark If spvar is not specified, the name is used to search for the
+ variable in the parse-time context. If the variable does not
+ exist, a error is set and NULL is returned to the caller.
+
+ @return An Item_splocal object representing the SP variable, or NULL on error.
+*/
+Item_splocal*
+LEX::create_item_for_sp_var(const Lex_ident_cli_st *cname, sp_variable *spvar)
+{
+ const Sp_rcontext_handler *rh;
+ Item_splocal *item;
+ const char *start_in_q= cname->pos();
+ const char *end_in_q= cname->end();
+ uint pos_in_q, len_in_q;
+ Lex_ident_sys name(thd, cname);
+
+ if (name.is_null())
+ return NULL; // EOM
+
+ /* If necessary, look for the variable. */
+ if (spcont && !spvar)
+ spvar= find_variable(&name, &rh);
+
+ if (!spvar)
+ {
+ my_error(ER_SP_UNDECLARED_VAR, MYF(0), name.str);
+ return NULL;
+ }
+
+ DBUG_ASSERT(spcont && spvar);
+
+ /* Position and length of the SP variable name in the query. */
+ pos_in_q= (uint)(start_in_q - sphead->m_tmp_query);
+ len_in_q= (uint)(end_in_q - start_in_q);
+
+ item= new (thd->mem_root)
+ Item_splocal(thd, rh, &name, spvar->offset, spvar->type_handler(),
+ pos_in_q, len_in_q);
+
+#ifdef DBUG_ASSERT_EXISTS
+ if (item)
+ item->m_sp= sphead;
+#endif
+
+ return item;
+}
+
+
+/**
+ Helper to resolve the SQL:2003 Syntax exception 1) in <in predicate>.
+ See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383.
+ This function returns the proper item for the SQL expression
+ <code>left [NOT] IN ( expr )</code>
+ @param thd the current thread
+ @param left the in predicand
+ @param equal true for IN predicates, false for NOT IN predicates
+ @param expr first and only expression of the in value list
+ @return an expression representing the IN predicate.
+*/
+Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
+ Item *expr)
+{
+ /*
+ Relevant references for this issue:
+ - SQL:2003, Part 2, section 8.4 <in predicate>, page 383,
+ - SQL:2003, Part 2, section 7.2 <row value expression>, page 296,
+ - SQL:2003, Part 2, section 6.3 <value expression primary>, page 174,
+ - SQL:2003, Part 2, section 7.15 <subquery>, page 370,
+ - SQL:2003 Feature F561, "Full value expressions".
+
+ The exception in SQL:2003 Note 184 means:
+ Item_singlerow_subselect, which corresponds to a <scalar subquery>,
+ should be re-interpreted as an Item_in_subselect, which corresponds
+ to a <table subquery> when used inside an <in predicate>.
+
+ Our reading of Note 184 is reccursive, so that all:
+ - IN (( <subquery> ))
+ - IN ((( <subquery> )))
+ - IN '('^N <subquery> ')'^N
+ - etc
+ should be interpreted as a <table subquery>, no matter how deep in the
+ expression the <subquery> is.
+ */
+
+ Item *result;
+
+ DBUG_ENTER("handle_sql2003_note184_exception");
+
+ if (expr->type() == Item::SUBSELECT_ITEM)
+ {
+ Item_subselect *expr2 = (Item_subselect*) expr;
+
+ if (expr2->substype() == Item_subselect::SINGLEROW_SUBS)
+ {
+ Item_singlerow_subselect *expr3 = (Item_singlerow_subselect*) expr2;
+ st_select_lex *subselect;
+
+ /*
+ Implement the mandated change, by altering the semantic tree:
+ left IN Item_singlerow_subselect(subselect)
+ is modified to
+ left IN (subselect)
+ which is represented as
+ Item_in_subselect(left, subselect)
+ */
+ subselect= expr3->invalidate_and_restore_select_lex();
+ result= new (thd->mem_root) Item_in_subselect(thd, left, subselect);
+
+ if (! equal)
+ result = negate_expression(thd, result);
+
+ DBUG_RETURN(result);
+ }
+ }
+
+ if (equal)
+ result= new (thd->mem_root) Item_func_eq(thd, left, expr);
+ else
+ result= new (thd->mem_root) Item_func_ne(thd, left, expr);
+
+ DBUG_RETURN(result);
+}
+
+/**
+ Create a separate LEX for each assignment if in SP.
+
+ If we are in SP we want have own LEX for each assignment.
+ This is mostly because it is hard for several sp_instr_set
+ and sp_instr_set_trigger instructions share one LEX.
+ (Well, it is theoretically possible but adds some extra
+ overhead on preparation for execution stage and IMO less
+ robust).
+
+ QQ: May be we should simply prohibit group assignments in SP?
+
+ @see sp_create_assignment_instr
+
+ @param thd Thread context
+ @param pos The position in the raw SQL buffer
+*/
+
+
+bool sp_create_assignment_lex(THD *thd, const char *pos)
+{
+ if (thd->lex->sphead)
+ {
+ sp_lex_local *new_lex;
+ if (!(new_lex= new (thd->mem_root) sp_lex_set_var(thd, thd->lex)) ||
+ new_lex->main_select_push())
+ return true;
+ new_lex->sphead->m_tmp_query= pos;
+ return thd->lex->sphead->reset_lex(thd, new_lex);
+ }
+ return false;
+}
+
+
+/**
+ Create a SP instruction for a SET assignment.
+
+ @see sp_create_assignment_lex
+
+ @param thd - Thread context
+ @param no_lookahead - True if the parser has no lookahead
+ @param need_set_keyword - if a SET statement "SET a=10",
+ or a direct assignment overwise "a:=10"
+ @return false if success, true otherwise.
+*/
+
+bool sp_create_assignment_instr(THD *thd, bool no_lookahead,
+ bool need_set_keyword)
+{
+ LEX *lex= thd->lex;
+
+ if (lex->sphead)
+ {
+ if (!lex->var_list.is_empty())
+ {
+ /*
+ - Every variable assignment from the same SET command, e.g.:
+ SET @var1=expr1, @var2=expr2;
+ produce each own sp_create_assignment_instr() call
+ lex->var_list.elements is 1 in this case.
+ - This query:
+ SET TRANSACTION READ ONLY, ISOLATION LEVEL SERIALIZABLE;
+ in translated to:
+ SET tx_read_only=1, tx_isolation=ISO_SERIALIZABLE;
+ but produces a single sp_create_assignment_instr() call
+ which includes the query fragment covering both options.
+ */
+ DBUG_ASSERT(lex->var_list.elements >= 1 && lex->var_list.elements <= 2);
+ /*
+ sql_mode=ORACLE's direct assignment of a global variable
+ is not possible by the grammar.
+ */
+ DBUG_ASSERT(lex->option_type != OPT_GLOBAL || need_set_keyword);
+ /*
+ We have assignment to user or system variable or
+ option setting, so we should construct sp_instr_stmt
+ for it.
+ */
+ Lex_input_stream *lip= &thd->m_parser_state->m_lip;
+
+ /*
+ Extract the query statement from the tokenizer. The
+ end is either lip->ptr, if there was no lookahead,
+ lip->tok_end otherwise.
+ */
+ static const LEX_CSTRING setlc= { STRING_WITH_LEN("SET ") };
+ static const LEX_CSTRING setgl= { STRING_WITH_LEN("SET GLOBAL ") };
+ const char *qend= no_lookahead ? lip->get_ptr() : lip->get_tok_end();
+ Lex_cstring qbuf(lex->sphead->m_tmp_query, qend);
+ if (lex->new_sp_instr_stmt(thd,
+ lex->option_type == OPT_GLOBAL ? setgl :
+ need_set_keyword ? setlc :
+ null_clex_str,
+ qbuf))
+ return true;
+ }
+ lex->pop_select();
+ if (lex->check_main_unit_semantics())
+ {
+ /*
+ "lex" can be referrenced by:
+ - sp_instr_set SET a= expr;
+ - sp_instr_set_row_field SET r.a= expr;
+ - sp_instr_stmt (just generated above) SET @a= expr;
+ In this case, "lex" is fully owned by sp_instr_xxx and it will
+ be deleted by the destructor ~sp_instr_xxx().
+ So we should remove "lex" from the stack sp_head::m_lex,
+ to avoid double free.
+ Note, in case "lex" is not owned by any sp_instr_xxx,
+ it's also safe to remove it from the stack right now.
+ So we can remove it unconditionally, without testing lex->sp_lex_in_use.
+ */
+ lex->sphead->restore_lex(thd);
+ return true;
+ }
+ enum_var_type inner_option_type= lex->option_type;
+ if (lex->sphead->restore_lex(thd))
+ return true;
+ /* Copy option_type to outer lex in case it has changed. */
+ thd->lex->option_type= inner_option_type;
+ }
+ return false;
+}
+
+
+void LEX::add_key_to_list(LEX_CSTRING *field_name,
+ enum Key::Keytype type, bool check_exists)
+{
+ Key *key;
+ MEM_ROOT *mem_root= thd->mem_root;
+ key= new (mem_root)
+ Key(type, &null_clex_str, HA_KEY_ALG_UNDEF, false,
+ DDL_options(check_exists ?
+ DDL_options::OPT_IF_NOT_EXISTS :
+ DDL_options::OPT_NONE));
+ key->columns.push_back(new (mem_root) Key_part_spec(field_name, 0),
+ mem_root);
+ alter_info.key_list.push_back(key, mem_root);
+}
+
+
+bool LEX::add_alter_list(LEX_CSTRING name, Virtual_column_info *expr,
+ bool exists)
+{
+ MEM_ROOT *mem_root= thd->mem_root;
+ Alter_column *ac= new (mem_root) Alter_column(name, expr, exists);
+ if (unlikely(ac == NULL))
+ return true;
+ alter_info.alter_list.push_back(ac, mem_root);
+ alter_info.flags|= ALTER_CHANGE_COLUMN_DEFAULT;
+ return false;
+}
+
+
+bool LEX::add_alter_list(LEX_CSTRING name, LEX_CSTRING new_name)
+{
+ Alter_column *ac= new (thd->mem_root) Alter_column(name, new_name);
+ if (unlikely(ac == NULL))
+ return true;
+ alter_info.alter_list.push_back(ac, thd->mem_root);
+ alter_info.flags|= ALTER_RENAME_COLUMN;
+ return false;
+}
+
+
+void LEX::init_last_field(Column_definition *field,
+ const LEX_CSTRING *field_name,
+ const CHARSET_INFO *cs)
+{
+ last_field= field;
+
+ field->field_name= *field_name;
+
+ /* reset LEX fields that are used in Create_field::set_and_check() */
+ charset= cs;
+}
+
+
+bool LEX::set_bincmp(CHARSET_INFO *cs, bool bin)
+{
+ /*
+ if charset is NULL - we're parsing a field declaration.
+ we cannot call find_bin_collation for a field here, because actual
+ field charset is determined in get_sql_field_charset() much later.
+ so we only set a flag.
+ */
+ if (!charset)
+ {
+ charset= cs;
+ last_field->flags|= bin ? BINCMP_FLAG : 0;
+ return false;
+ }
+
+ charset= bin ? find_bin_collation(cs ? cs : charset)
+ : cs ? cs : charset;
+ return charset == NULL;
+}
+
+
+Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
+{
+ Virtual_column_info *v= new (thd->mem_root) Virtual_column_info();
+ if (unlikely(!v))
+ return 0;
+ v->expr= expr;
+ v->utf8= 0; /* connection charset */
+ return v;
+}
+
+
+
/**
@note The order of the elements of this array must correspond to
the order of elements in enum_binlog_stmt_unsafe.
@@ -350,7 +879,7 @@ size_t Lex_input_stream::get_body_utf8_maximum_length(THD *thd)
"2" should be a reasonable multiplier that safely covers escaping needs.
*/
return (m_buf_length / thd->variables.character_set_client->mbminlen) *
- my_charset_utf8_bin.mbmaxlen * 2/*for escaping*/;
+ my_charset_utf8mb3_bin.mbmaxlen * 2/*for escaping*/;
}
@@ -455,14 +984,14 @@ extern "C" {
@param end - the end of the destination string
@returns - a code according to the wc_mb() convension.
*/
-int my_wc_mb_utf8_with_escape(CHARSET_INFO *cs, my_wc_t escape, my_wc_t wc,
- uchar *str, uchar *end)
+int my_wc_mb_utf8mb3_with_escape(CHARSET_INFO *cs, my_wc_t escape, my_wc_t wc,
+ uchar *str, uchar *end)
{
DBUG_ASSERT(escape > 0);
if (str + 1 >= end)
return MY_CS_TOOSMALL2; // Not enough space, need at least two bytes.
*str= (uchar)escape;
- int cnvres= my_charset_utf8_handler.wc_mb(cs, wc, str + 1, end);
+ int cnvres= my_charset_utf8mb3_handler.wc_mb(cs, wc, str + 1, end);
if (cnvres > 0)
return cnvres + 1; // The character was normally put
if (cnvres == MY_CS_ILUNI)
@@ -484,12 +1013,12 @@ int my_wc_mb_utf8_with_escape(CHARSET_INFO *cs, my_wc_t escape, my_wc_t wc,
@param end - the end of the destination string
@returns - a code according to the wc_mb() conversion.
*/
-int my_wc_mb_utf8_opt_escape(CHARSET_INFO *cs,
- my_wc_t wc, my_wc_t escape, my_wc_t ewc,
- uchar *str, uchar *end)
+int my_wc_mb_utf8mb3_opt_escape(CHARSET_INFO *cs,
+ my_wc_t wc, my_wc_t escape, my_wc_t ewc,
+ uchar *str, uchar *end)
{
- return escape ? my_wc_mb_utf8_with_escape(cs, escape, ewc, str, end) :
- my_charset_utf8_handler.wc_mb(cs, wc, str, end);
+ return escape ? my_wc_mb_utf8mb3_with_escape(cs, escape, ewc, str, end) :
+ my_charset_utf8mb3_handler.wc_mb(cs, wc, str, end);
}
/**
@@ -508,54 +1037,55 @@ int my_wc_mb_utf8_opt_escape(CHARSET_INFO *cs,
@param escape - the escape character (backslash, or 0)
@returns - a code according to the wc_mb() convension.
*/
-int my_wc_mb_utf8_escape(CHARSET_INFO *cs, my_wc_t wc, uchar *str, uchar *end,
- my_wc_t sep, my_wc_t escape)
+int my_wc_mb_utf8mb3_escape(CHARSET_INFO *cs, my_wc_t wc,
+ uchar *str, uchar *end,
+ my_wc_t sep, my_wc_t escape)
{
DBUG_ASSERT(escape == 0 || escape == '\\');
DBUG_ASSERT(sep == '"' || sep == '\'');
switch (wc) {
- case 0: return my_wc_mb_utf8_opt_escape(cs, wc, escape, '0', str, end);
- case '\t': return my_wc_mb_utf8_opt_escape(cs, wc, escape, 't', str, end);
- case '\r': return my_wc_mb_utf8_opt_escape(cs, wc, escape, 'r', str, end);
- case '\n': return my_wc_mb_utf8_opt_escape(cs, wc, escape, 'n', str, end);
- case '\032': return my_wc_mb_utf8_opt_escape(cs, wc, escape, 'Z', str, end);
+ case 0: return my_wc_mb_utf8mb3_opt_escape(cs, wc, escape, '0', str, end);
+ case '\t': return my_wc_mb_utf8mb3_opt_escape(cs, wc, escape, 't', str, end);
+ case '\r': return my_wc_mb_utf8mb3_opt_escape(cs, wc, escape, 'r', str, end);
+ case '\n': return my_wc_mb_utf8mb3_opt_escape(cs, wc, escape, 'n', str, end);
+ case '\032': return my_wc_mb_utf8mb3_opt_escape(cs, wc, escape, 'Z', str, end);
case '\'':
case '\"':
if (wc == sep)
- return my_wc_mb_utf8_with_escape(cs, wc, wc, str, end);
+ return my_wc_mb_utf8mb3_with_escape(cs, wc, wc, str, end);
}
- return my_charset_utf8_handler.wc_mb(cs, wc, str, end); // No escaping needed
+ return my_charset_utf8mb3_handler.wc_mb(cs, wc, str, end); // No escaping needed
}
/** wc_mb() compatible routines for all sql_mode and delimiter combinations */
-int my_wc_mb_utf8_escape_single_quote_and_backslash(CHARSET_INFO *cs,
+int my_wc_mb_utf8mb3_escape_single_quote_and_backslash(CHARSET_INFO *cs,
my_wc_t wc,
uchar *str, uchar *end)
{
- return my_wc_mb_utf8_escape(cs, wc, str, end, '\'', '\\');
+ return my_wc_mb_utf8mb3_escape(cs, wc, str, end, '\'', '\\');
}
-int my_wc_mb_utf8_escape_double_quote_and_backslash(CHARSET_INFO *cs,
+int my_wc_mb_utf8mb3_escape_double_quote_and_backslash(CHARSET_INFO *cs,
my_wc_t wc,
uchar *str, uchar *end)
{
- return my_wc_mb_utf8_escape(cs, wc, str, end, '"', '\\');
+ return my_wc_mb_utf8mb3_escape(cs, wc, str, end, '"', '\\');
}
-int my_wc_mb_utf8_escape_single_quote(CHARSET_INFO *cs, my_wc_t wc,
+int my_wc_mb_utf8mb3_escape_single_quote(CHARSET_INFO *cs, my_wc_t wc,
uchar *str, uchar *end)
{
- return my_wc_mb_utf8_escape(cs, wc, str, end, '\'', 0);
+ return my_wc_mb_utf8mb3_escape(cs, wc, str, end, '\'', 0);
}
-int my_wc_mb_utf8_escape_double_quote(CHARSET_INFO *cs, my_wc_t wc,
+int my_wc_mb_utf8mb3_escape_double_quote(CHARSET_INFO *cs, my_wc_t wc,
uchar *str, uchar *end)
{
- return my_wc_mb_utf8_escape(cs, wc, str, end, '"', 0);
+ return my_wc_mb_utf8mb3_escape(cs, wc, str, end, '"', 0);
}
}; // End of extern "C"
@@ -569,10 +1099,10 @@ my_charset_conv_wc_mb
Lex_input_stream::get_escape_func(THD *thd, my_wc_t sep) const
{
return thd->backslash_escapes() ?
- (sep == '"' ? my_wc_mb_utf8_escape_double_quote_and_backslash:
- my_wc_mb_utf8_escape_single_quote_and_backslash) :
- (sep == '"' ? my_wc_mb_utf8_escape_double_quote:
- my_wc_mb_utf8_escape_single_quote);
+ (sep == '"' ? my_wc_mb_utf8mb3_escape_double_quote_and_backslash:
+ my_wc_mb_utf8mb3_escape_single_quote_and_backslash) :
+ (sep == '"' ? my_wc_mb_utf8mb3_escape_double_quote:
+ my_wc_mb_utf8mb3_escape_single_quote);
}
@@ -612,7 +1142,7 @@ void Lex_input_stream::body_utf8_append_escape(THD *thd,
DBUG_ASSERT(m_body_utf8 + get_body_utf8_maximum_length(thd) >=
m_body_utf8_ptr + txt->length * 2);
uint32 cnv_length= my_convert_using_func(m_body_utf8_ptr, txt->length * 2,
- &my_charset_utf8_general_ci,
+ &my_charset_utf8mb3_general_ci,
get_escape_func(thd, sep),
txt->str, txt->length,
cs, cs->cset->mb_wc,
@@ -705,7 +1235,6 @@ void LEX::start(THD *thd_arg)
set_var_list.empty();
param_list.empty();
view_list.empty();
- with_column_list.empty();
with_persistent_for_clause= FALSE;
column_list= NULL;
index_list= NULL;
@@ -945,6 +1474,9 @@ bool is_native_function(THD *thd, const LEX_CSTRING *name)
if (is_lex_native_function(name))
return true;
+ if (Type_handler::handler_by_name(thd, *name))
+ return true;
+
return false;
}
@@ -1014,7 +1546,7 @@ my_unescape(CHARSET_INFO *cs, char *to, const char *str, const char *end,
{
#ifdef USE_MB
int l;
- if (use_mb(cs) && (l= my_ismbchar(cs, str, end)))
+ if (cs->use_mb() && (l= my_ismbchar(cs, str, end)))
{
while (l--)
*to++ = *str++;
@@ -1092,7 +1624,7 @@ bool Lex_input_stream::get_text(Lex_string_with_metadata_st *dst, uint sep,
#ifdef USE_MB
{
int l;
- if (use_mb(cs) &&
+ if (cs->use_mb() &&
(l = my_ismbchar(cs,
get_ptr() -1,
get_end_of_query()))) {
@@ -2025,7 +2557,7 @@ int Lex_input_stream::lex_one_token(YYSTYPE *yylval, THD *thd)
next_state= MY_LEX_HOSTNAME;
break;
}
- yylval->lex_str.str= (char*) get_ptr();
+ yylval->lex_str.str= (char*) get_ptr() - 1;
yylval->lex_str.length= 1;
return((int) '@');
case MY_LEX_HOSTNAME: // end '@' of user@hostname
@@ -2123,12 +2655,12 @@ int Lex_input_stream::scan_ident_start(THD *thd, Lex_ident_cli_st *str)
const uchar *const ident_map= cs->ident_map;
DBUG_ASSERT(m_tok_start <= m_ptr);
- if (use_mb(cs))
+ if (cs->use_mb())
{
is_8bit= true;
while (ident_map[c= yyGet()])
{
- int char_length= my_charlen(cs, get_ptr() - 1, get_end_of_query());
+ int char_length= cs->charlen(get_ptr() - 1, get_end_of_query());
if (char_length <= 0)
break;
skip_binary(char_length - 1);
@@ -2166,10 +2698,10 @@ int Lex_input_stream::scan_ident_middle(THD *thd, Lex_ident_cli_st *str,
bool resolve_introducer= true;
DBUG_ASSERT(m_ptr == m_tok_start + 1); // m_ptr points to the second byte
- if (use_mb(cs))
+ if (cs->use_mb())
{
is_8bit= true;
- int char_length= my_charlen(cs, get_ptr() - 1, get_end_of_query());
+ int char_length= cs->charlen(get_ptr() - 1, get_end_of_query());
if (char_length <= 0)
{
*st= MY_LEX_CHAR;
@@ -2179,7 +2711,7 @@ int Lex_input_stream::scan_ident_middle(THD *thd, Lex_ident_cli_st *str,
while (ident_map[c= yyGet()])
{
- char_length= my_charlen(cs, get_ptr() - 1, get_end_of_query());
+ char_length= cs->charlen(get_ptr() - 1, get_end_of_query());
if (char_length <= 0)
break;
if (char_length > 1 || (c & 0x80))
@@ -2268,7 +2800,7 @@ int Lex_input_stream::scan_ident_delimited(THD *thd,
while ((c= yyGet()))
{
- int var_length= my_charlen(cs, get_ptr() - 1, get_end_of_query());
+ int var_length= cs->charlen(get_ptr() - 1, get_end_of_query());
if (var_length == 1)
{
if (c == quote_char)
@@ -2347,10 +2879,10 @@ void st_select_lex_unit::init_query()
{
init_query_common();
set_linkage(GLOBAL_OPTIONS_TYPE);
- select_limit_cnt= HA_POS_ERROR;
- offset_limit_cnt= 0;
+ lim.set_unlimited();
union_distinct= 0;
prepared= optimized= optimized_2= executed= 0;
+ bag_set_op_optimized= 0;
optimize_started= 0;
item= 0;
union_result= 0;
@@ -2366,8 +2898,8 @@ void st_select_lex_unit::init_query()
with_clause= 0;
with_element= 0;
columns_are_renamed= false;
- intersect_mark= NULL;
with_wrapped_tvc= false;
+ have_except_all_or_intersect_all= false;
}
void st_select_lex::init_query()
@@ -2465,6 +2997,7 @@ void st_select_lex::init_select()
curr_tvc_name= 0;
in_tvc= false;
versioned_tables= 0;
+ nest_flags= 0;
}
/*
@@ -2981,11 +3514,74 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
}
+/*
+ @brief
+ Print the whole statement
+
+ @param str Print into this string
+ @param query_type Flags describing how to print
+
+ @detail
+ The intent is to allow to eventually print back any query.
+
+ This is useful e.g. for storage engines that take over diferrent kinds of
+ queries
+*/
+
+void LEX::print(String *str, enum_query_type query_type)
+{
+ if (sql_command == SQLCOM_UPDATE)
+ {
+ SELECT_LEX *sel= first_select_lex();
+ str->append(STRING_WITH_LEN("UPDATE "));
+ if (ignore)
+ str->append(STRING_WITH_LEN("IGNORE "));
+ // table name
+ str->append(query_tables->alias);
+ str->append(STRING_WITH_LEN(" SET "));
+ // print item assignments
+ List_iterator<Item> it(sel->item_list);
+ List_iterator<Item> it2(value_list);
+ Item *col_ref, *value;
+ bool first= true;
+ while ((col_ref= it++) && (value= it2++))
+ {
+ if (first)
+ first= false;
+ else
+ str->append(STRING_WITH_LEN(", "));
+ col_ref->print(str, query_type);
+ str->append(STRING_WITH_LEN("="));
+ value->print(str, query_type);
+ }
+
+ str->append(STRING_WITH_LEN(" WHERE "));
+ sel->where->print(str, query_type);
+
+ if (sel->order_list.elements)
+ {
+ str->append(STRING_WITH_LEN(" ORDER BY "));
+ for (ORDER *ord= sel->order_list.first; ord; ord= ord->next)
+ {
+ if (ord != sel->order_list.first)
+ str->append(STRING_WITH_LEN(", "));
+ (*ord->item)->print(str, query_type);
+ }
+ }
+ if (sel->select_limit)
+ {
+ str->append(STRING_WITH_LEN(" LIMIT "));
+ sel->select_limit->print(str, query_type);
+ }
+ }
+ else
+ DBUG_ASSERT(0); // Not implemented yet
+}
+
void st_select_lex_unit::print(String *str, enum_query_type query_type)
{
- bool union_all= !union_distinct;
if (with_clause)
- with_clause->print(str, query_type);
+ with_clause->print(thd, str, query_type);
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
{
if (sl != first_select())
@@ -2997,8 +3593,6 @@ void st_select_lex_unit::print(String *str, enum_query_type query_type)
/* fall through */
case UNION_TYPE:
str->append(STRING_WITH_LEN(" union "));
- if (union_all)
- str->append(STRING_WITH_LEN("all "));
break;
case INTERSECT_TYPE:
str->append(STRING_WITH_LEN(" intersect "));
@@ -3007,8 +3601,8 @@ void st_select_lex_unit::print(String *str, enum_query_type query_type)
str->append(STRING_WITH_LEN(" except "));
break;
}
- if (sl == union_distinct)
- union_all= TRUE;
+ if (!sl->distinct)
+ str->append(STRING_WITH_LEN("all "));
}
if (sl->braces)
str->append('(');
@@ -3232,12 +3826,12 @@ LEX::LEX()
default_used(0), is_lex_started(0), limit_rows_examined_cnt(ULONGLONG_MAX)
{
- init_dynamic_array2(&plugins, sizeof(plugin_ref), plugins_static_buffer,
- INITIAL_LEX_PLUGIN_LIST_SIZE,
+ init_dynamic_array2(PSI_INSTRUMENT_ME, &plugins, sizeof(plugin_ref),
+ plugins_static_buffer, INITIAL_LEX_PLUGIN_LIST_SIZE,
INITIAL_LEX_PLUGIN_LIST_SIZE, 0);
reset_query_tables_list(TRUE);
mi.init();
- init_dynamic_array2(&delete_gtid_domain, sizeof(uint32),
+ init_dynamic_array2(PSI_INSTRUMENT_ME, &delete_gtid_domain, sizeof(uint32),
gtid_domain_static_buffer,
initial_gtid_domain_buffer_size,
initial_gtid_domain_buffer_size, 0);
@@ -3492,12 +4086,7 @@ void st_select_lex_unit::set_limit(st_select_lex *sl)
{
DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare());
- offset_limit_cnt= sl->get_offset();
- select_limit_cnt= sl->get_limit();
- if (select_limit_cnt + offset_limit_cnt >= select_limit_cnt)
- select_limit_cnt+= offset_limit_cnt;
- else
- select_limit_cnt= HA_POS_ERROR;
+ lim.set_limit(sl->get_limit(), sl->get_offset());
}
@@ -3521,6 +4110,8 @@ bool st_select_lex_unit::union_needs_tmp_table()
with_wrapped_tvc= true;
break;
}
+ if (sl != first_select() && sl->linkage != UNION_TYPE)
+ return true;
}
}
if (with_wrapped_tvc)
@@ -5068,8 +5659,8 @@ bool LEX::set_arena_for_set_stmt(Query_arena *backup)
mem_root_for_set_stmt= new MEM_ROOT();
if (unlikely(!(mem_root_for_set_stmt)))
DBUG_RETURN(1);
- init_sql_alloc(mem_root_for_set_stmt, "set_stmt",
- ALLOC_ROOT_SET, ALLOC_ROOT_SET, MYF(MY_THREAD_SPECIFIC));
+ init_sql_alloc(PSI_INSTRUMENT_ME, mem_root_for_set_stmt, ALLOC_ROOT_SET,
+ ALLOC_ROOT_SET, MYF(MY_THREAD_SPECIFIC));
}
if (unlikely(!(arena_for_set_stmt= new(mem_root_for_set_stmt)
Query_arena_memroot(mem_root_for_set_stmt,
@@ -5196,7 +5787,7 @@ int st_select_lex_unit::save_union_explain(Explain_query *output)
eu->connection_type= Explain_node::EXPLAIN_NODE_DERIVED;
/*
Note: Non-merged semi-joins cannot be made out of UNIONs currently, so we
- dont ever set EXPLAIN_NODE_NON_MERGED_SJ.
+ don't ever set EXPLAIN_NODE_NON_MERGED_SJ.
*/
for (SELECT_LEX *sl= first; sl; sl= sl->next_select())
eu->add_select(sl->select_number);
@@ -5227,10 +5818,8 @@ int st_select_lex_unit::save_union_explain_part2(Explain_query *output)
for (SELECT_LEX_UNIT *unit= fake_select_lex->first_inner_unit();
unit; unit= unit->next_unit())
{
- if (!(unit->item && unit->item->eliminated))
- {
+ if (unit->explainable())
eu->add_child(unit->first_select()->select_number);
- }
}
fake_select_lex->join->explain= &eu->fake_select_lex_explain;
}
@@ -5391,7 +5980,7 @@ LEX::wrap_unit_into_derived(SELECT_LEX_UNIT *unit)
Name_resolution_context *context= &wrapping_sel->context;
context->init();
wrapping_sel->automatic_brackets= FALSE;
-
+ wrapping_sel->mark_as_unit_nest();
wrapping_sel->register_unit(unit, context);
/* stuff dummy SELECT * FROM (...) */
@@ -5401,8 +5990,7 @@ LEX::wrap_unit_into_derived(SELECT_LEX_UNIT *unit)
/* add SELECT list*/
{
- Item *item= new (thd->mem_root)
- Item_field(thd, context, NULL, NULL, &star_clex_str);
+ Item *item= new (thd->mem_root) Item_field(thd, context, star_clex_str);
if (item == NULL)
goto err;
if (add_item_to_list(thd, item))
@@ -5464,8 +6052,7 @@ SELECT_LEX *LEX::wrap_select_chain_into_derived(SELECT_LEX *sel)
/* add SELECT list*/
{
- Item *item= new (thd->mem_root)
- Item_field(thd, context, NULL, NULL, &star_clex_str);
+ Item *item= new (thd->mem_root) Item_field(thd, context, star_clex_str);
if (item == NULL)
goto err;
if (add_item_to_list(thd, item))
@@ -5586,9 +6173,22 @@ sp_variable *LEX::sp_param_init(LEX_CSTRING *name)
}
-bool LEX::sp_param_fill_definition(sp_variable *spvar)
+bool LEX::sp_param_fill_definition(sp_variable *spvar,
+ const Lex_field_type_st &def)
{
- return sphead->fill_spvar_definition(thd, last_field, &spvar->name);
+ return
+ last_field->set_attributes(thd, def, charset,
+ COLUMN_DEFINITION_ROUTINE_PARAM) ||
+ sphead->fill_spvar_definition(thd, last_field, &spvar->name);
+}
+
+
+bool LEX::sf_return_fill_definition(const Lex_field_type_st &def)
+{
+ return
+ last_field->set_attributes(thd, def, charset,
+ COLUMN_DEFINITION_FUNCTION_RETURN) ||
+ sphead->fill_field_definition(thd, last_field);
}
@@ -5598,6 +6198,7 @@ void LEX::set_stmt_init()
mysql_init_select(this);
option_type= OPT_SESSION;
autocommit= 0;
+ var_list.empty();
};
@@ -5655,7 +6256,7 @@ static bool is_old(const char *str)
bool LEX::is_trigger_new_or_old_reference(const LEX_CSTRING *name) const
{
// "name" is not necessarily NULL-terminated!
- return sphead && sphead->m_handler->type() == TYPE_ENUM_TRIGGER &&
+ return sphead && sphead->m_handler->type() == SP_TYPE_TRIGGER &&
name->length == 3 && (is_new(name->str) || is_old(name->str));
}
@@ -5977,9 +6578,9 @@ sp_variable *LEX::sp_add_for_loop_variable(THD *thd, const LEX_CSTRING *name,
sp_variable *spvar= spcont->add_variable(thd, name);
spcont->declare_var_boundary(1);
spvar->field_def.field_name= spvar->name;
- spvar->field_def.set_handler(&type_handler_longlong);
- type_handler_longlong.Column_definition_prepare_stage2(&spvar->field_def,
- NULL, HA_CAN_GEOMETRY);
+ spvar->field_def.set_handler(&type_handler_slonglong);
+ type_handler_slonglong.Column_definition_prepare_stage2(&spvar->field_def,
+ NULL, HA_CAN_GEOMETRY);
if (!value && unlikely(!(value= new (thd->mem_root) Item_null(thd))))
return NULL;
@@ -6022,7 +6623,7 @@ bool LEX::sp_for_loop_implicit_cursor_statement(THD *thd,
SELECT rec.a, rec.b;
END FOR;
*/
- if (!(item= new (thd->mem_root) Item_field(thd, NULL, NullS, NullS, &name)))
+ if (!(item= new (thd->mem_root) Item_field(thd, NULL, name)))
return true;
bounds->m_index->set_item_and_free_list(item, NULL);
if (thd->lex->sphead->restore_lex(thd))
@@ -6175,7 +6776,7 @@ bool LEX::sp_for_loop_cursor_declarations(THD *thd,
name= item_splocal->m_name;
else if ((item_field= item->type() == Item::FIELD_ITEM ?
static_cast<Item_field *>(item) : NULL) &&
- item_field->table_name == NULL)
+ item_field->table_name.str == NULL)
name= item_field->field_name;
else if (item->type() == Item::FUNC_ITEM &&
static_cast<Item_func*>(item)->functype() == Item_func::FUNC_SP &&
@@ -6807,7 +7408,7 @@ bool LEX::sp_exit_block(THD *thd, sp_label *lab, Item *when)
sp_instr_jump_if_not *i= new (thd->mem_root)
sp_instr_jump_if_not(sphead->instructions(),
spcont,
- when, thd->lex);
+ when, this);
if (unlikely(i == NULL) ||
unlikely(sphead->add_instr(i)) ||
unlikely(sp_exit_block(thd, lab)))
@@ -6870,17 +7471,40 @@ bool LEX::sp_continue_loop(THD *thd, sp_label *lab)
}
-bool LEX::sp_continue_loop(THD *thd, sp_label *lab, Item *when)
+bool LEX::sp_continue_statement(THD *thd)
{
- if (!when)
- return sp_continue_loop(thd, lab);
+ sp_label *lab= spcont->find_label_current_loop_start();
+ if (unlikely(!lab))
+ {
+ my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "CONTINUE", "");
+ return true;
+ }
+ DBUG_ASSERT(lab->type == sp_label::ITERATION);
+ return sp_continue_loop(thd, lab);
+}
+
+bool LEX::sp_continue_statement(THD *thd, const LEX_CSTRING *label_name)
+{
+ sp_label *lab= spcont->find_label(label_name);
+ if (!lab || lab->type != sp_label::ITERATION)
+ {
+ my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "CONTINUE", label_name->str);
+ return true;
+ }
+ return sp_continue_loop(thd, lab);
+}
+
+
+bool LEX::sp_continue_loop(THD *thd, sp_label *lab, Item *when)
+{
+ DBUG_ASSERT(when);
DBUG_ASSERT(sphead == thd->lex->sphead);
DBUG_ASSERT(spcont == thd->lex->spcont);
sp_instr_jump_if_not *i= new (thd->mem_root)
sp_instr_jump_if_not(sphead->instructions(),
spcont,
- when, thd->lex);
+ when, this);
if (unlikely(i == NULL) ||
unlikely(sphead->add_instr(i)) ||
unlikely(sp_continue_loop(thd, lab)))
@@ -6890,7 +7514,7 @@ bool LEX::sp_continue_loop(THD *thd, sp_label *lab, Item *when)
}
-bool LEX::sp_continue_statement(THD *thd, Item *when)
+bool sp_expr_lex::sp_continue_when_statement(THD *thd)
{
sp_label *lab= spcont->find_label_current_loop_start();
if (unlikely(!lab))
@@ -6899,12 +7523,12 @@ bool LEX::sp_continue_statement(THD *thd, Item *when)
return true;
}
DBUG_ASSERT(lab->type == sp_label::ITERATION);
- return sp_continue_loop(thd, lab, when);
+ return sp_continue_loop(thd, lab, get_item());
}
-bool LEX::sp_continue_statement(THD *thd, const LEX_CSTRING *label_name,
- Item *when)
+bool sp_expr_lex::sp_continue_when_statement(THD *thd,
+ const LEX_CSTRING *label_name)
{
sp_label *lab= spcont->find_label(label_name);
if (!lab || lab->type != sp_label::ITERATION)
@@ -6912,7 +7536,7 @@ bool LEX::sp_continue_statement(THD *thd, const LEX_CSTRING *label_name,
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "CONTINUE", label_name->str);
return true;
}
- return sp_continue_loop(thd, lab, when);
+ return sp_continue_loop(thd, lab, get_item());
}
@@ -6977,10 +7601,10 @@ void LEX::sp_pop_loop_empty_label(THD *thd)
}
-bool LEX::sp_while_loop_expression(THD *thd, Item *expr)
+bool LEX::sp_while_loop_expression(THD *thd, Item *item)
{
sp_instr_jump_if_not *i= new (thd->mem_root)
- sp_instr_jump_if_not(sphead->instructions(), spcont, expr, this);
+ sp_instr_jump_if_not(sphead->instructions(), spcont, item, this);
return (unlikely(i == NULL) ||
/* Jumping forward */
unlikely(sphead->push_backpatch(thd, i, spcont->last_label())) ||
@@ -7031,7 +7655,7 @@ Item *LEX::create_and_link_Item_trigger_field(THD *thd,
new_row ?
Item_trigger_field::NEW_ROW:
Item_trigger_field::OLD_ROW,
- name, SELECT_ACL, tmp_read_only);
+ *name, SELECT_ACL, tmp_read_only);
/*
Let us add this item to list of all Item_trigger_field objects
in trigger.
@@ -7180,7 +7804,7 @@ Item *LEX::create_item_for_loop_bound(THD *thd,
Pass NULL as the name resolution context.
This is OK, fix_fields() won't be called for this Item_field.
*/
- return new (thd->mem_root) Item_field(thd, NULL, a->str, b->str, c);
+ return new (thd->mem_root) Item_field(thd, NULL, *a, *b, *c);
}
@@ -7218,7 +7842,7 @@ Item *LEX::create_item_ident_nospvar(THD *thd,
if (current_select->parsing_place == FOR_LOOP_BOUND)
return create_item_for_loop_bound(thd, &null_clex_str, a, b);
- return create_item_ident_field(thd, NullS, a->str, b);
+ return create_item_ident_field(thd, Lex_ident_sys(), *a, *b);
}
@@ -7391,11 +8015,11 @@ Item *LEX::create_item_ident(THD *thd,
if ((thd->variables.sql_mode & MODE_ORACLE) && b.length == 7)
{
- if (!my_strnncoll(system_charset_info,
+ if (!system_charset_info->strnncoll(
(const uchar *) b.str, 7,
(const uchar *) "NEXTVAL", 7))
return create_item_func_nextval(thd, &null_clex_str, &a);
- else if (!my_strnncoll(system_charset_info,
+ else if (!system_charset_info->strnncoll(
(const uchar *) b.str, 7,
(const uchar *) "CURRVAL", 7))
return create_item_func_lastval(thd, &null_clex_str, &a);
@@ -7410,16 +8034,15 @@ Item *LEX::create_item_ident(THD *thd,
const Lex_ident_sys_st *b,
const Lex_ident_sys_st *c)
{
- const char *schema= (thd->client_capabilities & CLIENT_NO_SCHEMA ?
- NullS : a->str);
-
+ Lex_ident_sys_st schema= thd->client_capabilities & CLIENT_NO_SCHEMA ?
+ Lex_ident_sys() : *a;
if ((thd->variables.sql_mode & MODE_ORACLE) && c->length == 7)
{
- if (!my_strnncoll(system_charset_info,
+ if (!system_charset_info->strnncoll(
(const uchar *) c->str, 7,
(const uchar *) "NEXTVAL", 7))
return create_item_func_nextval(thd, a, b);
- else if (!my_strnncoll(system_charset_info,
+ else if (!system_charset_info->strnncoll(
(const uchar *) c->str, 7,
(const uchar *) "CURRVAL", 7))
return create_item_func_lastval(thd, a, b);
@@ -7434,7 +8057,7 @@ Item *LEX::create_item_ident(THD *thd,
if (current_select->parsing_place == FOR_LOOP_BOUND)
return create_item_for_loop_bound(thd, &null_clex_str, b, c);
- return create_item_ident_field(thd, schema, b->str, c);
+ return create_item_ident_field(thd, schema, *b, *c);
}
@@ -7520,11 +8143,12 @@ bool LEX::set_user_variable(THD *thd, const LEX_CSTRING *name, Item *val)
}
-Item *LEX::create_item_ident_field(THD *thd, const char *db,
- const char *table,
- const Lex_ident_sys_st *name)
+Item *LEX::create_item_ident_field(THD *thd,
+ const Lex_ident_sys_st &db,
+ const Lex_ident_sys_st &table,
+ const Lex_ident_sys_st &name)
{
- if (check_expr_allows_fields_or_error(thd, name->str))
+ if (check_expr_allows_fields_or_error(thd, name.str))
return NULL;
if (current_select->parsing_place != IN_HAVING ||
@@ -7593,7 +8217,7 @@ Item *LEX::create_item_ident_sp(THD *thd, Lex_ident_sys_st *name,
-bool LEX::set_variable(const LEX_CSTRING *name, Item *item)
+bool LEX::set_variable(const Lex_ident_sys_st *name, Item *item)
{
sp_pcontext *ctx;
const Sp_rcontext_handler *rh;
@@ -7607,8 +8231,8 @@ bool LEX::set_variable(const LEX_CSTRING *name, Item *item)
Generate instructions for:
SET x.y= expr;
*/
-bool LEX::set_variable(const LEX_CSTRING *name1,
- const LEX_CSTRING *name2,
+bool LEX::set_variable(const Lex_ident_sys_st *name1,
+ const Lex_ident_sys_st *name2,
Item *item)
{
const Sp_rcontext_handler *rh;
@@ -7638,10 +8262,10 @@ bool LEX::set_variable(const LEX_CSTRING *name1,
bool LEX::set_default_system_variable(enum_var_type var_type,
- const LEX_CSTRING *name,
+ const Lex_ident_sys_st *name,
Item *val)
{
- static LEX_CSTRING default_base_name= {STRING_WITH_LEN("default")};
+ static Lex_ident_sys default_base_name= {STRING_WITH_LEN("default")};
sys_var *var= find_sys_var(thd, name->str, name->length);
if (!var)
return true;
@@ -7655,18 +8279,19 @@ bool LEX::set_default_system_variable(enum_var_type var_type,
bool LEX::set_system_variable(enum_var_type var_type,
- const LEX_CSTRING *name,
+ const Lex_ident_sys_st *name,
Item *val)
{
sys_var *var= find_sys_var(thd, name->str, name->length);
DBUG_ASSERT(thd->is_error() || var != NULL);
- return likely(var) ? set_system_variable(var_type, var, &null_clex_str, val) : true;
+ static Lex_ident_sys null_str;
+ return likely(var) ? set_system_variable(var_type, var, &null_str, val) : true;
}
bool LEX::set_system_variable(THD *thd, enum_var_type var_type,
- const LEX_CSTRING *name1,
- const LEX_CSTRING *name2,
+ const Lex_ident_sys_st *name1,
+ const Lex_ident_sys_st *name2,
Item *val)
{
sys_var *tmp;
@@ -8348,15 +8973,15 @@ bool LEX::call_statement_start(THD *thd, sp_name *name)
}
-bool LEX::call_statement_start(THD *thd, const LEX_CSTRING *name)
+bool LEX::call_statement_start(THD *thd, const Lex_ident_sys_st *name)
{
sp_name *spname= make_sp_name(thd, name);
return unlikely(!spname) || call_statement_start(thd, spname);
}
-bool LEX::call_statement_start(THD *thd, const LEX_CSTRING *name1,
- const LEX_CSTRING *name2)
+bool LEX::call_statement_start(THD *thd, const Lex_ident_sys_st *name1,
+ const Lex_ident_sys_st *name2)
{
sp_name *spname= make_sp_name(thd, name1, name2);
return unlikely(!spname) || call_statement_start(thd, spname);
@@ -8384,7 +9009,7 @@ sp_package *LEX::create_package_start(THD *thd,
}
if (unlikely(set_command_with_check(command, options)))
return NULL;
- if (sph->type() == TYPE_ENUM_PACKAGE_BODY)
+ if (sph->type() == SP_TYPE_PACKAGE_BODY)
{
/*
If we start parsing a "CREATE PACKAGE BODY", we need to load
@@ -8459,16 +9084,13 @@ bool LEX::create_package_finalize(THD *thd,
}
-bool LEX::add_grant_command(THD *thd, enum_sql_command sql_command_arg,
- stored_procedure_type type_arg)
+bool LEX::add_grant_command(THD *thd, const List<LEX_COLUMN> &columns)
{
if (columns.elements)
{
thd->parse_error();
return true;
}
- sql_command= sql_command_arg,
- type= type_arg;
return false;
}
@@ -8505,9 +9127,9 @@ bool SELECT_LEX::vers_push_field(THD *thd, TABLE_LIST *table,
{
DBUG_ASSERT(field_name.str);
Item_field *fld= new (thd->mem_root) Item_field(thd, &context,
- table->db.str,
- table->alias.str,
- &field_name);
+ table->db,
+ table->alias,
+ field_name);
if (unlikely(!fld) || unlikely(item_list.push_back(fld)))
return true;
@@ -8620,13 +9242,27 @@ Item *LEX::make_item_func_call_generic(THD *thd, Lex_ident_cli_st *cdb,
}
+Item *LEX::make_item_func_call_native_or_parse_error(THD *thd,
+ Lex_ident_cli_st &name,
+ List<Item> *args)
+{
+ Create_func *builder= find_native_function_builder(thd, &name);
+ DBUG_EXECUTE_IF("make_item_func_call_native_simulate_not_found",
+ builder= NULL;);
+ if (builder)
+ return builder->create_func(thd, &name, args);
+ thd->parse_error(ER_SYNTAX_ERROR, name.end());
+ return NULL;
+}
+
+
Item *LEX::create_item_qualified_asterisk(THD *thd,
const Lex_ident_sys_st *name)
{
Item *item;
if (!(item= new (thd->mem_root) Item_field(thd, current_context(),
- NullS, name->str,
- &star_clex_str)))
+ null_clex_str, *name,
+ star_clex_str)))
return NULL;
current_select->with_wild++;
return item;
@@ -8638,11 +9274,10 @@ Item *LEX::create_item_qualified_asterisk(THD *thd,
const Lex_ident_sys_st *b)
{
Item *item;
- const char* schema= thd->client_capabilities & CLIENT_NO_SCHEMA ?
- NullS : a->str;
+ Lex_ident_sys_st schema= thd->client_capabilities & CLIENT_NO_SCHEMA ?
+ Lex_ident_sys() : *a;
if (!(item= new (thd->mem_root) Item_field(thd, current_context(),
- schema, b->str,
- &star_clex_str)))
+ schema, *b, star_clex_str)))
return NULL;
current_select->with_wild++;
return item;
@@ -9177,6 +9812,17 @@ LEX::add_primary_to_query_expression_body(SELECT_LEX_UNIT *unit,
}
+SELECT_LEX_UNIT *
+LEX::add_primary_to_query_expression_body(SELECT_LEX_UNIT *unit,
+ SELECT_LEX *sel,
+ enum sub_select_type unit_type,
+ bool distinct)
+{
+ return
+ add_primary_to_query_expression_body(unit, sel, unit_type, distinct,
+ thd->variables.sql_mode & MODE_ORACLE);
+}
+
/**
Add query primary to a parenthesized query primary
pruducing a new query expression body
@@ -10376,6 +11022,89 @@ bool LEX::stmt_create_stored_function_start(const DDL_options_st &options,
}
+bool LEX::stmt_drop_function(const DDL_options_st &options,
+ const Lex_ident_sys_st &db,
+ const Lex_ident_sys_st &name)
+{
+ if (unlikely(db.str && check_db_name((LEX_STRING*) &db)))
+ {
+ my_error(ER_WRONG_DB_NAME, MYF(0), db.str);
+ return true;
+ }
+ if (unlikely(sphead))
+ {
+ my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
+ return true;
+ }
+ set_command(SQLCOM_DROP_FUNCTION, options);
+ spname= new (thd->mem_root) sp_name(&db, &name, true);
+ return spname == NULL;
+}
+
+
+bool LEX::stmt_drop_function(const DDL_options_st &options,
+ const Lex_ident_sys_st &name)
+{
+ LEX_CSTRING db= {0, 0};
+ if (unlikely(sphead))
+ {
+ my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
+ return true;
+ }
+ if (thd->db.str && unlikely(copy_db_to(&db)))
+ return true;
+ set_command(SQLCOM_DROP_FUNCTION, options);
+ spname= new (thd->mem_root) sp_name(&db, &name, false);
+ return spname == NULL;
+}
+
+
+bool LEX::stmt_drop_procedure(const DDL_options_st &options,
+ sp_name *name)
+{
+ if (unlikely(sphead))
+ {
+ my_error(ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE");
+ return true;
+ }
+ set_command(SQLCOM_DROP_PROCEDURE, options);
+ spname= name;
+ return false;
+}
+
+
+bool LEX::stmt_alter_function_start(sp_name *name)
+{
+ if (unlikely(sphead))
+ {
+ my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
+ return true;
+ }
+ if (main_select_push())
+ return true;
+ sp_chistics.init();
+ sql_command= SQLCOM_ALTER_FUNCTION;
+ spname= name;
+ return false;
+}
+
+
+bool LEX::stmt_alter_procedure_start(sp_name *name)
+{
+ if (unlikely(sphead))
+ {
+ my_error(ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE");
+ return true;
+ }
+ if (main_select_push())
+ return true;
+ sp_chistics.init();
+ sql_command= SQLCOM_ALTER_PROCEDURE;
+ spname= name;
+ return false;
+}
+
+
Spvar_definition *LEX::row_field_name(THD *thd, const Lex_ident_sys_st &name)
{
Spvar_definition *res;
@@ -10390,3 +11119,265 @@ Spvar_definition *LEX::row_field_name(THD *thd, const Lex_ident_sys_st &name)
init_last_field(res, &name, thd->variables.collation_database);
return res;
}
+
+
+Item *
+Lex_cast_type_st::create_typecast_item_or_error(THD *thd, Item *item,
+ CHARSET_INFO *cs) const
+{
+ Item *tmp= create_typecast_item(thd, item, cs);
+ if (!tmp)
+ {
+ Name name= m_type_handler->name();
+ char buf[128];
+ size_t length= my_snprintf(buf, sizeof(buf), "CAST(expr AS %.*s)",
+ (int) name.length(), name.ptr());
+ my_error(ER_UNKNOWN_OPERATOR, MYF(0),
+ ErrConvString(buf, length, system_charset_info).ptr());
+ }
+ return tmp;
+}
+
+
+void Lex_field_type_st::set_handler_length_flags(const Type_handler *handler,
+ const char *length,
+ uint32 flags)
+{
+ DBUG_ASSERT(!handler->is_unsigned());
+ if (flags & UNSIGNED_FLAG)
+ handler= handler->type_handler_unsigned();
+ set(handler, length, NULL);
+}
+
+
+bool LEX::set_field_type_udt(Lex_field_type_st *type,
+ const LEX_CSTRING &name,
+ const Lex_length_and_dec_st &attr)
+{
+ const Type_handler *h;
+ if (!(h= Type_handler::handler_by_name_or_error(thd, name)))
+ return true;
+ type->set(h, attr);
+ charset= &my_charset_bin;
+ return false;
+}
+
+
+bool LEX::set_cast_type_udt(Lex_cast_type_st *type,
+ const LEX_CSTRING &name)
+{
+ const Type_handler *h;
+ if (!(h= Type_handler::handler_by_name_or_error(thd, name)))
+ return true;
+ type->set(h);
+ charset= NULL;
+ return false;
+}
+
+
+bool sp_expr_lex::sp_repeat_loop_finalize(THD *thd)
+{
+ uint ip= sphead->instructions();
+ sp_label *lab= spcont->last_label(); /* Jumping back */
+ sp_instr_jump_if_not *i= new (thd->mem_root)
+ sp_instr_jump_if_not(ip, spcont, get_item(), lab->ip, this);
+ if (unlikely(i == NULL) ||
+ unlikely(sphead->add_instr(i)))
+ return true;
+ /* We can shortcut the cont_backpatch here */
+ i->m_cont_dest= ip+1;
+ return false;
+}
+
+
+bool sp_expr_lex::sp_if_expr(THD *thd)
+{
+ uint ip= sphead->instructions();
+ sp_instr_jump_if_not *i= new (thd->mem_root)
+ sp_instr_jump_if_not(ip, spcont, get_item(), this);
+ return
+ (unlikely(i == NULL) ||
+ unlikely(sphead->push_backpatch(thd, i,
+ spcont->push_label(thd, &empty_clex_str,
+ 0))) ||
+ unlikely(sphead->add_cont_backpatch(i)) ||
+ unlikely(sphead->add_instr(i)));
+}
+
+
+bool LEX::sp_if_after_statements(THD *thd)
+{
+ uint ip= sphead->instructions();
+ sp_instr_jump *i= new (thd->mem_root) sp_instr_jump(ip, spcont);
+ if (unlikely(i == NULL) ||
+ unlikely(sphead->add_instr(i)))
+ return true;
+ sphead->backpatch(spcont->pop_label());
+ sphead->push_backpatch(thd, i, spcont->push_label(thd, &empty_clex_str, 0));
+ return false;
+}
+
+
+sp_condition_value *LEX::stmt_signal_value(const Lex_ident_sys_st &ident)
+{
+ sp_condition_value *cond;
+ /* SIGNAL foo cannot be used outside of stored programs */
+ if (unlikely(spcont == NULL))
+ {
+ my_error(ER_SP_COND_MISMATCH, MYF(0), ident.str);
+ return NULL;
+ }
+ cond= spcont->find_declared_or_predefined_condition(thd, &ident);
+ if (unlikely(cond == NULL))
+ {
+ my_error(ER_SP_COND_MISMATCH, MYF(0), ident.str);
+ return NULL;
+ }
+ bool bad= thd->variables.sql_mode & MODE_ORACLE ?
+ !cond->has_sql_state() :
+ cond->type != sp_condition_value::SQLSTATE;
+ if (unlikely(bad))
+ {
+ my_error(ER_SIGNAL_BAD_CONDITION_TYPE, MYF(0));
+ return NULL;
+ }
+ return cond;
+}
+
+
+bool LEX::add_table_foreign_key(const LEX_CSTRING *name,
+ const LEX_CSTRING *constraint_name,
+ Table_ident *ref_table_name,
+ DDL_options ddl_options)
+{
+ Key *key= new (thd->mem_root) Foreign_key(name,
+ &last_key->columns,
+ constraint_name,
+ &ref_table_name->db,
+ &ref_table_name->table,
+ &ref_list,
+ fk_delete_opt,
+ fk_update_opt,
+ fk_match_option,
+ ddl_options);
+ if (unlikely(key == NULL))
+ return true;
+
+ /*
+ handle_if_exists_options() expects the two keys in this order:
+ the Foreign_key, followed by its auto-generated Key.
+ */
+ alter_info.key_list.push_back(key, thd->mem_root);
+ alter_info.key_list.push_back(last_key, thd->mem_root);
+
+ option_list= NULL;
+
+ /* Only used for ALTER TABLE. Ignored otherwise. */
+ alter_info.flags|= ALTER_ADD_FOREIGN_KEY;
+
+ return false;
+}
+
+
+bool LEX::add_column_foreign_key(const LEX_CSTRING *name,
+ const LEX_CSTRING *constraint_name,
+ Table_ident *ref_table_name,
+ DDL_options ddl_options)
+{
+ if (last_field->vcol_info || last_field->vers_sys_field())
+ {
+ thd->parse_error();
+ return true;
+ }
+ if (unlikely(!(last_key= (new (thd->mem_root)
+ Key(Key::MULTIPLE, constraint_name,
+ HA_KEY_ALG_UNDEF, true, ddl_options)))))
+ return true;
+ Key_part_spec *key= new (thd->mem_root) Key_part_spec(name, 0);
+ if (unlikely(key == NULL))
+ return true;
+ last_key->columns.push_back(key, thd->mem_root);
+ if (ref_list.is_empty())
+ {
+ ref_list.push_back(key, thd->mem_root);
+ }
+ if (unlikely(add_table_foreign_key(constraint_name, constraint_name,
+ ref_table_name, ddl_options)))
+ return true;
+ option_list= NULL;
+
+ /* Only used for ALTER TABLE. Ignored otherwise. */
+ alter_info.flags|= ALTER_ADD_FOREIGN_KEY;
+
+ return false;
+}
+
+
+bool LEX::stmt_grant_table(THD *thd,
+ Grant_privilege *grant,
+ const Lex_grant_object_name &ident,
+ privilege_t grant_option)
+{
+ sql_command= SQLCOM_GRANT;
+ return
+ grant->set_object_name(thd, ident, current_select, grant_option) ||
+ !(m_sql_cmd= new (thd->mem_root) Sql_cmd_grant_table(sql_command, *grant));
+}
+
+
+bool LEX::stmt_revoke_table(THD *thd,
+ Grant_privilege *grant,
+ const Lex_grant_object_name &ident)
+{
+ sql_command= SQLCOM_REVOKE;
+ return
+ grant->set_object_name(thd, ident, current_select, NO_ACL) ||
+ !(m_sql_cmd= new (thd->mem_root) Sql_cmd_grant_table(sql_command, *grant));
+}
+
+
+bool LEX::stmt_grant_sp(THD *thd,
+ Grant_privilege *grant,
+ const Lex_grant_object_name &ident,
+ const Sp_handler &sph,
+ privilege_t grant_option)
+{
+ sql_command= SQLCOM_GRANT;
+ return
+ grant->set_object_name(thd, ident, current_select, grant_option) ||
+ add_grant_command(thd, grant->columns()) ||
+ !(m_sql_cmd= new (thd->mem_root) Sql_cmd_grant_sp(sql_command,
+ *grant, sph));
+}
+
+
+bool LEX::stmt_revoke_sp(THD *thd,
+ Grant_privilege *grant,
+ const Lex_grant_object_name &ident,
+ const Sp_handler &sph)
+{
+ sql_command= SQLCOM_REVOKE;
+ return
+ grant->set_object_name(thd, ident, current_select, NO_ACL) ||
+ add_grant_command(thd, grant->columns()) ||
+ !(m_sql_cmd= new (thd->mem_root) Sql_cmd_grant_sp(sql_command,
+ *grant, sph));
+}
+
+
+bool LEX::stmt_grant_proxy(THD *thd, LEX_USER *user, privilege_t grant_option)
+{
+ users_list.push_front(user);
+ sql_command= SQLCOM_GRANT;
+ return !(m_sql_cmd= new (thd->mem_root) Sql_cmd_grant_proxy(sql_command,
+ grant_option));
+}
+
+
+bool LEX::stmt_revoke_proxy(THD *thd, LEX_USER *user)
+{
+ users_list.push_front(user);
+ sql_command= SQLCOM_REVOKE;
+ return !(m_sql_cmd= new (thd->mem_root) Sql_cmd_grant_proxy(sql_command,
+ NO_ACL));
+}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 0983cea44d0..b2f0272a7d2 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -25,13 +25,15 @@
#include "sql_trigger.h"
#include "thr_lock.h" /* thr_lock_type, TL_UNLOCK */
#include "mem_root_array.h"
+#include "grant.h"
#include "sql_cmd.h"
#include "sql_alter.h" // Alter_info
#include "sql_window.h"
#include "sql_trigger.h"
-#include "sp.h" // enum stored_procedure_type
+#include "sp.h" // enum enum_sp_type
#include "sql_tvc.h"
#include "item.h"
+#include "sql_limit.h" // Select_limit_counters
/* Used for flags of nesting constructs */
#define SELECT_NESTING_MAP_SIZE 64
@@ -182,6 +184,24 @@ public:
};
+struct Lex_column_list_privilege_st
+{
+ List<Lex_ident_sys> *m_columns;
+ privilege_t m_privilege;
+};
+
+
+class Lex_column_list_privilege: public Lex_column_list_privilege_st
+{
+public:
+ Lex_column_list_privilege(List<Lex_ident_sys> *columns, privilege_t privilege)
+ {
+ m_columns= columns;
+ m_privilege= privilege;
+ }
+};
+
+
/**
ORDER BY ... LIMIT parameters;
*/
@@ -207,6 +227,14 @@ enum sub_select_type
GLOBAL_OPTIONS_TYPE, DERIVED_TABLE_TYPE, OLAP_TYPE
};
+enum set_op_type
+{
+ UNSPECIFIED,
+ UNION_DISTINCT, UNION_ALL,
+ EXCEPT_DISTINCT, EXCEPT_ALL,
+ INTERSECT_DISTINCT, INTERSECT_ALL
+};
+
inline int cmp_unit_op(enum sub_select_type op1, enum sub_select_type op2)
{
DBUG_ASSERT(op1 >= UNION_TYPE && op1 <= EXCEPT_TYPE);
@@ -258,6 +286,7 @@ class sp_name;
class sp_instr;
class sp_pcontext;
class sp_variable;
+class sp_expr_lex;
class sp_assignment_lex;
class st_alter_tablespace;
class partition_info;
@@ -481,11 +510,11 @@ struct LEX_MASTER_INFO
void init()
{
bzero(this, sizeof(*this));
- my_init_dynamic_array(&repl_ignore_server_ids,
+ my_init_dynamic_array(PSI_INSTRUMENT_ME, &repl_ignore_server_ids,
sizeof(::server_id), 0, 16, MYF(0));
- my_init_dynamic_array(&repl_do_domain_ids,
+ my_init_dynamic_array(PSI_INSTRUMENT_ME, &repl_do_domain_ids,
sizeof(ulong), 0, 16, MYF(0));
- my_init_dynamic_array(&repl_ignore_domain_ids,
+ my_init_dynamic_array(PSI_INSTRUMENT_ME, &repl_ignore_domain_ids,
sizeof(ulong), 0, 16, MYF(0));
sql_delay= -1;
}
@@ -821,6 +850,7 @@ void create_explain_query(LEX *lex, MEM_ROOT *mem_root);
void create_explain_query_if_not_exists(LEX *lex, MEM_ROOT *mem_root);
bool print_explain_for_slow_log(LEX *lex, THD *thd, String *str);
+
class st_select_lex_unit: public st_select_lex_node {
protected:
TABLE_LIST result_table_list;
@@ -841,8 +871,8 @@ public:
// Ensures that at least all members used during cleanup() are initialized.
st_select_lex_unit()
: union_result(NULL), table(NULL), result(NULL),
- cleaned(false),
- fake_select_lex(NULL)
+ cleaned(false), bag_set_op_optimized(false),
+ have_except_all_or_intersect_all(false), fake_select_lex(NULL)
{
}
@@ -853,9 +883,11 @@ public:
optimized, // optimize phase already performed for UNION (unit)
optimized_2,
executed, // already executed
- cleaned;
+ cleaned,
+ bag_set_op_optimized;
bool optimize_started;
+ bool have_except_all_or_intersect_all;
// list of fields which points to temporary table for union
List<Item> item_list;
@@ -868,11 +900,6 @@ public:
*/
List<Item> types;
/**
- There is INTERSECT and it is item used in creating temporary
- table for it
- */
- Item_int *intersect_mark;
- /**
TRUE if the unit contained TVC at the top level that has been wrapped
into SELECT:
VALUES (v1) ... (vn) => SELECT * FROM (VALUES (v1) ... (vn)) as tvc
@@ -903,7 +930,7 @@ public:
//node on which we should return current_select pointer after parsing subquery
st_select_lex *return_to;
/* LIMIT clause runtime counters */
- ha_rows select_limit_cnt, offset_limit_cnt;
+ Select_limit_counters lim;
/* not NULL if unit used in subselect, point to subselect item */
Item_subselect *item;
/*
@@ -928,8 +955,9 @@ public:
fake_select_lex is used.
*/
st_select_lex *saved_fake_select_lex;
-
- st_select_lex *union_distinct; /* pointer to the last UNION DISTINCT */
+
+ /* pointer to the last node before last subsequence of UNION ALL */
+ st_select_lex *union_distinct;
bool describe; /* union exec() called for EXPLAIN */
Procedure *last_procedure; /* Pointer to procedure, if such exists */
@@ -955,6 +983,7 @@ public:
bool prepare(TABLE_LIST *derived_arg, select_result *sel_result,
ulong additional_options);
bool optimize();
+ void optimize_bag_operation(bool is_outer_distinct);
bool exec();
bool exec_recursive();
bool cleanup();
@@ -986,6 +1015,21 @@ public:
int save_union_explain_part2(Explain_query *output);
unit_common_op common_op();
+ bool explainable()
+ {
+ /*
+ EXPLAIN/ANALYZE unit, when:
+ (1) if it's a subquery - it's not part of eliminated WHERE/ON clause.
+ (2) if it's a CTE - it's not hanging (needed for execution)
+ (3) if it's a derived - it's not merged
+ if it's not 1/2/3 - it's some weird internal thing, ignore it
+ */
+ return item ? !item->eliminated : // (1)
+ with_element ? derived && derived->derived_result : // (2)
+ derived ? derived->is_materialized_derived() : // (3)
+ false;
+ }
+
void reset_distinct();
void fix_distinct();
@@ -1025,7 +1069,7 @@ Field_pair *find_matching_field_pair(Item *item, List<Field_pair> pair_list);
#define TOUCHED_SEL_COND 1/* WHERE/HAVING/ON should be reinited before use */
#define TOUCHED_SEL_DERIVED (1<<1)/* derived should be reinited before use */
-
+#define UNIT_NEST_FL 1
/*
SELECT_LEX - store information of parsed SELECT statment
*/
@@ -1048,7 +1092,7 @@ public:
select1->first_nested points to select1.
*/
st_select_lex *first_nested;
-
+ uint8 nest_flags;
Name_resolution_context context;
LEX_CSTRING db;
Item *where, *having; /* WHERE & HAVING clauses */
@@ -1524,6 +1568,13 @@ public:
select_handler *find_select_handler(THD *thd);
+ bool is_set_op()
+ {
+ return linkage == UNION_TYPE ||
+ linkage == EXCEPT_TYPE ||
+ linkage == INTERSECT_TYPE;
+ }
+
private:
bool m_non_agg_field_used;
bool m_agg_func_used;
@@ -1570,6 +1621,8 @@ public:
void add_statistics(SELECT_LEX_UNIT *unit);
bool make_unique_derived_name(THD *thd, LEX_CSTRING *alias);
void lex_start(LEX *plex);
+ bool is_unit_nest() { return (nest_flags & UNIT_NEST_FL); }
+ void mark_as_unit_nest() { nest_flags= UNIT_NEST_FL; }
};
typedef class st_select_lex SELECT_LEX;
@@ -2910,15 +2963,6 @@ protected:
bool impossible_where;
bool no_partitions;
public:
- /*
- When single-table UPDATE updates a VIEW, that VIEW's select is still
- listed as the first child. When we print EXPLAIN, it looks like a
- subquery.
- In order to get rid of it, updating_a_view=TRUE means that first child
- select should not be shown when printing EXPLAIN.
- */
- bool updating_a_view;
-
/* Allocate things there */
MEM_ROOT *mem_root;
@@ -3066,6 +3110,28 @@ public:
};
+class Lex_grant_object_name: public Grant_object_name, public Sql_alloc
+{
+public:
+ Lex_grant_object_name(Table_ident *table_ident)
+ :Grant_object_name(table_ident)
+ { }
+ Lex_grant_object_name(const LEX_CSTRING &db, Type type)
+ :Grant_object_name(db, type)
+ { }
+};
+
+
+class Lex_grant_privilege: public Grant_privilege, public Sql_alloc
+{
+public:
+ Lex_grant_privilege() {}
+ Lex_grant_privilege(privilege_t grant, bool all_privileges= false)
+ :Grant_privilege(grant, all_privileges)
+ { }
+};
+
+
struct LEX: public Query_tables_list
{
SELECT_LEX_UNIT unit; /* most upper unit */
@@ -3073,14 +3139,14 @@ struct LEX: public Query_tables_list
private:
SELECT_LEX builtin_select;
- /* current SELECT_LEX in parsing */
public:
+ /* current SELECT_LEX in parsing */
SELECT_LEX *current_select;
/* list of all SELECT_LEX */
SELECT_LEX *all_selects_list;
/* current with clause in parsing if any, otherwise 0*/
- With_clause *curr_with_clause;
+ With_clause *curr_with_clause;
/* pointer to the first with clause in the current statement */
With_clause *with_clauses_list;
/*
@@ -3162,7 +3228,6 @@ public:
Table_type table_type; /* Used for SHOW CREATE */
List<Key_part_spec> ref_list;
List<LEX_USER> users_list;
- List<LEX_COLUMN> columns;
List<Item> *insert_list,field_list,value_list,update_list;
List<List_item> many_values;
List<set_var_base> var_list;
@@ -3178,7 +3243,6 @@ private:
bool sp_exit_block(THD *thd, sp_label *lab, Item *when);
bool sp_continue_loop(THD *thd, sp_label *lab);
- bool sp_continue_loop(THD *thd, sp_label *lab, Item *when);
bool sp_for_loop_condition(THD *thd, const Lex_for_loop_st &loop);
bool sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop);
@@ -3189,6 +3253,10 @@ private:
@retval true ERROR (fields are not allowed). Error is raised.
*/
bool check_expr_allows_fields_or_error(THD *thd, const char *name) const;
+
+protected:
+ bool sp_continue_loop(THD *thd, sp_label *lab, Item *when);
+
public:
void parse_error(uint err_number= ER_SYNTAX_ERROR);
inline bool is_arena_for_set_stmt() {return arena_for_set_stmt != 0;}
@@ -3196,10 +3264,10 @@ public:
void reset_arena_for_set_stmt(Query_arena *backup);
void free_arena_for_set_stmt();
+ void print(String *str, enum_query_type qtype);
List<Item_func_set_user_var> set_var_list; // in-query assignment list
List<Item_param> param_list;
List<LEX_CSTRING> view_list; // view list (list of field names in view)
- List<LEX_CSTRING> with_column_list; // list of column names in with_list_element
List<LEX_STRING> *column_list; // list of column names (in ANALYZE)
List<LEX_STRING> *index_list; // list of index names (in ANALYZE)
/*
@@ -3282,7 +3350,6 @@ public:
uint profile_query_id;
uint profile_options;
- uint grant, grant_tot_col, which_columns;
enum backup_stages backup_stage;
enum Foreign_key::fk_match_opt fk_match_option;
enum_fk_option fk_update_opt;
@@ -3335,7 +3402,6 @@ public:
sp_head *sphead;
sp_name *spname;
bool sp_lex_in_use; // Keep track on lex usage in SPs for error handling
- bool all_privileges;
sp_pcontext *spcont;
@@ -3704,25 +3770,25 @@ public:
bool sp_proc_stmt_statement_finalize(THD *, bool no_lookahead);
sp_variable *sp_param_init(LEX_CSTRING *name);
- bool sp_param_fill_definition(sp_variable *spvar);
+ bool sp_param_fill_definition(sp_variable *spvar,
+ const Lex_field_type_st &def);
+ bool sf_return_fill_definition(const Lex_field_type_st &def);
- int case_stmt_action_expr(Item* expr);
- int case_stmt_action_when(Item *when, bool simple);
int case_stmt_action_then();
bool setup_select_in_parentheses();
bool set_trigger_new_row(const LEX_CSTRING *name, Item *val);
bool set_trigger_field(const LEX_CSTRING *name1, const LEX_CSTRING *name2,
Item *val);
bool set_system_variable(enum_var_type var_type, sys_var *var,
- const LEX_CSTRING *base_name, Item *val);
- bool set_system_variable(enum_var_type var_type, const LEX_CSTRING *name,
- Item *val);
+ const Lex_ident_sys_st *base_name, Item *val);
+ bool set_system_variable(enum_var_type var_type,
+ const Lex_ident_sys_st *name, Item *val);
bool set_system_variable(THD *thd, enum_var_type var_type,
- const LEX_CSTRING *name1,
- const LEX_CSTRING *name2,
+ const Lex_ident_sys_st *name1,
+ const Lex_ident_sys_st *name2,
Item *val);
bool set_default_system_variable(enum_var_type var_type,
- const LEX_CSTRING *name,
+ const Lex_ident_sys_st *name,
Item *val);
bool set_user_variable(THD *thd, const LEX_CSTRING *name, Item *val);
void set_stmt_init();
@@ -3752,9 +3818,9 @@ public:
const char *body_start,
const char *body_end);
bool call_statement_start(THD *thd, sp_name *name);
- bool call_statement_start(THD *thd, const LEX_CSTRING *name);
- bool call_statement_start(THD *thd, const LEX_CSTRING *name1,
- const LEX_CSTRING *name2);
+ bool call_statement_start(THD *thd, const Lex_ident_sys_st *name);
+ bool call_statement_start(THD *thd, const Lex_ident_sys_st *name1,
+ const Lex_ident_sys_st *name2);
sp_variable *find_variable(const LEX_CSTRING *name,
sp_pcontext **ctx,
const Sp_rcontext_handler **rh) const;
@@ -3764,9 +3830,9 @@ public:
sp_pcontext *not_used_ctx;
return find_variable(name, &not_used_ctx, rh);
}
- bool set_variable(const LEX_CSTRING *name, Item *item);
- bool set_variable(const LEX_CSTRING *name1, const LEX_CSTRING *name2,
- Item *item);
+ bool set_variable(const Lex_ident_sys_st *name, Item *item);
+ bool set_variable(const Lex_ident_sys_st *name1,
+ const Lex_ident_sys_st *name2, Item *item);
void sp_variable_declarations_init(THD *thd, int nvars);
bool sp_variable_declarations_finalize(THD *thd, int nvars,
const Column_definition *cdef,
@@ -3831,11 +3897,13 @@ public:
return create_item_qualified_asterisk(thd, &a, &b);
}
- Item *create_item_ident_field(THD *thd, const char *db, const char *table,
- const Lex_ident_sys_st *name);
+ Item *create_item_ident_field(THD *thd,
+ const Lex_ident_sys_st &db,
+ const Lex_ident_sys_st &table,
+ const Lex_ident_sys_st &name);
Item *create_item_ident_nosp(THD *thd, Lex_ident_sys_st *name)
{
- return create_item_ident_field(thd, NullS, NullS, name);
+ return create_item_ident_field(thd, Lex_ident_sys(), Lex_ident_sys(), *name);
}
Item *create_item_ident_sp(THD *thd, Lex_ident_sys_st *name,
const char *start, const char *end);
@@ -3981,6 +4049,9 @@ public:
Item *make_item_func_substr(THD *thd, Item *a, Item *b);
Item *make_item_func_call_generic(THD *thd, Lex_ident_cli_st *db,
Lex_ident_cli_st *name, List<Item> *args);
+ Item *make_item_func_call_native_or_parse_error(THD *thd,
+ Lex_ident_cli_st &name,
+ List<Item> *args);
my_var *create_outvar(THD *thd, const LEX_CSTRING *name);
/*
@@ -4067,8 +4138,8 @@ public:
bool sp_leave_statement(THD *thd, const LEX_CSTRING *label_name);
bool sp_goto_statement(THD *thd, const LEX_CSTRING *label_name);
- bool sp_continue_statement(THD *thd, Item *when);
- bool sp_continue_statement(THD *thd, const LEX_CSTRING *label_name, Item *when);
+ bool sp_continue_statement(THD *thd);
+ bool sp_continue_statement(THD *thd, const LEX_CSTRING *label_name);
bool sp_iterate_statement(THD *thd, const LEX_CSTRING *label_name);
bool maybe_start_compound_statement(THD *thd);
@@ -4078,6 +4149,7 @@ public:
void sp_pop_loop_empty_label(THD *thd);
bool sp_while_loop_expression(THD *thd, Item *expr);
bool sp_while_loop_finalize(THD *thd);
+ bool sp_if_after_statements(THD *thd);
bool sp_push_goto_label(THD *thd, const LEX_CSTRING *label_name);
Item_param *add_placeholder(THD *thd, const LEX_CSTRING *name,
@@ -4249,8 +4321,9 @@ public:
alter_info.check_constraint_list.push_back(constr);
return false;
}
- bool add_alter_list(const char *par_name, Virtual_column_info *expr,
+ bool add_alter_list(LEX_CSTRING par_name, Virtual_column_info *expr,
bool par_exists);
+ bool add_alter_list(LEX_CSTRING name, LEX_CSTRING new_name);
void set_command(enum_sql_command command,
DDL_options_st options)
{
@@ -4341,8 +4414,30 @@ public:
bool add_create_view(THD *thd, DDL_options_st ddl,
uint16 algorithm, enum_view_suid suid,
Table_ident *table_ident);
- bool add_grant_command(THD *thd, enum_sql_command sql_command_arg,
- stored_procedure_type type_arg);
+ bool add_grant_command(THD *thd, const List<LEX_COLUMN> &columns);
+
+ bool stmt_grant_table(THD *thd,
+ Grant_privilege *grant,
+ const Lex_grant_object_name &ident,
+ privilege_t grant_option);
+
+ bool stmt_revoke_table(THD *thd,
+ Grant_privilege *grant,
+ const Lex_grant_object_name &ident);
+
+ bool stmt_grant_sp(THD *thd,
+ Grant_privilege *grant,
+ const Lex_grant_object_name &ident,
+ const Sp_handler &sph,
+ privilege_t grant_option);
+
+ bool stmt_revoke_sp(THD *thd,
+ Grant_privilege *grant,
+ const Lex_grant_object_name &ident,
+ const Sp_handler &sph);
+
+ bool stmt_grant_proxy(THD *thd, LEX_USER *user, privilege_t grant_option);
+ bool stmt_revoke_proxy(THD *thd, LEX_USER *user);
Vers_parse_info &vers_get_info()
{
@@ -4405,6 +4500,12 @@ public:
SELECT_LEX_UNIT *create_unit(SELECT_LEX*);
SELECT_LEX *wrap_unit_into_derived(SELECT_LEX_UNIT *unit);
SELECT_LEX *wrap_select_chain_into_derived(SELECT_LEX *sel);
+ void init_select()
+ {
+ current_select->init_select();
+ wild= 0;
+ exchange= 0;
+ }
bool main_select_push();
bool insert_select_hack(SELECT_LEX *sel);
SELECT_LEX *create_priority_nest(SELECT_LEX *first_in_nest);
@@ -4447,6 +4548,11 @@ public:
bool distinct,
bool oracle);
SELECT_LEX_UNIT *
+ add_primary_to_query_expression_body(SELECT_LEX_UNIT *unit,
+ SELECT_LEX *sel,
+ enum sub_select_type unit_type,
+ bool distinct);
+ SELECT_LEX_UNIT *
add_primary_to_query_expression_body_ext_parens(
SELECT_LEX_UNIT *unit,
SELECT_LEX *sel,
@@ -4484,6 +4590,11 @@ public:
void stmt_purge_to(const LEX_CSTRING &to);
bool stmt_purge_before(Item *item);
+ SELECT_LEX *returning()
+ { return &builtin_select; }
+ bool has_returning()
+ { return !builtin_select.item_list.is_empty(); }
+
private:
bool stmt_create_routine_start(const DDL_options_st &options)
{
@@ -4516,9 +4627,40 @@ public:
const Lex_ident_sys_st &name,
Item_result return_type,
const LEX_CSTRING &soname);
+
+ bool stmt_drop_function(const DDL_options_st &options,
+ const Lex_ident_sys_st &db,
+ const Lex_ident_sys_st &name);
+
+ bool stmt_drop_function(const DDL_options_st &options,
+ const Lex_ident_sys_st &name);
+
+ bool stmt_drop_procedure(const DDL_options_st &options,
+ sp_name *name);
+
+ bool stmt_alter_function_start(sp_name *name);
+ bool stmt_alter_procedure_start(sp_name *name);
+
+ sp_condition_value *stmt_signal_value(const Lex_ident_sys_st &ident);
+
Spvar_definition *row_field_name(THD *thd, const Lex_ident_sys_st &name);
+ bool set_field_type_udt(Lex_field_type_st *type,
+ const LEX_CSTRING &name,
+ const Lex_length_and_dec_st &attr);
+ bool set_cast_type_udt(Lex_cast_type_st *type,
+ const LEX_CSTRING &name);
+
void mark_first_table_as_inserting();
+
+ bool add_table_foreign_key(const LEX_CSTRING *name,
+ const LEX_CSTRING *constraint_name,
+ Table_ident *table_name,
+ DDL_options ddl_options);
+ bool add_column_foreign_key(const LEX_CSTRING *name,
+ const LEX_CSTRING *constraint_name,
+ Table_ident *ref_table_name,
+ DDL_options ddl_options);
};
@@ -4727,6 +4869,51 @@ public:
};
+class sp_lex_set_var: public sp_lex_local
+{
+public:
+ sp_lex_set_var(THD *thd, const LEX *oldlex)
+ :sp_lex_local(thd, oldlex)
+ {
+ // Set new LEX as if we at start of set rule
+ init_select();
+ sql_command= SQLCOM_SET_OPTION;
+ var_list.empty();
+ autocommit= 0;
+ option_type= oldlex->option_type; // Inherit from the outer lex
+ }
+};
+
+
+class sp_expr_lex: public sp_lex_local
+{
+ Item *m_item; // The expression
+public:
+ sp_expr_lex(THD *thd, LEX *oldlex)
+ :sp_lex_local(thd, oldlex),
+ m_item(NULL)
+ { }
+ void set_item(Item *item)
+ {
+ m_item= item;
+ }
+ Item *get_item() const
+ {
+ return m_item;
+ }
+ bool sp_continue_when_statement(THD *thd);
+ bool sp_continue_when_statement(THD *thd, const LEX_CSTRING *label_name);
+ int case_stmt_action_expr();
+ int case_stmt_action_when(bool simple);
+ bool sp_while_loop_expression(THD *thd)
+ {
+ return LEX::sp_while_loop_expression(thd, get_item());
+ }
+ bool sp_repeat_loop_finalize(THD *thd);
+ bool sp_if_expr(THD *thd);
+};
+
+
/**
An assignment specific LEX, which additionally has an Item (an expression)
and an associated with the Item free_list, which is usually freed
@@ -4806,8 +4993,9 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr);
Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
Item *expr);
-void sp_create_assignment_lex(THD *thd, bool no_lookahead);
-bool sp_create_assignment_instr(THD *thd, bool no_lookahead);
+bool sp_create_assignment_lex(THD *thd, const char *pos);
+bool sp_create_assignment_instr(THD *thd, bool no_lookahead,
+ bool need_set_keyword= true);
void mark_or_conds_to_avoid_pushdown(Item *cond);
diff --git a/sql/sql_limit.h b/sql/sql_limit.h
new file mode 100644
index 00000000000..a4fcedac14a
--- /dev/null
+++ b/sql/sql_limit.h
@@ -0,0 +1,72 @@
+/* Copyright (c) 2019, 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 St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+
+#ifndef INCLUDES_MARIADB_SQL_LIMIT_H
+#define INCLUDES_MARIADB_SQL_LIMIT_H
+/**
+ LIMIT/OFFSET parameters for execution.
+*/
+
+class Select_limit_counters
+{
+ ha_rows select_limit_cnt, offset_limit_cnt;
+
+ public:
+ Select_limit_counters():
+ select_limit_cnt(0), offset_limit_cnt(0)
+ {};
+ Select_limit_counters(Select_limit_counters &orig):
+ select_limit_cnt(orig.select_limit_cnt),
+ offset_limit_cnt(orig.offset_limit_cnt)
+ {};
+
+ void set_limit(ha_rows limit, ha_rows offset)
+ {
+ offset_limit_cnt= offset;
+ select_limit_cnt= limit;
+ if (select_limit_cnt + offset_limit_cnt >=
+ select_limit_cnt)
+ select_limit_cnt+= offset_limit_cnt;
+ else
+ select_limit_cnt= HA_POS_ERROR;
+ }
+
+ void set_single_row()
+ {
+ offset_limit_cnt= 0;
+ select_limit_cnt= 1;
+ }
+
+ bool is_unlimited()
+ { return select_limit_cnt == HA_POS_ERROR; }
+ bool is_unrestricted()
+ { return select_limit_cnt == HA_POS_ERROR && offset_limit_cnt == 0; }
+ void set_unlimited()
+ { select_limit_cnt= HA_POS_ERROR; offset_limit_cnt= 0; }
+
+ bool check_offset(ha_rows sent)
+ {
+ return sent < offset_limit_cnt;
+ }
+ void remove_offset() { offset_limit_cnt= 0; }
+
+ ha_rows get_select_limit()
+ { return select_limit_cnt; }
+ ha_rows get_offset_limit()
+ { return offset_limit_cnt; }
+};
+
+#endif // INCLUDES_MARIADB_SQL_LIMIT_H
diff --git a/sql/sql_list.h b/sql/sql_list.h
index 9d1c01a484d..91134bcbeb2 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -677,7 +677,8 @@ struct ilink
struct ilink **prev,*next;
static void *operator new(size_t size) throw ()
{
- return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE | ME_FATAL));
+ return (void*)my_malloc(PSI_INSTRUMENT_ME,
+ (uint)size, MYF(MY_WME | MY_FAE | ME_FATAL));
}
static void operator delete(void* ptr_arg, size_t)
{
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 89cc3f8da64..6d3f9e540a7 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2010, 2018, MariaDB Corporation.
+ Copyright (c) 2010, 2020, 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
@@ -190,7 +190,7 @@ class READ_INFO: public Load_data_param
bool read_mbtail(String *str)
{
int chlen;
- if ((chlen= my_charlen(charset(), str->end() - 1, str->end())) == 1)
+ if ((chlen= charset()->charlen(str->end() - 1, str->end())) == 1)
return false; // Single byte character found
for (uint32 length0= str->length() - 1 ; MY_CS_IS_TOOSMALL(chlen); )
{
@@ -201,7 +201,7 @@ class READ_INFO: public Load_data_param
return true; // EOF
}
str->append(chr);
- chlen= my_charlen(charset(), str->ptr() + length0, str->end());
+ chlen= charset()->charlen(str->ptr() + length0, str->end());
if (chlen == MY_CS_ILSEQ)
{
/**
@@ -1587,7 +1587,7 @@ int READ_INFO::read_field()
}
}
data.append(chr);
- if (use_mb(charset()) && read_mbtail(&data))
+ if (charset()->use_mb() && read_mbtail(&data))
goto found_eof;
}
/*
@@ -1686,8 +1686,8 @@ int READ_INFO::next_line()
if (getbyte(&buf[0]))
return 1; // EOF
- if (use_mb(charset()) &&
- (chlen= my_charlen(charset(), buf, buf + 1)) != 1)
+ if (charset()->use_mb() &&
+ (chlen= charset()->charlen(buf, buf + 1)) != 1)
{
uint i;
for (i= 1; MY_CS_IS_TOOSMALL(chlen); )
@@ -1696,7 +1696,7 @@ int READ_INFO::next_line()
DBUG_ASSERT(chlen != 1);
if (getbyte(&buf[i++]))
return 1; // EOF
- chlen= my_charlen(charset(), buf, buf + i);
+ chlen= charset()->charlen(buf, buf + i);
}
/*
@@ -1867,7 +1867,7 @@ int READ_INFO::read_value(int delim, String *val)
else
{
val->append(chr);
- if (use_mb(charset()) && read_mbtail(val))
+ if (charset()->use_mb() && read_mbtail(val))
return my_b_EOF;
}
}
diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc
index 2ad8d8a914a..a3d1a7242e4 100644
--- a/sql/sql_manager.cc
+++ b/sql/sql_manager.cc
@@ -51,7 +51,8 @@ bool mysql_manager_submit(void (*action)())
cb= &(*cb)->next;
if (!*cb)
{
- *cb= (struct handler_cb *)my_malloc(sizeof(struct handler_cb), MYF(MY_WME));
+ *cb= (struct handler_cb *)my_malloc(PSI_INSTRUMENT_ME,
+ sizeof(struct handler_cb), MYF(MY_WME));
if (!*cb)
result= TRUE;
else
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 9af4afd4b03..cb0d210b12c 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
- Copyright (c) 2008, 2019, MariaDB
+ Copyright (c) 2008, 2020, 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
@@ -56,13 +56,6 @@
#include "sql_rename.h" // mysql_rename_tables
#include "sql_tablespace.h" // mysql_alter_tablespace
#include "hostname.h" // hostname_cache_refresh
-#include "sql_acl.h" // *_ACL, check_grant, is_acl_user,
- // has_any_table_level_privileges,
- // mysql_drop_user, mysql_rename_user,
- // check_grant_routine,
- // mysql_routine_grant,
- // mysql_show_grants,
- // sp_grant_privileges, ...
#include "sql_test.h" // mysql_print_status
#include "sql_select.h" // handle_select, mysql_select,
// mysql_explain_union
@@ -101,6 +94,7 @@
#include "sql_bootstrap.h"
#include "sql_sequence.h"
#include "opt_trace.h"
+#include "mysql/psi/mysql_sp.h"
#include "my_json_writer.h"
@@ -133,6 +127,10 @@ static void sql_kill_user(THD *thd, LEX_USER *user, killed_state state);
static bool lock_tables_precheck(THD *thd, TABLE_LIST *tables);
static bool execute_show_status(THD *, TABLE_LIST *);
static bool check_rename_table(THD *, TABLE_LIST *, TABLE_LIST *);
+static bool generate_incident_event(THD *thd);
+static int show_create_db(THD *thd, LEX *lex);
+static bool alter_routine(THD *thd, LEX *lex);
+static bool drop_routine(THD *thd, LEX *lex);
const char *any_db="*any*"; // Special symbol for check_access
@@ -675,7 +673,7 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_SHOW_CREATE_USER]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE_DB]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_MASTER_STAT]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_BINLOG_STAT]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_SLAVE_STAT]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE_FUNC]= CF_STATUS_COMMAND;
@@ -994,7 +992,7 @@ int bootstrap(MYSQL_FILE *file)
thd->bootstrap=1;
my_net_init(&thd->net,(st_vio*) 0, thd, MYF(0));
thd->max_client_packet_length= thd->net.max_packet;
- thd->security_ctx->master_access= ~(ulong)0;
+ thd->security_ctx->master_access= ALL_KNOWN_ACL;
#ifndef EMBEDDED_LIBRARY
mysql_thread_set_psi_id(thd->thread_id);
@@ -1006,7 +1004,8 @@ int bootstrap(MYSQL_FILE *file)
thd->thread_stack= (char*) &thd;
thd->store_globals();
- thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
+ thd->security_ctx->user= (char*) my_strdup(key_memory_MPVIO_EXT_auth_info,
+ "boot", MYF(MY_WME));
thd->security_ctx->priv_user[0]= thd->security_ctx->priv_host[0]=
thd->security_ctx->priv_role[0]= 0;
/*
@@ -1400,8 +1399,7 @@ static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables)
LEX *lex= thd->lex;
/* Super user is allowed to do changes */
- if (((ulong)(thd->security_ctx->master_access & SUPER_ACL) ==
- (ulong)SUPER_ACL))
+ if ((thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY) != NO_ACL)
DBUG_RETURN(FALSE);
/* Check if command doesn't update anything */
@@ -1441,10 +1439,10 @@ static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables)
static my_bool wsrep_read_only_option(THD *thd, TABLE_LIST *all_tables)
{
int opt_readonly_saved = opt_readonly;
- ulong flag_saved = (ulong)(thd->security_ctx->master_access & SUPER_ACL);
+ privilege_t flag_saved= thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY;
opt_readonly = 0;
- thd->security_ctx->master_access &= ~SUPER_ACL;
+ thd->security_ctx->master_access &= ~PRIV_IGNORE_READ_ONLY;
my_bool ret = !deny_updates_if_read_only_option(thd, all_tables);
@@ -1461,7 +1459,7 @@ static void wsrep_copy_query(THD *thd)
if (thd->wsrep_retry_query) {
my_free(thd->wsrep_retry_query);
}
- thd->wsrep_retry_query = (char *)my_malloc(
+ thd->wsrep_retry_query = (char *)my_malloc(PSI_INSTRUMENT_ME,
thd->wsrep_retry_query_len + 1, MYF(0));
strncpy(thd->wsrep_retry_query, thd->query(), thd->wsrep_retry_query_len);
thd->wsrep_retry_query[thd->wsrep_retry_query_len] = '\0';
@@ -1905,8 +1903,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state,
com_statement_info[command].m_key,
thd->db.str, thd->db.length,
- thd->charset());
- THD_STAGE_INFO(thd, stage_init);
+ thd->charset(), NULL);
+ THD_STAGE_INFO(thd, stage_starting);
MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, beginning_of_next_stmt,
length);
@@ -2088,7 +2086,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
status_var_increment(thd->status_var.com_other);
thd->query_plan_flags|= QPLAN_ADMIN;
- if (check_global_access(thd, REPL_SLAVE_ACL))
+ if (check_global_access(thd, PRIV_COM_BINLOG_DUMP))
break;
/* TODO: The following has to be changed to an 8 byte integer */
@@ -2218,13 +2216,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif
my_snprintf(buff, buff_len - 1,
"Uptime: %lu Threads: %d Questions: %lu "
- "Slow queries: %lu Opens: %lu Flush tables: %lld "
+ "Slow queries: %lu Opens: %lu "
"Open tables: %u Queries per second avg: %u.%03u",
uptime,
(int) thread_count, (ulong) thd->query_id,
current_global_status_var->long_query_count,
current_global_status_var->opened_tables,
- tdc_refresh_version(),
tc_records(),
(uint) (queries_per_second1000 / 1000),
(uint) (queries_per_second1000 % 1000));
@@ -2245,12 +2242,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_PROCESS_INFO:
status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST]);
if (!thd->security_ctx->priv_user[0] &&
- check_global_access(thd, PROCESS_ACL))
+ check_global_access(thd, PRIV_COM_PROCESS_INFO))
break;
general_log_print(thd, command, NullS);
mysqld_list_processes(thd,
- thd->security_ctx->master_access & PROCESS_ACL ?
- NullS : thd->security_ctx->priv_user, 0);
+ thd->security_ctx->master_access & PRIV_COM_PROCESS_INFO ?
+ NullS : thd->security_ctx->priv_user, 0);
break;
case COM_PROCESS_KILL:
{
@@ -2282,7 +2279,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_DEBUG:
status_var_increment(thd->status_var.com_other);
- if (check_global_access(thd, SUPER_ACL))
+ if (check_global_access(thd, PRIV_DEBUG))
break; /* purecov: inspected */
mysql_print_status();
general_log_print(thd, command, NullS);
@@ -2836,7 +2833,7 @@ bool sp_process_definer(THD *thd)
!my_strcasecmp(system_charset_info, d->host.str,
thd->security_ctx->priv_host);
if (!curuserhost && !currole &&
- check_global_access(thd, SUPER_ACL, false))
+ check_global_access(thd, PRIV_DEFINER_CLAUSE, false))
DBUG_RETURN(TRUE);
}
@@ -2868,7 +2865,8 @@ bool sp_process_definer(THD *thd)
@return FALSE in case of success, TRUE in case of error.
*/
-static bool lock_tables_open_and_lock_tables(THD *thd, TABLE_LIST *tables)
+static bool __attribute__ ((noinline))
+lock_tables_open_and_lock_tables(THD *thd, TABLE_LIST *tables)
{
Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
MDL_deadlock_and_lock_abort_error_handler deadlock_handler;
@@ -3029,7 +3027,8 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
}
-static int mysql_create_routine(THD *thd, LEX *lex)
+static int __attribute__ ((noinline))
+mysql_create_routine(THD *thd, LEX *lex)
{
DBUG_ASSERT(lex->sphead != 0);
DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */
@@ -3058,7 +3057,7 @@ static int mysql_create_routine(THD *thd, LEX *lex)
const LEX_CSTRING *name= lex->sphead->name();
#ifdef HAVE_DLOPEN
- if (lex->sphead->m_handler->type() == TYPE_ENUM_FUNCTION)
+ if (lex->sphead->m_handler->type() == SP_TYPE_FUNCTION)
{
udf_func *udf = find_udf(name->str, name->length);
@@ -3074,6 +3073,7 @@ static int mysql_create_routine(THD *thd, LEX *lex)
return true;
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
@@ -3164,7 +3164,8 @@ wsrep_error_label:
from other cases: bad database error, no access error.
This can be done by testing thd->is_error().
*/
-static bool prepare_db_action(THD *thd, ulong want_access, LEX_CSTRING *dbname)
+static bool prepare_db_action(THD *thd, privilege_t want_access,
+ LEX_CSTRING *dbname)
{
if (check_db_name((LEX_STRING*)dbname))
{
@@ -3820,7 +3821,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_EXPLAIN:
{
if (!thd->security_ctx->priv_user[0] &&
- check_global_access(thd,PROCESS_ACL))
+ check_global_access(thd, PRIV_STMT_SHOW_EXPLAIN))
break;
/*
@@ -3884,8 +3885,8 @@ mysql_execute_command(THD *thd)
lex->exchange != NULL implies SELECT .. INTO OUTFILE and this
requires FILE_ACL access.
*/
- ulong privileges_requested= lex->exchange ? SELECT_ACL | FILE_ACL :
- SELECT_ACL;
+ privilege_t privileges_requested= lex->exchange ? SELECT_ACL | FILE_ACL :
+ SELECT_ACL;
if (all_tables)
res= check_table_access(thd,
@@ -3938,7 +3939,7 @@ mysql_execute_command(THD *thd)
#ifndef EMBEDDED_LIBRARY
case SQLCOM_PURGE:
{
- if (check_global_access(thd, SUPER_ACL))
+ if (check_global_access(thd, PRIV_STMT_PURGE_BINLOG))
goto error;
/* PURGE MASTER LOGS TO 'file' */
res = purge_master_logs(thd, lex->to_log);
@@ -3948,7 +3949,7 @@ mysql_execute_command(THD *thd)
{
Item *it;
- if (check_global_access(thd, SUPER_ACL))
+ if (check_global_access(thd, PRIV_STMT_PURGE_BINLOG))
goto error;
/* PURGE MASTER LOGS BEFORE 'data' */
it= (Item *)lex->value_list.head();
@@ -3995,16 +3996,23 @@ mysql_execute_command(THD *thd)
#ifdef HAVE_REPLICATION
case SQLCOM_SHOW_SLAVE_HOSTS:
{
- if (check_global_access(thd, REPL_SLAVE_ACL))
+ if (check_global_access(thd, PRIV_STMT_SHOW_SLAVE_HOSTS))
goto error;
res = show_slave_hosts(thd);
break;
}
- case SQLCOM_SHOW_RELAYLOG_EVENTS: /* fall through */
+ case SQLCOM_SHOW_RELAYLOG_EVENTS:
+ {
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
+ if (check_global_access(thd, PRIV_STMT_SHOW_RELAYLOG_EVENTS))
+ goto error;
+ res = mysql_show_binlog_events(thd);
+ break;
+ }
case SQLCOM_SHOW_BINLOG_EVENTS:
{
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
- if (check_global_access(thd, REPL_SLAVE_ACL))
+ if (check_global_access(thd, PRIV_STMT_SHOW_BINLOG_EVENTS))
goto error;
res = mysql_show_binlog_events(thd);
break;
@@ -4041,7 +4049,7 @@ mysql_execute_command(THD *thd)
bool new_master= 0;
bool master_info_added;
- if (check_global_access(thd, SUPER_ACL))
+ if (check_global_access(thd, PRIV_STMT_CHANGE_MASTER))
goto error;
/*
In this code it's ok to use LOCK_active_mi as we are adding new things
@@ -4095,35 +4103,11 @@ mysql_execute_command(THD *thd)
mysql_mutex_unlock(&LOCK_active_mi);
break;
}
- case SQLCOM_SHOW_SLAVE_STAT:
- {
- /* Accept one of two privileges */
- if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
- goto error;
- if (lex->verbose)
- {
- mysql_mutex_lock(&LOCK_active_mi);
- res= show_all_master_info(thd);
- mysql_mutex_unlock(&LOCK_active_mi);
- }
- else
- {
- LEX_MASTER_INFO *lex_mi= &thd->lex->mi;
- Master_info *mi;
- if ((mi= get_master_info(&lex_mi->connection_name,
- Sql_condition::WARN_LEVEL_ERROR)))
- {
- res= show_master_info(thd, mi, 0);
- mi->release();
- }
- }
- break;
- }
- case SQLCOM_SHOW_MASTER_STAT:
+ case SQLCOM_SHOW_BINLOG_STAT:
{
/* Accept one of two privileges */
- if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
+ if (check_global_access(thd, PRIV_STMT_SHOW_BINLOG_STATUS))
goto error;
res = show_binlog_info(thd);
break;
@@ -4132,14 +4116,14 @@ mysql_execute_command(THD *thd)
#endif /* HAVE_REPLICATION */
case SQLCOM_SHOW_ENGINE_STATUS:
{
- if (check_global_access(thd, PROCESS_ACL))
+ if (check_global_access(thd, PRIV_STMT_SHOW_ENGINE_STATUS))
goto error;
res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_STATUS);
break;
}
case SQLCOM_SHOW_ENGINE_MUTEX:
{
- if (check_global_access(thd, PROCESS_ACL))
+ if (check_global_access(thd, PRIV_STMT_SHOW_ENGINE_MUTEX))
goto error;
res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX);
break;
@@ -4165,12 +4149,14 @@ mysql_execute_command(THD *thd)
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_one_table_access(thd, INDEX_ACL, all_tables))
goto error; /* purecov: inspected */
- WSREP_TO_ISOLATION_BEGIN(first_table->db.str, first_table->table_name.str, NULL);
bzero((char*) &create_info, sizeof(create_info));
create_info.db_type= 0;
create_info.row_type= ROW_TYPE_NOT_USED;
create_info.default_table_charset= thd->variables.collation_database;
+ create_info.alter_info= &alter_info;
+
+ WSREP_TO_ISOLATION_BEGIN(first_table->db.str, first_table->table_name.str, NULL);
res= mysql_alter_table(thd, &first_table->db, &first_table->table_name,
&create_info, first_table, &alter_info,
@@ -4298,7 +4284,7 @@ mysql_execute_command(THD *thd)
goto error;
#else
{
- if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
+ if (check_global_access(thd, PRIV_STMT_SHOW_BINARY_LOGS))
goto error;
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
res = show_binlogs(thd);
@@ -4372,7 +4358,7 @@ mysql_execute_command(THD *thd)
select_lex->where,
select_lex->order_list.elements,
select_lex->order_list.first,
- unit->select_limit_cnt,
+ unit->lim.get_select_limit(),
lex->ignore, &found, &updated);
MYSQL_UPDATE_DONE(res, found, updated);
/* mysql_update return 2 if we need to switch to multi-update */
@@ -4430,7 +4416,7 @@ mysql_execute_command(THD *thd)
if (res)
break;
if (opt_readonly &&
- !(thd->security_ctx->master_access & SUPER_ACL) &&
+ !(thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY) &&
some_non_temp_table_to_be_updated(thd, all_tables))
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
@@ -4467,44 +4453,13 @@ mysql_execute_command(THD *thd)
break;
}
case SQLCOM_REPLACE:
-#ifndef DBUG_OFF
- if (mysql_bin_log.is_open())
- {
- /*
- Generate an incident log event before writing the real event
- to the binary log. We put this event is before the statement
- since that makes it simpler to check that the statement was
- not executed on the slave (since incidents usually stop the
- slave).
-
- Observe that any row events that are generated will be
- generated before.
-
- This is only for testing purposes and will not be present in a
- release build.
- */
-
- Incident incident= INCIDENT_NONE;
- DBUG_PRINT("debug", ("Just before generate_incident()"));
- DBUG_EXECUTE_IF("incident_database_resync_on_replace",
- incident= INCIDENT_LOST_EVENTS;);
- if (incident)
- {
- Incident_log_event ev(thd, incident);
- (void) mysql_bin_log.write(&ev); /* error is ignored */
- if (mysql_bin_log.rotate_and_purge(true))
- {
- res= 1;
- break;
- }
- }
- DBUG_PRINT("debug", ("Just after generate_incident()"));
- }
-#endif
+ if ((res= generate_incident_event(thd)))
+ break;
/* fall through */
case SQLCOM_INSERT:
{
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE);
+ select_result *sel_result= NULL;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE);
@@ -4525,9 +4480,41 @@ mysql_execute_command(THD *thd)
break;
MYSQL_INSERT_START(thd->query());
+ Protocol* save_protocol=NULL;
+
+ if (lex->has_returning())
+ {
+ status_var_increment(thd->status_var.feature_insert_returning);
+
+ /* This is INSERT ... RETURNING. It will return output to the client */
+ if (thd->lex->analyze_stmt)
+ {
+ /*
+ Actually, it is ANALYZE .. INSERT .. RETURNING. We need to produce
+ output and then discard it.
+ */
+ sel_result= new (thd->mem_root) select_send_analyze(thd);
+ save_protocol= thd->protocol;
+ thd->protocol= new Protocol_discard(thd);
+ }
+ else
+ {
+ if (!(sel_result= new (thd->mem_root) select_send(thd)))
+ goto error;
+ }
+ }
+
res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
- lex->update_list, lex->value_list,
- lex->duplicates, lex->ignore);
+ lex->update_list, lex->value_list,
+ lex->duplicates, lex->ignore, sel_result);
+ if (save_protocol)
+ {
+ delete thd->protocol;
+ thd->protocol= save_protocol;
+ }
+ if (!res && thd->lex->analyze_stmt)
+ res= thd->lex->explain->send_explain(thd);
+ delete sel_result;
MYSQL_INSERT_DONE(res, (ulong) thd->get_row_count_func());
/*
If we have inserted into a VIEW, and the base table has
@@ -4542,12 +4529,8 @@ mysql_execute_command(THD *thd)
#ifdef ENABLED_DEBUG_SYNC
DBUG_EXECUTE_IF("after_mysql_insert",
{
- const char act1[]=
- "now "
- "wait_for signal.continue";
- const char act2[]=
- "now "
- "signal signal.continued";
+ const char act1[]= "now wait_for signal.continue";
+ const char act2[]= "now signal signal.continued";
DBUG_ASSERT(debug_sync_service);
DBUG_ASSERT(!debug_sync_set_action(thd,
STRING_WITH_LEN(act1)));
@@ -4563,6 +4546,7 @@ mysql_execute_command(THD *thd)
{
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE);
select_insert *sel_result;
+ select_result *result= NULL;
bool explain= MY_TEST(lex->describe);
DBUG_ASSERT(first_table == all_tables && first_table != 0);
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE);
@@ -4611,6 +4595,31 @@ mysql_execute_command(THD *thd)
Only the INSERT table should be merged. Other will be handled by
select.
*/
+
+ Protocol* save_protocol=NULL;
+
+ if (lex->has_returning())
+ {
+ status_var_increment(thd->status_var.feature_insert_returning);
+
+ /* This is INSERT ... RETURNING. It will return output to the client */
+ if (thd->lex->analyze_stmt)
+ {
+ /*
+ Actually, it is ANALYZE .. INSERT .. RETURNING. We need to produce
+ output and then discard it.
+ */
+ result= new (thd->mem_root) select_send_analyze(thd);
+ save_protocol= thd->protocol;
+ thd->protocol= new Protocol_discard(thd);
+ }
+ else
+ {
+ if (!(result= new (thd->mem_root) select_send(thd)))
+ goto error;
+ }
+ }
+
/* Skip first table, which is the table we are inserting in */
TABLE_LIST *second_table= first_table->next_local;
/*
@@ -4621,17 +4630,19 @@ mysql_execute_command(THD *thd)
be done properly as well)
*/
select_lex->table_list.first= second_table;
- select_lex->context.table_list=
+ select_lex->context.table_list=
select_lex->context.first_name_resolution_table= second_table;
- res= mysql_insert_select_prepare(thd);
- if (!res && (sel_result= new (thd->mem_root) select_insert(thd,
- first_table,
- first_table->table,
- &lex->field_list,
- &lex->update_list,
- &lex->value_list,
- lex->duplicates,
- lex->ignore)))
+ res= mysql_insert_select_prepare(thd, result);
+ if (!res &&
+ (sel_result= new (thd->mem_root)
+ select_insert(thd, first_table,
+ first_table->table,
+ &lex->field_list,
+ &lex->update_list,
+ &lex->value_list,
+ lex->duplicates,
+ lex->ignore,
+ result)))
{
if (lex->analyze_stmt)
((select_result_interceptor*)sel_result)->disable_my_ok_calls();
@@ -4667,7 +4678,12 @@ mysql_execute_command(THD *thd)
}
delete sel_result;
}
-
+ delete result;
+ if (save_protocol)
+ {
+ delete thd->protocol;
+ thd->protocol= save_protocol;
+ }
if (!res && (explain || lex->analyze_stmt))
res= thd->lex->explain->send_explain(thd);
@@ -4700,10 +4716,9 @@ mysql_execute_command(THD *thd)
unit->set_limit(select_lex);
MYSQL_DELETE_START(thd->query());
- Protocol * UNINIT_VAR(save_protocol);
- bool replaced_protocol= false;
+ Protocol *save_protocol= NULL;
- if (!select_lex->item_list.is_empty())
+ if (lex->has_returning())
{
/* This is DELETE ... RETURNING. It will return output to the client */
if (thd->lex->analyze_stmt)
@@ -4713,7 +4728,6 @@ mysql_execute_command(THD *thd)
output and then discard it.
*/
sel_result= new (thd->mem_root) select_send_analyze(thd);
- replaced_protocol= true;
save_protocol= thd->protocol;
thd->protocol= new Protocol_discard(thd);
}
@@ -4726,10 +4740,10 @@ mysql_execute_command(THD *thd)
res = mysql_delete(thd, all_tables,
select_lex->where, &select_lex->order_list,
- unit->select_limit_cnt, select_lex->options,
+ unit->lim.get_select_limit(), select_lex->options,
lex->result ? lex->result : sel_result);
- if (replaced_protocol)
+ if (save_protocol)
{
delete thd->protocol;
thd->protocol= save_protocol;
@@ -4783,7 +4797,6 @@ mysql_execute_command(THD *thd)
goto multi_delete_error;
res= mysql_select(thd,
select_lex->get_table_list(),
- select_lex->with_wild,
select_lex->item_list,
select_lex->where,
0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
@@ -4847,6 +4860,7 @@ mysql_execute_command(THD *thd)
slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT)
lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
+#ifdef WITH_WSREP
if (WSREP(thd))
{
for (TABLE_LIST *table= all_tables; table; table= table->next_global)
@@ -4860,7 +4874,8 @@ mysql_execute_command(THD *thd)
}
}
}
-
+#endif /* WITH_WSREP */
+
/* DDL and binlog write order are protected by metadata locks. */
res= mysql_rm_table(thd, first_table, lex->if_exists(), lex->tmp_table(),
lex->table_type == TABLE_TYPE_SEQUENCE);
@@ -4871,19 +4886,19 @@ mysql_execute_command(THD *thd)
*/
if(!res && (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
{
- SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
+ thd->session_tracker.state_change.mark_as_changed(thd);
}
break;
}
case SQLCOM_SHOW_PROCESSLIST:
if (!thd->security_ctx->priv_user[0] &&
- check_global_access(thd,PROCESS_ACL))
+ check_global_access(thd, PRIV_STMT_SHOW_PROCESSLIST))
break;
mysqld_list_processes(thd,
- (thd->security_ctx->master_access & PROCESS_ACL ?
- NullS :
- thd->security_ctx->priv_user),
- lex->verbose);
+ (thd->security_ctx->master_access & PRIV_STMT_SHOW_PROCESSLIST ?
+ NullS :
+ thd->security_ctx->priv_user),
+ lex->verbose);
break;
case SQLCOM_SHOW_AUTHORS:
res= mysqld_show_authors(thd);
@@ -4918,17 +4933,18 @@ mysql_execute_command(THD *thd)
case SQLCOM_LOAD:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- uint privilege= (lex->duplicates == DUP_REPLACE ?
- INSERT_ACL | DELETE_ACL : INSERT_ACL) |
- (lex->local_file ? 0 : FILE_ACL);
+ privilege_t privilege= (lex->duplicates == DUP_REPLACE ?
+ INSERT_ACL | DELETE_ACL : INSERT_ACL) |
+ (lex->local_file ? NO_ACL : FILE_ACL);
if (lex->local_file)
{
if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
!opt_local_infile)
{
- my_message(ER_NOT_ALLOWED_COMMAND, ER_THD(thd, ER_NOT_ALLOWED_COMMAND), MYF(0));
- goto error;
+ my_message(ER_LOAD_INFILE_CAPABILITY_DISABLED,
+ ER_THD(thd, ER_LOAD_INFILE_CAPABILITY_DISABLED), MYF(0));
+ goto error;
}
}
@@ -5060,7 +5076,9 @@ mysql_execute_command(THD *thd)
(CREATE_ACL | DROP_ACL) : CREATE_ACL,
&lex->name))
break;
+
WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL);
+
res= mysql_create_db(thd, &lex->name,
lex->create_info, &lex->create_info);
break;
@@ -5069,7 +5087,9 @@ mysql_execute_command(THD *thd)
{
if (prepare_db_action(thd, DROP_ACL, &lex->name))
break;
+
WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL);
+
res= mysql_rm_db(thd, &lex->name, lex->if_exists());
break;
}
@@ -5101,7 +5121,9 @@ mysql_execute_command(THD *thd)
res= 1;
break;
}
+
WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL);
+
res= mysql_upgrade_db(thd, db);
if (!res)
my_ok(thd);
@@ -5112,31 +5134,16 @@ mysql_execute_command(THD *thd)
LEX_CSTRING *db= &lex->name;
if (prepare_db_action(thd, ALTER_ACL, db))
break;
+
WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL);
+
res= mysql_alter_db(thd, db, &lex->create_info);
break;
}
case SQLCOM_SHOW_CREATE_DB:
- {
- char db_name_buff[NAME_LEN+1];
- LEX_CSTRING db_name;
- DBUG_EXECUTE_IF("4x_server_emul",
- my_error(ER_UNKNOWN_ERROR, MYF(0)); goto error;);
-
- db_name.str= db_name_buff;
- db_name.length= lex->name.length;
- strmov(db_name_buff, lex->name.str);
-
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
-
- if (check_db_name((LEX_STRING*) &db_name))
- {
- my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str);
- break;
- }
- res= mysqld_show_create_db(thd, &db_name, &lex->name, lex->create_info);
+ res= show_create_db(thd, lex);
break;
- }
case SQLCOM_CREATE_EVENT:
case SQLCOM_ALTER_EVENT:
#ifdef HAVE_EVENT_SCHEDULER
@@ -5203,6 +5210,7 @@ mysql_execute_command(THD *thd)
break;
#ifdef HAVE_DLOPEN
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
if (!(res = mysql_create_function(thd, &lex->udf)))
my_ok(thd);
#else
@@ -5220,7 +5228,9 @@ mysql_execute_command(THD *thd)
"mysql", NULL, NULL, 1, 1) &&
check_global_access(thd,CREATE_USER_ACL))
break;
+
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
/* Conditionally writes to binlog */
if (!(res= mysql_create_user(thd, lex->users_list,
lex->sql_command == SQLCOM_CREATE_ROLE)))
@@ -5233,8 +5243,10 @@ mysql_execute_command(THD *thd)
if (check_access(thd, DELETE_ACL, "mysql", NULL, NULL, 1, 1) &&
check_global_access(thd,CREATE_USER_ACL))
break;
- /* Conditionally writes to binlog */
+
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
+ /* Conditionally writes to binlog */
if (!(res= mysql_drop_user(thd, lex->users_list,
lex->sql_command == SQLCOM_DROP_ROLE)))
my_ok(thd);
@@ -5246,8 +5258,10 @@ mysql_execute_command(THD *thd)
if (check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 1) &&
check_global_access(thd,CREATE_USER_ACL))
break;
- /* Conditionally writes to binlog */
+
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
+ /* Conditionally writes to binlog */
if (lex->sql_command == SQLCOM_ALTER_USER)
res= mysql_alter_user(thd, lex->users_list);
else
@@ -5262,123 +5276,19 @@ mysql_execute_command(THD *thd)
check_global_access(thd,CREATE_USER_ACL))
break;
- /* Conditionally writes to binlog */
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
+ /* Conditionally writes to binlog */
if (!(res = mysql_revoke_all(thd, lex->users_list)))
my_ok(thd);
break;
}
- case SQLCOM_REVOKE:
- case SQLCOM_GRANT:
- {
- if (lex->type != TYPE_ENUM_PROXY &&
- check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
- first_table ? first_table->db.str : select_lex->db.str,
- first_table ? &first_table->grant.privilege : NULL,
- first_table ? &first_table->grant.m_internal : NULL,
- first_table ? 0 : 1, 0))
- goto error;
-
- /* Replicate current user as grantor */
- thd->binlog_invoker(false);
-
- if (thd->security_ctx->user) // If not replication
- {
- LEX_USER *user;
- bool first_user= TRUE;
-
- List_iterator <LEX_USER> user_list(lex->users_list);
- while ((user= user_list++))
- {
- if (specialflag & SPECIAL_NO_RESOLVE &&
- hostname_requires_resolving(user->host.str))
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WARN_HOSTNAME_WONT_WORK,
- ER_THD(thd, ER_WARN_HOSTNAME_WONT_WORK));
-
- /*
- GRANT/REVOKE PROXY has the target user as a first entry in the list.
- */
- if (lex->type == TYPE_ENUM_PROXY && first_user)
- {
- if (!(user= get_current_user(thd, user)) || !user->host.str)
- goto error;
- first_user= FALSE;
- if (acl_check_proxy_grant_access (thd, user->host.str, user->user.str,
- lex->grant & GRANT_ACL))
- goto error;
- }
- }
- }
- if (first_table)
- {
- const Sp_handler *sph= Sp_handler::handler((stored_procedure_type)
- lex->type);
- if (sph)
- {
- uint grants= lex->all_privileges
- ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
- : lex->grant;
- if (check_grant_routine(thd, grants | GRANT_ACL, all_tables, sph, 0))
- goto error;
- /* Conditionally writes to binlog */
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
- res= mysql_routine_grant(thd, all_tables, sph,
- lex->users_list, grants,
- lex->sql_command == SQLCOM_REVOKE, TRUE);
- if (!res)
- my_ok(thd);
- }
- else
- {
- if (check_grant(thd,(lex->grant | lex->grant_tot_col | GRANT_ACL),
- all_tables, FALSE, UINT_MAX, FALSE))
- goto error;
- /* Conditionally writes to binlog */
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
- res= mysql_table_grant(thd, all_tables, lex->users_list,
- lex->columns, lex->grant,
- lex->sql_command == SQLCOM_REVOKE);
- }
- }
- else
- {
- if (lex->columns.elements || (lex->type && lex->type != TYPE_ENUM_PROXY))
- {
- my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER_THD(thd, ER_ILLEGAL_GRANT_FOR_TABLE),
- MYF(0));
- goto error;
- }
- else
- {
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
- /* Conditionally writes to binlog */
- res= mysql_grant(thd, select_lex->db.str, lex->users_list, lex->grant,
- lex->sql_command == SQLCOM_REVOKE,
- lex->type == TYPE_ENUM_PROXY);
- }
- if (!res)
- {
- if (lex->sql_command == SQLCOM_GRANT)
- {
- List_iterator <LEX_USER> str_list(lex->users_list);
- LEX_USER *user, *tmp_user;
- while ((tmp_user=str_list++))
- {
- if (!(user= get_current_user(thd, tmp_user)))
- goto error;
- reset_mqh(user, 0);
- }
- }
- }
- }
- break;
- }
case SQLCOM_REVOKE_ROLE:
case SQLCOM_GRANT_ROLE:
{
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
if (!(res= mysql_grant_role(thd, lex->users_list,
lex->sql_command != SQLCOM_GRANT_ROLE)))
my_ok(thd);
@@ -5592,7 +5502,8 @@ mysql_execute_command(THD *thd)
res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
lex->insert_list, lex->ha_rkey_mode, select_lex->where,
- unit->select_limit_cnt, unit->offset_limit_cnt);
+ unit->lim.get_select_limit(),
+ unit->lim.get_offset_limit());
break;
case SQLCOM_BEGIN:
@@ -5707,162 +5618,32 @@ mysql_execute_command(THD *thd)
break; /* break super switch */
} /* end case group bracket */
case SQLCOM_COMPOUND:
+ {
+ sp_head *sp= lex->sphead;
DBUG_ASSERT(all_tables == 0);
DBUG_ASSERT(thd->in_sub_stmt == 0);
- lex->sphead->m_sql_mode= thd->variables.sql_mode;
+ sp->m_sql_mode= thd->variables.sql_mode;
+ sp->m_sp_share= MYSQL_GET_SP_SHARE(sp->m_handler->type(),
+ sp->m_db.str, static_cast<uint>(sp->m_db.length),
+ sp->m_name.str, static_cast<uint>(sp->m_name.length));
if (do_execute_sp(thd, lex->sphead))
goto error;
break;
+ }
case SQLCOM_ALTER_PROCEDURE:
case SQLCOM_ALTER_FUNCTION:
- {
- int sp_result;
- const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
- if (check_routine_access(thd, ALTER_PROC_ACL, &lex->spname->m_db,
- &lex->spname->m_name, sph, 0))
- goto error;
-
- /*
- Note that if you implement the capability of ALTER FUNCTION to
- alter the body of the function, this command should be made to
- follow the restrictions that log-bin-trust-function-creators=0
- already puts on CREATE FUNCTION.
- */
- /* Conditionally writes to binlog */
- sp_result= sph->sp_update_routine(thd, lex->spname, &lex->sp_chistics);
- switch (sp_result)
- {
- case SP_OK:
- my_ok(thd);
- break;
- case SP_KEY_NOT_FOUND:
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
- sph->type_str(), ErrConvDQName(lex->spname).ptr());
- goto error;
- default:
- my_error(ER_SP_CANT_ALTER, MYF(0),
- sph->type_str(), ErrConvDQName(lex->spname).ptr());
- goto error;
- }
- break;
- }
+ if (alter_routine(thd, lex))
+ goto error;
+ break;
case SQLCOM_DROP_PROCEDURE:
case SQLCOM_DROP_FUNCTION:
case SQLCOM_DROP_PACKAGE:
case SQLCOM_DROP_PACKAGE_BODY:
- {
-#ifdef HAVE_DLOPEN
- if (lex->sql_command == SQLCOM_DROP_FUNCTION &&
- ! lex->spname->m_explicit_name)
- {
- /* DROP FUNCTION <non qualified name> */
- udf_func *udf = find_udf(lex->spname->m_name.str,
- lex->spname->m_name.length);
- if (udf)
- {
- if (check_access(thd, DELETE_ACL, "mysql", NULL, NULL, 1, 0))
- goto error;
+ if (drop_routine(thd, lex))
- if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
- {
- my_ok(thd);
- break;
- }
- my_error(ER_SP_DROP_FAILED, MYF(0),
- "FUNCTION (UDF)", lex->spname->m_name.str);
- goto error;
- }
-
- if (lex->spname->m_db.str == NULL)
- {
- if (lex->if_exists())
- {
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_SP_DOES_NOT_EXIST, ER_THD(thd, ER_SP_DOES_NOT_EXIST),
- "FUNCTION (UDF)", lex->spname->m_name.str);
- res= FALSE;
- my_ok(thd);
- break;
- }
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
- "FUNCTION (UDF)", lex->spname->m_name.str);
- goto error;
- }
- /* Fall thought to test for a stored function */
- }
-#endif
-
- int sp_result;
- const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
-
- if (check_routine_access(thd, ALTER_PROC_ACL, &lex->spname->m_db, &lex->spname->m_name,
- Sp_handler::handler(lex->sql_command), 0))
- goto error;
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
-
- /* Conditionally writes to binlog */
- sp_result= sph->sp_drop_routine(thd, lex->spname);
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- /*
- We're going to issue an implicit REVOKE statement so we close all
- open tables. We have to keep metadata locks as this ensures that
- this statement is atomic against concurent FLUSH TABLES WITH READ
- LOCK. Deadlocks which can arise due to fact that this implicit
- statement takes metadata locks should be detected by a deadlock
- detector in MDL subsystem and reported as errors.
-
- No need to commit/rollback statement transaction, it's not started.
-
- TODO: Long-term we should either ensure that implicit REVOKE statement
- is written into binary log as a separate statement or make both
- dropping of routine and implicit REVOKE parts of one fully atomic
- statement.
- */
- DBUG_ASSERT(thd->transaction.stmt.is_empty());
- close_thread_tables(thd);
-
- if (sp_result != SP_KEY_NOT_FOUND &&
- sp_automatic_privileges && !opt_noacl &&
- sp_revoke_privileges(thd, lex->spname->m_db.str, lex->spname->m_name.str,
- Sp_handler::handler(lex->sql_command)))
- {
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_PROC_AUTO_REVOKE_FAIL,
- ER_THD(thd, ER_PROC_AUTO_REVOKE_FAIL));
- /* If this happens, an error should have been reported. */
- goto error;
- }
-#endif
-
- res= sp_result;
- switch (sp_result) {
- case SP_OK:
- my_ok(thd);
- break;
- case SP_KEY_NOT_FOUND:
- if (lex->if_exists())
- {
- res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_SP_DOES_NOT_EXIST, ER_THD(thd, ER_SP_DOES_NOT_EXIST),
- sph->type_str(),
- ErrConvDQName(lex->spname).ptr());
- if (!res)
- my_ok(thd);
- break;
- }
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
- sph->type_str(), ErrConvDQName(lex->spname).ptr());
- goto error;
- default:
- my_error(ER_SP_DROP_FAILED, MYF(0),
- sph->type_str(), ErrConvDQName(lex->spname).ptr());
- goto error;
- }
- break;
- }
+ goto error;
+ break;
case SQLCOM_SHOW_CREATE_PROC:
case SQLCOM_SHOW_CREATE_FUNC:
case SQLCOM_SHOW_CREATE_PACKAGE:
@@ -5926,8 +5707,10 @@ mysql_execute_command(THD *thd)
{
if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE))
goto error;
- /* Conditionally writes to binlog. */
+
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
+ /* Conditionally writes to binlog. */
res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
break;
}
@@ -6027,7 +5810,7 @@ mysql_execute_command(THD *thd)
{
DBUG_PRINT("info", ("case SQLCOM_CREATE_SERVER"));
- if (check_global_access(thd, SUPER_ACL))
+ if (check_global_access(thd, PRIV_STMT_CREATE_SERVER))
break;
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
@@ -6040,7 +5823,7 @@ mysql_execute_command(THD *thd)
int error;
DBUG_PRINT("info", ("case SQLCOM_ALTER_SERVER"));
- if (check_global_access(thd, SUPER_ACL))
+ if (check_global_access(thd, PRIV_STMT_ALTER_SERVER))
break;
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
@@ -6060,7 +5843,7 @@ mysql_execute_command(THD *thd)
int err_code;
DBUG_PRINT("info", ("case SQLCOM_DROP_SERVER"));
- if (check_global_access(thd, SUPER_ACL))
+ if (check_global_access(thd, PRIV_STMT_DROP_SERVER))
break;
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
@@ -6093,12 +5876,17 @@ mysql_execute_command(THD *thd)
DBUG_ASSERT(first_table == all_tables && first_table != 0);
/* fall through */
case SQLCOM_ALTER_SEQUENCE:
+ case SQLCOM_SHOW_SLAVE_STAT:
case SQLCOM_SIGNAL:
case SQLCOM_RESIGNAL:
case SQLCOM_GET_DIAGNOSTICS:
case SQLCOM_CALL:
+ case SQLCOM_REVOKE:
+ case SQLCOM_GRANT:
DBUG_ASSERT(lex->m_sql_cmd != NULL);
res= lex->m_sql_cmd->execute(thd);
+ DBUG_PRINT("result", ("res: %d killed: %d is_error: %d",
+ res, thd->killed, thd->is_error()));
break;
default:
@@ -6228,7 +6016,7 @@ finish:
#ifdef WITH_WSREP
thd->wsrep_consistency_check= NO_CONSISTENCY_CHECK;
-
+
WSREP_TO_ISOLATION_END;
/*
Force release of transactional locks if not in active MST and wsrep is on.
@@ -6303,8 +6091,8 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
/*
Do like the original select_describe did: remove OFFSET from the
top-level LIMIT
- */
- result->reset_offset_limit();
+ */
+ result->remove_offset_limit();
if (lex->explain_json)
{
lex->explain->print_explain_json(result, lex->analyze_stmt);
@@ -6382,7 +6170,15 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
}
-static bool execute_show_status(THD *thd, TABLE_LIST *all_tables)
+/**
+ SHOW STATUS
+
+ Notes: This is noinline as we don't want to have system_status_var (> 3K)
+ to be on the stack of mysql_execute_command()
+*/
+
+static bool __attribute__ ((noinline))
+execute_show_status(THD *thd, TABLE_LIST *all_tables)
{
bool res;
system_status_var old_status_var= thd->status_var;
@@ -6392,6 +6188,7 @@ static bool execute_show_status(THD *thd, TABLE_LIST *all_tables)
UINT_MAX, FALSE)))
res= execute_sqlcom_select(thd, all_tables);
+ thd->initial_status_var= NULL;
/* Don't log SHOW STATUS commands to slow query log */
thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED |
SERVER_QUERY_NO_GOOD_INDEX_USED);
@@ -6467,8 +6264,9 @@ static TABLE *find_temporary_table_for_rename(THD *thd,
}
-static bool check_rename_table(THD *thd, TABLE_LIST *first_table,
- TABLE_LIST *all_tables)
+static bool __attribute__ ((noinline))
+check_rename_table(THD *thd, TABLE_LIST *first_table,
+ TABLE_LIST *all_tables)
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *table;
@@ -6507,6 +6305,227 @@ static bool check_rename_table(THD *thd, TABLE_LIST *first_table,
return 0;
}
+/*
+ Generate an incident log event before writing the real event
+ to the binary log. We put this event is before the statement
+ since that makes it simpler to check that the statement was
+ not executed on the slave (since incidents usually stop the
+ slave).
+
+ Observe that any row events that are generated will be generated before.
+
+ This is only for testing purposes and will not be present in a release build.
+*/
+
+#ifndef DBUG_OFF
+static bool __attribute__ ((noinline)) generate_incident_event(THD *thd)
+{
+ if (mysql_bin_log.is_open())
+ {
+
+ Incident incident= INCIDENT_NONE;
+ DBUG_PRINT("debug", ("Just before generate_incident()"));
+ DBUG_EXECUTE_IF("incident_database_resync_on_replace",
+ incident= INCIDENT_LOST_EVENTS;);
+ if (incident)
+ {
+ Incident_log_event ev(thd, incident);
+ (void) mysql_bin_log.write(&ev); /* error is ignored */
+ if (mysql_bin_log.rotate_and_purge(true))
+ return 1;
+ }
+ DBUG_PRINT("debug", ("Just after generate_incident()"));
+ }
+ return 0;
+}
+#else
+static bool generate_incident_event(THD *thd)
+{
+ return 0;
+}
+#endif
+
+
+static int __attribute__ ((noinline))
+show_create_db(THD *thd, LEX *lex)
+{
+ char db_name_buff[NAME_LEN+1];
+ LEX_CSTRING db_name;
+ DBUG_EXECUTE_IF("4x_server_emul",
+ my_error(ER_UNKNOWN_ERROR, MYF(0)); return 1;);
+
+ db_name.str= db_name_buff;
+ db_name.length= lex->name.length;
+ strmov(db_name_buff, lex->name.str);
+
+ if (check_db_name((LEX_STRING*) &db_name))
+ {
+ my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str);
+ return 1;
+ }
+ return mysqld_show_create_db(thd, &db_name, &lex->name, lex->create_info);
+}
+
+
+/**
+ Called on SQLCOM_ALTER_PROCEDURE and SQLCOM_ALTER_FUNCTION
+*/
+
+static bool __attribute__ ((noinline))
+alter_routine(THD *thd, LEX *lex)
+{
+ int sp_result;
+ const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
+ if (check_routine_access(thd, ALTER_PROC_ACL, &lex->spname->m_db,
+ &lex->spname->m_name, sph, 0))
+ return 1;
+ /*
+ Note that if you implement the capability of ALTER FUNCTION to
+ alter the body of the function, this command should be made to
+ follow the restrictions that log-bin-trust-function-creators=0
+ already puts on CREATE FUNCTION.
+ */
+ /* Conditionally writes to binlog */
+ sp_result= sph->sp_update_routine(thd, lex->spname, &lex->sp_chistics);
+ switch (sp_result) {
+ case SP_OK:
+ my_ok(thd);
+ return 0;
+ case SP_KEY_NOT_FOUND:
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
+ sph->type_str(), ErrConvDQName(lex->spname).ptr());
+ return 1;
+ default:
+ my_error(ER_SP_CANT_ALTER, MYF(0),
+ sph->type_str(), ErrConvDQName(lex->spname).ptr());
+ return 1;
+ }
+ return 0; /* purecov: deadcode */
+}
+
+
+static bool __attribute__ ((noinline))
+drop_routine(THD *thd, LEX *lex)
+{
+ int sp_result;
+#ifdef HAVE_DLOPEN
+ if (lex->sql_command == SQLCOM_DROP_FUNCTION &&
+ ! lex->spname->m_explicit_name)
+ {
+ /* DROP FUNCTION <non qualified name> */
+ udf_func *udf = find_udf(lex->spname->m_name.str,
+ lex->spname->m_name.length);
+ if (udf)
+ {
+ if (check_access(thd, DELETE_ACL, "mysql", NULL, NULL, 1, 0))
+ return 1;
+
+ if (!mysql_drop_function(thd, &lex->spname->m_name))
+ {
+ my_ok(thd);
+ return 0;
+ }
+ my_error(ER_SP_DROP_FAILED, MYF(0),
+ "FUNCTION (UDF)", lex->spname->m_name.str);
+ return 1;
+ }
+
+ if (lex->spname->m_db.str == NULL)
+ {
+ if (lex->if_exists())
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_SP_DOES_NOT_EXIST,
+ ER_THD(thd, ER_SP_DOES_NOT_EXIST),
+ "FUNCTION (UDF)", lex->spname->m_name.str);
+ my_ok(thd);
+ return 0;
+ }
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
+ "FUNCTION (UDF)", lex->spname->m_name.str);
+ return 1;
+ }
+ /* Fall trough to test for a stored function */
+ }
+#endif /* HAVE_DLOPEN */
+
+ const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
+
+ if (check_routine_access(thd, ALTER_PROC_ACL, &lex->spname->m_db,
+ &lex->spname->m_name,
+ Sp_handler::handler(lex->sql_command), 0))
+ return 1;
+
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
+ /* Conditionally writes to binlog */
+ sp_result= sph->sp_drop_routine(thd, lex->spname);
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /*
+ We're going to issue an implicit REVOKE statement so we close all
+ open tables. We have to keep metadata locks as this ensures that
+ this statement is atomic against concurent FLUSH TABLES WITH READ
+ LOCK. Deadlocks which can arise due to fact that this implicit
+ statement takes metadata locks should be detected by a deadlock
+ detector in MDL subsystem and reported as errors.
+
+ No need to commit/rollback statement transaction, it's not started.
+
+ TODO: Long-term we should either ensure that implicit REVOKE statement
+ is written into binary log as a separate statement or make both
+ dropping of routine and implicit REVOKE parts of one fully atomic
+ statement.
+ */
+ DBUG_ASSERT(thd->transaction.stmt.is_empty());
+ close_thread_tables(thd);
+
+ if (sp_result != SP_KEY_NOT_FOUND &&
+ sp_automatic_privileges && !opt_noacl &&
+ sp_revoke_privileges(thd, lex->spname->m_db.str, lex->spname->m_name.str,
+ Sp_handler::handler(lex->sql_command)))
+ {
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_PROC_AUTO_REVOKE_FAIL,
+ ER_THD(thd, ER_PROC_AUTO_REVOKE_FAIL));
+ /* If this happens, an error should have been reported. */
+ return 1;
+ }
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+
+ switch (sp_result) {
+ case SP_OK:
+ my_ok(thd);
+ return 0;
+ case SP_KEY_NOT_FOUND:
+ int res;
+ if (lex->if_exists())
+ {
+ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_SP_DOES_NOT_EXIST,
+ ER_THD(thd, ER_SP_DOES_NOT_EXIST),
+ sph->type_str(),
+ ErrConvDQName(lex->spname).ptr());
+ if (res)
+ return 1;
+ my_ok(thd);
+ return 0;
+ }
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
+ sph->type_str(), ErrConvDQName(lex->spname).ptr());
+ return 1;
+ default:
+ my_error(ER_SP_DROP_FAILED, MYF(0),
+ sph->type_str(), ErrConvDQName(lex->spname).ptr());
+ return 1;
+ }
+
+#ifdef WITH_WSREP
+wsrep_error_label:
+ return 1;
+#endif
+}
/**
@brief Compare requested privileges with the privileges acquired from the
@@ -6536,7 +6555,8 @@ static bool check_rename_table(THD *thd, TABLE_LIST *first_table,
*/
bool
-check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
+check_access(THD *thd, privilege_t want_access,
+ const char *db, privilege_t *save_priv,
GRANT_INTERNAL_INFO *grant_internal_info,
bool dont_check_global_grants, bool no_errors)
{
@@ -6546,7 +6566,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
return false;
#else
Security_context *sctx= thd->security_ctx;
- ulong db_access;
+ privilege_t db_access(NO_ACL);
/*
GRANT command:
@@ -6558,17 +6578,19 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
set db_is_pattern according to 'dont_check_global_grants' value.
*/
bool db_is_pattern= ((want_access & GRANT_ACL) && dont_check_global_grants);
- ulong dummy;
+ privilege_t dummy(NO_ACL);
DBUG_ENTER("check_access");
- DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu",
- db ? db : "", want_access, sctx->master_access));
+ DBUG_PRINT("enter",("db: %s want_access: %llx master_access: %llx",
+ db ? db : "",
+ (longlong) want_access,
+ (longlong) sctx->master_access));
if (save_priv)
- *save_priv=0;
+ *save_priv= NO_ACL;
else
{
save_priv= &dummy;
- dummy= 0;
+ dummy= NO_ACL;
}
/* check access may be called twice in a row. Don't change to same stage */
@@ -6686,8 +6708,8 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
}
else
db_access= sctx->db_access;
- DBUG_PRINT("info",("db_access: %lu want_access: %lu",
- db_access, want_access));
+ DBUG_PRINT("info",("db_access: %llx want_access: %llx",
+ (longlong) db_access, (longlong) want_access));
/*
Save the union of User-table and the intersection between Db-table and
@@ -6755,7 +6777,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
1 access denied, error is sent to client
*/
-bool check_single_table_access(THD *thd, ulong privilege,
+bool check_single_table_access(THD *thd, privilege_t privilege,
TABLE_LIST *all_tables, bool no_errors)
{
Switch_to_definer_security_ctx backup_sctx(thd, all_tables);
@@ -6796,7 +6818,8 @@ bool check_single_table_access(THD *thd, ulong privilege,
1 access denied, error is sent to client
*/
-bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
+bool check_one_table_access(THD *thd, privilege_t privilege,
+ TABLE_LIST *all_tables)
{
if (check_single_table_access (thd,privilege,all_tables, FALSE))
return 1;
@@ -6948,7 +6971,7 @@ static bool check_show_access(THD *thd, TABLE_LIST *table)
*/
bool
-check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
+check_table_access(THD *thd, privilege_t requirements, TABLE_LIST *tables,
bool any_combination_of_privileges_will_do,
uint number, bool no_errors)
{
@@ -6967,7 +6990,7 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
tables->correspondent_table : tables;
Switch_to_definer_security_ctx backup_ctx(thd, table_ref);
- ulong want_access= requirements;
+ privilege_t want_access(requirements);
/*
Register access for view underlying table.
@@ -7010,7 +7033,7 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
bool
-check_routine_access(THD *thd, ulong want_access, const LEX_CSTRING *db,
+check_routine_access(THD *thd, privilege_t want_access, const LEX_CSTRING *db,
const LEX_CSTRING *name,
const Sp_handler *sph, bool no_errors)
{
@@ -7032,7 +7055,7 @@ check_routine_access(THD *thd, ulong want_access, const LEX_CSTRING *db,
as long as this code path is not abused to create routines.
The assert enforce that.
*/
- DBUG_ASSERT((want_access & CREATE_PROC_ACL) == 0);
+ DBUG_ASSERT((want_access & CREATE_PROC_ACL) == NO_ACL);
if ((thd->security_ctx->master_access & want_access) == want_access)
tables->grant.privilege= want_access;
else if (check_access(thd, want_access, db->str,
@@ -7061,7 +7084,7 @@ check_routine_access(THD *thd, ulong want_access, const LEX_CSTRING *db,
bool check_some_routine_access(THD *thd, const char *db, const char *name,
const Sp_handler *sph)
{
- ulong save_priv;
+ privilege_t save_priv(NO_ACL);
/*
The following test is just a shortcut for check_access() (to avoid
calculating db_access)
@@ -7092,16 +7115,15 @@ bool check_some_routine_access(THD *thd, const char *db, const char *name,
1 error
*/
-bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
+bool check_some_access(THD *thd, privilege_t want_access, TABLE_LIST *table)
{
- ulong access;
DBUG_ENTER("check_some_access");
- /* This loop will work as long as we have less than 32 privileges */
- for (access= 1; access < want_access ; access<<= 1)
+ for (ulonglong bit= 1; bit < (ulonglong) want_access ; bit<<= 1)
{
- if (access & want_access)
+ if (bit & want_access)
{
+ privilege_t access= ALL_KNOWN_ACL & bit;
if (!check_access(thd, access, table->db.str,
&table->grant.privilege,
&table->grant.m_internal,
@@ -7124,10 +7146,8 @@ bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
@param want_access Use should have any of these global rights
@warning
- One gets access right if one has ANY of the rights in want_access.
- This is useful as one in most cases only need one global right,
- but in some case we want to check if the user has SUPER or
- REPL_CLIENT_ACL rights.
+ Starting from 10.5.2 only one bit is allowed in want_access.
+ Access denied error is returned if want_access has multiple bits set.
@retval
0 ok
@@ -7135,11 +7155,11 @@ bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
1 Access denied. In this case an error is sent to the client
*/
-bool check_global_access(THD *thd, ulong want_access, bool no_errors)
+bool check_global_access(THD *thd, privilege_t want_access, bool no_errors)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
char command[128];
- if ((thd->security_ctx->master_access & want_access))
+ if (thd->security_ctx->master_access & want_access)
return 0;
if (unlikely(!no_errors))
{
@@ -7187,8 +7207,7 @@ bool check_fk_parent_table_access(THD *thd,
LEX_CSTRING db_name;
LEX_CSTRING table_name= { fk_key->ref_table.str,
fk_key->ref_table.length };
- const ulong privileges= (SELECT_ACL | INSERT_ACL | UPDATE_ACL |
- DELETE_ACL | REFERENCES_ACL);
+ const privilege_t privileges(COL_DML_ACLS | REFERENCES_ACL);
// Check if tablename is valid or not.
DBUG_ASSERT(table_name.str != NULL);
@@ -7302,8 +7321,17 @@ long max_stack_used;
corresponding exec. (Thus we only have to check in fix_fields.)
- Passing to check_stack_overrun() prevents the compiler from removing it.
*/
-bool check_stack_overrun(THD *thd, long margin,
- uchar *buf __attribute__((unused)))
+
+bool
+#if defined __GNUC__ && !defined __clang__
+/*
+ Do not optimize the function in order to preserve a stack variable creation.
+ Otherwise, the variable pointed as "buf" can be removed due to a missing
+ usage.
+ */
+__attribute__((optimize("-O0")))
+#endif
+check_stack_overrun(THD *thd, long margin, uchar *buf __attribute__((unused)))
{
long stack_used;
DBUG_ASSERT(thd == current_thd);
@@ -7345,11 +7373,11 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, size_t *yystacksize)
old_info= *yystacksize;
*yystacksize= set_zone((int)(*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX);
if (!(state->yacc_yyvs= (uchar*)
- my_realloc(state->yacc_yyvs,
+ my_realloc(key_memory_bison_stack, state->yacc_yyvs,
*yystacksize*sizeof(**yyvs),
MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
!(state->yacc_yyss= (uchar*)
- my_realloc(state->yacc_yyss,
+ my_realloc(key_memory_bison_stack, state->yacc_yyss,
*yystacksize*sizeof(**yyss),
MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
return 1;
@@ -7486,10 +7514,7 @@ void THD::reset_for_next_command(bool do_clear_error)
void
mysql_init_select(LEX *lex)
{
- SELECT_LEX *select_lex= lex->current_select;
- select_lex->init_select();
- lex->wild= 0;
- lex->exchange= 0;
+ lex->init_select();
}
@@ -7630,7 +7655,7 @@ void mysql_init_multi_delete(LEX *lex)
lex->sql_command= SQLCOM_DELETE_MULTI;
mysql_init_select(lex);
lex->first_select_lex()->select_limit= 0;
- lex->unit.select_limit_cnt= HA_POS_ERROR;
+ lex->unit.lim.set_unlimited();
lex->first_select_lex()->table_list.
save_and_clear(&lex->auxiliary_table_list);
lex->query_tables= 0;
@@ -7819,7 +7844,8 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
{
int error __attribute__((unused));
DBUG_ENTER("mysql_parse");
- DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on(););
+ DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on_MYSQLparse(););
+ DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on_ORAparse(););
/*
Warning.
@@ -8201,9 +8227,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
// Pure table aliases do not need to be locked:
if (ptr->db.str && !(table_options & TL_OPTION_ALIAS))
{
- ptr->mdl_request.init(MDL_key::TABLE, ptr->db.str, ptr->table_name.str,
- mdl_type,
- MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&ptr->mdl_request, MDL_key::TABLE, ptr->db.str,
+ ptr->table_name.str, mdl_type, MDL_TRANSACTION);
}
DBUG_RETURN(ptr);
}
@@ -9072,11 +9097,11 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ
*/
#ifdef WITH_WSREP
- if (((thd->security_ctx->master_access & SUPER_ACL) ||
+ if (((thd->security_ctx->master_access & PRIV_KILL_OTHER_USER_PROCESS) ||
thd->security_ctx->user_matches(tmp->security_ctx)) &&
!wsrep_thd_is_BF(tmp, false) && !tmp->wsrep_applier)
#else
- if ((thd->security_ctx->master_access & SUPER_ACL) ||
+ if ((thd->security_ctx->master_access & PRIV_KILL_OTHER_USER_PROCESS) ||
thd->security_ctx->user_matches(tmp->security_ctx))
#endif /* WITH_WSREP */
{
@@ -9129,7 +9154,8 @@ static my_bool kill_threads_callback(THD *thd, kill_threads_callback_arg *arg)
!strcmp(thd->security_ctx->host_or_ip, arg->user->host.str)) &&
!strcmp(thd->security_ctx->user, arg->user->user.str))
{
- if (!(arg->thd->security_ctx->master_access & SUPER_ACL) &&
+ if (!(arg->thd->security_ctx->master_access &
+ PRIV_KILL_OTHER_USER_PROCESS) &&
!arg->thd->security_ctx->user_matches(thd->security_ctx))
return 1;
if (!arg->threads_to_kill.push_back(thd, arg->thd->mem_root))
@@ -9211,8 +9237,8 @@ void sql_kill(THD *thd, longlong id, killed_state state, killed_type type)
}
-static
-void sql_kill_user(THD *thd, LEX_USER *user, killed_state state)
+static void __attribute__ ((noinline))
+sql_kill_user(THD *thd, LEX_USER *user, killed_state state)
{
uint error;
ha_rows rows;
@@ -9373,7 +9399,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
check_grant(thd, SELECT_ACL, table, FALSE, 1, FALSE)))
DBUG_RETURN(TRUE);
- table->grant.orig_want_privilege= 0;
+ table->grant.orig_want_privilege= NO_ACL;
table->table_in_first_from_clause= 1;
}
/*
@@ -9634,9 +9660,9 @@ bool insert_precheck(THD *thd, TABLE_LIST *tables)
Check that we have modify privileges for the first table and
select privileges for the rest
*/
- ulong privilege= (INSERT_ACL |
- (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
- (lex->value_list.elements ? UPDATE_ACL : 0));
+ privilege_t privilege= (INSERT_ACL |
+ (lex->duplicates == DUP_REPLACE ? DELETE_ACL : NO_ACL) |
+ (lex->value_list.elements ? UPDATE_ACL : NO_ACL));
if (check_one_table_access(thd, privilege, tables))
DBUG_RETURN(TRUE);
@@ -9696,7 +9722,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
{
LEX *lex= thd->lex;
SELECT_LEX *select_lex= lex->first_select_lex();
- ulong want_priv;
+ privilege_t want_priv(NO_ACL);
bool error= TRUE; // Error message is given
DBUG_ENTER("create_table_precheck");
@@ -9705,8 +9731,8 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
CREATE TABLE ... SELECT, also require INSERT.
*/
- want_priv= lex->tmp_table() ? CREATE_TMP_ACL :
- (CREATE_ACL | (select_lex->item_list.elements ? INSERT_ACL : 0));
+ want_priv= lex->tmp_table() ? CREATE_TMP_ACL :
+ (CREATE_ACL | (select_lex->item_list.elements ? INSERT_ACL : NO_ACL));
/* CREATE OR REPLACE on not temporary tables require DROP_ACL */
if (lex->create_info.or_replace() && !lex->tmp_table())
@@ -10045,10 +10071,10 @@ int path_starts_from_data_home_dir(const char *path)
if (lower_case_file_system)
{
- if (!my_strnncoll(default_charset_info, (const uchar*) path,
- mysql_unpacked_real_data_home_len,
- (const uchar*) mysql_unpacked_real_data_home,
- mysql_unpacked_real_data_home_len))
+ if (!default_charset_info->strnncoll(path,
+ mysql_unpacked_real_data_home_len,
+ mysql_unpacked_real_data_home,
+ mysql_unpacked_real_data_home_len))
{
DBUG_PRINT("error", ("Path is part of mysql_real_data_home"));
DBUG_RETURN(1);
diff --git a/sql/sql_parse.h b/sql/sql_parse.h
index 1d25b898ca4..6b0ee75b57b 100644
--- a/sql/sql_parse.h
+++ b/sql/sql_parse.h
@@ -41,7 +41,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables);
int mysql_multi_update_prepare(THD *thd);
int mysql_multi_delete_prepare(THD *thd);
-bool mysql_insert_select_prepare(THD *thd);
+bool mysql_insert_select_prepare(THD *thd,select_result *sel_res);
bool update_precheck(THD *thd, TABLE_LIST *tables);
bool delete_precheck(THD *thd, TABLE_LIST *tables);
bool insert_precheck(THD *thd, TABLE_LIST *tables);
@@ -143,32 +143,32 @@ inline bool check_identifier_name(LEX_CSTRING *str)
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
-bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables);
-bool check_single_table_access(THD *thd, ulong privilege,
- TABLE_LIST *tables, bool no_errors);
-bool check_routine_access(THD *thd,ulong want_access,
+bool check_one_table_access(THD *thd, privilege_t privilege, TABLE_LIST *tables);
+bool check_single_table_access(THD *thd, privilege_t privilege,
+ TABLE_LIST *tables, bool no_errors);
+bool check_routine_access(THD *thd, privilege_t want_access,
const LEX_CSTRING *db,
const LEX_CSTRING *name,
const Sp_handler *sph, bool no_errors);
-bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
+bool check_some_access(THD *thd, privilege_t want_access, TABLE_LIST *table);
bool check_some_routine_access(THD *thd, const char *db, const char *name,
const Sp_handler *sph);
-bool check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
+bool check_table_access(THD *thd, privilege_t requirements,TABLE_LIST *tables,
bool any_combination_of_privileges_will_do,
uint number,
bool no_errors);
#else
-inline bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables)
+inline bool check_one_table_access(THD *thd, privilege_t privilege, TABLE_LIST *tables)
{ return false; }
-inline bool check_single_table_access(THD *thd, ulong privilege,
- TABLE_LIST *tables, bool no_errors)
+inline bool check_single_table_access(THD *thd, privilege_t privilege,
+ TABLE_LIST *tables, bool no_errors)
{ return false; }
-inline bool check_routine_access(THD *thd,ulong want_access,
+inline bool check_routine_access(THD *thd, privilege_t want_access,
const LEX_CSTRING *db,
const LEX_CSTRING *name,
const Sp_handler *sph, bool no_errors)
{ return false; }
-inline bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
+inline bool check_some_access(THD *thd, privilege_t want_access, TABLE_LIST *table)
{
table->grant.privilege= want_access;
return false;
@@ -178,7 +178,7 @@ inline bool check_some_routine_access(THD *thd, const char *db,
const Sp_handler *sph)
{ return false; }
inline bool
-check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
+check_table_access(THD *thd, privilege_t requirements,TABLE_LIST *tables,
bool any_combination_of_privileges_will_do,
uint number,
bool no_errors)
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 12198d34c88..f722dc54fb4 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2005, 2017, Oracle and/or its affiliates.
- Copyright (c) 2009, 2018, MariaDB
+ Copyright (c) 2009, 2020, 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
@@ -1864,7 +1864,7 @@ bool field_is_partition_charset(Field *field)
DESCRIPTION
We will check in this routine that the fields of the partition functions
do not contain unallowed parts. It can also be used to check if there
- are fields that require special care by calling my_strnxfrm before
+ are fields that require special care by calling strnxfrm before
calling the functions to calculate partition id.
*/
@@ -2013,7 +2013,7 @@ bool fix_partition_func(THD *thd, TABLE *table, bool is_create_table_ind)
else
{
if (part_info->part_type == VERSIONING_PARTITION &&
- part_info->vers_setup_expression(thd))
+ part_info->vers_fix_field_list(thd))
goto end;
if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
table, FALSE, is_create_table_ind)))
@@ -2241,80 +2241,6 @@ static int add_partition_options(String *str, partition_element *p_elem)
/*
- Check partition fields for result type and if they need
- to check the character set.
-
- SYNOPSIS
- check_part_field()
- sql_type Type provided by user
- field_name Name of field, used for error handling
- result_type Out value: Result type of field
- need_cs_check Out value: Do we need character set check
-
- RETURN VALUES
- TRUE Error
- FALSE Ok
-*/
-
-static int check_part_field(enum_field_types sql_type,
- const char *field_name,
- Item_result *result_type,
- bool *need_cs_check)
-{
- if (sql_type >= MYSQL_TYPE_TINY_BLOB &&
- sql_type <= MYSQL_TYPE_BLOB)
- {
- my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR, MYF(0));
- return TRUE;
- }
- switch (sql_type)
- {
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_LONGLONG:
- case MYSQL_TYPE_INT24:
- *result_type= INT_RESULT;
- *need_cs_check= FALSE;
- return FALSE;
- case MYSQL_TYPE_NEWDATE:
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_TIME2:
- case MYSQL_TYPE_DATETIME2:
- *result_type= STRING_RESULT;
- *need_cs_check= TRUE;
- return FALSE;
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_STRING:
- case MYSQL_TYPE_VAR_STRING:
- *result_type= STRING_RESULT;
- *need_cs_check= TRUE;
- return FALSE;
- case MYSQL_TYPE_NEWDECIMAL:
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_TIMESTAMP:
- case MYSQL_TYPE_TIMESTAMP2:
- case MYSQL_TYPE_NULL:
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_DOUBLE:
- case MYSQL_TYPE_BIT:
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_GEOMETRY:
- goto error;
- default:
- goto error;
- }
-error:
- my_error(ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD, MYF(0),
- field_name);
- return TRUE;
-}
-
-
-/*
Find the given field's Create_field object using name of field
SYNOPSIS
@@ -2377,8 +2303,7 @@ static int add_column_list_values(String *str, partition_info *part_info,
else
{
CHARSET_INFO *field_cs;
- bool need_cs_check= FALSE;
- Item_result result_type= STRING_RESULT;
+ const Type_handler *th= NULL;
/*
This function is called at a very early stage, even before
@@ -2396,57 +2321,24 @@ static int add_column_list_values(String *str, partition_info *part_info,
my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
return 1;
}
- if (check_part_field(sql_field->real_field_type(),
- sql_field->field_name.str,
- &result_type,
- &need_cs_check))
+ th= sql_field->type_handler();
+ if (th->partition_field_check(sql_field->field_name, item_expr))
return 1;
- if (need_cs_check)
- field_cs= get_sql_field_charset(sql_field, create_info);
- else
- field_cs= NULL;
+ field_cs= get_sql_field_charset(sql_field, create_info);
}
else
{
Field *field= part_info->part_field_array[i];
- result_type= field->result_type();
- if (check_part_field(field->real_type(),
- field->field_name.str,
- &result_type,
- &need_cs_check))
+ th= field->type_handler();
+ if (th->partition_field_check(field->field_name, item_expr))
return 1;
- DBUG_ASSERT(result_type == field->result_type());
- if (need_cs_check)
- field_cs= field->charset();
- else
- field_cs= NULL;
+ field_cs= field->charset();
}
- if (result_type != item_expr->result_type())
- {
- my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
+ if (th->partition_field_append_value(str, item_expr, field_cs,
+ alter_info == NULL ?
+ PARTITION_VALUE_PRINT_MODE_SHOW:
+ PARTITION_VALUE_PRINT_MODE_FRM))
return 1;
- }
- if (field_cs && field_cs != item_expr->collation.collation)
- {
- if (!(item_expr= convert_charset_partition_constant(item_expr,
- field_cs)))
- {
- my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
- return 1;
- }
- }
- {
- StringBuffer<MAX_KEY_LENGTH> buf;
- String val_conv, *res;
- val_conv.set_charset(system_charset_info);
- res= item_expr->val_str(&buf);
- if (get_cs_converted_part_value_from_string(current_thd,
- item_expr, res,
- &val_conv, field_cs,
- (bool)(alter_info != NULL)))
- return 1;
- err+= str->append(val_conv);
- }
}
}
if (i != (num_elements - 1))
@@ -2587,11 +2479,13 @@ char *generate_partition_syntax_for_frm(THD *thd, partition_info *part_info,
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;
+ Sql_mode_instant_remove sms(thd, MODE_ANSI_QUOTES);
char *res= generate_partition_syntax(thd, part_info, buf_length,
true, create_info, alter_info);
- thd->variables.sql_mode= old_mode;
+ DBUG_EXECUTE_IF("generate_partition_syntax_for_frm",
+ push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, ER_YES,
+ ErrConvString(res, (uint32) *buf_length,
+ system_charset_info).ptr()););
return res;
}
@@ -2675,11 +2569,21 @@ char *generate_partition_syntax(THD *thd, partition_info *part_info,
err+= str.append(STRING_WITH_LEN("INTERVAL "));
err+= append_interval(&str, vers_info->interval.type,
vers_info->interval.step);
+ err+= str.append(STRING_WITH_LEN(" STARTS "));
if (create_info) // not SHOW CREATE
{
- err+= str.append(STRING_WITH_LEN(" STARTS "));
err+= str.append_ulonglong(vers_info->interval.start);
}
+ else
+ {
+ MYSQL_TIME ltime;
+ char ctime[MAX_DATETIME_WIDTH + 1];
+ thd->variables.time_zone->gmt_sec_to_TIME(&ltime, vers_info->interval.start);
+ uint ctime_len= my_datetime_to_str(&ltime, ctime, 0);
+ err+= str.append(STRING_WITH_LEN("TIMESTAMP'"));
+ err+= str.append(ctime, ctime_len);
+ err+= str.append('\'');
+ }
}
if (vers_info->limit)
{
@@ -3067,8 +2971,8 @@ static void copy_to_part_field_buffers(Field **ptr,
if (field->type() == MYSQL_TYPE_VARCHAR)
{
uint len_bytes= ((Field_varstring*)field)->length_bytes;
- my_strnxfrm(cs, field_buf + len_bytes, max_len,
- field->ptr + len_bytes, data_len);
+ cs->strnxfrm(field_buf + len_bytes, max_len,
+ field->ptr + len_bytes, data_len);
if (len_bytes == 1)
*field_buf= (uchar) data_len;
else
@@ -3076,8 +2980,8 @@ static void copy_to_part_field_buffers(Field **ptr,
}
else
{
- my_strnxfrm(cs, field_buf, max_len,
- field->ptr, max_len);
+ cs->strnxfrm(field_buf, max_len,
+ field->ptr, max_len);
}
field->ptr= field_buf;
}
@@ -4901,7 +4805,6 @@ static void check_datadir_altered_for_innodb(THD *thd,
uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
HA_CREATE_INFO *create_info,
- Alter_table_ctx *alter_ctx,
bool *partition_changed,
bool *fast_alter_table)
{
@@ -4996,8 +4899,8 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
object to allow fast_alter_partition_table to perform the changes.
*/
DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE,
- alter_ctx->db.str,
- alter_ctx->table_name.str,
+ table->s->db.str,
+ table->s->table_name.str,
MDL_INTENTION_EXCLUSIVE));
tab_part_info= table->part_info;
@@ -7597,7 +7500,7 @@ void append_row_to_str(String &str, const uchar *row, TABLE *table)
rec= row;
/* Create a new array of all read fields. */
- fields= (Field**) my_malloc(sizeof(void*) * (num_fields + 1),
+ fields= (Field**) my_malloc(PSI_INSTRUMENT_ME, sizeof(void*) * (num_fields + 1),
MYF(0));
if (!fields)
return;
diff --git a/sql/sql_partition.h b/sql/sql_partition.h
index ea197a6fc2c..58ba82dcd9f 100644
--- a/sql/sql_partition.h
+++ b/sql/sql_partition.h
@@ -98,12 +98,6 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
const key_range *key_spec,
part_id_range *part_spec);
uint get_partition_field_store_length(Field *field);
-int get_cs_converted_part_value_from_string(THD *thd,
- Item *item,
- String *input_str,
- String *output_str,
- CHARSET_INFO *cs,
- bool use_hex);
void get_full_part_id_from_key(const TABLE *table, uchar *buf,
KEY *key_info,
const key_range *key_spec,
@@ -268,7 +262,6 @@ bool set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
enum partition_state part_state);
uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
HA_CREATE_INFO *create_info,
- Alter_table_ctx *alter_ctx,
bool *partition_changed,
bool *fast_alter_table);
char *generate_partition_syntax(THD *thd, partition_info *part_info,
diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc
index 54484846609..92ac1b2ce4c 100644
--- a/sql/sql_partition_admin.cc
+++ b/sql/sql_partition_admin.cc
@@ -63,7 +63,7 @@ bool Sql_cmd_alter_table_exchange_partition::execute(THD *thd)
*/
IF_DBUG(HA_CREATE_INFO create_info(lex->create_info);,)
Alter_info alter_info(lex->alter_info, thd->mem_root);
- ulong priv_needed= ALTER_ACL | DROP_ACL | INSERT_ACL | CREATE_ACL;
+ privilege_t priv_needed(ALTER_ACL | DROP_ACL | INSERT_ACL | CREATE_ACL);
DBUG_ENTER("Sql_cmd_alter_table_exchange_partition::execute");
@@ -826,7 +826,7 @@ bool Sql_cmd_alter_table_truncate_partition::execute(THD *thd)
DBUG_RETURN(TRUE);
tdc_remove_table(thd, TDC_RT_REMOVE_NOT_OWN, first_table->db.str,
- first_table->table_name.str, FALSE);
+ first_table->table_name.str);
partition= (ha_partition*) first_table->table->file;
/* Invoke the handler method responsible for truncating the partition. */
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 5fd3d0f0f6b..1d18b0ef392 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2005, 2018, Oracle and/or its affiliates.
- Copyright (c) 2010, 2018, MariaDB Corporation
+ Copyright (c) 2010, 2020, 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
@@ -28,7 +28,6 @@
#include "sql_table.h"
#include "sql_show.h" // remove_status_vars, add_status_vars
#include "strfunc.h" // find_set
-#include "sql_acl.h" // *_ACL
#include "records.h" // init_read_record, end_read_record
#include <my_pthread.h>
#include <my_getopt.h>
@@ -38,8 +37,16 @@
#include <mysql/plugin_auth.h>
#include <mysql/plugin_password_validation.h>
#include <mysql/plugin_encryption.h>
+#include <mysql/plugin_data_type.h>
+#include <mysql/plugin_function.h>
#include "sql_plugin_compat.h"
+static PSI_memory_key key_memory_plugin_mem_root;
+static PSI_memory_key key_memory_plugin_int_mem_root;
+static PSI_memory_key key_memory_mysql_plugin;
+static PSI_memory_key key_memory_mysql_plugin_dl;
+static PSI_memory_key key_memory_plugin_bookmark;
+
#ifdef HAVE_LINK_H
#include <link.h>
#endif
@@ -90,7 +97,9 @@ const LEX_CSTRING plugin_type_names[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{ STRING_WITH_LEN("REPLICATION") },
{ STRING_WITH_LEN("AUTHENTICATION") },
{ STRING_WITH_LEN("PASSWORD VALIDATION") },
- { STRING_WITH_LEN("ENCRYPTION") }
+ { STRING_WITH_LEN("ENCRYPTION") },
+ { STRING_WITH_LEN("DATA TYPE") },
+ { STRING_WITH_LEN("FUNCTION") }
};
extern int initialize_schema_table(st_plugin_int *plugin);
@@ -102,6 +111,8 @@ extern int finalize_audit_plugin(st_plugin_int *plugin);
extern int initialize_encryption_plugin(st_plugin_int *plugin);
extern int finalize_encryption_plugin(st_plugin_int *plugin);
+extern int initialize_data_type_plugin(st_plugin_int *plugin);
+
/*
The number of elements in both plugin_type_initialize and
plugin_type_deinitialize should equal to the number of plugins
@@ -110,13 +121,15 @@ extern int finalize_encryption_plugin(st_plugin_int *plugin);
plugin_type_init plugin_type_initialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
0, ha_initialize_handlerton, 0, 0,initialize_schema_table,
- initialize_audit_plugin, 0, 0, 0, initialize_encryption_plugin
+ initialize_audit_plugin, 0, 0, 0, initialize_encryption_plugin,
+ initialize_data_type_plugin, 0
};
plugin_type_init plugin_type_deinitialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
0, ha_finalize_handlerton, 0, 0, finalize_schema_table,
- finalize_audit_plugin, 0, 0, 0, finalize_encryption_plugin
+ finalize_audit_plugin, 0, 0, 0, finalize_encryption_plugin, 0,
+ 0 // FUNCTION
};
/*
@@ -128,6 +141,8 @@ static int plugin_type_initialization_order[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
MYSQL_DAEMON_PLUGIN,
MariaDB_ENCRYPTION_PLUGIN,
+ MariaDB_DATA_TYPE_PLUGIN,
+ MariaDB_FUNCTION_PLUGIN,
MYSQL_STORAGE_ENGINE_PLUGIN,
MYSQL_INFORMATION_SCHEMA_PLUGIN,
MYSQL_FTPARSER_PLUGIN,
@@ -169,7 +184,9 @@ static int min_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
MYSQL_REPLICATION_INTERFACE_VERSION,
MIN_AUTHENTICATION_INTERFACE_VERSION,
MariaDB_PASSWORD_VALIDATION_INTERFACE_VERSION,
- MariaDB_ENCRYPTION_INTERFACE_VERSION
+ MariaDB_ENCRYPTION_INTERFACE_VERSION,
+ MariaDB_DATA_TYPE_INTERFACE_VERSION,
+ MariaDB_FUNCTION_INTERFACE_VERSION
};
static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
@@ -182,7 +199,9 @@ static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
MYSQL_REPLICATION_INTERFACE_VERSION,
MYSQL_AUTHENTICATION_INTERFACE_VERSION,
MariaDB_PASSWORD_VALIDATION_INTERFACE_VERSION,
- MariaDB_ENCRYPTION_INTERFACE_VERSION
+ MariaDB_ENCRYPTION_INTERFACE_VERSION,
+ MariaDB_DATA_TYPE_INTERFACE_VERSION,
+ MariaDB_FUNCTION_INTERFACE_VERSION
};
static struct
@@ -440,9 +459,8 @@ static struct st_plugin_dl *plugin_dl_find(const LEX_CSTRING *dl)
{
tmp= *dynamic_element(&plugin_dl_array, i, struct st_plugin_dl **);
if (tmp->ref_count &&
- ! my_strnncoll(files_charset_info,
- (const uchar *)dl->str, dl->length,
- (const uchar *)tmp->dl.str, tmp->dl.length))
+ ! files_charset_info->strnncoll(dl->str, dl->length,
+ tmp->dl.str, tmp->dl.length))
DBUG_RETURN(tmp);
}
DBUG_RETURN(0);
@@ -560,7 +578,7 @@ static my_bool read_mysql_plugin_info(struct st_plugin_dl *plugin_dl,
/* no op */;
cur= (struct st_maria_plugin*)
- my_malloc((i + 1) * sizeof(struct st_maria_plugin),
+ my_malloc(key_memory_mysql_plugin, (i + 1) * sizeof(struct st_maria_plugin),
MYF(MY_ZEROFILL|MY_WME));
if (!cur)
{
@@ -680,7 +698,7 @@ static my_bool read_maria_plugin_info(struct st_plugin_dl *plugin_dl,
/* no op */;
cur= (struct st_maria_plugin*)
- my_malloc((i + 1) * sizeof(struct st_maria_plugin),
+ my_malloc(key_memory_mysql_plugin, (i + 1) * sizeof(struct st_maria_plugin),
MYF(MY_ZEROFILL|MY_WME));
if (!cur)
{
@@ -805,7 +823,8 @@ static st_plugin_dl *plugin_dl_add(const LEX_CSTRING *dl, myf MyFlags)
if (plugin_dl.nbackups)
{
size_t bytes= plugin_dl.nbackups * sizeof(plugin_dl.ptr_backup[0]);
- plugin_dl.ptr_backup= (st_ptr_backup *)my_malloc(bytes, MYF(0));
+ plugin_dl.ptr_backup= (st_ptr_backup *)my_malloc(key_memory_mysql_plugin_dl,
+ bytes, MYF(0));
if (!plugin_dl.ptr_backup)
{
restore_ptr_backup(plugin_dl.nbackups, tmp_backup);
@@ -817,7 +836,8 @@ static st_plugin_dl *plugin_dl_add(const LEX_CSTRING *dl, myf MyFlags)
/* Duplicate and convert dll name */
plugin_dl.dl.length= dl->length * files_charset_info->mbmaxlen + 1;
- if (! (plugin_dl.dl.str= (char*) my_malloc(plugin_dl.dl.length, MYF(0))))
+ if (! (plugin_dl.dl.str= (char*) my_malloc(key_memory_mysql_plugin_dl,
+ plugin_dl.dl.length, MYF(0))))
{
my_error(ER_OUTOFMEMORY, MyFlags,
static_cast<int>(plugin_dl.dl.length));
@@ -964,7 +984,8 @@ static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc,
memory manager and/or valgrind to track locked references and
double unlocks to aid resolving reference counting problems.
*/
- if (!(plugin= (plugin_ref) my_malloc(sizeof(pi), MYF(MY_WME))))
+ if (!(plugin= (plugin_ref) my_malloc(PSI_NOT_INSTRUMENTED, sizeof(pi),
+ MYF(MY_WME))))
DBUG_RETURN(NULL);
*plugin= pi;
@@ -1114,9 +1135,8 @@ static enum install_status plugin_add(MEM_ROOT *tmp_root, bool if_not_exists,
tmp.plugin_dl->mariaversion == 0))
continue; // unsupported plugin type
- if (name->str && my_strnncoll(system_charset_info,
- (const uchar *)name->str, name->length,
- (const uchar *)tmp.name.str, tmp.name.length))
+ if (name->str && system_charset_info->strnncoll(name->str, name->length,
+ tmp.name.str, tmp.name.length))
continue; // plugin name doesn't match
if (!name->str &&
@@ -1174,7 +1194,8 @@ static enum install_status plugin_add(MEM_ROOT *tmp_root, bool if_not_exists,
goto err;
if (my_hash_insert(&plugin_hash[plugin->type], (uchar*)tmp_plugin_ptr))
tmp_plugin_ptr->state= PLUGIN_IS_FREED;
- init_alloc_root(&tmp_plugin_ptr->mem_root, "plugin", 4096, 4096, MYF(0));
+ init_alloc_root(key_memory_plugin_int_mem_root, &tmp_plugin_ptr->mem_root,
+ 4096, 4096, MYF(0));
if (name->str)
DBUG_RETURN(INSTALL_GOOD); // all done
@@ -1529,6 +1550,15 @@ static PSI_mutex_info all_plugin_mutexes[]=
{ &key_LOCK_plugin, "LOCK_plugin", PSI_FLAG_GLOBAL}
};
+static PSI_memory_info all_plugin_memory[]=
+{
+ { &key_memory_plugin_mem_root, "plugin_mem_root", PSI_FLAG_GLOBAL},
+ { &key_memory_plugin_int_mem_root, "plugin_int_mem_root", 0},
+ { &key_memory_mysql_plugin_dl, "mysql_plugin_dl", 0},
+ { &key_memory_mysql_plugin, "mysql_plugin", 0},
+ { &key_memory_plugin_bookmark, "plugin_bookmark", PSI_FLAG_GLOBAL}
+};
+
static void init_plugin_psi_keys(void)
{
const char* category= "sql";
@@ -1539,7 +1569,12 @@ static void init_plugin_psi_keys(void)
count= array_elements(all_plugin_mutexes);
PSI_server->register_mutex(category, all_plugin_mutexes, count);
+
+ count= array_elements(all_plugin_memory);
+ mysql_memory_register(category, all_plugin_memory, count);
}
+#else
+static void init_plugin_psi_keys(void) {}
#endif /* HAVE_PSI_INTERFACE */
/*
@@ -1566,11 +1601,13 @@ int plugin_init(int *argc, char **argv, int flags)
dlopen_count =0;
- init_alloc_root(&plugin_mem_root, "plugin", 4096, 4096, MYF(0));
- init_alloc_root(&plugin_vars_mem_root, "plugin_vars", 4096, 4096, MYF(0));
- init_alloc_root(&tmp_root, "plugin_tmp", 4096, 4096, MYF(0));
+ init_plugin_psi_keys();
- if (my_hash_init(&bookmark_hash, &my_charset_bin, 32, 0, 0,
+ init_alloc_root(key_memory_plugin_mem_root, &plugin_mem_root, 4096, 4096, MYF(0));
+ init_alloc_root(key_memory_plugin_mem_root, &plugin_vars_mem_root, 4096, 4096, MYF(0));
+ init_alloc_root(PSI_NOT_INSTRUMENTED, &tmp_root, 4096, 4096, MYF(0));
+
+ if (my_hash_init(key_memory_plugin_bookmark, &bookmark_hash, &my_charset_bin, 32, 0, 0,
get_bookmark_hash_key, NULL, HASH_UNIQUE))
goto err;
@@ -1578,15 +1615,15 @@ int plugin_init(int *argc, char **argv, int flags)
The 80 is from 2016-04-27 when we had 71 default plugins
Big enough to avoid many mallocs even in future
*/
- if (my_init_dynamic_array(&plugin_dl_array,
+ if (my_init_dynamic_array(key_memory_mysql_plugin_dl, &plugin_dl_array,
sizeof(struct st_plugin_dl *), 16, 16, MYF(0)) ||
- my_init_dynamic_array(&plugin_array,
+ my_init_dynamic_array(key_memory_mysql_plugin, &plugin_array,
sizeof(struct st_plugin_int *), 80, 32, MYF(0)))
goto err;
for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
{
- if (my_hash_init(&plugin_hash[i], system_charset_info, 32, 0, 0,
+ if (my_hash_init(key_memory_plugin_mem_root, &plugin_hash[i], system_charset_info, 32, 0, 0,
get_plugin_hash_key, NULL, HASH_UNIQUE))
goto err;
}
@@ -1620,8 +1657,7 @@ int plugin_init(int *argc, char **argv, int flags)
for (plugin= *builtins; plugin->info; plugin++)
{
if (opt_ignore_builtin_innodb &&
- !my_strnncoll(&my_charset_latin1, (const uchar*) plugin->name,
- 6, (const uchar*) "InnoDB", 6))
+ !my_charset_latin1.strnncoll(plugin->name, 6, "InnoDB", 6))
continue;
bzero(&tmp, sizeof(tmp));
@@ -2203,6 +2239,7 @@ bool mysql_install_plugin(THD *thd, const LEX_CSTRING *name,
mysql_audit_acquire_plugins(thd, event_class_mask);
mysql_mutex_lock(&LOCK_plugin);
+ DEBUG_SYNC(thd, "acquired_LOCK_plugin");
error= plugin_add(thd->mem_root, thd->lex->create_info.if_not_exists(),
name, &dl, MYF(0));
if (unlikely(error != INSTALL_GOOD))
@@ -2821,7 +2858,8 @@ static void update_func_str(THD *thd, struct st_mysql_sys_var *var,
{
char *old= *(char**) tgt;
if (value)
- *(char**) tgt= my_strdup(value, MYF(0));
+ *(char**) tgt= my_strdup(key_memory_global_system_variables,
+ value, MYF(0));
else
*(char**) tgt= 0;
my_free(old);
@@ -2965,10 +3003,12 @@ static st_bookmark *register_var(const char *plugin, const char *name,
if (new_size > global_variables_dynamic_size)
{
global_system_variables.dynamic_variables_ptr= (char*)
- my_realloc(global_system_variables.dynamic_variables_ptr, new_size,
+ my_realloc(key_memory_global_system_variables,
+ global_system_variables.dynamic_variables_ptr, new_size,
MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
max_system_variables.dynamic_variables_ptr= (char*)
- my_realloc(max_system_variables.dynamic_variables_ptr, new_size,
+ my_realloc(key_memory_global_system_variables,
+ max_system_variables.dynamic_variables_ptr, new_size,
MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
/*
Clear the new variable value space. This is required for string
@@ -3010,7 +3050,8 @@ void sync_dynamic_session_variables(THD* thd, bool global_lock)
uint idx;
thd->variables.dynamic_variables_ptr= (char*)
- my_realloc(thd->variables.dynamic_variables_ptr,
+ my_realloc(key_memory_THD_variables,
+ thd->variables.dynamic_variables_ptr,
global_variables_dynamic_size,
MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
@@ -3044,7 +3085,7 @@ void sync_dynamic_session_variables(THD* thd, bool global_lock)
{
char **pp= (char**) (thd->variables.dynamic_variables_ptr + v->offset);
if (*pp)
- *pp= my_strdup(*pp, MYF(MY_WME|MY_FAE));
+ *pp= my_strdup(key_memory_THD_variables, *pp, MYF(MY_WME|MY_FAE));
}
}
@@ -3901,7 +3942,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
(opt->flags & PLUGIN_VAR_MEMALLOC))
{
char *def_val= *(char**)var_def_ptr(opt);
- *(char**)val= def_val ? my_strdup(def_val, MYF(0)) : NULL;
+ *(char**)val= def_val ? my_strdup(PSI_INSTRUMENT_ME, def_val, MYF(0)) : NULL;
}
else
memcpy(val, var_def_ptr(opt), var_storage_size(opt->flags));
@@ -3972,13 +4013,19 @@ static my_option *construct_help_options(MEM_ROOT *mem_root,
DBUG_RETURN(opts);
}
-extern "C" my_bool mark_changed(int, const struct my_option *, char *);
-my_bool mark_changed(int, const struct my_option *opt, char *)
+extern "C" my_bool mark_changed(const struct my_option *, char *, const char *);
+my_bool mark_changed(const struct my_option *opt, char *, const char *filename)
{
if (opt->app_type)
{
sys_var *var= (sys_var*) opt->app_type;
- var->value_origin= sys_var::CONFIG;
+ if (*filename)
+ {
+ var->origin_filename= filename;
+ var->value_origin= sys_var::CONFIG;
+ }
+ else
+ var->value_origin= sys_var::COMMAND_LINE;
}
return 0;
}
@@ -4151,7 +4198,7 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
if (tmp->plugin->system_vars)
{
- for (opt= tmp->plugin->system_vars; *opt; opt++)
+ if (mysqld_server_started)
{
/*
PLUGIN_VAR_STR command-line options without PLUGIN_VAR_MEMALLOC, point
@@ -4164,13 +4211,22 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
Thus, for all plugins loaded after the server was started,
we copy string values to a plugin's memroot.
*/
- if (mysqld_server_started &&
- (((*opt)->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_NOCMDOPT |
- PLUGIN_VAR_MEMALLOC)) == PLUGIN_VAR_STR))
+ for (opt= tmp->plugin->system_vars; *opt; opt++)
{
- sysvar_str_t* str= (sysvar_str_t *)*opt;
- if (*str->value)
- *str->value= strdup_root(mem_root, *str->value);
+ if ((((*opt)->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_NOCMDOPT |
+ PLUGIN_VAR_MEMALLOC)) == PLUGIN_VAR_STR))
+ {
+ sysvar_str_t* str= (sysvar_str_t *)*opt;
+ if (*str->value)
+ *str->value= strdup_root(mem_root, *str->value);
+ }
+ }
+ /* same issue with config file names */
+ for (my_option *mo=opts; mo->name; mo++)
+ {
+ sys_var *var= (sys_var*) mo->app_type;
+ if (var && var->value_origin == sys_var::CONFIG)
+ var->origin_filename= strdup_root(mem_root, var->origin_filename);
}
}
@@ -4323,9 +4379,7 @@ int thd_setspecific(MYSQL_THD thd, MYSQL_THD_KEY_T key, void *value)
void plugin_mutex_init()
{
-#ifdef HAVE_PSI_INTERFACE
init_plugin_psi_keys();
-#endif
mysql_mutex_init(key_LOCK_plugin, &LOCK_plugin, MY_MUTEX_INIT_FAST);
}
diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic
index c7ecfcd482e..2db426e7b57 100644
--- a/sql/sql_plugin_services.ic
+++ b/sql/sql_plugin_services.ic
@@ -1,5 +1,5 @@
/* Copyright (c) 2009, 2010, Oracle and/or its affiliates.
- Copyright (c) 2012, 2014, Monty Program Ab
+ Copyright (c) 2012, 2019, 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
@@ -17,6 +17,7 @@
/* support for Services */
#include <service_versions.h>
#include <mysql/service_wsrep.h>
+#include <mysql/service_thd_mdl.h>
struct st_service_ref {
const char *name;
@@ -173,7 +174,10 @@ static struct wsrep_service_st wsrep_handler = {
wsrep_get_sr_table_name,
wsrep_get_debug,
wsrep_commit_ordered,
- wsrep_thd_is_applying
+ wsrep_thd_is_applying,
+ wsrep_OSU_method_get,
+ wsrep_thd_has_ignored_error,
+ wsrep_thd_set_ignored_error
};
static struct thd_specifics_service_st thd_specifics_handler=
@@ -218,6 +222,11 @@ struct json_service_st json_handler=
json_unescape_json
};
+static struct thd_mdl_service_st thd_mdl_handler=
+{
+ thd_mdl_context
+};
+
static struct st_service_ref list_of_services[]=
{
{ "base64_service", VERSION_base64, &base64_handler },
@@ -241,6 +250,7 @@ static struct st_service_ref list_of_services[]=
{ "thd_timezone_service", VERSION_thd_timezone, &thd_timezone_handler },
{ "thd_wait_service", VERSION_thd_wait, &thd_wait_handler },
{ "wsrep_service", VERSION_wsrep, &wsrep_handler },
- { "json_service", VERSION_json, &json_handler }
+ { "json_service", VERSION_json, &json_handler },
+ { "thd_mdl_service", VERSION_thd_mdl, &thd_mdl_handler }
};
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 3f8a9df1efe..98ffc842196 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -99,7 +99,6 @@ When one supplies long data for a placeholder:
#include "sql_insert.h" // upgrade_lock_type_for_insert, mysql_prepare_insert
#include "sql_update.h" // mysql_prepare_update
#include "sql_db.h" // mysql_opt_change_db, mysql_change_db
-#include "sql_acl.h" // *_ACL
#include "sql_derived.h" // mysql_derived_prepare,
// mysql_handle_derived
#include "sql_cte.h"
@@ -122,6 +121,7 @@ When one supplies long data for a placeholder:
#include "lock.h" // MYSQL_OPEN_FORCE_SHARED_MDL
#include "sql_handler.h"
#include "transaction.h" // trans_rollback_implicit
+#include "mysql/psi/mysql_ps.h" // MYSQL_EXECUTE_PS
#include "wsrep_mysqld.h"
/**
@@ -160,6 +160,7 @@ public:
};
THD *thd;
+ PSI_prepared_stmt* m_prepared_stmt;
Select_fetch_protocol_binary result;
Item_param **param_array;
Server_side_cursor *cursor;
@@ -739,6 +740,8 @@ void Item_param::setup_conversion(THD *thd, uchar param_type)
*/
if (!h)
h= &type_handler_string;
+ else if (unsigned_flag)
+ h= h->type_handler_unsigned();
set_handler(h);
h->Item_param_setup_conversion(thd, this);
}
@@ -1357,7 +1360,7 @@ static int mysql_test_update(Prepared_statement *stmt,
TABLE_LIST *update_source_table;
SELECT_LEX *select= stmt->lex->first_select_lex();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- uint want_privilege;
+ privilege_t want_privilege(NO_ACL);
#endif
DBUG_ENTER("mysql_test_update");
@@ -1480,8 +1483,6 @@ static bool mysql_test_delete(Prepared_statement *stmt,
}
DBUG_RETURN(mysql_prepare_delete(thd, table_list,
- lex->first_select_lex()->with_wild,
- lex->first_select_lex()->item_list,
&lex->first_select_lex()->where,
&delete_while_scanning));
error:
@@ -1516,7 +1517,7 @@ static int mysql_test_select(Prepared_statement *stmt,
lex->first_select_lex()->context.resolve_in_select_list= TRUE;
- ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
+ privilege_t privilege(lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL);
if (tables)
{
if (check_table_access(thd, privilege, tables, FALSE, UINT_MAX, FALSE))
@@ -1933,20 +1934,21 @@ static int mysql_test_show_grants(Prepared_statement *stmt)
TRUE error, error message is set in THD
*/
-static int mysql_test_show_slave_status(Prepared_statement *stmt)
+static int mysql_test_show_slave_status(Prepared_statement *stmt,
+ bool show_all_slaves_stat)
{
DBUG_ENTER("mysql_test_show_slave_status");
THD *thd= stmt->thd;
List<Item> fields;
- show_master_info_get_fields(thd, &fields, thd->lex->verbose, 0);
-
+ show_master_info_get_fields(thd, &fields, show_all_slaves_stat, 0);
+
DBUG_RETURN(send_stmt_metadata(thd, stmt, &fields));
}
/**
- Validate and prepare for execution SHOW MASTER STATUS statement.
+ Validate and prepare for execution SHOW BINLOG STATUS statement.
@param stmt prepared statement
@@ -1956,9 +1958,9 @@ static int mysql_test_show_slave_status(Prepared_statement *stmt)
TRUE error, error message is set in THD
*/
-static int mysql_test_show_master_status(Prepared_statement *stmt)
+static int mysql_test_show_binlog_status(Prepared_statement *stmt)
{
- DBUG_ENTER("mysql_test_show_master_status");
+ DBUG_ENTER("mysql_test_show_binlog_status");
THD *thd= stmt->thd;
List<Item> fields;
@@ -2154,7 +2156,7 @@ static int mysql_insert_select_prepare_tester(THD *thd)
thd->lex->first_select_lex()->context.first_name_resolution_table=
second_table;
- return mysql_insert_select_prepare(thd);
+ return mysql_insert_select_prepare(thd, NULL);
}
@@ -2393,14 +2395,22 @@ static bool check_prepared_statement(Prepared_statement *stmt)
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
#ifndef EMBEDDED_LIBRARY
case SQLCOM_SHOW_SLAVE_STAT:
- if ((res= mysql_test_show_slave_status(stmt)) == 2)
{
- /* Statement and field info has already been sent */
- DBUG_RETURN(FALSE);
+ DBUG_ASSERT(thd->lex->m_sql_cmd);
+ Sql_cmd_show_slave_status *cmd;
+ cmd= dynamic_cast<Sql_cmd_show_slave_status*>(thd->lex->m_sql_cmd);
+ DBUG_ASSERT(cmd);
+ if ((res= mysql_test_show_slave_status(stmt,
+ cmd->is_show_all_slaves_stat()))
+ == 2)
+ {
+ /* Statement and field info has already been sent */
+ DBUG_RETURN(FALSE);
+ }
+ break;
}
- break;
- case SQLCOM_SHOW_MASTER_STAT:
- if ((res= mysql_test_show_master_status(stmt)) == 2)
+ case SQLCOM_SHOW_BINLOG_STAT:
+ if ((res= mysql_test_show_binlog_status(stmt)) == 2)
{
/* Statement and field info has already been sent */
DBUG_RETURN(FALSE);
@@ -2655,6 +2665,11 @@ void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length)
thd->protocol= &thd->protocol_binary;
+ /* Create PS table entry, set query text after rewrite. */
+ stmt->m_prepared_stmt= MYSQL_CREATE_PS(stmt, stmt->id,
+ thd->m_statement_psi,
+ stmt->name.str, stmt->name.length);
+
if (stmt->prepare(packet, packet_length))
{
/* Statement map deletes statement on erase */
@@ -2856,6 +2871,11 @@ void mysql_sql_stmt_prepare(THD *thd)
*/
Item_change_list_savepoint change_list_savepoint(thd);
+ /* Create PS table entry, set query text after rewrite. */
+ stmt->m_prepared_stmt= MYSQL_CREATE_PS(stmt, stmt->id,
+ thd->m_statement_psi,
+ stmt->name.str, stmt->name.length);
+
if (stmt->prepare(query.str, (uint) query.length))
{
/* Statement map deletes the statement on erase */
@@ -2863,7 +2883,7 @@ void mysql_sql_stmt_prepare(THD *thd)
}
else
{
- SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
+ thd->session_tracker.state_change.mark_as_changed(thd);
my_ok(thd, 0L, 0L, "Statement prepared");
}
change_list_savepoint.rollback(thd);
@@ -3251,6 +3271,8 @@ static void mysql_stmt_execute_common(THD *thd,
open_cursor= MY_TEST(cursor_flags & (ulong) CURSOR_TYPE_READ_ONLY);
thd->protocol= &thd->protocol_binary;
+ MYSQL_EXECUTE_PS(thd->m_statement_psi, stmt->m_prepared_stmt);
+
if (!bulk_op)
stmt->execute_loop(&expanded_query, open_cursor, packet, packet_end);
else
@@ -3360,6 +3382,8 @@ void mysql_sql_stmt_execute(THD *thd)
CALL p1('x');
*/
Item_change_list_savepoint change_list_savepoint(thd);
+ MYSQL_EXECUTE_PS(thd->m_statement_psi, stmt->m_prepared_stmt);
+
(void) stmt->execute_loop(&expanded_query, FALSE, NULL, NULL);
change_list_savepoint.rollback(thd);
thd->free_items(); // Free items created by execute_loop()
@@ -3543,7 +3567,7 @@ void mysql_sql_stmt_close(THD *thd)
else
{
stmt->deallocate();
- SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
+ thd->session_tracker.state_change.mark_as_changed(thd);
my_ok(thd);
}
}
@@ -3778,6 +3802,7 @@ Prepared_statement::Prepared_statement(THD *thd_arg)
STMT_INITIALIZED,
((++thd_arg->statement_id_counter) & STMT_ID_MASK)),
thd(thd_arg),
+ m_prepared_stmt(NULL),
result(thd_arg),
param_array(0),
cursor(0),
@@ -3791,10 +3816,9 @@ Prepared_statement::Prepared_statement(THD *thd_arg)
read_types(0),
m_sql_mode(thd->variables.sql_mode)
{
- init_sql_alloc(&main_mem_root, "Prepared_statement",
- thd_arg->variables.query_alloc_block_size,
- thd_arg->variables.query_prealloc_size,
- MYF(MY_THREAD_SPECIFIC));
+ init_sql_alloc(key_memory_prepared_statement_main_mem_root,
+ &main_mem_root, thd_arg->variables.query_alloc_block_size,
+ thd_arg->variables.query_prealloc_size, MYF(MY_THREAD_SPECIFIC));
*last_error= '\0';
}
@@ -3860,6 +3884,9 @@ Prepared_statement::~Prepared_statement()
DBUG_ENTER("Prepared_statement::~Prepared_statement");
DBUG_PRINT("enter",("stmt: %p cursor: %p",
this, cursor));
+
+ MYSQL_DESTROY_PS(m_prepared_stmt);
+
delete cursor;
/*
We have to call free on the items even if cleanup is called as some items,
@@ -4093,6 +4120,8 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
state= Query_arena::STMT_PREPARED;
flags&= ~ (uint) IS_IN_USE;
+ MYSQL_SET_PS_TEXT(m_prepared_stmt, query(), query_length());
+
/*
Log COM_EXECUTE to the general log. Note, that in case of SQL
prepared statements this causes two records to be output:
@@ -4499,18 +4528,18 @@ Prepared_statement::reprepare()
TRUE, &cur_db_changed)))
return TRUE;
- sql_mode_t save_sql_mode= thd->variables.sql_mode;
- thd->variables.sql_mode= m_sql_mode;
+ Sql_mode_instant_set sms(thd, m_sql_mode);
+
error= ((name.str && copy.set_name(&name)) ||
copy.prepare(query(), query_length()) ||
validate_metadata(&copy));
- thd->variables.sql_mode= save_sql_mode;
if (cur_db_changed)
mysql_change_db(thd, (LEX_CSTRING*) &saved_cur_db_name, TRUE);
if (likely(!error))
{
+ MYSQL_REPREPARE_PS(m_prepared_stmt);
swap_prepared_statement(&copy);
swap_parameter_array(param_array, copy.param_array, param_count);
#ifdef DBUG_ASSERT_EXISTS
@@ -4748,17 +4777,13 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
if (query_cache_send_result_to_client(thd, thd->query(),
thd->query_length()) <= 0)
{
- PSI_statement_locker *parent_locker;
MYSQL_QUERY_EXEC_START(thd->query(),
thd->thread_id,
thd->get_db(),
&thd->security_ctx->priv_user[0],
(char *) thd->security_ctx->host_or_ip,
1);
- parent_locker= thd->m_statement_psi;
- thd->m_statement_psi= NULL;
error= mysql_execute_command(thd);
- thd->m_statement_psi= parent_locker;
MYSQL_QUERY_EXEC_DONE(error);
}
else
@@ -4871,7 +4896,11 @@ bool Prepared_statement::execute_immediate(const char *query, uint query_len)
set_sql_prepare();
name= execute_immediate_stmt_name; // for DBUG_PRINT etc
- if (unlikely(prepare(query, query_len)))
+
+ m_prepared_stmt= MYSQL_CREATE_PS(this, id, thd->m_statement_psi,
+ name.str, name.length);
+
+ if (prepare(query, query_len))
DBUG_RETURN(true);
if (param_count != thd->lex->prepared_stmt.param_count())
@@ -4881,6 +4910,7 @@ bool Prepared_statement::execute_immediate(const char *query, uint query_len)
DBUG_RETURN(true);
}
+ MYSQL_EXECUTE_PS(thd->m_statement_psi, m_prepared_stmt);
(void) execute_loop(&expanded_query, FALSE, NULL, NULL);
deallocate_immediate();
DBUG_RETURN(false);
@@ -5380,8 +5410,8 @@ bool Protocol_local::send_result_set_metadata(List<Item> *columns, uint)
{
DBUG_ASSERT(m_rset == 0 && !alloc_root_inited(&m_rset_root));
- init_sql_alloc(&m_rset_root, "send_result_set_metadata",
- MEM_ROOT_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC));
+ init_sql_alloc(PSI_INSTRUMENT_ME, &m_rset_root, MEM_ROOT_BLOCK_SIZE, 0,
+ MYF(MY_THREAD_SPECIFIC));
if (! (m_rset= new (&m_rset_root) List<Ed_row>))
return TRUE;
diff --git a/sql/sql_priv.h b/sql/sql_priv.h
index 0d1c9881c17..7be2692a33b 100644
--- a/sql/sql_priv.h
+++ b/sql/sql_priv.h
@@ -229,6 +229,7 @@
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY (1ULL << 32)
#define OPTIMIZER_SWITCH_USE_ROWID_FILTER (1ULL << 33)
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FROM_HAVING (1ULL << 34)
+#define OPTIMIZER_SWITCH_NOT_NULL_RANGE_SCAN (1ULL << 35)
#define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \
OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \
@@ -389,7 +390,8 @@ enum enum_yes_no_unknown
/* sql_yacc.cc */
#ifndef DBUG_OFF
-extern void turn_parser_debug_on();
+extern void turn_parser_debug_on_MYSQLparse();
+extern void turn_parser_debug_on_ORAparse();
#endif
diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc
index f36805012b2..2a47aa846eb 100644
--- a/sql/sql_profile.cc
+++ b/sql/sql_profile.cc
@@ -32,7 +32,7 @@
#include "mariadb.h"
#include "sql_priv.h"
#include "sql_profile.h"
-#include "sql_show.h" // schema_table_store_record
+#include "sql_i_s.h" // schema_table_store_record
#include "sql_class.h" // THD
#ifdef _WIN32
@@ -60,30 +60,32 @@ int fill_query_profile_statistics_info(THD *thd, TABLE_LIST *tables,
#endif
}
+namespace Show {
+
ST_FIELD_INFO query_profile_statistics_info[]=
{
- /* name, length, type, value, maybe_null, old_name, open_method */
- {"QUERY_ID", 20, MYSQL_TYPE_LONG, 0, false, "Query_id", SKIP_OPEN_TABLE},
- {"SEQ", 20, MYSQL_TYPE_LONG, 0, false, "Seq", SKIP_OPEN_TABLE},
- {"STATE", 30, MYSQL_TYPE_STRING, 0, false, "Status", SKIP_OPEN_TABLE},
- {"DURATION", TIME_I_S_DECIMAL_SIZE, MYSQL_TYPE_DECIMAL, 0, false, "Duration", SKIP_OPEN_TABLE},
- {"CPU_USER", TIME_I_S_DECIMAL_SIZE, MYSQL_TYPE_DECIMAL, 0, true, "CPU_user", SKIP_OPEN_TABLE},
- {"CPU_SYSTEM", TIME_I_S_DECIMAL_SIZE, MYSQL_TYPE_DECIMAL, 0, true, "CPU_system", SKIP_OPEN_TABLE},
- {"CONTEXT_VOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, "Context_voluntary", SKIP_OPEN_TABLE},
- {"CONTEXT_INVOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, "Context_involuntary", SKIP_OPEN_TABLE},
- {"BLOCK_OPS_IN", 20, MYSQL_TYPE_LONG, 0, true, "Block_ops_in", SKIP_OPEN_TABLE},
- {"BLOCK_OPS_OUT", 20, MYSQL_TYPE_LONG, 0, true, "Block_ops_out", SKIP_OPEN_TABLE},
- {"MESSAGES_SENT", 20, MYSQL_TYPE_LONG, 0, true, "Messages_sent", SKIP_OPEN_TABLE},
- {"MESSAGES_RECEIVED", 20, MYSQL_TYPE_LONG, 0, true, "Messages_received", SKIP_OPEN_TABLE},
- {"PAGE_FAULTS_MAJOR", 20, MYSQL_TYPE_LONG, 0, true, "Page_faults_major", SKIP_OPEN_TABLE},
- {"PAGE_FAULTS_MINOR", 20, MYSQL_TYPE_LONG, 0, true, "Page_faults_minor", SKIP_OPEN_TABLE},
- {"SWAPS", 20, MYSQL_TYPE_LONG, 0, true, "Swaps", SKIP_OPEN_TABLE},
- {"SOURCE_FUNCTION", 30, MYSQL_TYPE_STRING, 0, true, "Source_function", SKIP_OPEN_TABLE},
- {"SOURCE_FILE", 20, MYSQL_TYPE_STRING, 0, true, "Source_file", SKIP_OPEN_TABLE},
- {"SOURCE_LINE", 20, MYSQL_TYPE_LONG, 0, true, "Source_line", SKIP_OPEN_TABLE},
- {NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL, 0}
+ Column("QUERY_ID", SLong(20), NOT_NULL, "Query_id"),
+ Column("SEQ", SLong(20), NOT_NULL, "Seq"),
+ Column("STATE", Varchar(30), NOT_NULL, "Status"),
+ Column("DURATION", Decimal(TIME_I_S_DECIMAL_SIZE), NOT_NULL, "Duration"),
+ Column("CPU_USER", Decimal(TIME_I_S_DECIMAL_SIZE), NULLABLE, "CPU_user"),
+ Column("CPU_SYSTEM", Decimal(TIME_I_S_DECIMAL_SIZE), NULLABLE, "CPU_system"),
+ Column("CONTEXT_VOLUNTARY", SLong(20), NULLABLE, "Context_voluntary"),
+ Column("CONTEXT_INVOLUNTARY", SLong(20), NULLABLE, "Context_involuntary"),
+ Column("BLOCK_OPS_IN", SLong(20), NULLABLE, "Block_ops_in"),
+ Column("BLOCK_OPS_OUT", SLong(20), NULLABLE, "Block_ops_out"),
+ Column("MESSAGES_SENT", SLong(20), NULLABLE, "Messages_sent"),
+ Column("MESSAGES_RECEIVED", SLong(20), NULLABLE, "Messages_received"),
+ Column("PAGE_FAULTS_MAJOR", SLong(20), NULLABLE, "Page_faults_major"),
+ Column("PAGE_FAULTS_MINOR", SLong(20), NULLABLE, "Page_faults_minor"),
+ Column("SWAPS", SLong(20), NULLABLE, "Swaps"),
+ Column("SOURCE_FUNCTION", Varchar(30), NULLABLE, "Source_function"),
+ Column("SOURCE_FILE", Varchar(20), NULLABLE, "Source_file"),
+ Column("SOURCE_LINE", SLong(20), NULLABLE, "Source_line"),
+ CEnd()
};
+} // namespace Show
int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
@@ -113,21 +115,17 @@ int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table)
Name_resolution_context *context= &thd->lex->first_select_lex()->context;
int i;
- for (i= 0; schema_table->fields_info[i].field_name != NULL; i++)
+ for (i= 0; !schema_table->fields_info[i].end_marker(); i++)
{
if (! fields_include_condition_truth_values[i])
continue;
field_info= &schema_table->fields_info[i];
- LEX_CSTRING field_name= {field_info->field_name,
- strlen(field_info->field_name) };
Item_field *field= new (thd->mem_root) Item_field(thd, context,
- NullS, NullS, &field_name);
+ field_info->name());
if (field)
{
- field->set_name(thd, field_info->old_name,
- (uint) strlen(field_info->old_name),
- system_charset_info);
+ field->set_name(thd, field_info->old_name());
if (add_item_to_list(thd, field))
return 1;
}
@@ -202,7 +200,8 @@ void PROF_MEASUREMENT::set_label(const char *status_arg,
sizes[1]= (function_arg == NULL) ? 0 : strlen(function_arg) + 1;
sizes[2]= (file_arg == NULL) ? 0 : strlen(file_arg) + 1;
- allocated_status_memory= (char *) my_malloc(sizes[0] + sizes[1] + sizes[2], MYF(0));
+ allocated_status_memory= (char *) my_malloc(key_memory_PROFILE, sizes[0] +
+ sizes[1] + sizes[2], MYF(0));
DBUG_ASSERT(allocated_status_memory != NULL);
cursor= allocated_status_memory;
@@ -291,7 +290,7 @@ void QUERY_PROFILE::set_query_source(char *query_source_arg, size_t query_length
DBUG_ASSERT(query_source == NULL); /* we don't leak memory */
if (query_source_arg != NULL)
- query_source= my_strndup(query_source_arg, length, MYF(0));
+ query_source= my_strndup(key_memory_PROFILE, query_source_arg, length, MYF(0));
}
void QUERY_PROFILE::new_status(const char *status_arg,
@@ -404,7 +403,7 @@ bool PROFILING::show_profiles()
MEM_ROOT *mem_root= thd->mem_root;
SELECT_LEX *sel= thd->lex->first_select_lex();
SELECT_LEX_UNIT *unit= &thd->lex->unit;
- ha_rows idx= 0;
+ ha_rows idx;
Protocol *protocol= thd->protocol;
void *iterator;
DBUG_ENTER("PROFILING::show_profiles");
@@ -428,9 +427,9 @@ bool PROFILING::show_profiles()
unit->set_limit(sel);
- for (iterator= history.new_iterator();
+ for (iterator= history.new_iterator(), idx= 1;
iterator != NULL;
- iterator= history.iterator_next(iterator))
+ iterator= history.iterator_next(iterator), idx++)
{
prof= history.iterator_value(iterator);
@@ -438,9 +437,9 @@ bool PROFILING::show_profiles()
double query_time_usecs= prof->m_end_time_usecs - prof->m_start_time_usecs;
- if (++idx <= unit->offset_limit_cnt)
+ if (unit->lim.check_offset(idx))
continue;
- if (idx > unit->select_limit_cnt)
+ if (idx > unit->lim.get_select_limit())
break;
protocol->prepare_for_resend();
diff --git a/sql/sql_profile.h b/sql/sql_profile.h
index 5b03acf59c0..85018a2598b 100644
--- a/sql/sql_profile.h
+++ b/sql/sql_profile.h
@@ -19,10 +19,13 @@
class Item;
struct TABLE_LIST;
class THD;
-typedef struct st_field_info ST_FIELD_INFO;
+class ST_FIELD_INFO;
typedef struct st_schema_table ST_SCHEMA_TABLE;
+namespace Show {
extern ST_FIELD_INFO query_profile_statistics_info[];
+} // namespace Show
+
int fill_query_profile_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond);
int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table);
@@ -51,6 +54,7 @@ int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table);
#include <sys/resource.h>
#endif
+extern PSI_memory_key key_memory_queue_item;
class PROF_MEASUREMENT;
class QUERY_PROFILE;
@@ -97,7 +101,8 @@ public:
{
struct queue_item *new_item;
- new_item= (struct queue_item *) my_malloc(sizeof(struct queue_item), MYF(0));
+ new_item= (struct queue_item *) my_malloc(key_memory_queue_item,
+ sizeof(struct queue_item), MYF(0));
new_item->payload= payload;
diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc
index 0898bea6d41..63b233faea6 100644
--- a/sql/sql_reload.cc
+++ b/sql/sql_reload.cc
@@ -133,7 +133,7 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
logger.flush_general_log();
if (options & REFRESH_ENGINE_LOG)
- if (ha_flush_logs(NULL))
+ if (ha_flush_logs())
result= 1;
if (options & REFRESH_BINARY_LOG)
@@ -551,7 +551,7 @@ bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
/* Request removal of table from cache. */
tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
table_list->db.str,
- table_list->table_name.str, FALSE);
+ table_list->table_name.str);
/* Reset ticket to satisfy asserts in open_tables(). */
table_list->mdl_request.ticket= NULL;
}
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index ada373546be..8f818e321dd 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -286,8 +286,15 @@ do_rename(THD *thd, TABLE_LIST *ren_table, const LEX_CSTRING *new_db,
if (ha_table_exists(thd, &ren_table->db, &old_alias, &hton) && hton)
{
DBUG_ASSERT(!thd->locked_tables_mode);
+
+#ifdef WITH_WSREP
+ if (WSREP(thd) && hton &&
+ !wsrep_should_replicate_ddl(thd, hton->db_type))
+ DBUG_RETURN(1);
+#endif
+
tdc_remove_table(thd, TDC_RT_REMOVE_ALL,
- ren_table->db.str, ren_table->table_name.str, false);
+ ren_table->db.str, ren_table->table_name.str);
if (hton != view_pseudo_hton)
{
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 31304c60418..b8de0d411e0 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2018, Oracle and/or its affiliates.
- Copyright (c) 2008, 2019, MariaDB Corporation
+ Copyright (c) 2008, 2020, 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
@@ -24,7 +24,6 @@
#include "rpl_mi.h"
#include "rpl_rli.h"
#include "sql_repl.h"
-#include "sql_acl.h" // SUPER_ACL
#include "log_event.h"
#include "rpl_filter.h"
#include <my_dir.h>
@@ -1221,7 +1220,8 @@ check_slave_start_position(binlog_send_info *info, const char **errormsg,
if (!delete_list)
{
if (!(delete_list= (slave_connection_state::entry **)
- my_malloc(sizeof(*delete_list) * st->hash.records, MYF(MY_WME))))
+ my_malloc(PSI_INSTRUMENT_ME,
+ sizeof(*delete_list) * st->hash.records, MYF(MY_WME))))
{
*errormsg= "Out of memory while checking slave start position";
err= ER_OUT_OF_RESOURCES;
@@ -1283,8 +1283,9 @@ gtid_find_binlog_file(slave_connection_state *state, char *out_name,
const char *errormsg= NULL;
char buf[FN_REFLEN];
- init_alloc_root(&memroot, "gtid_find_binlog_file",
- 8192, 0, MYF(MY_THREAD_SPECIFIC));
+ init_alloc_root(PSI_INSTRUMENT_ME, &memroot,
+ 10*(FN_REFLEN+sizeof(binlog_file_entry)), 0,
+ MYF(MY_THREAD_SPECIFIC));
if (!(list= get_binlog_list(&memroot)))
{
errormsg= "Out of memory while looking for GTID position in binlog";
@@ -1651,7 +1652,7 @@ is_until_reached(binlog_send_info *info, ulong *ev_offset,
return false;
break;
case GTID_UNTIL_STOP_AFTER_TRANSACTION:
- if (event_type != XID_EVENT &&
+ if (event_type != XID_EVENT && event_type != XA_PREPARE_LOG_EVENT &&
(event_type != QUERY_EVENT || /* QUERY_COMPRESSED_EVENT would never be commmit or rollback */
!Query_log_event::peek_is_commit_rollback
(info->packet->ptr()+*ev_offset,
@@ -1886,7 +1887,7 @@ send_event_to_slave(binlog_send_info *info, Log_event_type event_type,
info->gtid_skip_group= GTID_SKIP_NOT;
return NULL;
case GTID_SKIP_TRANSACTION:
- if (event_type == XID_EVENT ||
+ if (event_type == XID_EVENT || event_type == XA_PREPARE_LOG_EVENT ||
(event_type == QUERY_EVENT && /* QUERY_COMPRESSED_EVENT would never be commmit or rollback */
Query_log_event::peek_is_commit_rollback(packet->ptr() + ev_offset,
len - ev_offset,
@@ -3079,7 +3080,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report)
char relay_log_info_file_tmp[FN_REFLEN];
DBUG_ENTER("start_slave");
- if (check_access(thd, SUPER_ACL, any_db, NULL, NULL, 0, 0))
+ if (check_global_access(thd, PRIV_STMT_START_SLAVE))
DBUG_RETURN(-1);
create_logfile_name_with_suffix(master_info_file_tmp,
@@ -3282,7 +3283,7 @@ int stop_slave(THD* thd, Master_info* mi, bool net_report )
DBUG_ENTER("stop_slave");
DBUG_PRINT("enter",("Connection: %s", mi->connection_name.str));
- if (check_access(thd, SUPER_ACL, any_db, NULL, NULL, 0, 0))
+ if (check_global_access(thd, PRIV_STMT_STOP_SLAVE))
DBUG_RETURN(-1);
THD_STAGE_INFO(thd, stage_killing_slave);
int thread_mask;
@@ -3506,7 +3507,7 @@ static bool get_string_parameter(char *to, const char *from, size_t length,
if (from) // Empty paramaters allowed
{
size_t from_length= strlen(from);
- size_t from_numchars= cs->cset->numchars(cs, from, from + from_length);
+ size_t from_numchars= cs->numchars(from, from + from_length);
if (from_numchars > length / cs->mbmaxlen)
{
my_error(ER_WRONG_STRING_LENGTH, MYF(0), from, name,
@@ -4021,7 +4022,7 @@ bool mysql_show_binlog_events(THD* thd)
if (binary_log->is_open())
{
SELECT_LEX_UNIT *unit= &thd->lex->unit;
- ha_rows event_count, limit_start, limit_end;
+ ha_rows event_count;
my_off_t pos = MY_MAX(BIN_LOG_HEADER_SIZE, lex_mi->pos); // user-friendly
char search_file_name[FN_REFLEN], *name;
const char *log_file_name = lex_mi->log_file_name;
@@ -4040,8 +4041,6 @@ bool mysql_show_binlog_events(THD* thd)
verify_checksum_once= true;
unit->set_limit(thd->lex->current_select);
- limit_start= unit->offset_limit_cnt;
- limit_end= unit->select_limit_cnt;
name= search_file_name;
if (log_file_name)
@@ -4121,13 +4120,13 @@ bool mysql_show_binlog_events(THD* thd)
(opt_master_verify_checksum ||
verify_checksum_once))); )
{
- if (event_count >= limit_start &&
- ev->net_send(protocol, linfo.log_file_name, pos))
+ if (!unit->lim.check_offset(event_count) &&
+ ev->net_send(protocol, linfo.log_file_name, pos))
{
- errmsg = "Net error";
- delete ev;
+ errmsg = "Net error";
+ delete ev;
mysql_mutex_unlock(log_lock);
- goto err;
+ goto err;
}
if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT)
@@ -4156,11 +4155,11 @@ bool mysql_show_binlog_events(THD* thd)
verify_checksum_once= false;
pos = my_b_tell(&log);
- if (++event_count >= limit_end)
- break;
+ if (++event_count >= unit->lim.get_select_limit())
+ break;
}
- if (unlikely(event_count < limit_end && log.error))
+ if (unlikely(event_count < unit->lim.get_select_limit() && log.error))
{
errmsg = "Wrong offset or I/O error";
mysql_mutex_unlock(log_lock);
@@ -4217,7 +4216,7 @@ void show_binlog_info_get_fields(THD *thd, List<Item> *field_list)
/**
- Execute a SHOW MASTER STATUS statement.
+ Execute a SHOW BINLOG STATUS statement.
@param thd Pointer to THD object for the client thread executing the
statement.
@@ -4309,8 +4308,7 @@ bool show_binlogs(THD* thd)
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
- init_alloc_root(&mem_root, "binlog_file_list", 8192, 0,
- MYF(MY_THREAD_SPECIFIC));
+ init_alloc_root(PSI_INSTRUMENT_ME, &mem_root, 8192, 0, MYF(MY_THREAD_SPECIFIC));
retry:
/*
The current mutex handling here is to ensure we get the current log position
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 99feb1006fb..35b5665d1d0 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2009, 2019, MariaDB Corporation.
+ Copyright (c) 2009, 2020, 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
@@ -43,7 +43,6 @@
#include "sql_base.h" // setup_wild, setup_fields, fill_record
#include "sql_parse.h" // check_stack_overrun
#include "sql_partition.h" // make_used_partitions_str
-#include "sql_acl.h" // *_ACL
#include "sql_test.h" // print_where, print_keyuse_array,
// print_sjm, print_plan, TEST_join
#include "records.h" // init_read_record, end_read_record
@@ -300,6 +299,14 @@ void set_postjoin_aggr_write_func(JOIN_TAB *tab);
static Item **get_sargable_cond(JOIN *join, TABLE *table);
+static
+bool build_notnull_conds_for_range_scans(JOIN *join, COND *cond,
+ table_map allowed);
+static
+void build_notnull_conds_for_inner_nest_of_outer_join(JOIN *join,
+ TABLE_LIST *nest_tbl);
+
+
#ifndef DBUG_OFF
/*
@@ -409,7 +416,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
*/
res= mysql_select(thd,
select_lex->table_list.first,
- select_lex->with_wild, select_lex->item_list,
+ select_lex->item_list,
select_lex->where,
select_lex->order_list.elements +
select_lex->group_list.elements,
@@ -563,9 +570,9 @@ fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
new_ref= direct_ref ?
new (thd->mem_root) Item_direct_ref(thd, ref->context, item_ref, ref->table_name,
- &ref->field_name, ref->alias_name_used) :
+ ref->field_name, ref->alias_name_used) :
new (thd->mem_root) Item_ref(thd, ref->context, item_ref, ref->table_name,
- &ref->field_name, ref->alias_name_used);
+ ref->field_name, ref->alias_name_used);
if (!new_ref)
return TRUE;
ref->outer_ref= new_ref;
@@ -773,11 +780,11 @@ Item* period_get_condition(THD *thd, TABLE_LIST *table, SELECT_LEX *select,
const LEX_CSTRING &fend= period->end_field(share)->field_name;
conds->field_start= newx Item_field(thd, &select->context,
- table->db.str, table->alias.str,
- thd->make_clex_string(fstart));
+ table->db, table->alias,
+ thd->strmake_lex_cstring(fstart));
conds->field_end= newx Item_field(thd, &select->context,
- table->db.str, table->alias.str,
- thd->make_clex_string(fend));
+ table->db, table->alias,
+ thd->strmake_lex_cstring(fend));
Item *cond1= NULL, *cond2= NULL, *cond3= NULL, *curr= NULL;
if (timestamp)
@@ -1044,7 +1051,7 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
storing vers_conditions as Item and make some magic related to
vers_system_time_t/VERS_TRX_ID at stage of fix_fields()
(this is large refactoring). */
- if (vers_conditions.resolve_units(thd))
+ if (vers_conditions.check_units(thd))
DBUG_RETURN(-1);
if (timestamps_only && (vers_conditions.start.unit == VERS_TRX_ID ||
vers_conditions.end.unit == VERS_TRX_ID))
@@ -1099,8 +1106,7 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
0 on success
*/
int
-JOIN::prepare(TABLE_LIST *tables_init,
- uint wild_num, COND *conds_init, uint og_num,
+JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num,
ORDER *order_init, bool skip_order_by,
ORDER *group_init, Item *having_init,
ORDER *proc_param_init, SELECT_LEX *select_lex_arg,
@@ -1222,8 +1228,7 @@ JOIN::prepare(TABLE_LIST *tables_init,
real_og_num+= select_lex->order_list.elements;
DBUG_ASSERT(select_lex->hidden_bit_fields == 0);
- if (setup_wild(thd, tables_list, fields_list, &all_fields, wild_num,
- &select_lex->hidden_bit_fields))
+ if (setup_wild(thd, tables_list, fields_list, &all_fields, select_lex))
DBUG_RETURN(-1);
if (select_lex->setup_ref_array(thd, real_og_num))
DBUG_RETURN(-1);
@@ -1791,7 +1796,7 @@ JOIN::optimize_inner()
{
DBUG_ENTER("JOIN::optimize");
subq_exit_fl= false;
- do_send_rows = (unit->select_limit_cnt) ? 1 : 0;
+ do_send_rows = (unit->lim.get_select_limit()) ? 1 : 0;
DEBUG_SYNC(thd, "before_join_optimize");
@@ -1866,9 +1871,9 @@ JOIN::optimize_inner()
DBUG_RETURN(-1);
row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR :
- unit->select_limit_cnt);
+ unit->lim.get_select_limit());
/* select_limit is used to decide if we are likely to scan the whole table */
- select_limit= unit->select_limit_cnt;
+ select_limit= unit->lim.get_select_limit();
if (having || (select_options & OPTION_FOUND_ROWS))
select_limit= HA_POS_ERROR;
#ifdef HAVE_REF_TO_FIELDS // Not done yet
@@ -2109,9 +2114,10 @@ JOIN::optimize_inner()
thd->change_item_tree(&sel->having, having);
}
if (cond_value == Item::COND_FALSE || having_value == Item::COND_FALSE ||
- (!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
+ (!unit->lim.get_select_limit() &&
+ !(select_options & OPTION_FOUND_ROWS)))
{ /* Impossible cond */
- if (unit->select_limit_cnt)
+ if (unit->lim.get_select_limit())
{
DBUG_PRINT("info", (having_value == Item::COND_FALSE ?
"Impossible HAVING" : "Impossible WHERE"));
@@ -3206,7 +3212,8 @@ bool JOIN::make_aggr_tables_info()
{
/* Check if the storage engine can intercept the query */
Query query= {&all_fields, select_distinct, tables_list, conds,
- group_list, order ? order : group_list, having};
+ group_list, order ? order : group_list, having,
+ &select_lex->master_unit()->lim};
group_by_handler *gbh= ht->create_group_by(thd, &query);
if (gbh)
@@ -3661,8 +3668,8 @@ bool JOIN::make_aggr_tables_info()
unit->select_limit_cnt == 1 (we only need one row in the result set)
*/
sort_tab->filesort->limit=
- (has_group_by || (join_tab + table_count > curr_tab + 1)) ?
- select_limit : unit->select_limit_cnt;
+ (has_group_by || (join_tab + top_join_tab_count > curr_tab + 1)) ?
+ select_limit : unit->lim.get_select_limit();
}
if (!only_const_tables() &&
!join_tab[const_tables].filesort &&
@@ -4047,9 +4054,6 @@ JOIN::reinit()
{
DBUG_ENTER("JOIN::reinit");
- unit->offset_limit_cnt= (ha_rows)(select_lex->offset_limit ?
- select_lex->offset_limit->val_uint() : 0);
-
first_record= false;
group_sent= false;
cleaned= false;
@@ -4171,9 +4175,8 @@ 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_SLOW_ASSERT(select_lex->select_number == UINT_MAX ||
- select_lex->select_number == INT_MAX ||
- !output ||
+ DBUG_ASSERT(select_lex->select_number == UINT_MAX ||
+ select_lex->select_number == INT_MAX || !output ||
!output->get_select(select_lex->select_number) ||
output->get_select(select_lex->select_number)->select_lex ==
select_lex);
@@ -4233,9 +4236,9 @@ void JOIN::exec()
select_lex->select_number))
dbug_serve_apcs(thd, 1);
);
- ANALYZE_START_TRACKING(&explain->time_tracker);
+ ANALYZE_START_TRACKING(thd, &explain->time_tracker);
exec_inner();
- ANALYZE_STOP_TRACKING(&explain->time_tracker);
+ ANALYZE_STOP_TRACKING(thd, &explain->time_tracker);
DBUG_EXECUTE_IF("show_explain_probe_join_exec_end",
if (dbug_user_var_equals_int(thd,
@@ -4320,7 +4323,8 @@ void JOIN::exec_inner()
{
if (do_send_rows &&
(procedure ? (procedure->send_row(procedure_fields_list) ||
- procedure->end_of_records()) : result->send_data(fields_list)> 0))
+ procedure->end_of_records()):
+ result->send_data_with_check(fields_list, unit, 0)> 0))
error= 1;
else
send_records= ((select_options & OPTION_FOUND_ROWS) ? 1 :
@@ -4533,11 +4537,6 @@ void JOIN::cleanup_item_list(List<Item> &items) const
the top-level select_lex for this query
@param tables list of all tables used in this query.
The tables have been pre-opened.
- @param wild_num number of wildcards used in the top level
- select of this query.
- For example statement
- SELECT *, t1.*, catalog.t2.* FROM t0, t1, t2;
- has 3 wildcards.
@param fields list of items in SELECT list of the top-level
select
e.g. SELECT a, b, c FROM t1 will have Item_field
@@ -4570,12 +4569,10 @@ void JOIN::cleanup_item_list(List<Item> &items) const
*/
bool
-mysql_select(THD *thd,
- TABLE_LIST *tables, uint wild_num, List<Item> &fields,
- COND *conds, uint og_num, ORDER *order, ORDER *group,
- Item *having, ORDER *proc_param, ulonglong select_options,
- select_result *result, SELECT_LEX_UNIT *unit,
- SELECT_LEX *select_lex)
+mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
+ uint og_num, ORDER *order, ORDER *group, Item *having,
+ ORDER *proc_param, ulonglong select_options, select_result *result,
+ SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
{
int err= 0;
bool free_join= 1;
@@ -4605,9 +4602,8 @@ mysql_select(THD *thd,
}
else
{
- if ((err= join->prepare( tables, wild_num,
- conds, og_num, order, false, group, having,
- proc_param, select_lex, unit)))
+ if ((err= join->prepare(tables, conds, og_num, order, false, group,
+ having, proc_param, select_lex, unit)))
{
goto err;
}
@@ -4629,9 +4625,8 @@ mysql_select(THD *thd,
DBUG_RETURN(TRUE);
THD_STAGE_INFO(thd, stage_init);
thd->lex->used_tables=0;
- if ((err= join->prepare(tables, wild_num,
- conds, og_num, order, false, group, having, proc_param,
- select_lex, unit)))
+ if ((err= join->prepare(tables, conds, og_num, order, false, group, having,
+ proc_param, select_lex, unit)))
{
goto err;
}
@@ -5345,6 +5340,9 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
}
}
+ join->join_tab= stat;
+ join->make_notnull_conds_for_range_scans();
+
/* Calc how many (possible) matched records in each table */
/*
@@ -5578,7 +5576,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
if (double rr= join->best_positions[i].records_read)
records= COST_MULT(records, rr);
ha_rows rows= records > (double) HA_ROWS_MAX ? HA_ROWS_MAX : (ha_rows) records;
- set_if_smaller(rows, unit->select_limit_cnt);
+ set_if_smaller(rows, unit->lim.get_select_limit());
join->select_lex->increase_derived_records(rows);
}
}
@@ -6405,18 +6403,18 @@ max_part_bit(key_part_map bits)
/**
Add a new keuse to the specified array of KEYUSE objects
- @param[in,out] keyuse_array array of keyuses to be extended
+ @param[in,out] keyuse_array array of keyuses to be extended
@param[in] key_field info on the key use occurrence
@param[in] key key number for the keyse to be added
@param[in] part key part for the keyuse to be added
@note
The function builds a new KEYUSE object for a key use utilizing the info
- on the left and right parts of the given key use extracted from the
- structure key_field, the key number and key part for this key use.
+ on the left and right parts of the given key use extracted from the
+ structure key_field, the key number and key part for this key use.
The built object is added to the dynamic array keyuse_array.
- @retval 0 the built object is succesfully added
+ @retval 0 the built object is successfully added
@retval 1 otherwise
*/
@@ -6780,7 +6778,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
/* set a barrier for the array of SARGABLE_PARAM */
(*sargables)[0].field= 0;
- if (my_init_dynamic_array2(keyuse, sizeof(KEYUSE),
+ if (my_init_dynamic_array2(thd->mem_root->m_psi_key, keyuse, sizeof(KEYUSE),
thd->alloc(sizeof(KEYUSE) * 20), 20, 64,
MYF(MY_THREAD_SPECIFIC)))
DBUG_RETURN(TRUE);
@@ -6967,7 +6965,6 @@ void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
}
}
-
/**
Check for the presence of AGGFN(DISTINCT a) queries that may be subject
to loose index scan.
@@ -7005,7 +7002,6 @@ is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args)
{
Item_sum **sum_item_ptr;
bool result= false;
- Field_map first_aggdistinct_fields;
if (join->table_count != 1 || /* reference more than 1 table */
join->select_distinct || /* or a DISTINCT */
@@ -7015,10 +7011,11 @@ is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args)
if (join->make_sum_func_list(join->all_fields, join->fields_list, true))
return false;
+ Bitmap<MAX_FIELDS> first_aggdistinct_fields;
+ bool first_aggdistinct_fields_initialized= false;
for (sum_item_ptr= join->sum_funcs; *sum_item_ptr; sum_item_ptr++)
{
Item_sum *sum_item= *sum_item_ptr;
- Field_map cur_aggdistinct_fields;
Item *expr;
/* aggregate is not AGGFN(DISTINCT) or more than 1 argument to it */
switch (sum_item->sum_func())
@@ -7041,6 +7038,8 @@ is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args)
We don't worry about duplicates as these will be sorted out later in
get_best_group_min_max
*/
+ Bitmap<MAX_FIELDS> cur_aggdistinct_fields;
+ cur_aggdistinct_fields.clear_all();
for (uint i= 0; i < sum_item->get_arg_count(); i++)
{
expr= sum_item->get_arg(i);
@@ -7059,8 +7058,11 @@ is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args)
If there are multiple aggregate functions, make sure that they all
refer to exactly the same set of columns.
*/
- if (first_aggdistinct_fields.is_clear_all())
- first_aggdistinct_fields.merge(cur_aggdistinct_fields);
+ if (!first_aggdistinct_fields_initialized)
+ {
+ first_aggdistinct_fields= cur_aggdistinct_fields;
+ first_aggdistinct_fields_initialized=true;
+ }
else if (first_aggdistinct_fields != cur_aggdistinct_fields)
return false;
}
@@ -8032,7 +8034,7 @@ best_access_path(JOIN *join,
if (!best_key &&
idx == join->const_tables &&
s->table == join->sort_by_table &&
- join->unit->select_limit_cnt >= records)
+ join->unit->lim.get_select_limit() >= records)
{
trace_access_scan.add("use_tmp_table", true);
join->sort_by_table= (TABLE*) 1; // Must use temporary table
@@ -10265,14 +10267,16 @@ bool JOIN::get_best_combination()
if (aggr_tables > 2)
aggr_tables= 2;
- if (!(join_tab= (JOIN_TAB*) thd->alloc(sizeof(JOIN_TAB)*
- (top_join_tab_count + aggr_tables))))
- DBUG_RETURN(TRUE);
full_join=0;
hash_join= FALSE;
fix_semijoin_strategies_for_picked_join_order(this);
+ top_join_tab_count= get_number_of_tables_at_top_level(this);
+
+ if (!(join_tab= (JOIN_TAB*) thd->alloc(sizeof(JOIN_TAB)*
+ (top_join_tab_count + aggr_tables))))
+ DBUG_RETURN(TRUE);
JOIN_TAB_RANGE *root_range;
if (!(root_range= new (thd->mem_root) JOIN_TAB_RANGE))
@@ -11592,7 +11596,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
!tab->loosescan_match_tab && // (1)
((cond && (!tab->keys.is_subset(tab->const_keys) && i > 0)) ||
(!tab->const_keys.is_clear_all() && i == join->const_tables &&
- join->unit->select_limit_cnt <
+ join->unit->lim.get_select_limit() <
join->best_positions[i].records_read &&
!(join->select_options & OPTION_FOUND_ROWS))))
{
@@ -11618,7 +11622,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
(join->select_options &
OPTION_FOUND_ROWS ?
HA_POS_ERROR :
- join->unit->select_limit_cnt), 0,
+ join->unit->lim.get_select_limit()), 0,
FALSE, FALSE, FALSE) < 0)
{
/*
@@ -11632,7 +11636,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
(join->select_options &
OPTION_FOUND_ROWS ?
HA_POS_ERROR :
- join->unit->select_limit_cnt),0,
+ join->unit->lim.get_select_limit()),0,
FALSE, FALSE, FALSE) < 0)
DBUG_RETURN(1); // Impossible WHERE
}
@@ -13290,7 +13294,7 @@ void JOIN_TAB::build_range_rowid_filter_if_needed()
Exec_time_tracker *table_tracker= table->file->get_time_tracker();
Rowid_filter_tracker *rowid_tracker= rowid_filter->get_tracker();
table->file->set_time_tracker(rowid_tracker->get_time_tracker());
- rowid_tracker->start_tracking();
+ rowid_tracker->start_tracking(join->thd);
if (!rowid_filter->build())
{
is_rowid_filter_built= true;
@@ -13300,7 +13304,7 @@ void JOIN_TAB::build_range_rowid_filter_if_needed()
delete rowid_filter;
rowid_filter= 0;
}
- rowid_tracker->stop_tracking();
+ rowid_tracker->stop_tracking(join->thd);
table->file->set_time_tracker(table_tracker);
}
}
@@ -13503,8 +13507,7 @@ bool JOIN_TAB::preread_init()
if ((!derived->get_unit()->executed ||
derived->is_recursive_with_table() ||
derived->get_unit()->uncacheable) &&
- mysql_handle_single_derived(join->thd->lex,
- derived, DT_CREATE | DT_FILL))
+ mysql_handle_single_derived(join->thd->lex, derived, DT_CREATE | DT_FILL))
return TRUE;
if (!(derived->get_unit()->uncacheable & UNCACHEABLE_DEPENDENT) ||
@@ -13529,6 +13532,21 @@ bool JOIN_TAB::preread_init()
}
+bool JOIN_TAB::pfs_batch_update(JOIN *join)
+{
+ /*
+ Use PFS batch mode if
+ 1. tab is an inner-most table, or
+ 2. will read more than one row (not eq_ref or const access type)
+ 3. no subqueries
+ */
+
+ return join->join_tab + join->table_count - 1 == this && // 1
+ type != JT_EQ_REF && type != JT_CONST && type != JT_SYSTEM && // 2
+ (!select_cond || !select_cond->with_subquery()); // 3
+}
+
+
/**
Build a TABLE_REF structure for index lookup in the temporary table
@@ -14067,7 +14085,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
ORDER BY and GROUP BY
*/
for (JOIN_TAB *tab= join->join_tab + join->const_tables;
- tab < join->join_tab + join->table_count;
+ tab < join->join_tab + join->top_join_tab_count;
tab++)
tab->cached_eq_ref_table= FALSE;
@@ -14075,7 +14093,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
*simple_order= head->on_expr_ref[0] == NULL;
if (*simple_order && head->table->file->ha_table_flags() & HA_SLOW_RND_POS)
{
- uint u1, u2, u3;
+ uint u1, u2, u3, u4;
/*
normally the condition is (see filesort_use_addons())
@@ -14086,7 +14104,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
TODO proper cost estimations
*/
- *simple_order= filesort_use_addons(head->table, 0, &u1, &u2, &u3);
+ *simple_order= filesort_use_addons(head->table, 0, &u1, &u2, &u3, &u4);
}
}
else
@@ -14352,7 +14370,7 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
{
bool send_error= FALSE;
if (send_row)
- send_error= result->send_data(fields) > 0;
+ send_error= result->send_data_with_check(fields, join->unit, 0) > 0;
if (likely(!send_error))
result->send_eof(); // Should be safe
}
@@ -14890,28 +14908,28 @@ bool Item_func_eq::check_equality(THD *thd, COND_EQUAL *cond_equal,
left_item, right_item, cond_equal);
}
-
+
/**
Item_xxx::build_equal_items()
-
+
Replace all equality predicates in a condition referenced by "this"
by multiple equality items.
At each 'and' level the function detects items for equality predicates
and replaced them by a set of multiple equality items of class Item_equal,
- taking into account inherited equalities from upper levels.
+ taking into account inherited equalities from upper levels.
If an equality predicate is used not in a conjunction it's just
replaced by a multiple equality predicate.
For each 'and' level the function set a pointer to the inherited
multiple equalities in the cond_equal field of the associated
- object of the type Item_cond_and.
+ object of the type Item_cond_and.
The function also traverses the cond tree and and for each field reference
sets a pointer to the multiple equality item containing the field, if there
is any. If this multiple equality equates fields to a constant the
- function replaces the field reference by the constant in the cases
+ function replaces the field reference by the constant in the cases
when the field is not of a string type or when the field reference is
just an argument of a comparison predicate.
- The function also determines the maximum number of members in
+ The function also determines the maximum number of members in
equality lists of each Item_cond_and object assigning it to
thd->lex->current_select->max_equal_elems.
@@ -14925,7 +14943,7 @@ bool Item_func_eq::check_equality(THD *thd, COND_EQUAL *cond_equal,
in a conjuction for a minimal set of multiple equality predicates.
This set can be considered as a canonical representation of the
sub-conjunction of the equality predicates.
- E.g. (t1.a=t2.b AND t2.b>5 AND t1.a=t3.c) is replaced by
+ E.g. (t1.a=t2.b AND t2.b>5 AND t1.a=t3.c) is replaced by
(=(t1.a,t2.b,t3.c) AND t2.b>5), not by
(=(t1.a,t2.b) AND =(t1.a,t3.c) AND t2.b>5);
while (t1.a=t2.b AND t2.b>5 AND t3.c=t4.d) is replaced by
@@ -14936,16 +14954,16 @@ bool Item_func_eq::check_equality(THD *thd, COND_EQUAL *cond_equal,
The function performs the substitution in a recursive descent by
the condtion tree, passing to the next AND level a chain of multiple
equality predicates which have been built at the upper levels.
- The Item_equal items built at the level are attached to other
+ The Item_equal items built at the level are attached to other
non-equality conjucts as a sublist. The pointer to the inherited
multiple equalities is saved in the and condition object (Item_cond_and).
- This chain allows us for any field reference occurence easyly to find a
- multiple equality that must be held for this occurence.
+ This chain allows us for any field reference occurrence easily to find a
+ multiple equality that must be held for this occurrence.
For each AND level we do the following:
- scan it for all equality predicate (=) items
- join them into disjoint Item_equal() groups
- - process the included OR conditions recursively to do the same for
- lower AND levels.
+ - process the included OR conditions recursively to do the same for
+ lower AND levels.
We need to do things in this order as lower AND levels need to know about
all possible Item_equal objects in upper levels.
@@ -14981,7 +14999,7 @@ COND *Item_cond_and::build_equal_items(THD *thd,
/*
Retrieve all conjuncts of this level detecting the equality
that are subject to substitution by multiple equality items and
- removing each such predicate from the conjunction after having
+ removing each such predicate from the conjunction after having
found/created a multiple equality whose inference the predicate is.
*/
while ((item= li++))
@@ -17706,16 +17724,20 @@ const_expression_in_where(COND *cond, Item *comp_item, Field *comp_field,
Create internal temporary table
****************************************************************************/
-Field *Item::create_tmp_field_int(TABLE *table, uint convert_int_length)
+Field *Item::create_tmp_field_int(MEM_ROOT *root, TABLE *table,
+ uint convert_int_length)
{
- const Type_handler *h= &type_handler_long;
+ const Type_handler *h= &type_handler_slong;
if (max_char_length() > convert_int_length)
- h= &type_handler_longlong;
- return h->make_and_init_table_field(&name, Record_addr(maybe_null),
+ h= &type_handler_slonglong;
+ if (unsigned_flag)
+ h= h->type_handler_unsigned();
+ return h->make_and_init_table_field(root, &name, Record_addr(maybe_null),
*this, table);
}
-Field *Item::tmp_table_field_from_field_type_maybe_null(TABLE *table,
+Field *Item::tmp_table_field_from_field_type_maybe_null(MEM_ROOT *root,
+ TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param,
bool is_explicit_null)
@@ -17727,7 +17749,7 @@ Field *Item::tmp_table_field_from_field_type_maybe_null(TABLE *table,
DBUG_ASSERT(!param->make_copy_field() || type() == CONST_ITEM);
DBUG_ASSERT(!is_result_field());
Field *result;
- if ((result= tmp_table_field_from_field_type(table)))
+ if ((result= tmp_table_field_from_field_type(root, table)))
{
if (result && is_explicit_null)
result->is_created_from_null_item= true;
@@ -17736,15 +17758,14 @@ Field *Item::tmp_table_field_from_field_type_maybe_null(TABLE *table,
}
-Field *Item_sum::create_tmp_field(bool group, TABLE *table)
+Field *Item_sum::create_tmp_field(MEM_ROOT *root, bool group, TABLE *table)
{
Field *UNINIT_VAR(new_field);
- MEM_ROOT *mem_root= table->in_use->mem_root;
switch (cmp_type()) {
case REAL_RESULT:
{
- new_field= new (mem_root)
+ new_field= new (root)
Field_double(max_char_length(), maybe_null, &name, decimals, TRUE);
break;
}
@@ -17752,7 +17773,7 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table)
case TIME_RESULT:
case DECIMAL_RESULT:
case STRING_RESULT:
- new_field= tmp_table_field_from_field_type(table);
+ new_field= tmp_table_field_from_field_type(root, table);
break;
case ROW_RESULT:
// This case should never be choosen
@@ -17767,47 +17788,11 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table)
/**
- Create field for information schema table.
-
- @param thd Thread handler
- @param table Temporary table
- @param item Item to create a field for
-
- @retval
- 0 on error
- @retval
- new_created field
-*/
-
-Field *Item::create_field_for_schema(THD *thd, TABLE *table)
-{
- if (field_type() == MYSQL_TYPE_VARCHAR)
- {
- Field *field;
- if (max_length > MAX_FIELD_VARCHARLENGTH)
- field= new (thd->mem_root) Field_blob(max_length, maybe_null, &name,
- collation.collation);
- else if (max_length > 0)
- field= new (thd->mem_root) Field_varstring(max_length, maybe_null, &name,
- table->s,
- collation.collation);
- else
- field= new Field_null((uchar*) 0, 0, Field::NONE, &name,
- collation.collation);
- if (field)
- field->init(table);
- return field;
- }
- return tmp_table_field_from_field_type(table);
-}
-
-
-/**
Create a temporary field for Item_field (or its descendant),
either direct or referenced by an Item_ref.
*/
Field *
-Item_field::create_tmp_field_from_item_field(TABLE *new_table,
+Item_field::create_tmp_field_from_item_field(MEM_ROOT *root, TABLE *new_table,
Item_ref *orig_item,
const Tmp_field_param *param)
{
@@ -17831,14 +17816,16 @@ Item_field::create_tmp_field_from_item_field(TABLE *new_table,
Record_addr rec(orig_item ? orig_item->maybe_null : maybe_null);
const Type_handler *handler= type_handler()->
type_handler_for_tmp_table(this);
- result= handler->make_and_init_table_field(orig_item ? &orig_item->name : &name,
+ result= handler->make_and_init_table_field(root,
+ orig_item ? &orig_item->name : &name,
rec, *this, new_table);
}
else if (param->table_cant_handle_bit_fields() &&
field->type() == MYSQL_TYPE_BIT)
{
- const Type_handler *handler= type_handler_long_or_longlong();
- result= handler->make_and_init_table_field(&name,
+ const Type_handler *handler=
+ Type_handler::type_handler_long_or_longlong(max_char_length(), true);
+ result= handler->make_and_init_table_field(root, &name,
Record_addr(maybe_null),
*this, new_table);
}
@@ -17847,8 +17834,7 @@ Item_field::create_tmp_field_from_item_field(TABLE *new_table,
LEX_CSTRING *tmp= orig_item ? &orig_item->name : &name;
bool tmp_maybe_null= param->modify_item() ? maybe_null :
field->maybe_null();
- result= field->create_tmp_field(new_table->in_use->mem_root, new_table,
- tmp_maybe_null);
+ result= field->create_tmp_field(root, new_table, tmp_maybe_null);
if (result)
result->field_name= *tmp;
}
@@ -17858,14 +17844,14 @@ Item_field::create_tmp_field_from_item_field(TABLE *new_table,
}
-Field *Item_field::create_tmp_field_ex(TABLE *table,
+Field *Item_field::create_tmp_field_ex(MEM_ROOT *root, TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(!is_result_field());
Field *result;
src->set_field(field);
- if (!(result= create_tmp_field_from_item_field(table, NULL, param)))
+ if (!(result= create_tmp_field_from_item_field(root, table, NULL, param)))
return NULL;
/*
Fields that are used as arguments to the DEFAULT() function already have
@@ -17878,7 +17864,7 @@ Field *Item_field::create_tmp_field_ex(TABLE *table,
}
-Field *Item_ref::create_tmp_field_ex(TABLE *table,
+Field *Item_ref::create_tmp_field_ex(MEM_ROOT *root, TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
@@ -17891,13 +17877,14 @@ Field *Item_ref::create_tmp_field_ex(TABLE *table,
Tmp_field_param prm2(*param);
prm2.set_modify_item(false);
src->set_field(field->field);
- if (!(result= field->create_tmp_field_from_item_field(table, this, &prm2)))
+ if (!(result= field->create_tmp_field_from_item_field(root, table,
+ this, &prm2)))
return NULL;
if (param->modify_item())
result_field= result;
return result;
}
- return Item_result_field::create_tmp_field_ex(table, src, param);
+ return Item_result_field::create_tmp_field_ex(root, table, src, param);
}
@@ -17916,9 +17903,13 @@ void Item_result_field::get_tmp_field_src(Tmp_field_src *src,
}
-Field *Item_result_field::create_tmp_field_ex(TABLE *table,
- Tmp_field_src *src,
- const Tmp_field_param *param)
+Field *
+Item_result_field::create_tmp_field_ex_from_handler(
+ MEM_ROOT *root,
+ TABLE *table,
+ Tmp_field_src *src,
+ const Tmp_field_param *param,
+ const Type_handler *h)
{
/*
Possible Item types:
@@ -17926,38 +17917,27 @@ Field *Item_result_field::create_tmp_field_ex(TABLE *table,
- Item_func
- Item_subselect
*/
+ DBUG_ASSERT(fixed);
DBUG_ASSERT(is_result_field());
DBUG_ASSERT(type() != NULL_ITEM);
get_tmp_field_src(src, param);
Field *result;
- if ((result= tmp_table_field_from_field_type(table)) && param->modify_item())
- result_field= result;
- return result;
-}
-
-
-Field *Item_func_user_var::create_tmp_field_ex(TABLE *table,
- Tmp_field_src *src,
- const Tmp_field_param *param)
-{
- DBUG_ASSERT(is_result_field());
- DBUG_ASSERT(type() != NULL_ITEM);
- get_tmp_field_src(src, param);
- Field *result;
- if ((result= create_table_field_from_handler(table)) && param->modify_item())
+ if ((result= h->make_and_init_table_field(root, &name,
+ Record_addr(maybe_null),
+ *this, table)) &&
+ param->modify_item())
result_field= result;
return result;
}
-Field *Item_func_sp::create_tmp_field_ex(TABLE *table,
+Field *Item_func_sp::create_tmp_field_ex(MEM_ROOT *root, TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
Field *result;
get_tmp_field_src(src, param);
- if ((result= sp_result_field->create_tmp_field(table->in_use->mem_root,
- table)))
+ if ((result= sp_result_field->create_tmp_field(root, table)))
{
result->field_name= name;
if (param->modify_item())
@@ -18003,7 +17983,8 @@ Field *create_tmp_field(TABLE *table, Item *item,
Tmp_field_src src;
Tmp_field_param prm(group, modify_item, table_cant_handle_bit_fields,
make_copy_field);
- Field *result= item->create_tmp_field_ex(table, &src, &prm);
+ Field *result= item->create_tmp_field_ex(table->in_use->mem_root,
+ table, &src, &prm);
*from_field= src.field();
*default_field= src.default_field();
if (src.item_result_field())
@@ -18055,6 +18036,114 @@ setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps)
}
+class Create_tmp_table: public Data_type_statistics
+{
+ // The following members are initialized only in start()
+ Field **m_from_field, **m_default_field;
+ KEY_PART_INFO *m_key_part_info;
+ uchar *m_group_buff, *m_bitmaps;
+ // The following members are initialized in ctor
+ uint m_alloced_field_count;
+ bool m_using_unique_constraint;
+ uint m_temp_pool_slot;
+ ORDER *m_group;
+ bool m_distinct;
+ bool m_save_sum_fields;
+ bool m_with_cycle;
+ ulonglong m_select_options;
+ ha_rows m_rows_limit;
+ uint m_group_null_items;
+
+ // counter for distinct/other fields
+ uint m_field_count[2];
+ // counter for distinct/other fields which can be NULL
+ uint m_null_count[2];
+ // counter for distinct/other blob fields
+ uint m_blobs_count[2];
+ // counter for "tails" of bit fields which do not fit in a byte
+ uint m_uneven_bit[2];
+
+public:
+ enum counter {distinct, other};
+ /*
+ shows which field we are processing: distinct/other (set in processing
+ cycles)
+ */
+ counter current_counter;
+ Create_tmp_table(const TMP_TABLE_PARAM *param,
+ ORDER *group, bool distinct, bool save_sum_fields,
+ ulonglong select_options, ha_rows rows_limit)
+ :m_alloced_field_count(0),
+ m_using_unique_constraint(false),
+ m_temp_pool_slot(MY_BIT_NONE),
+ m_group(group),
+ m_distinct(distinct),
+ m_save_sum_fields(save_sum_fields),
+ m_with_cycle(false),
+ m_select_options(select_options),
+ m_rows_limit(rows_limit),
+ m_group_null_items(0),
+ current_counter(other)
+ {
+ m_field_count[Create_tmp_table::distinct]= 0;
+ m_field_count[Create_tmp_table::other]= 0;
+ m_null_count[Create_tmp_table::distinct]= 0;
+ m_null_count[Create_tmp_table::other]= 0;
+ m_blobs_count[Create_tmp_table::distinct]= 0;
+ m_blobs_count[Create_tmp_table::other]= 0;
+ m_uneven_bit[Create_tmp_table::distinct]= 0;
+ m_uneven_bit[Create_tmp_table::other]= 0;
+ }
+
+ void add_field(TABLE *table, Field *field, uint fieldnr, bool force_not_null_cols);
+
+ TABLE *start(THD *thd,
+ TMP_TABLE_PARAM *param,
+ const LEX_CSTRING *table_alias);
+
+ bool add_fields(THD *thd, TABLE *table,
+ TMP_TABLE_PARAM *param, List<Item> &fields);
+
+ bool add_schema_fields(THD *thd, TABLE *table,
+ TMP_TABLE_PARAM *param,
+ const ST_SCHEMA_TABLE &schema_table,
+ const MY_BITMAP &bitmap);
+
+ bool finalize(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
+ bool do_not_open, bool keep_row_order);
+ void cleanup_on_failure(THD *thd, TABLE *table);
+};
+
+
+void Create_tmp_table::add_field(TABLE *table, Field *field, uint fieldnr, bool force_not_null_cols)
+{
+ DBUG_ASSERT(!field->field_name.str || strlen(field->field_name.str) == field->field_name.length);
+
+ if (force_not_null_cols)
+ {
+ field->flags|= NOT_NULL_FLAG;
+ field->null_ptr= NULL;
+ }
+
+ if (!(field->flags & NOT_NULL_FLAG))
+ m_null_count[current_counter]++;
+
+ table->s->reclength+= field->pack_length();
+
+ // Assign it here, before update_data_type_statistics() changes m_blob_count
+ if (field->flags & BLOB_FLAG)
+ {
+ table->s->blob_field[m_blob_count]= fieldnr;
+ m_blobs_count[current_counter]++;
+ }
+
+ table->field[fieldnr]= field;
+ field->field_index= fieldnr;
+
+ field->update_data_type_statistics(this);
+}
+
+
/**
Create a temp table according to a field list.
@@ -18089,61 +18178,36 @@ setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps)
inserted, the engine should preserve this order
*/
-TABLE *
-create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
- ORDER *group, bool distinct, bool save_sum_fields,
- ulonglong select_options, ha_rows rows_limit,
- const LEX_CSTRING *table_alias, bool do_not_open,
- bool keep_row_order)
+TABLE *Create_tmp_table::start(THD *thd,
+ TMP_TABLE_PARAM *param,
+ const LEX_CSTRING *table_alias)
{
MEM_ROOT *mem_root_save, own_root;
TABLE *table;
TABLE_SHARE *share;
- uint i,field_count,null_count,null_pack_length;
uint copy_func_count= param->func_count;
- uint hidden_null_count, hidden_null_pack_length, hidden_field_count;
- uint blob_count,group_null_items, string_count;
- uint temp_pool_slot=MY_BIT_NONE;
- uint fieldnr= 0;
- ulong reclength, string_total_length;
- bool using_unique_constraint= false;
- bool use_packed_rows= false;
- bool not_all_columns= !(select_options & TMP_TABLE_ALL_COLUMNS);
char *tmpname,path[FN_REFLEN];
- uchar *pos, *group_buff, *bitmaps;
- uchar *null_flags;
- Field **reg_field, **from_field, **default_field;
+ Field **reg_field;
uint *blob_field;
- Copy_field *copy=0;
- KEY *keyinfo;
- KEY_PART_INFO *key_part_info;
- Item **copy_func;
- TMP_ENGINE_COLUMNDEF *recinfo;
- /*
- total_uneven_bit_length is uneven bit length for visible fields
- hidden_uneven_bit_length is uneven bit length for hidden fields
- */
- uint total_uneven_bit_length= 0, hidden_uneven_bit_length= 0;
- bool force_copy_fields= param->force_copy_fields;
/* Treat sum functions as normal ones when loose index scan is used. */
- save_sum_fields|= param->precomputed_group_by;
- DBUG_ENTER("create_tmp_table");
+ m_save_sum_fields|= param->precomputed_group_by;
+ DBUG_ENTER("Create_tmp_table::start");
DBUG_PRINT("enter",
("table_alias: '%s' distinct: %d save_sum_fields: %d "
"rows_limit: %lu group: %d", table_alias->str,
- (int) distinct, (int) save_sum_fields,
- (ulong) rows_limit, MY_TEST(group)));
+ (int) m_distinct, (int) m_save_sum_fields,
+ (ulong) m_rows_limit, MY_TEST(m_group)));
if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES))
- temp_pool_slot = bitmap_lock_set_next(&temp_pool);
+ m_temp_pool_slot = bitmap_lock_set_next(&temp_pool);
- if (temp_pool_slot != MY_BIT_NONE) // we got a slot
- sprintf(path, "%s_%lx_%i", tmp_file_prefix,
- current_pid, temp_pool_slot);
+ if (m_temp_pool_slot != MY_BIT_NONE) // we got a slot
+ sprintf(path, "%s-%lx-%i", tmp_file_prefix,
+ current_pid, m_temp_pool_slot);
else
{
/* if we run out of slots or we are not using tempool */
- sprintf(path, "%s%lx_%lx_%x", tmp_file_prefix,current_pid,
+ sprintf(path, "%s-%lx-%lx-%x", tmp_file_prefix,current_pid,
(ulong) thd->thread_id, thd->tmp_table++);
}
@@ -18154,12 +18218,12 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
fn_format(path, path, mysql_tmpdir, "",
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
- if (group)
+ if (m_group)
{
- ORDER **prev= &group;
+ ORDER **prev= &m_group;
if (!param->quick_group)
- group=0; // Can't use group key
- else for (ORDER *tmp=group ; tmp ; tmp=tmp->next)
+ m_group= 0; // Can't use group key
+ else for (ORDER *tmp= m_group ; tmp ; tmp= tmp->next)
{
/* Exclude found constant from the list */
if ((*tmp->item)->const_item())
@@ -18178,16 +18242,17 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
*/
(*tmp->item)->marker=4; // Store null in key
if ((*tmp->item)->too_big_for_varchar())
- using_unique_constraint= true;
+ m_using_unique_constraint= true;
}
if (param->group_length >= MAX_BLOB_WIDTH)
- using_unique_constraint= true;
- if (group)
- distinct=0; // Can't use distinct
+ m_using_unique_constraint= true;
+ if (m_group)
+ m_distinct= 0; // Can't use distinct
}
- field_count=param->field_count+param->func_count+param->sum_func_count;
- hidden_field_count=param->hidden_field_count;
+ m_alloced_field_count= param->field_count+param->func_count+param->sum_func_count;
+ DBUG_ASSERT(m_alloced_field_count);
+ const uint field_count= m_alloced_field_count;
/*
When loose index scan is employed as access method, it already
@@ -18199,48 +18264,44 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
if (param->precomputed_group_by)
copy_func_count+= param->sum_func_count;
- init_sql_alloc(&own_root, "tmp_table", TABLE_ALLOC_BLOCK_SIZE, 0,
+ init_sql_alloc(key_memory_TABLE, &own_root, TABLE_ALLOC_BLOCK_SIZE, 0,
MYF(MY_THREAD_SPECIFIC));
if (!multi_alloc_root(&own_root,
&table, sizeof(*table),
&share, sizeof(*share),
&reg_field, sizeof(Field*) * (field_count+1),
- &default_field, sizeof(Field*) * (field_count),
+ &m_default_field, sizeof(Field*) * (field_count),
&blob_field, sizeof(uint)*(field_count+1),
- &from_field, sizeof(Field*)*field_count,
- &copy_func, sizeof(*copy_func)*(copy_func_count+1),
+ &m_from_field, sizeof(Field*)*field_count,
+ &param->items_to_copy,
+ sizeof(param->items_to_copy[0])*(copy_func_count+1),
&param->keyinfo, sizeof(*param->keyinfo),
- &key_part_info,
- sizeof(*key_part_info)*(param->group_parts+1),
+ &m_key_part_info,
+ sizeof(*m_key_part_info)*(param->group_parts+1),
&param->start_recinfo,
sizeof(*param->recinfo)*(field_count*2+4),
&tmpname, (uint) strlen(path)+1,
- &group_buff, (group && ! using_unique_constraint ?
+ &m_group_buff, (m_group && ! m_using_unique_constraint ?
param->group_length : 0),
- &bitmaps, bitmap_buffer_size(field_count)*6,
+ &m_bitmaps, bitmap_buffer_size(field_count)*6,
NullS))
{
- if (temp_pool_slot != MY_BIT_NONE)
- bitmap_lock_clear_bit(&temp_pool, temp_pool_slot);
DBUG_RETURN(NULL); /* purecov: inspected */
}
/* Copy_field belongs to TMP_TABLE_PARAM, allocate it in THD mem_root */
- if (!(param->copy_field= copy= new (thd->mem_root) Copy_field[field_count]))
+ if (!(param->copy_field= new (thd->mem_root) Copy_field[field_count]))
{
- if (temp_pool_slot != MY_BIT_NONE)
- bitmap_lock_clear_bit(&temp_pool, temp_pool_slot);
free_root(&own_root, MYF(0)); /* purecov: inspected */
DBUG_RETURN(NULL); /* purecov: inspected */
}
- param->items_to_copy= copy_func;
strmov(tmpname, path);
/* make table according to fields */
bzero((char*) table,sizeof(*table));
- bzero((char*) reg_field,sizeof(Field*)*(field_count+1));
- bzero((char*) default_field, sizeof(Field*) * (field_count));
- bzero((char*) from_field,sizeof(Field*)*field_count);
+ bzero((char*) reg_field, sizeof(Field*) * (field_count+1));
+ bzero((char*) m_default_field, sizeof(Field*) * (field_count));
+ bzero((char*) m_from_field, sizeof(Field*) * field_count);
table->mem_root= own_root;
mem_root_save= thd->mem_root;
@@ -18251,7 +18312,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
table->reginfo.lock_type=TL_WRITE; /* Will be updated */
table->map=1;
- table->temp_pool_slot = temp_pool_slot;
+ table->temp_pool_slot= m_temp_pool_slot;
table->copy_blobs= 1;
table->in_use= thd;
table->no_rows_with_nulls= param->force_not_null_cols;
@@ -18266,17 +18327,60 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
if (param->schema_table)
share->db= INFORMATION_SCHEMA_NAME;
- /* Calculate which type of fields we will store in the temporary table */
-
- reclength= string_total_length= 0;
- blob_count= string_count= null_count= hidden_null_count= group_null_items= 0;
param->using_outer_summary_function= 0;
+ thd->mem_root= mem_root_save;
+ DBUG_RETURN(table);
+}
+
+
+bool Create_tmp_table::add_fields(THD *thd,
+ TABLE *table,
+ TMP_TABLE_PARAM *param,
+ List<Item> &fields)
+{
+ DBUG_ENTER("Create_tmp_table::add_fields");
+ DBUG_ASSERT(table);
+ DBUG_ASSERT(table->field);
+ DBUG_ASSERT(table->s->blob_field);
+ DBUG_ASSERT(table->s->reclength == 0);
+ DBUG_ASSERT(table->s->fields == 0);
+ DBUG_ASSERT(table->s->blob_fields == 0);
+
+ const bool not_all_columns= !(m_select_options & TMP_TABLE_ALL_COLUMNS);
+ bool distinct_record_structure= m_distinct;
+ uint fieldnr= 0;
+ TABLE_SHARE *share= table->s;
+ Item **copy_func= param->items_to_copy;
+
+ MEM_ROOT *mem_root_save= thd->mem_root;
+ thd->mem_root= &table->mem_root;
List_iterator_fast<Item> li(fields);
Item *item;
- Field **tmp_from_field=from_field;
+ Field **tmp_from_field= m_from_field;
+ while (!m_with_cycle && (item= li++))
+ if (item->common_flags & IS_IN_WITH_CYCLE)
+ {
+ m_with_cycle= true;
+ /*
+ Following distinct_record_structure is (m_distinct || m_with_cycle)
+
+ Note: distinct_record_structure can be true even if m_distinct is
+ false, for example for incr_table in recursive CTE
+ (see select_union_recursive::create_result_table)
+ */
+ distinct_record_structure= true;
+ }
+ li.rewind();
+ uint uneven_delta= 0;
while ((item=li++))
{
+ current_counter= (((param->hidden_field_count < (fieldnr + 1)) &&
+ distinct_record_structure &&
+ (!m_with_cycle ||
+ (item->common_flags & IS_IN_WITH_CYCLE)))?
+ distinct :
+ other);
Item::Type type= item->type();
if (type == Item::COPY_STR_ITEM)
{
@@ -18292,98 +18396,85 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
if ((item->real_type() == Item::SUBSELECT_ITEM) ||
(item->used_tables() & ~OUTER_REF_TABLE_BIT))
{
- /*
- Mark that the we have ignored an item that refers to a summary
- function. We need to know this if someone is going to use
- DISTINCT on the result.
- */
- param->using_outer_summary_function=1;
- continue;
+ /*
+ Mark that the we have ignored an item that refers to a summary
+ function. We need to know this if someone is going to use
+ DISTINCT on the result.
+ */
+ param->using_outer_summary_function=1;
+ continue;
}
}
- if (item->const_item() && (int) hidden_field_count <= 0)
+ if (item->const_item() &&
+ param->hidden_field_count < (fieldnr + 1))
continue; // We don't have to store this
}
- if (type == Item::SUM_FUNC_ITEM && !group && !save_sum_fields)
+ if (type == Item::SUM_FUNC_ITEM && !m_group && !m_save_sum_fields)
{ /* Can't calc group yet */
Item_sum *sum_item= (Item_sum *) item;
sum_item->result_field=0;
- for (i=0 ; i < sum_item->get_arg_count() ; i++)
+ for (uint i= 0 ; i < sum_item->get_arg_count() ; i++)
{
- Item *arg= sum_item->get_arg(i);
- if (!arg->const_item())
- {
+ Item *arg= sum_item->get_arg(i);
+ if (!arg->const_item())
+ {
Item *tmp_item;
Field *new_field=
create_tmp_field(table, arg, &copy_func,
- tmp_from_field, &default_field[fieldnr],
- group != 0,not_all_columns,
- distinct, false);
- if (!new_field)
- goto err; // Should be OOM
- DBUG_ASSERT(!new_field->field_name.str || strlen(new_field->field_name.str) == new_field->field_name.length);
- tmp_from_field++;
- reclength+=new_field->pack_length();
- if (new_field->flags & BLOB_FLAG)
- {
- *blob_field++= fieldnr;
- blob_count++;
- }
- if (new_field->type() == MYSQL_TYPE_BIT)
- total_uneven_bit_length+= new_field->field_length & 7;
- *(reg_field++)= new_field;
- if (new_field->real_type() == MYSQL_TYPE_STRING ||
- new_field->real_type() == MYSQL_TYPE_VARCHAR)
- {
- string_count++;
- string_total_length+= new_field->pack_length();
- }
+ tmp_from_field, &m_default_field[fieldnr],
+ m_group != 0, not_all_columns,
+ distinct_record_structure , false);
+ if (!new_field)
+ goto err; // Should be OOM
+ tmp_from_field++;
+
thd->mem_root= mem_root_save;
if (!(tmp_item= new (thd->mem_root)
Item_temptable_field(thd, new_field)))
goto err;
arg= sum_item->set_arg(i, thd, tmp_item);
thd->mem_root= &table->mem_root;
- if (param->force_not_null_cols)
- {
- new_field->flags|= NOT_NULL_FLAG;
- new_field->null_ptr= NULL;
- }
- if (!(new_field->flags & NOT_NULL_FLAG))
+
+ uneven_delta= m_uneven_bit_length;
+ add_field(table, new_field, fieldnr++, param->force_not_null_cols);
+ uneven_delta= m_uneven_bit_length - uneven_delta;
+ m_field_count[current_counter]++;
+
+ if (!(new_field->flags & NOT_NULL_FLAG))
{
- null_count++;
/*
new_field->maybe_null() is still false, it will be
changed below. But we have to setup Item_field correctly
*/
arg->maybe_null=1;
}
- new_field->field_index= fieldnr++;
- }
+ if (current_counter == distinct)
+ new_field->flags|= FIELD_PART_OF_TMP_UNIQUE;
+ }
}
}
else
{
/*
- The last parameter to create_tmp_field_ex() is a bit tricky:
+ The last parameter to create_tmp_field_ex() is a bit tricky:
- We need to set it to 0 in union, to get fill_record() to modify the
- temporary table.
- We need to set it to 1 on multi-table-update and in select to
- write rows to the temporary table.
- We here distinguish between UNION and multi-table-updates by the fact
- that in the later case group is set to the row pointer.
+ We need to set it to 0 in union, to get fill_record() to modify the
+ temporary table.
+ We need to set it to 1 on multi-table-update and in select to
+ write rows to the temporary table.
+ We here distinguish between UNION and multi-table-updates by the fact
+ that in the later case group is set to the row pointer.
The test for item->marker == 4 is ensure we don't create a group-by
key over a bit field as heap tables can't handle that.
*/
- Field *new_field= (param->schema_table) ?
- item->create_field_for_schema(thd, table) :
+ DBUG_ASSERT(!param->schema_table);
+ Field *new_field=
create_tmp_field(table, item, &copy_func,
- tmp_from_field, &default_field[fieldnr],
- group != 0,
- !force_copy_fields &&
- (not_all_columns || group !=0),
+ tmp_from_field, &m_default_field[fieldnr],
+ m_group != 0,
+ !param->force_copy_fields &&
+ (not_all_columns || m_group !=0),
/*
If item->marker == 4 then we force create_tmp_field
to create a 64-bit longs for BIT fields because HEAP
@@ -18392,14 +18483,13 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
to be usable in this case too.
*/
item->marker == 4 || param->bit_fields_as_long,
- force_copy_fields);
+ param->force_copy_fields);
if (!new_field)
{
- if (unlikely(thd->is_fatal_error))
- goto err; // Got OOM
- continue; // Some kind of const item
+ if (unlikely(thd->is_fatal_error))
+ goto err; // Got OOM
+ continue; // Some kind of const item
}
- DBUG_ASSERT(!new_field->field_name.str || strlen(new_field->field_name.str) == new_field->field_name.length);
if (type == Item::SUM_FUNC_ITEM)
{
Item_sum *agg_item= (Item_sum *) item;
@@ -18426,82 +18516,83 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
agg_item->result_field= new_field;
}
tmp_from_field++;
- if (param->force_not_null_cols)
- {
- new_field->flags|= NOT_NULL_FLAG;
- new_field->null_ptr= NULL;
- }
- reclength+=new_field->pack_length();
- if (!(new_field->flags & NOT_NULL_FLAG))
- null_count++;
- if (new_field->type() == MYSQL_TYPE_BIT)
- total_uneven_bit_length+= new_field->field_length & 7;
- if (new_field->flags & BLOB_FLAG)
- {
- *blob_field++= fieldnr;
- blob_count++;
- }
- if (new_field->real_type() == MYSQL_TYPE_STRING ||
- new_field->real_type() == MYSQL_TYPE_VARCHAR)
- {
- string_count++;
- string_total_length+= new_field->pack_length();
- }
+ uneven_delta= m_uneven_bit_length;
+ add_field(table, new_field, fieldnr++, param->force_not_null_cols);
+ uneven_delta= m_uneven_bit_length - uneven_delta;
+ m_field_count[current_counter]++;
if (item->marker == 4 && item->maybe_null)
{
- group_null_items++;
- new_field->flags|= GROUP_FLAG;
+ m_group_null_items++;
+ new_field->flags|= GROUP_FLAG;
}
- new_field->field_index= fieldnr++;
- *(reg_field++)= new_field;
- }
- if (!--hidden_field_count)
- {
- /*
- This was the last hidden field; Remember how many hidden fields could
- have null
- */
- hidden_null_count=null_count;
- /*
- We need to update hidden_field_count as we may have stored group
- functions with constant arguments
- */
- param->hidden_field_count= fieldnr;
- null_count= 0;
- /*
- On last hidden field we store uneven bit length in
- hidden_uneven_bit_length and proceed calculation of
- uneven bits for visible fields into
- total_uneven_bit_length variable.
- */
- hidden_uneven_bit_length= total_uneven_bit_length;
- total_uneven_bit_length= 0;
+ if (current_counter == distinct)
+ new_field->flags|= FIELD_PART_OF_TMP_UNIQUE;
}
+ m_uneven_bit[current_counter]+= uneven_delta;
}
- DBUG_ASSERT(fieldnr == (uint) (reg_field - table->field));
- DBUG_ASSERT(field_count >= (uint) (reg_field - table->field));
- field_count= fieldnr;
- *reg_field= 0;
- *blob_field= 0; // End marker
- share->fields= field_count;
+ DBUG_ASSERT(fieldnr == m_field_count[other] + m_field_count[distinct]);
+ DBUG_ASSERT(m_blob_count == m_blobs_count[other] + m_blobs_count[distinct]);
+ share->fields= fieldnr;
+ share->blob_fields= m_blob_count;
+ table->field[fieldnr]= 0; // End marker
+ share->blob_field[m_blob_count]= 0; // End marker
+ copy_func[0]= 0; // End marker
+ param->func_count= (uint) (copy_func - param->items_to_copy);
share->column_bitmap_size= bitmap_buffer_size(share->fields);
+ thd->mem_root= mem_root_save;
+ DBUG_RETURN(false);
+
+err:
+ thd->mem_root= mem_root_save;
+ DBUG_RETURN(true);
+}
+
+
+bool Create_tmp_table::finalize(THD *thd,
+ TABLE *table,
+ TMP_TABLE_PARAM *param,
+ bool do_not_open, bool keep_row_order)
+{
+ DBUG_ENTER("Create_tmp_table::finalize");
+ DBUG_ASSERT(table);
+
+ uint null_pack_length[2];
+ uint null_pack_base[2];
+ uint null_counter[2]= {0, 0};
+
+ uint whole_null_pack_length;
+
+ bool use_packed_rows= false;
+ uchar *pos;
+ uchar *null_flags;
+ KEY *keyinfo;
+ TMP_ENGINE_COLUMNDEF *recinfo;
+ TABLE_SHARE *share= table->s;
+ Copy_field *copy= param->copy_field;
+
+ MEM_ROOT *mem_root_save= thd->mem_root;
+ thd->mem_root= &table->mem_root;
+
+ DBUG_ASSERT(m_alloced_field_count >= share->fields);
+ DBUG_ASSERT(m_alloced_field_count >= share->blob_fields);
+
/* If result table is small; use a heap */
/* future: storage engine selection can be made dynamic? */
- if (blob_count || using_unique_constraint
- || (thd->variables.big_tables && !(select_options & SELECT_SMALL_RESULT))
- || (select_options & TMP_TABLE_FORCE_MYISAM)
+ if (share->blob_fields || m_using_unique_constraint
+ || (thd->variables.big_tables && !(m_select_options & SELECT_SMALL_RESULT))
+ || (m_select_options & TMP_TABLE_FORCE_MYISAM)
|| thd->variables.tmp_memory_table_size == 0)
{
share->db_plugin= ha_lock_engine(0, TMP_ENGINE_HTON);
table->file= get_new_handler(share, &table->mem_root,
share->db_type());
- if (group &&
+ if (m_group &&
(param->group_parts > table->file->max_key_parts() ||
param->group_length > table->file->max_key_length()))
- using_unique_constraint= true;
+ m_using_unique_constraint= true;
}
else
{
@@ -18518,35 +18609,38 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
goto err;
}
- if (!using_unique_constraint)
- reclength+= group_null_items; // null flag is stored separately
+ if (!m_using_unique_constraint)
+ share->reclength+= m_group_null_items; // null flag is stored separately
- share->blob_fields= blob_count;
- if (blob_count == 0)
+ if (share->blob_fields == 0)
{
/* We need to ensure that first byte is not 0 for the delete link */
- if (param->hidden_field_count)
- hidden_null_count++;
+ if (m_field_count[other])
+ m_null_count[other]++;
else
- null_count++;
- }
- hidden_null_pack_length= (hidden_null_count + 7 +
- hidden_uneven_bit_length) / 8;
- null_pack_length= (hidden_null_pack_length +
- (null_count + total_uneven_bit_length + 7) / 8);
- reclength+=null_pack_length;
- if (!reclength)
- reclength=1; // Dummy select
+ m_null_count[distinct]++;
+ }
+
+ null_pack_length[other]= (m_null_count[other] + 7 +
+ m_uneven_bit[other]) / 8;
+ null_pack_base[other]= 0;
+ null_pack_length[distinct]= (m_null_count[distinct] + 7 +
+ m_uneven_bit[distinct]) / 8;
+ null_pack_base[distinct]= null_pack_length[other];
+ whole_null_pack_length= null_pack_length[other] +
+ null_pack_length[distinct];
+ share->reclength+= whole_null_pack_length;
+ if (!share->reclength)
+ share->reclength= 1; // Dummy select
/* Use packed rows if there is blobs or a lot of space to gain */
- if (blob_count ||
- (string_total_length >= STRING_TOTAL_LENGTH_TO_PACK_ROWS &&
- (reclength / string_total_length <= RATIO_TO_PACK_ROWS ||
- string_total_length / string_count >= AVG_STRING_LENGTH_TO_PACK_ROWS)))
+ if (share->blob_fields ||
+ (string_total_length() >= STRING_TOTAL_LENGTH_TO_PACK_ROWS &&
+ (share->reclength / string_total_length() <= RATIO_TO_PACK_ROWS ||
+ string_total_length() / string_count() >= AVG_STRING_LENGTH_TO_PACK_ROWS)))
use_packed_rows= 1;
- share->reclength= reclength;
{
- uint alloc_length=ALIGN_SIZE(reclength+MI_UNIQUE_HASH_LENGTH+1);
+ uint alloc_length= ALIGN_SIZE(share->reclength + MI_UNIQUE_HASH_LENGTH+1);
share->rec_buff_length= alloc_length;
if (!(table->record[0]= (uchar*)
alloc_root(&table->mem_root, alloc_length*3)))
@@ -18554,50 +18648,58 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
table->record[1]= table->record[0]+alloc_length;
share->default_values= table->record[1]+alloc_length;
}
- copy_func[0]=0; // End marker
- param->func_count= (uint)(copy_func - param->items_to_copy);
- setup_tmp_table_column_bitmaps(table, bitmaps);
+ setup_tmp_table_column_bitmaps(table, m_bitmaps);
recinfo=param->start_recinfo;
null_flags=(uchar*) table->record[0];
- pos=table->record[0]+ null_pack_length;
- if (null_pack_length)
+ pos=table->record[0]+ whole_null_pack_length;
+ if (whole_null_pack_length)
{
bzero((uchar*) recinfo,sizeof(*recinfo));
recinfo->type=FIELD_NORMAL;
- recinfo->length=null_pack_length;
+ recinfo->length= whole_null_pack_length;
recinfo++;
- bfill(null_flags,null_pack_length,255); // Set null fields
+ bfill(null_flags, whole_null_pack_length, 255); // Set null fields
table->null_flags= (uchar*) table->record[0];
- share->null_fields= null_count+ hidden_null_count;
- share->null_bytes= share->null_bytes_for_compare= null_pack_length;
+ share->null_fields= m_null_count[other] + m_null_count[distinct];
+ share->null_bytes= share->null_bytes_for_compare= whole_null_pack_length;
+ }
+
+ if (share->blob_fields == 0)
+ {
+ null_counter[(m_field_count[other] ? other : distinct)]++;
}
- null_count= (blob_count == 0) ? 1 : 0;
- hidden_field_count=param->hidden_field_count;
- for (i=0,reg_field=table->field; i < field_count; i++,reg_field++,recinfo++)
+ for (uint i= 0; i < share->fields; i++, recinfo++)
{
- Field *field= *reg_field;
+ Field *field= table->field[i];
uint length;
bzero((uchar*) recinfo,sizeof(*recinfo));
+ current_counter= ((field->flags & FIELD_PART_OF_TMP_UNIQUE) ?
+ distinct :
+ other);
+
if (!(field->flags & NOT_NULL_FLAG))
{
- recinfo->null_bit= (uint8)1 << (null_count & 7);
- recinfo->null_pos= null_count/8;
- field->move_field(pos,null_flags+null_count/8,
- (uint8)1 << (null_count & 7));
- null_count++;
+
+ recinfo->null_bit= (uint8)1 << (null_counter[current_counter] & 7);
+ recinfo->null_pos= (null_pack_base[current_counter] +
+ null_counter[current_counter]/8);
+ field->move_field(pos, null_flags + recinfo->null_pos, recinfo->null_bit);
+ null_counter[current_counter]++;
}
else
field->move_field(pos,(uchar*) 0,0);
if (field->type() == MYSQL_TYPE_BIT)
{
/* We have to reserve place for extra bits among null bits */
- ((Field_bit*) field)->set_bit_ptr(null_flags + null_count / 8,
- null_count & 7);
- null_count+= (field->field_length & 7);
+ ((Field_bit*) field)->set_bit_ptr(null_flags +
+ null_pack_base[current_counter] +
+ null_counter[current_counter]/8,
+ null_counter[current_counter] & 7);
+ null_counter[current_counter]+= (field->field_length & 7);
}
field->reset();
@@ -18605,14 +18707,14 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
Test if there is a default field value. The test for ->ptr is to skip
'offset' fields generated by initialize_tables
*/
- if (default_field[i] && default_field[i]->ptr)
+ if (m_default_field[i] && m_default_field[i]->ptr)
{
/*
default_field[i] is set only in the cases when 'field' can
inherit the default value that is defined for the field referred
by the Item_field object from which 'field' has been created.
*/
- const Field *orig_field= default_field[i];
+ const Field *orig_field= m_default_field[i];
/* Get the value from default_values */
if (orig_field->is_null_in_record(orig_field->table->s->default_values))
field->set_null();
@@ -18625,9 +18727,9 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
}
}
- if (from_field[i])
+ if (m_from_field[i])
{ /* Not a table Item */
- copy->set(field,from_field[i],save_sum_fields);
+ copy->set(field, m_from_field[i], m_save_sum_fields);
copy++;
}
length=field->pack_length();
@@ -18635,25 +18737,13 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
/* Make entry for create table */
recinfo->length=length;
- if (field->flags & BLOB_FLAG)
- recinfo->type= FIELD_BLOB;
- else if (use_packed_rows &&
- field->real_type() == MYSQL_TYPE_STRING &&
- length >= MIN_STRING_LENGTH_TO_PACK_ROWS)
- recinfo->type= FIELD_SKIP_ENDSPACE;
- else if (field->real_type() == MYSQL_TYPE_VARCHAR)
- recinfo->type= FIELD_VARCHAR;
- else
- recinfo->type= FIELD_NORMAL;
-
- if (!--hidden_field_count)
- null_count=(null_count+7) & ~7; // move to next byte
+ recinfo->type= field->tmp_engine_column_type(use_packed_rows);
// fix table name in field entry
field->set_table_name(&table->alias);
}
- param->copy_field_end=copy;
+ param->copy_field_end= copy;
param->recinfo= recinfo; // Pointer to after last field
store_record(table,s->default_values); // Make empty default record
@@ -18663,29 +18753,29 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
share->max_rows= (ha_rows) (((share->db_type() == heap_hton) ?
MY_MIN(thd->variables.tmp_memory_table_size,
thd->variables.max_heap_table_size) :
- thd->variables.tmp_memory_table_size) /
+ thd->variables.tmp_disk_table_size) /
share->reclength);
set_if_bigger(share->max_rows,1); // For dummy start options
/*
Push the LIMIT clause to the temporary table creation, so that we
materialize only up to 'rows_limit' records instead of all result records.
*/
- set_if_smaller(share->max_rows, rows_limit);
- param->end_write_records= rows_limit;
+ set_if_smaller(share->max_rows, m_rows_limit);
+ param->end_write_records= m_rows_limit;
keyinfo= param->keyinfo;
- if (group)
+ if (m_group)
{
DBUG_PRINT("info",("Creating group key in temporary table"));
- table->group=group; /* Table is grouped by key */
- param->group_buff=group_buff;
+ table->group= m_group; /* Table is grouped by key */
+ param->group_buff= m_group_buff;
share->keys=1;
- share->uniques= MY_TEST(using_unique_constraint);
+ share->uniques= MY_TEST(m_using_unique_constraint);
table->key_info= table->s->key_info= keyinfo;
table->keys_in_use_for_query.set_bit(0);
share->keys_in_use.set_bit(0);
- keyinfo->key_part=key_part_info;
+ keyinfo->key_part= m_key_part_info;
keyinfo->flags=HA_NOSAME | HA_BINARY_PACK_KEY | HA_PACK_KEY;
keyinfo->ext_key_flags= keyinfo->flags;
keyinfo->usable_key_parts=keyinfo->user_defined_key_parts= param->group_parts;
@@ -18697,29 +18787,29 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
keyinfo->algorithm= HA_KEY_ALG_UNDEF;
keyinfo->is_statistics_from_stat_tables= FALSE;
keyinfo->name= group_key;
- ORDER *cur_group= group;
- for (; cur_group ; cur_group= cur_group->next, key_part_info++)
+ ORDER *cur_group= m_group;
+ for (; cur_group ; cur_group= cur_group->next, m_key_part_info++)
{
Field *field=(*cur_group->item)->get_tmp_table_field();
DBUG_ASSERT(field->table == table);
bool maybe_null=(*cur_group->item)->maybe_null;
- key_part_info->null_bit=0;
- key_part_info->field= field;
- key_part_info->fieldnr= field->field_index + 1;
- if (cur_group == group)
+ m_key_part_info->null_bit=0;
+ m_key_part_info->field= field;
+ m_key_part_info->fieldnr= field->field_index + 1;
+ if (cur_group == m_group)
field->key_start.set_bit(0);
- key_part_info->offset= field->offset(table->record[0]);
- key_part_info->length= (uint16) field->key_length();
- key_part_info->type= (uint8) field->key_type();
- key_part_info->key_type =
- ((ha_base_keytype) key_part_info->type == HA_KEYTYPE_TEXT ||
- (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT1 ||
- (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT2) ?
+ m_key_part_info->offset= field->offset(table->record[0]);
+ m_key_part_info->length= (uint16) field->key_length();
+ m_key_part_info->type= (uint8) field->key_type();
+ m_key_part_info->key_type =
+ ((ha_base_keytype) m_key_part_info->type == HA_KEYTYPE_TEXT ||
+ (ha_base_keytype) m_key_part_info->type == HA_KEYTYPE_VARTEXT1 ||
+ (ha_base_keytype) m_key_part_info->type == HA_KEYTYPE_VARTEXT2) ?
0 : FIELDFLAG_BINARY;
- key_part_info->key_part_flag= 0;
- if (!using_unique_constraint)
+ m_key_part_info->key_part_flag= 0;
+ if (!m_using_unique_constraint)
{
- cur_group->buff=(char*) group_buff;
+ cur_group->buff=(char*) m_group_buff;
if (maybe_null && !field->null_bit)
{
@@ -18734,9 +18824,9 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
}
if (!(cur_group->field= field->new_key_field(thd->mem_root,table,
- group_buff +
+ m_group_buff +
MY_TEST(maybe_null),
- key_part_info->length,
+ m_key_part_info->length,
field->null_ptr,
field->null_bit)))
goto err; /* purecov: inspected */
@@ -18750,26 +18840,29 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
The NULL flag is updated in 'end_update()' and 'end_write()'
*/
keyinfo->flags|= HA_NULL_ARE_EQUAL; // def. that NULL == NULL
- key_part_info->null_bit=field->null_bit;
- key_part_info->null_offset= (uint) (field->null_ptr -
+ m_key_part_info->null_bit=field->null_bit;
+ m_key_part_info->null_offset= (uint) (field->null_ptr -
(uchar*) table->record[0]);
cur_group->buff++; // Pointer to field data
- group_buff++; // Skipp null flag
+ m_group_buff++; // Skipp null flag
}
- group_buff+= cur_group->field->pack_length();
+ m_group_buff+= cur_group->field->pack_length();
}
- keyinfo->key_length+= key_part_info->length;
+ keyinfo->key_length+= m_key_part_info->length;
}
/*
Ensure we didn't overrun the group buffer. The < is only true when
some maybe_null fields was changed to be not null fields.
*/
- DBUG_ASSERT(using_unique_constraint ||
- group_buff <= param->group_buff + param->group_length);
+ DBUG_ASSERT(m_using_unique_constraint ||
+ m_group_buff <= param->group_buff + param->group_length);
}
- if (distinct && field_count != param->hidden_field_count)
+ if (m_distinct && (share->fields != param->hidden_field_count ||
+ m_with_cycle))
{
+ uint i;
+ Field **reg_field;
/*
Create an unique key or an unique constraint over all columns
that should be in the result. In the temporary table, there are
@@ -18778,7 +18871,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
*/
DBUG_PRINT("info",("hidden_field_count: %d", param->hidden_field_count));
- if (blob_count)
+ if (m_blobs_count[distinct])
{
/*
Special mode for index creation in MyISAM used to support unique
@@ -18787,23 +18880,21 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
*/
share->uniques= 1;
}
- null_pack_length-=hidden_null_pack_length;
- keyinfo->user_defined_key_parts=
- ((field_count-param->hidden_field_count)+
- (share->uniques ? MY_TEST(null_pack_length) : 0));
+ keyinfo->user_defined_key_parts= m_field_count[distinct] +
+ (share->uniques ? MY_TEST(null_pack_length[distinct]) : 0);
keyinfo->ext_key_parts= keyinfo->user_defined_key_parts;
keyinfo->usable_key_parts= keyinfo->user_defined_key_parts;
table->distinct= 1;
share->keys= 1;
- if (!(key_part_info= (KEY_PART_INFO*)
+ if (!(m_key_part_info= (KEY_PART_INFO*)
alloc_root(&table->mem_root,
keyinfo->user_defined_key_parts * sizeof(KEY_PART_INFO))))
goto err;
- bzero((void*) key_part_info, keyinfo->user_defined_key_parts * sizeof(KEY_PART_INFO));
+ bzero((void*) m_key_part_info, keyinfo->user_defined_key_parts * sizeof(KEY_PART_INFO));
table->keys_in_use_for_query.set_bit(0);
share->keys_in_use.set_bit(0);
table->key_info= table->s->key_info= keyinfo;
- keyinfo->key_part=key_part_info;
+ keyinfo->key_part= m_key_part_info;
keyinfo->flags=HA_NOSAME | HA_NULL_ARE_EQUAL | HA_BINARY_PACK_KEY | HA_PACK_KEY;
keyinfo->ext_key_flags= keyinfo->flags;
keyinfo->key_length= 0; // Will compute the sum of the parts below.
@@ -18833,41 +18924,43 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
blobs can distinguish NULL from 0. This extra field is not needed
when we do not use UNIQUE indexes for blobs.
*/
- if (null_pack_length && share->uniques)
+ if (null_pack_length[distinct] && share->uniques)
{
- key_part_info->null_bit=0;
- key_part_info->offset=hidden_null_pack_length;
- key_part_info->length=null_pack_length;
- key_part_info->field= new Field_string(table->record[0],
- (uint32) key_part_info->length,
+ m_key_part_info->null_bit=0;
+ m_key_part_info->offset= null_pack_base[distinct];
+ m_key_part_info->length= null_pack_length[distinct];
+ m_key_part_info->field= new Field_string(table->record[0],
+ (uint32) m_key_part_info->length,
(uchar*) 0,
(uint) 0,
Field::NONE,
&null_clex_str, &my_charset_bin);
- if (!key_part_info->field)
+ if (!m_key_part_info->field)
goto err;
- key_part_info->field->init(table);
- key_part_info->key_type=FIELDFLAG_BINARY;
- key_part_info->type= HA_KEYTYPE_BINARY;
- key_part_info->fieldnr= key_part_info->field->field_index + 1;
- key_part_info++;
+ m_key_part_info->field->init(table);
+ m_key_part_info->key_type=FIELDFLAG_BINARY;
+ m_key_part_info->type= HA_KEYTYPE_BINARY;
+ m_key_part_info->fieldnr= m_key_part_info->field->field_index + 1;
+ m_key_part_info++;
}
/* Create a distinct key over the columns we are going to return */
- for (i=param->hidden_field_count, reg_field=table->field + i ;
- i < field_count;
- i++, reg_field++, key_part_info++)
+ for (i= param->hidden_field_count, reg_field= table->field + i ;
+ i < share->fields;
+ i++, reg_field++)
{
- key_part_info->field= *reg_field;
+ if (!((*reg_field)->flags & FIELD_PART_OF_TMP_UNIQUE))
+ continue;
+ m_key_part_info->field= *reg_field;
(*reg_field)->flags |= PART_KEY_FLAG;
- if (key_part_info == keyinfo->key_part)
+ if (m_key_part_info == keyinfo->key_part)
(*reg_field)->key_start.set_bit(0);
- key_part_info->null_bit= (*reg_field)->null_bit;
- key_part_info->null_offset= (uint) ((*reg_field)->null_ptr -
+ m_key_part_info->null_bit= (*reg_field)->null_bit;
+ m_key_part_info->null_offset= (uint) ((*reg_field)->null_ptr -
(uchar*) table->record[0]);
- key_part_info->offset= (*reg_field)->offset(table->record[0]);
- key_part_info->length= (uint16) (*reg_field)->pack_length();
- key_part_info->fieldnr= (*reg_field)->field_index + 1;
+ m_key_part_info->offset= (*reg_field)->offset(table->record[0]);
+ m_key_part_info->length= (uint16) (*reg_field)->pack_length();
+ m_key_part_info->fieldnr= (*reg_field)->field_index + 1;
/* TODO:
The below method of computing the key format length of the
key part is a copy/paste from opt_range.cc, and table.cc.
@@ -18876,34 +18969,25 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
methods is supposed to compute the same length. If so, it
might be reused.
*/
- key_part_info->store_length= key_part_info->length;
+ m_key_part_info->store_length= m_key_part_info->length;
if ((*reg_field)->real_maybe_null())
{
- key_part_info->store_length+= HA_KEY_NULL_LENGTH;
- key_part_info->key_part_flag |= HA_NULL_PART;
- }
- if ((*reg_field)->type() == MYSQL_TYPE_BLOB ||
- (*reg_field)->real_type() == MYSQL_TYPE_VARCHAR ||
- (*reg_field)->type() == MYSQL_TYPE_GEOMETRY)
- {
- if ((*reg_field)->type() == MYSQL_TYPE_BLOB ||
- (*reg_field)->type() == MYSQL_TYPE_GEOMETRY)
- key_part_info->key_part_flag|= HA_BLOB_PART;
- else
- key_part_info->key_part_flag|= HA_VAR_LENGTH_PART;
-
- key_part_info->store_length+=HA_KEY_BLOB_LENGTH;
+ m_key_part_info->store_length+= HA_KEY_NULL_LENGTH;
+ m_key_part_info->key_part_flag |= HA_NULL_PART;
}
+ m_key_part_info->key_part_flag|= (*reg_field)->key_part_flag();
+ m_key_part_info->store_length+= (*reg_field)->key_part_length_bytes();
+ keyinfo->key_length+= m_key_part_info->store_length;
- keyinfo->key_length+= key_part_info->store_length;
-
- key_part_info->type= (uint8) (*reg_field)->key_type();
- key_part_info->key_type =
- ((ha_base_keytype) key_part_info->type == HA_KEYTYPE_TEXT ||
- (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT1 ||
- (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT2) ?
+ m_key_part_info->type= (uint8) (*reg_field)->key_type();
+ m_key_part_info->key_type =
+ ((ha_base_keytype) m_key_part_info->type == HA_KEYTYPE_TEXT ||
+ (ha_base_keytype) m_key_part_info->type == HA_KEYTYPE_VARTEXT1 ||
+ (ha_base_keytype) m_key_part_info->type == HA_KEYTYPE_VARTEXT2) ?
0 : FIELDFLAG_BINARY;
+
+ m_key_part_info++;
}
}
@@ -18917,7 +19001,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
if (!do_not_open)
{
if (instantiate_tmp_table(table, param->keyinfo, param->start_recinfo,
- &param->recinfo, select_options))
+ &param->recinfo, m_select_options))
goto err;
}
@@ -18926,14 +19010,119 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
thd->mem_root= mem_root_save;
- DBUG_RETURN(table);
+ DBUG_RETURN(false);
err:
thd->mem_root= mem_root_save;
- free_tmp_table(thd,table); /* purecov: inspected */
- if (temp_pool_slot != MY_BIT_NONE)
- bitmap_lock_clear_bit(&temp_pool, temp_pool_slot);
- DBUG_RETURN(NULL); /* purecov: inspected */
+ DBUG_RETURN(true); /* purecov: inspected */
+}
+
+
+bool Create_tmp_table::add_schema_fields(THD *thd, TABLE *table,
+ TMP_TABLE_PARAM *param,
+ const ST_SCHEMA_TABLE &schema_table,
+ const MY_BITMAP &bitmap)
+{
+ DBUG_ENTER("Create_tmp_table::add_schema_fields");
+ DBUG_ASSERT(table);
+ DBUG_ASSERT(table->field);
+ DBUG_ASSERT(table->s->blob_field);
+ DBUG_ASSERT(table->s->reclength == 0);
+ DBUG_ASSERT(table->s->fields == 0);
+ DBUG_ASSERT(table->s->blob_fields == 0);
+
+ TABLE_SHARE *share= table->s;
+ ST_FIELD_INFO *defs= schema_table.fields_info;
+ uint fieldnr;
+ MEM_ROOT *mem_root_save= thd->mem_root;
+ thd->mem_root= &table->mem_root;
+
+ for (fieldnr= 0; !defs[fieldnr].end_marker(); fieldnr++)
+ {
+ const ST_FIELD_INFO &def= defs[fieldnr];
+ bool visible= bitmap_is_set(&bitmap, fieldnr);
+ Record_addr addr(def.nullable());
+ const Type_handler *h= def.type_handler();
+ Field *field= h->make_schema_field(&table->mem_root, table,
+ addr, def, visible);
+ if (!field)
+ {
+ thd->mem_root= mem_root_save;
+ DBUG_RETURN(true); // EOM
+ }
+ field->init(table);
+ switch (def.def()) {
+ case DEFAULT_NONE:
+ field->flags|= NO_DEFAULT_VALUE_FLAG;
+ break;
+ case DEFAULT_TYPE_IMPLICIT:
+ break;
+ default:
+ DBUG_ASSERT(0);
+ break;
+ }
+ add_field(table, field, fieldnr, param->force_not_null_cols);
+ }
+
+ share->fields= fieldnr;
+ share->blob_fields= m_blob_count;
+ table->field[fieldnr]= 0; // End marker
+ share->blob_field[m_blob_count]= 0; // End marker
+ param->func_count= 0;
+ share->column_bitmap_size= bitmap_buffer_size(share->fields);
+
+ thd->mem_root= mem_root_save;
+ DBUG_RETURN(false);
+}
+
+
+void Create_tmp_table::cleanup_on_failure(THD *thd, TABLE *table)
+{
+ if (table)
+ free_tmp_table(thd, table);
+ if (m_temp_pool_slot != MY_BIT_NONE)
+ bitmap_lock_clear_bit(&temp_pool, m_temp_pool_slot);
+}
+
+
+TABLE *create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
+ ORDER *group, bool distinct, bool save_sum_fields,
+ ulonglong select_options, ha_rows rows_limit,
+ const LEX_CSTRING *table_alias, bool do_not_open,
+ bool keep_row_order)
+{
+ TABLE *table;
+ Create_tmp_table maker(param, group,
+ distinct, save_sum_fields, select_options, rows_limit);
+ if (!(table= maker.start(thd, param, table_alias)) ||
+ maker.add_fields(thd, table, param, fields) ||
+ maker.finalize(thd, table, param, do_not_open, keep_row_order))
+ {
+ maker.cleanup_on_failure(thd, table);
+ return NULL;
+ }
+ return table;
+}
+
+
+TABLE *create_tmp_table_for_schema(THD *thd, TMP_TABLE_PARAM *param,
+ const ST_SCHEMA_TABLE &schema_table,
+ const MY_BITMAP &bitmap,
+ longlong select_options,
+ const LEX_CSTRING &table_alias,
+ bool keep_row_order)
+{
+ TABLE *table;
+ Create_tmp_table maker(param, (ORDER *) NULL, false, false,
+ select_options, HA_POS_ERROR);
+ if (!(table= maker.start(thd, param, &table_alias)) ||
+ maker.add_schema_fields(thd, table, param, schema_table, bitmap) ||
+ maker.finalize(thd, table, param, false, keep_row_order))
+ {
+ maker.cleanup_on_failure(thd, table);
+ return NULL;
+ }
+ return table;
}
@@ -19051,10 +19240,8 @@ bool Virtual_tmp_table::sp_find_field_by_name(uint *idx,
for (uint i= 0; (f= field[i]); i++)
{
// Use the same comparison style with sp_context::find_variable()
- if (!my_strnncoll(system_charset_info,
- (const uchar *) f->field_name.str,
- f->field_name.length,
- (const uchar *) name.str, name.length))
+ if (!system_charset_info->strnncoll(f->field_name.str, f->field_name.length,
+ name.str, name.length))
{
*idx= i;
return false;
@@ -19809,8 +19996,7 @@ do_select(JOIN *join, Procedure *procedure)
if (join->pushdown_query->store_data_in_temp_table)
{
- JOIN_TAB *last_tab= join->join_tab + join->table_count -
- join->exec_join_tab_cnt();
+ JOIN_TAB *last_tab= join->join_tab + join->exec_join_tab_cnt();
last_tab->next_select= end_send;
enum_nested_loop_state state= last_tab->aggr->end_send();
@@ -19845,7 +20031,7 @@ do_select(JOIN *join, Procedure *procedure)
// HAVING will be checked by end_select
error= (*end_select)(join, 0, 0);
if (error >= NESTED_LOOP_OK)
- error= (*end_select)(join, 0, 1);
+ error= (*end_select)(join, 0, 1);
/*
If we don't go through evaluate_join_record(), do the counting
@@ -19861,7 +20047,8 @@ do_select(JOIN *join, Procedure *procedure)
{
List<Item> *columns_list= (procedure ? &join->procedure_fields_list :
join->fields);
- rc= join->result->send_data(*columns_list) > 0;
+ rc= join->result->send_data_with_check(*columns_list,
+ join->unit, 0) > 0;
}
}
/*
@@ -20343,6 +20530,10 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
if (join_tab->loosescan_match_tab)
join_tab->loosescan_match_tab->found_match= FALSE;
+ const bool pfs_batch_update= join_tab->pfs_batch_update(join);
+ if (pfs_batch_update)
+ join_tab->table->file->start_psi_batch_mode();
+
if (rc != NESTED_LOOP_NO_MORE_ROWS)
{
error= (*join_tab->read_first_record)(join_tab);
@@ -20394,6 +20585,9 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
join_tab->last_inner && !join_tab->found)
rc= evaluate_null_complemented_join_record(join, join_tab);
+ if (pfs_batch_update)
+ join_tab->table->file->end_psi_batch_mode();
+
if (rc == NESTED_LOOP_NO_MORE_ROWS)
rc= NESTED_LOOP_OK;
DBUG_RETURN(rc);
@@ -21537,7 +21731,9 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
int error;
/* result < 0 if row was not accepted and should not be counted */
- if (unlikely((error= join->result->send_data(*fields))))
+ if (unlikely((error= join->result->send_data_with_check(*fields,
+ join->unit,
+ join->send_records))))
{
if (error > 0)
DBUG_RETURN(NESTED_LOOP_ERROR);
@@ -21547,7 +21743,7 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
}
++join->send_records;
- if (join->send_records >= join->unit->select_limit_cnt &&
+ if (join->send_records >= join->unit->lim.get_select_limit() &&
!join->do_send_rows)
{
/*
@@ -21565,7 +21761,7 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
DBUG_RETURN(NESTED_LOOP_QUERY_LIMIT);
}
}
- if (join->send_records >= join->unit->select_limit_cnt &&
+ if (join->send_records >= join->unit->lim.get_select_limit() &&
join->do_send_rows)
{
if (join->select_options & OPTION_FOUND_ROWS)
@@ -21685,7 +21881,9 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
if (join->do_send_rows)
{
- error=join->result->send_data(*fields);
+ error= join->result->send_data_with_check(*fields,
+ join->unit,
+ join->send_records);
if (unlikely(error < 0))
{
/* Duplicate row, don't count */
@@ -21706,13 +21904,13 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
if (end_of_records)
DBUG_RETURN(NESTED_LOOP_OK);
- if (join->send_records >= join->unit->select_limit_cnt &&
+ if (join->send_records >= join->unit->lim.get_select_limit() &&
join->do_send_rows)
{
if (!(join->select_options & OPTION_FOUND_ROWS))
DBUG_RETURN(NESTED_LOOP_QUERY_LIMIT); // Abort nicely
join->do_send_rows=0;
- join->unit->select_limit_cnt = HA_POS_ERROR;
+ join->unit->lim.set_unlimited();
}
else if (join->send_records >= join->fetch_limit)
{
@@ -21797,7 +21995,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (!(join->select_options & OPTION_FOUND_ROWS))
DBUG_RETURN(NESTED_LOOP_QUERY_LIMIT);
join->do_send_rows=0;
- join->unit->select_limit_cnt = HA_POS_ERROR;
+ join->unit->lim.set_unlimited();
}
}
}
@@ -23159,8 +23357,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
(tab->join->select_options &
OPTION_FOUND_ROWS) ?
HA_POS_ERROR :
- tab->join->unit->select_limit_cnt,TRUE,
- TRUE, FALSE, FALSE) <= 0;
+ tab->join->unit->
+ lim.get_select_limit(),
+ TRUE, TRUE, FALSE, FALSE) <= 0;
if (res)
{
select->cond= save_cond;
@@ -23261,7 +23460,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
select->test_quick_select(join->thd, tmp_map, 0,
join->select_options & OPTION_FOUND_ROWS ?
HA_POS_ERROR :
- join->unit->select_limit_cnt,
+ join->unit->lim.get_select_limit(),
TRUE, FALSE, FALSE, FALSE);
if (cond_saved)
@@ -23707,7 +23906,7 @@ JOIN_TAB::remove_duplicates()
if (!field_count && !(join->select_options & OPTION_FOUND_ROWS) && !having)
{ // only const items with no OPTION_FOUND_ROWS
- join->unit->select_limit_cnt= 1; // Only send first row
+ join->unit->lim.set_single_row(); // Only send first row
DBUG_RETURN(false);
}
@@ -23844,21 +24043,21 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
Field **ptr;
DBUG_ENTER("remove_dup_with_hash_index");
- if (unlikely(!my_multi_malloc(MYF(MY_WME),
- &key_buffer,
- (uint) ((key_length + extra_length) *
- (long) file->stats.records),
- &field_lengths,
- (uint) (field_count*sizeof(*field_lengths)),
- NullS)))
+ if (!my_multi_malloc(key_memory_hash_index_key_buffer, MYF(MY_WME),
+ &key_buffer,
+ (uint) ((key_length + extra_length) *
+ (long) file->stats.records),
+ &field_lengths,
+ (uint) (field_count*sizeof(*field_lengths)),
+ NullS))
DBUG_RETURN(1);
for (ptr= first_field, field_length=field_lengths ; *ptr ; ptr++)
(*field_length++)= (*ptr)->sort_length();
- if (unlikely(my_hash_init(&hash, &my_charset_bin,
- (uint) file->stats.records, 0,
- key_length, (my_hash_get_key) 0, 0, 0)))
+ if (my_hash_init(key_memory_hash_index_key_buffer, &hash, &my_charset_bin,
+ (uint) file->stats.records, 0, key_length,
+ (my_hash_get_key) 0, 0, 0))
{
my_free(key_buffer);
DBUG_RETURN(1);
@@ -23894,7 +24093,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
field_length=field_lengths;
for (ptr= first_field ; *ptr ; ptr++)
{
- (*ptr)->make_sort_key(key_pos, *field_length);
+ (*ptr)->make_sort_key_part(key_pos, *field_length);
key_pos+= (*ptr)->maybe_null() + *field_length++;
}
/* Check if it exists before */
@@ -25519,7 +25718,7 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select)
****************************************************************************/
/**
- Replace occurences of group by fields in an expression by ref items.
+ Replace occurrences of group by fields in an expression by ref items.
The function replaces occurrences of group by fields in expr
by ref objects for these fields unless they are under aggregate
@@ -25580,8 +25779,9 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list,
{
Item *new_item;
if (!(new_item= new (thd->mem_root) Item_ref(thd, context,
- group_tmp->item, 0,
- &item->name)))
+ group_tmp->item,
+ null_clex_str,
+ item->name)))
return 1; // fatal_error is set
thd->change_item_tree(arg, new_item);
arg_changed= TRUE;
@@ -25906,8 +26106,9 @@ int JOIN::rollup_send_data(uint idx)
copy_ref_ptr_array(ref_ptrs, rollup.ref_pointer_arrays[i]);
if ((!having || having->val_int()))
{
- if (send_records < unit->select_limit_cnt && do_send_rows &&
- (res= result->send_data(rollup.fields[i])) > 0)
+ if (send_records < unit->lim.get_select_limit() && do_send_rows &&
+ (res= result->send_data_with_check(rollup.fields[i],
+ unit, send_records)) > 0)
return 1;
if (!res)
send_records++;
@@ -26139,8 +26340,10 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta,
/* Enable the table access time tracker only for "ANALYZE stmt" */
if (thd->lex->analyze_stmt)
+ {
table->file->set_time_tracker(&eta->op_tracker);
-
+ eta->op_tracker.my_gap_tracker = &eta->extra_time_tracker;
+ }
/* No need to save id and select_type here, they are kept in Explain_select */
/* table */
@@ -26320,16 +26523,14 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta,
table_list->schema_table->i_s_requested_object & OPTIMIZE_I_S_TABLE)
{
IS_table_read_plan *is_table_read_plan= table_list->is_table_read_plan;
- const char *tmp_buff;
- int f_idx;
StringBuffer<64> key_name_buf;
if (is_table_read_plan->trivial_show_command ||
is_table_read_plan->has_db_lookup_value())
{
/* The "key" has the name of the column referring to the database */
- f_idx= table_list->schema_table->idx_field1;
- tmp_buff= table_list->schema_table->fields_info[f_idx].field_name;
- key_name_buf.append(tmp_buff, strlen(tmp_buff), cs);
+ int f_idx= table_list->schema_table->idx_field1;
+ LEX_CSTRING tmp= table_list->schema_table->fields_info[f_idx].name();
+ key_name_buf.append(tmp, cs);
}
if (is_table_read_plan->trivial_show_command ||
is_table_read_plan->has_table_lookup_value())
@@ -26338,9 +26539,9 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta,
is_table_read_plan->has_db_lookup_value())
key_name_buf.append(',');
- f_idx= table_list->schema_table->idx_field2;
- tmp_buff= table_list->schema_table->fields_info[f_idx].field_name;
- key_name_buf.append(tmp_buff, strlen(tmp_buff), cs);
+ int f_idx= table_list->schema_table->idx_field2;
+ LEX_CSTRING tmp= table_list->schema_table->fields_info[f_idx].name();
+ key_name_buf.append(tmp, cs);
}
if (key_name_buf.length())
@@ -26813,21 +27014,8 @@ int JOIN::save_explain_data_intern(Explain_query *output,
tmp_unit;
tmp_unit= tmp_unit->next_unit())
{
- /*
- Display subqueries only if
- (1) they are not parts of ON clauses that were eliminated by table
- elimination.
- (2) they are not merged derived tables
- (3) they are not hanging CTEs (they are needed for execution)
- */
- if (!(tmp_unit->item && tmp_unit->item->eliminated) && // (1)
- (!tmp_unit->derived ||
- tmp_unit->derived->is_materialized_derived()) && // (2)
- !(tmp_unit->with_element &&
- (!tmp_unit->derived || !tmp_unit->derived->derived_result))) // (3)
- {
+ if (tmp_unit->explainable())
explain->add_child(tmp_unit->first_select()->select_number);
- }
}
if (select_lex->is_top_level_node())
@@ -26881,16 +27069,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
DBUG_ASSERT(ref == unit->item);
}
- /*
- Save plans for child subqueries, when
- (1) they are not parts of eliminated WHERE/ON clauses.
- (2) they are not VIEWs that were "merged for INSERT".
- (3) they are not hanging CTEs (they are needed for execution)
- */
- if (!(unit->item && unit->item->eliminated) && // (1)
- !(unit->derived && unit->derived->merged_for_insert) && // (2)
- !(unit->with_element &&
- (!unit->derived || !unit->derived->derived_result))) // (3)
+ if (unit->explainable())
{
if (mysql_explain_union(thd, unit, result))
DBUG_VOID_RETURN;
@@ -26932,15 +27111,11 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
{
thd->lex->current_select= first;
unit->set_limit(unit->global_parameters());
- res= mysql_select(thd,
- first->table_list.first,
- first->with_wild, first->item_list,
+ res= mysql_select(thd, first->table_list.first, first->item_list,
first->where,
first->order_list.elements + first->group_list.elements,
- first->order_list.first,
- first->group_list.first,
- first->having,
- thd->lex->proc_list.first,
+ first->order_list.first, first->group_list.first,
+ first->having, thd->lex->proc_list.first,
first->options | thd->variables.option_bits | SELECT_DESCRIBE,
result, unit, first);
}
@@ -27147,7 +27322,7 @@ Index_hint::print(THD *thd, String *str)
str->append (STRING_WITH_LEN(" ("));
if (key_name.length)
{
- if (thd && !my_strnncoll(system_charset_info,
+ if (thd && !system_charset_info->strnncoll(
(const uchar *)key_name.str, key_name.length,
(const uchar *)primary_key_name,
strlen(primary_key_name)))
@@ -27397,7 +27572,7 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type)
else
str->append(',');
- if (is_subquery_function() && item->is_autogenerated_name)
+ if (is_subquery_function() && item->is_autogenerated_name())
{
/*
Do not print auto-generated aliases in subqueries. It has no purpose
@@ -27693,8 +27868,8 @@ JOIN::reoptimize(Item *added_where, table_map join_tables,
reset_query_plan();
if (!keyuse.buffer &&
- my_init_dynamic_array(&keyuse, sizeof(KEYUSE), 20, 64,
- MYF(MY_THREAD_SPECIFIC)))
+ my_init_dynamic_array(thd->mem_root->m_psi_key, &keyuse, sizeof(KEYUSE),
+ 20, 64, MYF(MY_THREAD_SPECIFIC)))
{
delete_dynamic(&added_keyuse);
return REOPT_ERROR;
@@ -28786,5 +28961,278 @@ select_handler *SELECT_LEX::find_select_handler(THD *thd)
/**
+ @brief
+ Construct not null conditions for provingly not nullable fields
+
+ @details
+ For each non-constant joined table the function creates a conjunction
+ of IS NOT NULL predicates containing a predicate for each field used
+ in the WHERE clause or an OR expression such that
+ - is declared as nullable
+ - for which it can proved be that it is null-rejected
+ - is a part of some index.
+ This conjunction could be anded with either the WHERE condition or with
+ an ON expression and the modified join query would produce the same
+ result set as the original one.
+ If a conjunction of IS NOT NULL predicates is constructed for an inner
+ table of an outer join OJ that is not an inner table of embedded outer
+ joins then it is to be anded with the ON expression of OJ.
+ The constructed conjunctions of IS NOT NULL predicates are attached
+ to the corresponding tables. They used for range analysis complementary
+ to other sargable range conditions.
+
+ @note
+ Let f be a field of the joined table t. In the context of the upper
+ paragraph field f is called null-rejected if any the following holds:
+
+ - t is a table of a top inner join and a conjunctive formula that rejects
+ rows with null values for f can be extracted from the WHERE condition
+
+ - t is an outer table of a top outer join operation and a conjunctive
+ formula over the outer tables of the outer join that rejects rows with
+ null values for can be extracted from the WHERE condition
+
+ - t is an outer table of a non-top outer join operation and a conjunctive
+ formula over the outer tables of the outer join that rejects rows with
+ null values for f can be extracted from the ON expression of the
+ embedding outer join
+
+ - the joined table is an inner table of a outer join operation and
+ a conjunctive formula over inner tables of the outer join that rejects
+ rows with null values for f can be extracted from the ON expression of
+ the outer join operation.
+
+ It is assumed above that all inner join nests have been eliminated and
+ that all possible conversions of outer joins into inner joins have been
+ already done.
+*/
+
+void JOIN::make_notnull_conds_for_range_scans()
+{
+ DBUG_ENTER("JOIN::make_notnull_conds_for_range_scans");
+
+
+ if (impossible_where ||
+ !optimizer_flag(thd, OPTIMIZER_SWITCH_NOT_NULL_RANGE_SCAN))
+ {
+ /* Complementary range analysis is not needed */
+ DBUG_VOID_RETURN;
+ }
+
+ if (conds && build_notnull_conds_for_range_scans(this, conds,
+ conds->used_tables()))
+ {
+ Item *false_cond= new (thd->mem_root) Item_int(thd, (longlong) 0, 1);
+ if (false_cond)
+ {
+ /*
+ Found a IS NULL conjunctive predicate for a null-rejected field
+ in the WHERE clause
+ */
+ conds= false_cond;
+ cond_equal= 0;
+ impossible_where= true;
+ }
+ DBUG_VOID_RETURN;
+ }
+
+ List_iterator<TABLE_LIST> li(*join_list);
+ TABLE_LIST *tbl;
+ while ((tbl= li++))
+ {
+ if (tbl->on_expr)
+ {
+ if (tbl->nested_join)
+ {
+ build_notnull_conds_for_inner_nest_of_outer_join(this, tbl);
+ }
+ else if (build_notnull_conds_for_range_scans(this, tbl->on_expr,
+ tbl->table->map))
+ {
+ /*
+ Found a IS NULL conjunctive predicate for a null-rejected field
+ of the inner table of an outer join with ON expression tbl->on_expr
+ */
+ Item *false_cond= new (thd->mem_root) Item_int(thd, (longlong) 0, 1);
+ if (false_cond)
+ tbl->on_expr= false_cond;
+ }
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief
+ Build not null conditions for range scans of given join tables
+
+ @param join the join for whose tables not null conditions are to be built
+ @param cond the condition from which not null predicates are to be inferred
+ @param allowed the bit map of join tables to be taken into account
+
+ @details
+ For each join table t from the 'allowed' set of tables the function finds
+ all fields whose null-rejectedness can be inferred from null-rejectedness
+ of the condition cond. For each found field f from table t such that it
+ participates at least in one index on table t a NOT NULL predicate is
+ constructed and a conjunction of all such predicates is attached to t.
+ If when looking for null-rejecting fields of t it is discovered one of its
+ fields has to be null-rejected and there is IS NULL conjunctive top level
+ predicate for this field then the function immediately returns true.
+ The function uses the bitmap TABLE::tmp_set to mark found null-rejected
+ fields of table t.
+
+ @note
+ Currently only top level conjuncts without disjunctive sub-formulas are
+ are taken into account when looking for null-rejected fields.
+
+ @retval
+ true if a contradiction is inferred
+ false otherwise
+*/
+
+static
+bool build_notnull_conds_for_range_scans(JOIN *join, Item *cond,
+ table_map allowed)
+{
+ THD *thd= join->thd;
+
+ DBUG_ENTER("build_notnull_conds_for_range_scans");
+
+ for (JOIN_TAB *s= join->join_tab + join->const_tables ;
+ s < join->join_tab + join->table_count ; s++)
+ {
+ /* Clear all needed bitmaps to mark found fields */
+ if (allowed & s->table->map)
+ bitmap_clear_all(&s->table->tmp_set);
+ }
+
+ /*
+ Find all null-rejected fields assuming that cond is null-rejected and
+ only formulas over tables from 'allowed' are to be taken into account
+ */
+ if (cond->find_not_null_fields(allowed))
+ DBUG_RETURN(true);
+
+ /*
+ For each table t from 'allowed' build a conjunction of NOT NULL predicates
+ constructed for all found fields if they are included in some indexes.
+ If the construction of the conjunction succeeds attach the formula to
+ t->table->notnull_cond. The condition will be used to look for complementary
+ range scans.
+ */
+ for (JOIN_TAB *s= join->join_tab + join->const_tables ;
+ s < join->join_tab + join->table_count ; s++)
+ {
+ TABLE *tab= s->table;
+ List<Item> notnull_list;
+ Item *notnull_cond= 0;
+
+ if (!(allowed & tab->map))
+ continue;
+
+ for (Field** field_ptr= tab->field; *field_ptr; field_ptr++)
+ {
+ Field *field= *field_ptr;
+ if (field->part_of_key.is_clear_all())
+ continue;
+ if (!bitmap_is_set(&tab->tmp_set, field->field_index))
+ continue;
+ Item_field *field_item= new (thd->mem_root) Item_field(thd, field);
+ if (!field_item)
+ continue;
+ Item *isnotnull_item=
+ new (thd->mem_root) Item_func_isnotnull(thd, field_item);
+ if (!isnotnull_item)
+ continue;
+ if (notnull_list.push_back(isnotnull_item, thd->mem_root))
+ continue;
+ s->const_keys.merge(field->part_of_key);
+ }
+
+ switch (notnull_list.elements) {
+ case 0:
+ break;
+ case 1:
+ notnull_cond= notnull_list.head();
+ break;
+ default:
+ notnull_cond=
+ new (thd->mem_root) Item_cond_and(thd, notnull_list);
+ }
+ if (notnull_cond && !notnull_cond->fix_fields(thd, 0))
+ {
+ tab->notnull_cond= notnull_cond;
+ }
+ }
+ DBUG_RETURN(false);
+}
+
+
+/**
+ @brief
+ Build not null conditions for inner nest tables of an outer join
+
+ @param join the join for whose table nest not null conditions are to be built
+ @param nest_tbl the nest of the inner tables of an outer join
+
+ @details
+ The function assumes that nest_tbl is the nest of the inner tables of an
+ outer join and so an ON expression for this outer join is attached to
+ nest_tbl.
+ The function selects the tables of the nest_tbl that are not inner tables of
+ embedded outer joins and then it calls build_notnull_conds_for_range_scans()
+ for nest_tbl->on_expr and the bitmap for the selected tables. This call
+ finds all fields belonging to the selected tables whose null-rejectedness
+ can be inferred from the null-rejectedness of nest_tbl->on_expr. After this
+ the function recursively finds all null_rejected fields for the remaining
+ tables from the nest of nest_tbl.
+*/
+
+static
+void build_notnull_conds_for_inner_nest_of_outer_join(JOIN *join,
+ TABLE_LIST *nest_tbl)
+{
+ TABLE_LIST *tbl;
+ table_map used_tables= 0;
+ THD *thd= join->thd;
+ List_iterator<TABLE_LIST> li(nest_tbl->nested_join->join_list);
+
+ while ((tbl= li++))
+ {
+ if (!tbl->on_expr)
+ used_tables|= tbl->table->map;
+ }
+ if (used_tables &&
+ build_notnull_conds_for_range_scans(join, nest_tbl->on_expr, used_tables))
+ {
+ Item *false_cond= new (thd->mem_root) Item_int(thd, (longlong) 0, 1);
+ if (false_cond)
+ nest_tbl->on_expr= false_cond;
+ }
+
+ li.rewind();
+ while ((tbl= li++))
+ {
+ if (tbl->on_expr)
+ {
+ if (tbl->nested_join)
+ {
+ build_notnull_conds_for_inner_nest_of_outer_join(join, tbl);
+ }
+ else if (build_notnull_conds_for_range_scans(join, tbl->on_expr,
+ tbl->table->map))
+ {
+ Item *false_cond= new (thd->mem_root) Item_int(thd, (longlong) 0, 1);
+ if (false_cond)
+ tbl->on_expr= false_cond;
+ }
+ }
+ }
+}
+
+
+/**
@} (end of group Query_Optimizer)
*/
diff --git a/sql/sql_select.h b/sql/sql_select.h
index b9043a851e7..8b2df74702b 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -247,13 +247,13 @@ class SplM_opt_info;
typedef struct st_join_table {
TABLE *table;
TABLE_LIST *tab_list;
- KEYUSE *keyuse; /**< pointer to first used key */
+ KEYUSE *keyuse; /**< pointer to first used key */
KEY *hj_key; /**< descriptor of the used best hash join key
- not supported by any index */
+ not supported by any index */
SQL_SELECT *select;
COND *select_cond;
COND *on_precond; /**< part of on condition to check before
- accessing the first inner table */
+ accessing the first inner table */
QUICK_SELECT_I *quick;
/*
The value of select_cond before we've attempted to do Index Condition
@@ -635,6 +635,8 @@ typedef struct st_join_table {
ha_rows get_examined_rows();
bool preread_init();
+ bool pfs_batch_update(JOIN *join);
+
bool is_sjm_nest() { return MY_TEST(bush_children); }
/*
@@ -1095,7 +1097,7 @@ protected:
keyuse.buffer= NULL;
keyuse.malloc_flags= 0;
best_positions= 0; /* To detect errors */
- error= my_multi_malloc(MYF(MY_WME),
+ error= my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME),
&best_positions,
sizeof(*best_positions) * (tables + 1),
&join_tab_keyuse,
@@ -1620,10 +1622,9 @@ public:
return exec_join_tab_cnt() + aggr_tables - 1;
}
- int prepare(TABLE_LIST *tables, uint wind_num,
- COND *conds, uint og_num, ORDER *order, bool skip_order_by,
- ORDER *group, Item *having, ORDER *proc_param, SELECT_LEX *select,
- SELECT_LEX_UNIT *unit);
+ int prepare(TABLE_LIST *tables, COND *conds, uint og_num, ORDER *order,
+ bool skip_order_by, ORDER *group, Item *having,
+ ORDER *proc_param, SELECT_LEX *select, SELECT_LEX_UNIT *unit);
bool prepare_stage2();
int optimize();
int optimize_inner();
@@ -1783,6 +1784,7 @@ public:
void add_keyuses_for_splitting();
bool inject_best_splitting_cond(table_map remaining_tables);
bool fix_all_splittings_in_plan();
+ void make_notnull_conds_for_range_scans();
bool transform_in_predicates_into_in_subq(THD *thd);
private:
@@ -2096,8 +2098,7 @@ int join_read_key2(THD *thd, struct st_join_table *tab, TABLE *table,
bool handle_select(THD *thd, LEX *lex, select_result *result,
ulong setup_tables_done_option);
-bool mysql_select(THD *thd,
- TABLE_LIST *tables, uint wild_num, List<Item> &list,
+bool mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &list,
COND *conds, uint og_num, ORDER *order, ORDER *group,
Item *having, ORDER *proc_param, ulonglong select_type,
select_result *result, SELECT_LEX_UNIT *unit,
@@ -2426,6 +2427,13 @@ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ulonglong select_options, ha_rows rows_limit,
const LEX_CSTRING *alias, bool do_not_open=FALSE,
bool keep_row_order= FALSE);
+TABLE *create_tmp_table_for_schema(THD *thd, TMP_TABLE_PARAM *param,
+ const ST_SCHEMA_TABLE &schema_table,
+ const MY_BITMAP &bitmap,
+ longlong select_options,
+ const LEX_CSTRING &alias,
+ bool keep_row_order);
+
void free_tmp_table(THD *thd, TABLE *entry);
bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table,
TMP_ENGINE_COLUMNDEF *start_recinfo,
diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc
index 035fb1211e6..a5676b8989a 100644
--- a/sql/sql_sequence.cc
+++ b/sql/sql_sequence.cc
@@ -48,20 +48,20 @@ struct Field_definition
static Field_definition sequence_structure[]=
{
- {"next_not_cached_value", 21, &type_handler_longlong,
+ {"next_not_cached_value", 21, &type_handler_slonglong,
{STRING_WITH_LEN("")}, FL},
- {"minimum_value", 21, &type_handler_longlong, {STRING_WITH_LEN("")}, FL},
- {"maximum_value", 21, &type_handler_longlong, {STRING_WITH_LEN("")}, FL},
- {"start_value", 21, &type_handler_longlong, {STRING_WITH_LEN("start value when sequences is created or value if RESTART is used")}, FL},
- {"increment", 21, &type_handler_longlong,
+ {"minimum_value", 21, &type_handler_slonglong, {STRING_WITH_LEN("")}, FL},
+ {"maximum_value", 21, &type_handler_slonglong, {STRING_WITH_LEN("")}, FL},
+ {"start_value", 21, &type_handler_slonglong, {STRING_WITH_LEN("start value when sequences is created or value if RESTART is used")}, FL},
+ {"increment", 21, &type_handler_slonglong,
{STRING_WITH_LEN("increment value")}, FL},
- {"cache_size", 21, &type_handler_longlong, {STRING_WITH_LEN("")},
+ {"cache_size", 21, &type_handler_ulonglong, {STRING_WITH_LEN("")},
FL | UNSIGNED_FLAG},
- {"cycle_option", 1, &type_handler_tiny, {STRING_WITH_LEN("0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed")},
+ {"cycle_option", 1, &type_handler_utiny, {STRING_WITH_LEN("0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed")},
FL | UNSIGNED_FLAG },
- {"cycle_count", 21, &type_handler_longlong,
+ {"cycle_count", 21, &type_handler_slonglong,
{STRING_WITH_LEN("How many cycles have been done")}, FL},
- {NULL, 0, &type_handler_longlong, {STRING_WITH_LEN("")}, 0}
+ {NULL, 0, &type_handler_slonglong, {STRING_WITH_LEN("")}, 0}
};
#undef FL
@@ -452,10 +452,9 @@ int SEQUENCE::read_initial_values(TABLE *table)
where we don't have a mdl lock on the table
*/
- mdl_request.init(MDL_key::TABLE,
- table->s->db.str,
- table->s->table_name.str,
- MDL_SHARED_READ, MDL_EXPLICIT);
+ MDL_REQUEST_INIT(&mdl_request, MDL_key::TABLE, table->s->db.str,
+ table->s->table_name.str, MDL_SHARED_READ,
+ MDL_EXPLICIT);
mdl_requests.push_front(&mdl_request);
if (thd->mdl_context.acquire_locks(&mdl_requests,
thd->variables.lock_wait_timeout))
diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc
index 7913a7d2b9f..1d12e95bbbb 100644
--- a/sql/sql_servers.cc
+++ b/sql/sql_servers.cc
@@ -93,6 +93,8 @@ static uchar *servers_cache_get_key(FOREIGN_SERVER *server, size_t *length,
DBUG_RETURN((uchar*) server->server_name);
}
+static PSI_memory_key key_memory_servers;
+
#ifdef HAVE_PSI_INTERFACE
static PSI_rwlock_key key_rwlock_THR_LOCK_servers;
@@ -101,6 +103,11 @@ static PSI_rwlock_info all_servers_cache_rwlocks[]=
{ &key_rwlock_THR_LOCK_servers, "THR_LOCK_servers", PSI_FLAG_GLOBAL}
};
+static PSI_memory_info all_servers_cache_memory[]=
+{
+ { &key_memory_servers, "servers_cache", PSI_FLAG_GLOBAL}
+};
+
static void init_servers_cache_psi_keys(void)
{
const char* category= "sql";
@@ -111,6 +118,9 @@ static void init_servers_cache_psi_keys(void)
count= array_elements(all_servers_cache_rwlocks);
PSI_server->register_rwlock(category, all_servers_cache_rwlocks, count);
+
+ count= array_elements(all_servers_cache_memory);
+ mysql_memory_register(category, all_servers_cache_memory, count);
}
#endif /* HAVE_PSI_INTERFACE */
@@ -148,7 +158,7 @@ bool servers_init(bool dont_read_servers_table)
DBUG_RETURN(TRUE);
/* initialise our servers cache */
- if (my_hash_init(&servers_cache, system_charset_info, 32, 0, 0,
+ if (my_hash_init(key_memory_servers, &servers_cache, system_charset_info, 32, 0, 0,
(my_hash_get_key) servers_cache_get_key, 0, 0))
{
return_val= TRUE; /* we failed, out of memory? */
@@ -156,7 +166,7 @@ bool servers_init(bool dont_read_servers_table)
}
/* Initialize the mem root for data */
- init_sql_alloc(&mem, "servers", ACL_ALLOC_BLOCK_SIZE, 0,
+ init_sql_alloc(key_memory_servers, &mem, ACL_ALLOC_BLOCK_SIZE, 0,
MYF(MY_THREAD_SPECIFIC));
if (dont_read_servers_table)
@@ -206,7 +216,7 @@ static bool servers_load(THD *thd, TABLE_LIST *tables)
my_hash_reset(&servers_cache);
free_root(&mem, MYF(0));
- init_sql_alloc(&mem, "servers_load", ACL_ALLOC_BLOCK_SIZE, 0, MYF(0));
+ init_sql_alloc(key_memory_servers, &mem, ACL_ALLOC_BLOCK_SIZE, 0, MYF(0));
if (init_read_record(&read_record_info,thd,table=tables[0].table, NULL, NULL,
1,0, FALSE))
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 409574d4686..2b1be46b807 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2009, 2019, MariaDB
+ Copyright (c) 2009, 2020, 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
@@ -93,7 +93,6 @@ enum enum_i_s_events_fields
ISE_DB_CL
};
-#define USERNAME_WITH_HOST_CHAR_LENGTH (USERNAME_CHAR_LENGTH + HOSTNAME_LENGTH + 2)
static const LEX_CSTRING trg_action_time_type_names[]=
{
@@ -123,14 +122,6 @@ static const char *ha_choice_values[] = {"", "0", "1"};
static void store_key_options(THD *, String *, TABLE *, KEY *);
-#ifdef WITH_PARTITION_STORAGE_ENGINE
-static void get_cs_converted_string_value(THD *thd,
- String *input_str,
- String *output_str,
- CHARSET_INFO *cs,
- bool use_hex);
-#endif
-
static int show_create_view(THD *thd, TABLE_LIST *table, String *buff);
static int show_create_sequence(THD *thd, TABLE_LIST *table_list,
String *packet);
@@ -355,15 +346,14 @@ int fill_all_plugins(THD *thd, TABLE_LIST *tables, COND *cond)
{
if (lookup.wild_db_value)
{
- if (my_wildcmp(files_charset_info, dl.str, dlend, wstr, wend,
- wild_prefix, wild_one, wild_many))
+ if (files_charset_info->wildcmp(dl.str, dlend, wstr, wend,
+ wild_prefix, wild_one, wild_many))
continue;
}
else
{
- if (my_strnncoll(files_charset_info,
- (uchar*)dl.str, dl.length,
- (uchar*)lookup.db_value.str, lookup.db_value.length))
+ if (files_charset_info->strnncoll(dl.str, dl.length,
+ lookup.db_value.str, lookup.db_value.length))
continue;
}
}
@@ -377,124 +367,6 @@ int fill_all_plugins(THD *thd, TABLE_LIST *tables, COND *cond)
}
-#ifdef HAVE_SPATIAL
-static int fill_spatial_ref_sys(THD *thd, TABLE_LIST *tables, COND *cond)
-{
- DBUG_ENTER("fill_spatial_ref_sys");
- TABLE *table= tables->table;
- CHARSET_INFO *cs= system_charset_info;
- int result= 1;
-
- restore_record(table, s->default_values);
-
- table->field[0]->store(-1, FALSE); /*SRID*/
- table->field[1]->store(STRING_WITH_LEN("Not defined"), cs); /*AUTH_NAME*/
- table->field[2]->store(-1, FALSE); /*AUTH_SRID*/
- table->field[3]->store(STRING_WITH_LEN(
- "LOCAL_CS[\"Spatial reference wasn't specified\","
- "LOCAL_DATUM[\"Unknown\",0]," "UNIT[\"m\",1.0]," "AXIS[\"x\",EAST],"
- "AXIS[\"y\",NORTH]]"), cs);/*SRTEXT*/
- if (schema_table_store_record(thd, table))
- goto exit;
-
- table->field[0]->store(0, TRUE); /*SRID*/
- table->field[1]->store(STRING_WITH_LEN("EPSG"), cs); /*AUTH_NAME*/
- table->field[2]->store(404000, TRUE); /*AUTH_SRID*/
- table->field[3]->store(STRING_WITH_LEN(
- "LOCAL_CS[\"Wildcard 2D cartesian plane in metric unit\","
- "LOCAL_DATUM[\"Unknown\",0]," "UNIT[\"m\",1.0],"
- "AXIS[\"x\",EAST]," "AXIS[\"y\",NORTH],"
- "AUTHORITY[\"EPSG\",\"404000\"]]"), cs);/*SRTEXT*/
- if (schema_table_store_record(thd, table))
- goto exit;
-
- result= 0;
-
-exit:
- DBUG_RETURN(result);
-}
-
-
-static int get_geometry_column_record(THD *thd, TABLE_LIST *tables,
- TABLE *table, bool res,
- const LEX_CSTRING *db_name,
- const LEX_CSTRING *table_name)
-{
- CHARSET_INFO *cs= system_charset_info;
- TABLE *show_table;
- Field **ptr, *field;
- DBUG_ENTER("get_geometry_column_record");
-
- if (res)
- {
- if (thd->lex->sql_command != SQLCOM_SHOW_FIELDS)
- {
- /*
- I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS
- rather than in SHOW COLUMNS
- */
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
- thd->get_stmt_da()->sql_errno(),
- thd->get_stmt_da()->message());
- thd->clear_error();
- res= 0;
- }
- DBUG_RETURN(res);
- }
-
- if (tables->schema_table)
- goto exit;
- show_table= tables->table;
- ptr= show_table->field;
- show_table->use_all_columns(); // Required for default
- restore_record(show_table, s->default_values);
-
- for (; (field= *ptr) ; ptr++)
- if (field->type() == MYSQL_TYPE_GEOMETRY)
- {
- Field_geom *fg= (Field_geom *) field;
-
- DEBUG_SYNC(thd, "get_schema_column");
-
- /* Get default row, with all NULL fields set to NULL */
- restore_record(table, s->default_values);
-
- /*F_TABLE_CATALOG*/
- table->field[0]->store(STRING_WITH_LEN("def"), cs);
- /*F_TABLE_SCHEMA*/
- table->field[1]->store(db_name->str, db_name->length, cs);
- /*F_TABLE_NAME*/
- table->field[2]->store(table_name->str, table_name->length, cs);
- /*G_TABLE_CATALOG*/
- table->field[4]->store(STRING_WITH_LEN("def"), cs);
- /*G_TABLE_SCHEMA*/
- table->field[5]->store(db_name->str, db_name->length, cs);
- /*G_TABLE_NAME*/
- table->field[6]->store(table_name->str, table_name->length, cs);
- /*G_GEOMETRY_COLUMN*/
- table->field[7]->store(field->field_name.str, field->field_name.length,
- cs);
- /*STORAGE_TYPE*/
- table->field[8]->store(1LL, TRUE); /*Always 1 (binary implementation)*/
- /*GEOMETRY_TYPE*/
- table->field[9]->store((longlong) (fg->get_geometry_type()), TRUE);
- /*COORD_DIMENSION*/
- table->field[10]->store(2LL, TRUE);
- /*MAX_PPR*/
- table->field[11]->set_null();
- /*SRID*/
- table->field[12]->store((longlong) (fg->get_srid()), TRUE);
-
- if (schema_table_store_record(thd, table))
- DBUG_RETURN(1);
- }
-
-exit:
- DBUG_RETURN(0);
-}
-#endif /*HAVE_SPATIAL*/
-
-
/***************************************************************************
** List all Authors.
** If you can update it, you get to be in it :)
@@ -608,7 +480,10 @@ static struct show_privileges_st sys_privileges[]=
{"Proxy", "Server Admin", "To make proxy user possible"},
{"References", "Databases,Tables", "To have references on tables"},
{"Reload", "Server Admin", "To reload or refresh tables, logs and privileges"},
- {"Replication client","Server Admin","To ask where the slave or master servers are"},
+ {"Binlog admin", "Server", "To purge binary logs"},
+ {"Binlog monitor", "Server", "To use SHOW BINLOG STATUS and SHOW BINARY LOG"},
+ {"Replication master admin", "Server", "To monitor connected slaves"},
+ {"Replication slave admin", "Server", "To start/monitor/stop slave and apply binlog events"},
{"Replication slave","Server Admin","To read binary log events from the master"},
{"Select", "Tables", "To retrieve rows from table"},
{"Show databases","Server Admin","To see all databases with SHOW DATABASES"},
@@ -618,6 +493,10 @@ static struct show_privileges_st sys_privileges[]=
{"Trigger","Tables", "To use triggers"},
{"Create tablespace", "Server Admin", "To create/alter/drop tablespaces"},
{"Update", "Tables", "To update existing rows"},
+ {"Set user","Server", "To create views and stored routines with a different definer"},
+ {"Federated admin", "Server", "To execute the CREATE SERVER, ALTER SERVER, DROP SERVER statements"},
+ {"Connection admin", "Server", "To bypass connection limits and kill other users' connections"},
+ {"Read_only admin", "Server", "To perform write operations even if @@read_only=ON"},
{"Usage","Server Admin","No privileges - allow connect only"},
{NullS, NullS, NullS}
};
@@ -699,8 +578,8 @@ static bool skip_ignored_dir_check= TRUE;
bool
ignore_db_dirs_init()
{
- return my_init_dynamic_array(&ignore_db_dirs_array, sizeof(LEX_CSTRING *),
- 0, 0, MYF(0));
+ return my_init_dynamic_array(key_memory_ignored_db, &ignore_db_dirs_array,
+ sizeof(LEX_STRING *), 0, 0, MYF(0));
}
@@ -748,8 +627,8 @@ push_ignored_db_dir(char *path)
return true;
// No need to normalize, it's only a directory name, not a path.
- if (!my_multi_malloc(0,
- &new_elt, sizeof(LEX_CSTRING),
+ if (!my_multi_malloc(key_memory_ignored_db, MYF(0),
+ &new_elt, sizeof(LEX_STRING),
&new_elt_buffer, path_len + 1,
NullS))
return true;
@@ -829,7 +708,7 @@ void ignore_db_dirs_append(const char *dirname_arg)
LEX_STRING *new_entry;
size_t len= strlen(dirname_arg);
- if (!my_multi_malloc(0,
+ if (!my_multi_malloc(PSI_INSTRUMENT_ME, MYF(0),
&new_entry, sizeof(LEX_STRING),
&new_entry_buf, len + 1,
NullS))
@@ -851,7 +730,7 @@ void ignore_db_dirs_append(const char *dirname_arg)
// Add one for comma and one for \0.
size_t newlen= curlen + len + 1 + 1;
char *new_db_dirs;
- if (!(new_db_dirs= (char*)my_malloc(newlen ,MYF(0))))
+ if (!(new_db_dirs= (char*)my_malloc(PSI_INSTRUMENT_ME, newlen, MYF(0))))
{
// This is not a critical condition
return;
@@ -877,12 +756,10 @@ ignore_db_dirs_process_additions()
skip_ignored_dir_check= TRUE;
- if (my_hash_init(&ignore_db_dirs_hash,
- lower_case_table_names ?
- character_set_filesystem : &my_charset_bin,
- 0, 0, 0, db_dirs_hash_get_key,
- dispose_db_dir,
- HASH_UNIQUE))
+ if (my_hash_init(key_memory_ignored_db, &ignore_db_dirs_hash,
+ lower_case_table_names ? character_set_filesystem :
+ &my_charset_bin, 0, 0, 0, db_dirs_hash_get_key,
+ dispose_db_dir, HASH_UNIQUE))
return true;
/* len starts from 1 because of the terminating zero. */
@@ -904,7 +781,8 @@ ignore_db_dirs_process_additions()
len--;
/* +1 the terminating zero */
- ptr= opt_ignore_db_dirs= (char *) my_malloc(len + 1, MYF(0));
+ ptr= opt_ignore_db_dirs= (char *) my_malloc(key_memory_ignored_db, len + 1,
+ MYF(0));
if (!ptr)
return true;
@@ -1274,10 +1152,10 @@ mysqld_show_create_get_fields(THD *thd, TABLE_LIST *table_list,
access is granted. We need to check if table_list->grant.privilege
contains any table-specific privilege.
*/
- DBUG_PRINT("debug", ("table_list->grant.privilege: %lx",
- table_list->grant.privilege));
+ DBUG_PRINT("debug", ("table_list->grant.privilege: %llx",
+ (longlong) (table_list->grant.privilege)));
if (check_some_access(thd, SHOW_CREATE_TABLE_ACLS, table_list) ||
- (table_list->grant.privilege & SHOW_CREATE_TABLE_ACLS) == 0)
+ (table_list->grant.privilege & SHOW_CREATE_TABLE_ACLS) == NO_ACL)
{
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
"SHOW", thd->security_ctx->priv_user,
@@ -1471,11 +1349,11 @@ bool mysqld_show_create_db(THD *thd, LEX_CSTRING *dbname,
LEX_CSTRING *orig_dbname,
const DDL_options_st &options)
{
- char buff[2048];
+ char buff[2048+DATABASE_COMMENT_MAXLEN];
String buffer(buff, sizeof(buff), system_charset_info);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *sctx= thd->security_ctx;
- uint db_access;
+ privilege_t db_access(NO_ACL);
#endif
Schema_specification_st create;
Protocol *protocol=thd->protocol;
@@ -1507,6 +1385,7 @@ bool mysqld_show_create_db(THD *thd, LEX_CSTRING *dbname,
{
*dbname= INFORMATION_SCHEMA_NAME;
create.default_table_charset= system_charset_info;
+ create.schema_comment= NULL;
}
else
{
@@ -1546,6 +1425,13 @@ bool mysqld_show_create_db(THD *thd, LEX_CSTRING *dbname,
}
buffer.append(STRING_WITH_LEN(" */"));
}
+
+ if (create.schema_comment)
+ {
+ buffer.append(STRING_WITH_LEN(" COMMENT "));
+ append_unescaped(&buffer, create.schema_comment->str,
+ create.schema_comment->length);
+ }
protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
if (protocol->write())
@@ -1613,7 +1499,7 @@ static const char *require_quotes(const char *name, uint name_length)
for (; name < end ; name++)
{
uchar chr= (uchar) *name;
- int length= my_charlen(system_charset_info, name, end);
+ int length= system_charset_info->charlen(name, end);
if (length == 1 && !system_charset_info->ident_map[chr])
return name;
if (length == 1 && (chr < '0' || chr > '9'))
@@ -1674,7 +1560,7 @@ append_identifier(THD *thd, String *packet, const char *name, size_t length)
for (name_end= name+length ; name < name_end ; )
{
uchar chr= (uchar) *name;
- int char_length= my_charlen(system_charset_info, name, name_end);
+ int char_length= system_charset_info->charlen(name, name_end);
/*
charlen can return 0 and negative numbers on a wrong multibyte
sequence. It is possible when upgrading from 4.0,
@@ -2096,6 +1982,14 @@ static void append_period(THD *thd, String *packet, const LEX_CSTRING &start,
packet->append(STRING_WITH_LEN(")"));
}
+int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
+ Table_specification_st *create_info_arg,
+ enum_with_db_name with_db_name)
+{
+ return show_create_table_ex(thd, table_list, NULL, NULL, packet,
+ create_info_arg, with_db_name);
+}
+
/*
Build a CREATE TABLE statement for a table.
@@ -2104,6 +1998,11 @@ static void append_period(THD *thd, String *packet, const LEX_CSTRING &start,
thd The thread
table_list A list containing one table to write statement
for.
+ force_db If not NULL, database name to use in the CREATE
+ TABLE statement.
+ force_name If not NULL, table name to use in the CREATE TABLE
+ statement. if NULL, the name from table_list will be
+ used.
packet Pointer to a string where statement will be
written.
create_info_arg Pointer to create information that can be used
@@ -2120,9 +2019,11 @@ static void append_period(THD *thd, String *packet, const LEX_CSTRING &start,
0 OK
*/
-int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
- Table_specification_st *create_info_arg,
- enum_with_db_name with_db_name)
+int show_create_table_ex(THD *thd, TABLE_LIST *table_list,
+ const char *force_db, const char *force_name,
+ String *packet,
+ Table_specification_st *create_info_arg,
+ enum_with_db_name with_db_name)
{
List<Item> field_list;
char tmp[MAX_FIELD_WIDTH], *for_str, def_value_buf[MAX_FIELD_WIDTH];
@@ -2172,41 +2073,55 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(STRING_WITH_LEN("TABLE "));
if (create_info_arg && create_info_arg->if_not_exists())
packet->append(STRING_WITH_LEN("IF NOT EXISTS "));
- if (table_list->schema_table)
+
+ if (force_name)
{
- alias.str= table_list->schema_table->table_name;
- alias.length= strlen(alias.str);
+ if (force_db)
+ {
+ append_identifier(thd, packet, force_db, strlen(force_db));
+ packet->append(STRING_WITH_LEN("."));
+ }
+ append_identifier(thd, packet, force_name, strlen(force_name));
}
else
{
- if (lower_case_table_names == 2)
+ if (table_list->schema_table)
{
- alias.str= table->alias.c_ptr();
- alias.length= table->alias.length();
+ alias.str= table_list->schema_table->table_name;
+ alias.length= strlen(alias.str);
}
else
- alias= share->table_name;
- }
+ {
+ if (lower_case_table_names == 2)
+ {
+ alias.str= table->alias.c_ptr();
+ alias.length= table->alias.length();
+ }
+ else
+ alias= share->table_name;
+ }
- /*
- Print the database before the table name if told to do that. The
- database name is only printed in the event that it is different
- from the current database. The main reason for doing this is to
- avoid having to update gazillions of tests and result files, but
- it also saves a few bytes of the binary log.
- */
- if (with_db_name == WITH_DB_NAME)
- {
- const LEX_CSTRING *const db=
- table_list->schema_table ? &INFORMATION_SCHEMA_NAME : &table->s->db;
- if (!thd->db.str || cmp(db, &thd->db))
- {
- append_identifier(thd, packet, db);
- packet->append(STRING_WITH_LEN("."));
+ /*
+ Print the database before the table name if told to do that. The
+ database name is only printed in the event that it is different
+ from the current database. The main reason for doing this is to
+ avoid having to update gazillions of tests and result files, but
+ it also saves a few bytes of the binary log.
+ */
+ if (with_db_name == WITH_DB_NAME)
+ {
+ const LEX_CSTRING *const db=
+ table_list->schema_table ? &INFORMATION_SCHEMA_NAME : &table->s->db;
+ if (!thd->db.str || cmp(db, &thd->db))
+ {
+ append_identifier(thd, packet, db);
+ packet->append(STRING_WITH_LEN("."));
+ }
}
+
+ append_identifier(thd, packet, &alias);
}
- append_identifier(thd, packet, &alias);
packet->append(STRING_WITH_LEN(" (\n"));
/*
We need this to get default values from the table
@@ -2235,12 +2150,6 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
field->sql_type(type);
packet->append(type.ptr(), type.length(), system_charset_info);
- DBUG_EXECUTE_IF("sql_type",
- packet->append(" /* ");
- packet->append(field->type_handler()->version().ptr());
- packet->append(" */ ");
- );
-
if (field->has_charset() && !(sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)))
{
if (field->charset() != share->table_charset)
@@ -3151,8 +3060,8 @@ int fill_show_explain(THD *thd, TABLE_LIST *table, COND *cond)
DBUG_ASSERT(cond==NULL);
thread_id= thd->lex->value_list.head()->val_int();
- calling_user= (thd->security_ctx->master_access & PROCESS_ACL) ? NullS :
- thd->security_ctx->priv_user;
+ calling_user= (thd->security_ctx->master_access & PRIV_STMT_SHOW_EXPLAIN) ?
+ NullS : thd->security_ctx->priv_user;
if ((tmp= find_thread_by_id(thread_id)))
{
@@ -3269,8 +3178,9 @@ static my_bool processlist_callback(THD *tmp, processlist_callback_arg *arg)
const char *val;
ulonglong max_counter;
bool got_thd_data;
- char *user= arg->thd->security_ctx->master_access & PROCESS_ACL ?
- NullS : arg->thd->security_ctx->priv_user;
+ char *user=
+ arg->thd->security_ctx->master_access & PRIV_STMT_SHOW_PROCESSLIST ?
+ NullS : arg->thd->security_ctx->priv_user;
if ((!tmp->vio_ok() && !tmp->system_thread) ||
(user && (tmp->system_thread || !tmp_sctx->user ||
@@ -3403,8 +3313,9 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
Status functions
*****************************************************************************/
-static DYNAMIC_ARRAY all_status_vars;
+DYNAMIC_ARRAY all_status_vars;
static bool status_vars_inited= 0;
+ulonglong status_var_array_version= 0;
C_MODE_START
static int show_var_cmp(const void *var1, const void *var2)
@@ -3432,6 +3343,7 @@ static void shrink_var_array(DYNAMIC_ARRAY *array)
}
else // array is completely empty - delete it
delete_dynamic(array);
+ status_var_array_version++;
}
/*
@@ -3459,7 +3371,8 @@ int add_status_vars(SHOW_VAR *list)
if (status_vars_inited)
mysql_rwlock_wrlock(&LOCK_all_status_vars);
if (!all_status_vars.buffer && // array is not allocated yet - do it now
- my_init_dynamic_array(&all_status_vars, sizeof(SHOW_VAR), 250, 50, MYF(0)))
+ my_init_dynamic_array(PSI_INSTRUMENT_ME, &all_status_vars,
+ sizeof(SHOW_VAR), 250, 50, MYF(0)))
{
res= 1;
goto err;
@@ -3470,6 +3383,7 @@ int add_status_vars(SHOW_VAR *list)
all_status_vars.elements--; // but next insert_dynamic should overwite it
if (status_vars_inited)
sort_dynamic(&all_status_vars, show_var_cmp);
+ status_var_array_version++;
err:
if (status_vars_inited)
mysql_rwlock_unlock(&LOCK_all_status_vars);
@@ -3488,6 +3402,7 @@ void init_status_vars()
{
status_vars_inited=1;
sort_dynamic(&all_status_vars, show_var_cmp);
+ status_var_array_version++;
}
void reset_status_vars()
@@ -3514,6 +3429,7 @@ void reset_status_vars()
void free_status_vars()
{
delete_dynamic(&all_status_vars);
+ status_var_array_version++;
}
/*
@@ -3575,6 +3491,11 @@ void remove_status_vars(SHOW_VAR *list)
}
}
+/* Current version of the all_status_vars. */
+ulonglong get_status_vars_version(void)
+{
+ return status_var_array_version;
+}
/**
@brief Returns the value of a system or a status variable.
@@ -3629,12 +3550,18 @@ const char* get_one_variable(THD *thd,
/* fall through */
case SHOW_ULONG:
case SHOW_LONG_NOFLUSH: // the difference lies in refresh_status()
+#ifndef _WIN64
+ case SHOW_SIZE_T:
+#endif
end= int10_to_str(*(long*) value, buff, 10);
break;
case SHOW_LONGLONG_STATUS:
value= ((char *) status_var + (intptr) value);
/* fall through */
case SHOW_ULONGLONG:
+#ifdef _WIN64
+ case SHOW_SIZE_T:
+#endif
end= longlong10_to_str(*(longlong*) value, buff, 10);
break;
case SHOW_HA_ROWS:
@@ -3963,9 +3890,9 @@ bool get_lookup_value(THD *thd, Item_func *item_func,
ST_SCHEMA_TABLE *schema_table= table->schema_table;
ST_FIELD_INFO *field_info= schema_table->fields_info;
const char *field_name1= schema_table->idx_field1 >= 0 ?
- field_info[schema_table->idx_field1].field_name : "";
+ field_info[schema_table->idx_field1].name().str : "";
const char *field_name2= schema_table->idx_field2 >= 0 ?
- field_info[schema_table->idx_field2].field_name : "";
+ field_info[schema_table->idx_field2].name().str : "";
if (item_func->functype() == Item_func::EQ_FUNC ||
item_func->functype() == Item_func::EQUAL_FUNC)
@@ -4001,18 +3928,18 @@ bool get_lookup_value(THD *thd, Item_func *item_func,
return 1;
/* Lookup value is database name */
- if (!cs->coll->strnncollsp(cs, (uchar *) field_name1, strlen(field_name1),
- (uchar *) item_field->field_name.str,
- item_field->field_name.length))
+ if (!cs->strnncollsp(field_name1, strlen(field_name1),
+ item_field->field_name.str,
+ item_field->field_name.length))
{
thd->make_lex_string(&lookup_field_vals->db_value,
tmp_str->ptr(), tmp_str->length());
}
/* Lookup value is table name */
- else if (!cs->coll->strnncollsp(cs, (uchar *) field_name2,
- strlen(field_name2),
- (uchar *) item_field->field_name.str,
- item_field->field_name.length))
+ else if (!cs->strnncollsp(field_name2,
+ strlen(field_name2),
+ item_field->field_name.str,
+ item_field->field_name.length))
{
thd->make_lex_string(&lookup_field_vals->table_value,
tmp_str->ptr(), tmp_str->length());
@@ -4101,16 +4028,16 @@ bool uses_only_table_name_fields(Item *item, TABLE_LIST *table)
ST_SCHEMA_TABLE *schema_table= table->schema_table;
ST_FIELD_INFO *field_info= schema_table->fields_info;
const char *field_name1= schema_table->idx_field1 >= 0 ?
- field_info[schema_table->idx_field1].field_name : "";
+ field_info[schema_table->idx_field1].name().str : "";
const char *field_name2= schema_table->idx_field2 >= 0 ?
- field_info[schema_table->idx_field2].field_name : "";
+ field_info[schema_table->idx_field2].name().str : "";
if (table->table != item_field->field->table ||
- (cs->coll->strnncollsp(cs, (uchar *) field_name1, strlen(field_name1),
- (uchar *) item_field->field_name.str,
- item_field->field_name.length) &&
- cs->coll->strnncollsp(cs, (uchar *) field_name2, strlen(field_name2),
- (uchar *) item_field->field_name.str,
- item_field->field_name.length)))
+ (cs->strnncollsp(field_name1, strlen(field_name1),
+ item_field->field_name.str,
+ item_field->field_name.length) &&
+ cs->strnncollsp(field_name2, strlen(field_name2),
+ item_field->field_name.str,
+ item_field->field_name.length)))
return 0;
}
else if (item->type() == Item::EXPR_CACHE_ITEM)
@@ -4806,18 +4733,18 @@ uint get_table_open_method(TABLE_LIST *tables,
if (schema_table->i_s_requested_object & OPTIMIZE_I_S_TABLE)
{
Field **ptr, *field;
- int table_open_method= 0, field_indx= 0;
+ uint table_open_method= 0, field_indx= 0;
uint star_table_open_method= OPEN_FULL_TABLE;
bool used_star= true; // true if '*' is used in select
for (ptr=tables->table->field; (field= *ptr) ; ptr++)
{
+ const ST_FIELD_INFO &def= schema_table->fields_info[field_indx];
star_table_open_method=
- MY_MIN(star_table_open_method,
- schema_table->fields_info[field_indx].open_method);
+ MY_MIN(star_table_open_method, (uint) def.open_method());
if (bitmap_is_set(tables->table->read_set, field->field_index))
{
used_star= false;
- table_open_method|= schema_table->fields_info[field_indx].open_method;
+ table_open_method|= (uint) def.open_method();
}
field_indx++;
}
@@ -4858,8 +4785,9 @@ try_acquire_high_prio_shared_mdl_lock(THD *thd, TABLE_LIST *table,
bool can_deadlock)
{
bool error;
- table->mdl_request.init(MDL_key::TABLE, table->db.str, table->table_name.str,
- MDL_SHARED_HIGH_PRIO, MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&table->mdl_request, MDL_key::TABLE, table->db.str,
+ table->table_name.str, MDL_SHARED_HIGH_PRIO,
+ MDL_TRANSACTION);
if (can_deadlock)
{
@@ -4981,8 +4909,8 @@ static int fill_schema_table_from_frm(THD *thd, TABLE *table,
if (schema_table->i_s_requested_object & OPEN_TRIGGER_ONLY)
{
- init_sql_alloc(&tbl.mem_root, "fill_schema_table_from_frm",
- TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0));
+ init_sql_alloc(key_memory_table_triggers_list,
+ &tbl.mem_root, TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0));
if (!Table_triggers_list::check_n_load(thd, db_name,
table_name, &tbl, 1))
{
@@ -5136,7 +5064,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
ST_SCHEMA_TABLE *schema_table= tables->schema_table;
IS_table_read_plan *plan= tables->is_table_read_plan;
enum enum_schema_tables schema_table_idx;
- Dynamic_array<LEX_CSTRING*> db_names;
+ Dynamic_array<LEX_CSTRING*> db_names(PSI_INSTRUMENT_MEM);
Item *partial_cond= plan->partial_cond;
int error= 1;
Open_tables_backup open_tables_state_backup;
@@ -5205,7 +5133,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
goto err;
/* Use tmp_mem_root to allocate data for opened tables */
- init_alloc_root(&tmp_mem_root, "get_all_tables", SHOW_ALLOC_BLOCK_SIZE,
+ init_alloc_root(PSI_INSTRUMENT_ME, &tmp_mem_root, SHOW_ALLOC_BLOCK_SIZE,
SHOW_ALLOC_BLOCK_SIZE, MY_THREAD_SPECIFIC);
for (size_t i=0; i < db_names.elements(); i++)
@@ -5220,7 +5148,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0))
#endif
{
- Dynamic_array<LEX_CSTRING*> table_names;
+ Dynamic_array<LEX_CSTRING*> table_names(PSI_INSTRUMENT_MEM);
int res= make_table_name_list(thd, &table_names, lex,
&plan->lookup_field_vals, db_name);
if (unlikely(res == 2)) /* Not fatal error, continue */
@@ -5313,14 +5241,17 @@ err:
}
-bool store_schema_shemata(THD* thd, TABLE *table, LEX_CSTRING *db_name,
- CHARSET_INFO *cs)
+bool store_schema_schemata(THD* thd, TABLE *table, LEX_CSTRING *db_name,
+ CHARSET_INFO *cs, LEX_CSTRING *schema_comment= NULL)
{
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(cs->csname, strlen(cs->csname), system_charset_info);
table->field[3]->store(cs->name, strlen(cs->name), system_charset_info);
+ if (schema_comment)
+ table->field[5]->store(schema_comment->str, schema_comment->length,
+ system_charset_info);
return schema_table_store_record(thd, table);
}
@@ -5333,7 +5264,7 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
*/
LOOKUP_FIELD_VALUES lookup_field_vals;
- Dynamic_array<LEX_CSTRING*> db_names;
+ Dynamic_array<LEX_CSTRING*> db_names(PSI_INSTRUMENT_MEM);
Schema_specification_st create;
TABLE *table= tables->table;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -5373,8 +5304,8 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
DBUG_ASSERT(db_name->length <= NAME_LEN);
if (db_name == &INFORMATION_SCHEMA_NAME)
{
- if (store_schema_shemata(thd, table, db_name,
- system_charset_info))
+ if (store_schema_schemata(thd, table, db_name,
+ system_charset_info))
DBUG_RETURN(1);
continue;
}
@@ -5382,13 +5313,14 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, false) ||
(sctx->priv_role[0] ?
- acl_get("", "", sctx->priv_role, db_name->str, false) : 0) ||
+ acl_get("", "", sctx->priv_role, db_name->str, false) : NO_ACL) ||
!check_grant_db(thd, db_name->str))
#endif
{
load_db_opt_by_name(thd, db_name->str, &create);
- if (store_schema_shemata(thd, table, db_name,
- create.default_table_charset))
+ if (store_schema_schemata(thd, table, db_name,
+ create.default_table_charset,
+ create.schema_comment))
DBUG_RETURN(1);
}
}
@@ -5946,10 +5878,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS
rather than in SHOW COLUMNS
*/
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
- thd->get_stmt_da()->sql_errno(),
- thd->get_stmt_da()->message());
- thd->clear_error();
+ convert_error_to_warning(thd);
res= 0;
}
DBUG_RETURN(res);
@@ -5980,7 +5909,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
restore_record(table, s->default_values);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- uint col_access;
+ ulonglong col_access;
check_access(thd,SELECT_ACL, db_name->str,
&tables->grant.privilege, 0, 0, MY_TEST(tables->schema_table));
col_access= get_column_grant(thd, &tables->grant,
@@ -6151,12 +6080,11 @@ static my_bool iter_schema_engines(THD *thd, plugin_ref plugin,
LEX_CSTRING yesno[2]= {{ STRING_WITH_LEN("NO") },
{ STRING_WITH_LEN("YES") }};
LEX_CSTRING *tmp;
- const char *option_name= show_comp_option_name[(int) hton->state];
+ const char *option_name= default_type != hton ? yesno[1].str
+ : "DEFAULT";
restore_record(table, s->default_values);
table->field[0]->store(name->str, name->length, scs);
- if (hton->state == SHOW_OPTION_YES && default_type == hton)
- option_name= "DEFAULT";
table->field[1]->store(option_name, strlen(option_name), scs);
table->field[2]->store(plugin_decl(plugin)->descr,
strlen(plugin_decl(plugin)->descr), scs);
@@ -6320,11 +6248,11 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str_nopad(thd->mem_root, &name);
proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str_nopad(thd->mem_root, &definer);
sql_mode= (sql_mode_t) proc_table->field[MYSQL_PROC_FIELD_SQL_MODE]->val_int();
- sph= Sp_handler::handler_mysql_proc((stored_procedure_type)
+ sph= Sp_handler::handler_mysql_proc((enum_sp_type)
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->
val_int());
- if (!sph || sph->type() == TYPE_ENUM_PACKAGE ||
- sph->type() == TYPE_ENUM_PACKAGE_BODY)
+ if (!sph || sph->type() == SP_TYPE_PACKAGE ||
+ sph->type() == SP_TYPE_PACKAGE_BODY)
DBUG_RETURN(0);
if (!full_access)
@@ -6335,7 +6263,7 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
proc_table->field[MYSQL_PROC_FIELD_PARAM_LIST]->val_str_nopad(thd->mem_root,
&params);
- if (sph->type() == TYPE_ENUM_FUNCTION)
+ if (sph->type() == SP_TYPE_FUNCTION)
proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root,
&returns);
sp= sph->sp_load_for_information_schema(thd, proc_table, db, name,
@@ -6348,7 +6276,7 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
Sql_mode_save sql_mode_backup(thd);
thd->variables.sql_mode= sql_mode;
- if (sph->type() == TYPE_ENUM_FUNCTION)
+ if (sph->type() == SP_TYPE_FUNCTION)
{
restore_record(table, s->default_values);
table->field[0]->store(STRING_WITH_LEN("def"), cs);
@@ -6432,7 +6360,7 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
proc_table->field[MYSQL_PROC_FIELD_DB]->val_str_nopad(thd->mem_root, &db);
proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str_nopad(thd->mem_root, &name);
proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str_nopad(thd->mem_root, &definer);
- sph= Sp_handler::handler_mysql_proc((stored_procedure_type)
+ sph= Sp_handler::handler_mysql_proc((enum_sp_type)
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->
val_int());
if (!sph)
@@ -6461,7 +6389,7 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
copy_field_as_string(table->field[4],
proc_table->field[MYSQL_PROC_MYSQL_TYPE]);
- if (sph->type() == TYPE_ENUM_FUNCTION)
+ if (sph->type() == SP_TYPE_FUNCTION)
{
sp_head *sp;
bool free_sp_head;
@@ -6761,12 +6689,11 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables,
else
{
TABLE_LIST table_list;
- uint view_access;
table_list.reset();
table_list.db= tables->db;
table_list.table_name= tables->table_name;
table_list.grant.privilege= thd->col_access;
- view_access= get_table_grant(thd, &table_list);
+ privilege_t view_access(get_table_grant(thd, &table_list));
if ((view_access & (SHOW_VIEW_ACL|SELECT_ACL)) ==
(SHOW_VIEW_ACL|SELECT_ACL))
tables->allowed_show= TRUE;
@@ -7246,56 +7173,6 @@ static void collect_partition_expr(THD *thd, List<const char> &field_list,
return;
}
-
-/*
- Convert a string in a given character set to a string which can be
- used for FRM file storage in which case use_hex is TRUE and we store
- the character constants as hex strings in the character set encoding
- their field have. In the case of SHOW CREATE TABLE and the
- PARTITIONS information schema table we instead provide utf8 strings
- to the user and convert to the utf8 character set.
-
- SYNOPSIS
- get_cs_converted_part_value_from_string()
- item Item from which constant comes
- input_str String as provided by val_str after
- conversion to character set
- output_str Out value: The string created
- cs Character set string is encoded in
- NULL for INT_RESULT's here
- use_hex TRUE => hex string created
- FALSE => utf8 constant string created
-
- RETURN VALUES
- TRUE Error
- FALSE Ok
-*/
-
-int get_cs_converted_part_value_from_string(THD *thd,
- Item *item,
- String *input_str,
- String *output_str,
- CHARSET_INFO *cs,
- bool use_hex)
-{
- if (item->result_type() == INT_RESULT)
- {
- longlong value= item->val_int();
- output_str->set(value, system_charset_info);
- return FALSE;
- }
- if (!input_str)
- {
- my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
- return TRUE;
- }
- get_cs_converted_string_value(thd,
- input_str,
- output_str,
- cs,
- use_hex);
- return FALSE;
-}
#endif
@@ -7387,24 +7264,14 @@ static int get_partition_column_description(THD *thd, partition_info *part_info,
tmp_str.append("NULL");
else
{
- char buffer[MAX_KEY_LENGTH];
- String str(buffer, sizeof(buffer), &my_charset_bin);
- String val_conv;
Item *item= col_val->item_expression;
-
- if (!(item= part_info->get_column_item(item,
- part_info->part_field_array[i])))
- {
- DBUG_RETURN(1);
- }
- String *res= item->val_str(&str);
- if (get_cs_converted_part_value_from_string(thd, item, res, &val_conv,
- part_info->part_field_array[i]->charset(),
- FALSE))
- {
- DBUG_RETURN(1);
- }
- tmp_str.append(val_conv);
+ StringBuffer<MAX_KEY_LENGTH> val;
+ const Field *field= part_info->part_field_array[i];
+ const Type_handler *th= field->type_handler();
+ th->partition_field_append_value(&val, item,
+ field->charset(),
+ PARTITION_VALUE_PRINT_MODE_SHOW);
+ tmp_str.append(val);
}
if (i != num_elements - 1)
tmp_str.append(",");
@@ -8148,9 +8015,9 @@ mark_all_fields_used_in_query(THD *thd,
bitmap_set_all(bitmap);
break;
}
- for (count=0; fields->field_name; fields++, count++)
+ for (count=0; !fields->end_marker(); fields++, count++)
{
- if (!my_strcasecmp(system_charset_info, fields->field_name,
+ if (!my_strcasecmp(system_charset_info, fields->name().str,
item_field->field_name.str))
{
bitmap_set_bit(bitmap, count);
@@ -8186,19 +8053,16 @@ mark_all_fields_used_in_query(THD *thd,
TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
{
uint field_count;
- Item *item, *all_items;
+ Item *all_items;
TABLE *table;
- List<Item> field_list;
ST_SCHEMA_TABLE *schema_table= table_list->schema_table;
ST_FIELD_INFO *fields_info= schema_table->fields_info;
ST_FIELD_INFO *fields;
- CHARSET_INFO *cs= system_charset_info;
- MEM_ROOT *mem_root= thd->mem_root;
MY_BITMAP bitmap;
my_bitmap_map *buf;
DBUG_ENTER("create_schema_table");
- for (field_count= 0, fields= fields_info; fields->field_name; fields++)
+ for (field_count= 0, fields= fields_info; !fields->end_marker(); fields++)
field_count++;
if (!(buf= (my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count))))
DBUG_RETURN(NULL);
@@ -8212,137 +8076,20 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
mark_all_fields_used_in_query(thd, fields_info, &bitmap, all_items);
- for (field_count=0; fields_info->field_name; fields_info++)
- {
- size_t field_name_length= strlen(fields_info->field_name);
- switch (fields_info->field_type) {
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_LONGLONG:
- case MYSQL_TYPE_INT24:
- if (!(item= new (mem_root)
- Item_return_int(thd, fields_info->field_name,
- fields_info->field_length,
- fields_info->field_type,
- fields_info->value)))
- {
- DBUG_RETURN(0);
- }
- item->unsigned_flag= (fields_info->field_flags & MY_I_S_UNSIGNED);
- break;
- case MYSQL_TYPE_DATE:
- if (!(item=new (mem_root)
- Item_return_date_time(thd, fields_info->field_name,
- (uint)field_name_length,
- fields_info->field_type)))
- DBUG_RETURN(0);
- break;
- case MYSQL_TYPE_TIME:
- if (!(item=new (mem_root)
- Item_return_date_time(thd, fields_info->field_name,
- (uint)field_name_length,
- fields_info->field_type)))
- DBUG_RETURN(0);
- break;
- case MYSQL_TYPE_TIMESTAMP:
- case MYSQL_TYPE_DATETIME:
- if (!(item=new (mem_root)
- Item_return_date_time(thd, fields_info->field_name,
- (uint)field_name_length,
- fields_info->field_type,
- fields_info->field_length)))
- DBUG_RETURN(0);
- item->decimals= fields_info->field_length;
- break;
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_DOUBLE:
- if ((item= new (mem_root)
- Item_float(thd, fields_info->field_name, 0.0,
- NOT_FIXED_DEC,
- fields_info->field_length)) == NULL)
- DBUG_RETURN(NULL);
- break;
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_NEWDECIMAL:
- if (!(item= new (mem_root)
- Item_decimal(thd, (longlong) fields_info->value, false)))
- {
- DBUG_RETURN(0);
- }
- /*
- Create a type holder, as we want the type of the item to defined
- the type of the object, not the value
- */
- if (!(item= new (mem_root) Item_type_holder(thd, item)))
- DBUG_RETURN(0);
- item->unsigned_flag= (fields_info->field_flags & MY_I_S_UNSIGNED);
- item->decimals= fields_info->field_length%10;
- item->max_length= (fields_info->field_length/100)%100;
- if (item->unsigned_flag == 0)
- item->max_length+= 1;
- if (item->decimals > 0)
- item->max_length+= 1;
- item->set_name(thd, fields_info->field_name, field_name_length, cs);
- break;
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- if (bitmap_is_set(&bitmap, field_count))
- {
- if (!(item= new (mem_root)
- Item_blob(thd, fields_info->field_name,
- fields_info->field_length)))
- {
- DBUG_RETURN(0);
- }
- }
- else
- {
- if (!(item= new (mem_root)
- Item_empty_string(thd, "", 0, cs)))
- {
- DBUG_RETURN(0);
- }
- item->set_name(thd, fields_info->field_name,
- field_name_length, cs);
- }
- break;
- default:
- {
- bool show_field;
- /* Don't let unimplemented types pass through. Could be a grave error. */
- DBUG_ASSERT(fields_info->field_type == MYSQL_TYPE_STRING);
-
- show_field= bitmap_is_set(&bitmap, field_count);
- if (!(item= new (mem_root)
- Item_empty_string(thd, "",
- show_field ? fields_info->field_length : 0, cs)))
- {
- DBUG_RETURN(0);
- }
- item->set_name(thd, fields_info->field_name,
- field_name_length, cs);
- break;
- }
- }
- field_list.push_back(item, thd->mem_root);
- item->maybe_null= (fields_info->field_flags & MY_I_S_MAYBE_NULL);
- field_count++;
- }
TMP_TABLE_PARAM *tmp_table_param = new (thd->mem_root) TMP_TABLE_PARAM;
tmp_table_param->init();
- tmp_table_param->table_charset= cs;
+ tmp_table_param->table_charset= system_charset_info;
tmp_table_param->field_count= field_count;
tmp_table_param->schema_table= 1;
SELECT_LEX *select_lex= table_list->select_lex;
bool keep_row_order= is_show_command(thd);
- if (!(table= create_tmp_table(thd, tmp_table_param,
- field_list, (ORDER*) 0, 0, 0,
- (select_lex->options | thd->variables.option_bits |
- TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR,
- &table_list->alias, false, keep_row_order)))
+ if (!(table= create_tmp_table_for_schema(thd, tmp_table_param,
+ *schema_table, bitmap,
+ (select_lex->options |
+ thd->variables.option_bits |
+ TMP_TABLE_ALL_COLUMNS),
+ table_list->alias,
+ keep_row_order)))
DBUG_RETURN(0);
my_bitmap_map* bitmaps=
(my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count));
@@ -8374,19 +8121,16 @@ static int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
ST_FIELD_INFO *field_info= schema_table->fields_info;
Name_resolution_context *context= &thd->lex->first_select_lex()->context;
- for (; field_info->field_name; field_info++)
+ for (; !field_info->end_marker(); field_info++)
{
- if (field_info->old_name)
+ if (field_info->old_name().str)
{
- LEX_CSTRING field_name= {field_info->field_name,
- strlen(field_info->field_name)};
+ LEX_CSTRING field_name= field_info->name();
Item_field *field= new (thd->mem_root)
- Item_field(thd, context, NullS, NullS, &field_name);
+ Item_field(thd, context, field_name);
if (field)
{
- field->set_name(thd, field_info->old_name,
- strlen(field_info->old_name),
- system_charset_info);
+ field->set_name(thd, field_info->old_name());
if (add_item_to_list(thd, field))
return 1;
}
@@ -8407,22 +8151,19 @@ int make_schemata_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
ST_FIELD_INFO *field_info= &schema_table->fields_info[1];
String buffer(tmp,sizeof(tmp), system_charset_info);
- LEX_CSTRING field_name= {field_info->field_name,
- strlen(field_info->field_name) };
-
Item_field *field= new (thd->mem_root) Item_field(thd, context,
- NullS, NullS, &field_name);
+ field_info->name());
if (!field || add_item_to_list(thd, field))
return 1;
buffer.length(0);
- buffer.append(field_info->old_name);
+ buffer.append(field_info->old_name());
if (lex->wild && lex->wild->ptr())
{
buffer.append(STRING_WITH_LEN(" ("));
buffer.append(lex->wild->ptr());
buffer.append(')');
}
- field->set_name(thd, buffer.ptr(), buffer.length(), system_charset_info);
+ field->set_name(thd, buffer.lex_cstring());
}
return 0;
}
@@ -8435,11 +8176,10 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
LEX *lex= thd->lex;
Name_resolution_context *context= &lex->first_select_lex()->context;
ST_FIELD_INFO *field_info= &schema_table->fields_info[2];
- LEX_CSTRING field_name= {field_info->field_name,
- strlen(field_info->field_name) };
+ LEX_CSTRING field_name= field_info->name();
buffer.length(0);
- buffer.append(field_info->old_name);
+ buffer.append(field_info->old_name());
buffer.append(&lex->first_select_lex()->db);
if (lex->wild && lex->wild->ptr())
{
@@ -8447,22 +8187,17 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
buffer.append(lex->wild->ptr());
buffer.append(')');
}
- Item_field *field= new (thd->mem_root) Item_field(thd, context,
- NullS, NullS, &field_name);
+ Item_field *field= new (thd->mem_root) Item_field(thd, context, field_name);
if (add_item_to_list(thd, field))
return 1;
- field->set_name(thd, buffer.ptr(), buffer.length(), system_charset_info);
+ field->set_name(thd, buffer.lex_cstring());
if (thd->lex->verbose)
{
field_info= &schema_table->fields_info[3];
- LEX_CSTRING field_name2= {field_info->field_name,
- strlen(field_info->field_name) };
- field= new (thd->mem_root) Item_field(thd, context, NullS, NullS,
- &field_name2);
+ field= new (thd->mem_root) Item_field(thd, context, field_info->name());
if (add_item_to_list(thd, field))
return 1;
- field->set_name(thd, field_info->old_name, strlen(field_info->old_name),
- system_charset_info);
+ field->set_name(thd, field_info->old_name());
}
return 0;
}
@@ -8478,19 +8213,15 @@ int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
for (; *field_num >= 0; field_num++)
{
field_info= &schema_table->fields_info[*field_num];
- LEX_CSTRING field_name= {field_info->field_name,
- strlen(field_info->field_name)};
if (!thd->lex->verbose && (*field_num == 14 ||
*field_num == 18 ||
*field_num == 19))
continue;
Item_field *field= new (thd->mem_root) Item_field(thd, context,
- NullS, NullS, &field_name);
+ field_info->name());
if (field)
{
- field->set_name(thd, field_info->old_name,
- strlen(field_info->old_name),
- system_charset_info);
+ field->set_name(thd, field_info->old_name());
if (add_item_to_list(thd, field))
return 1;
}
@@ -8509,15 +8240,11 @@ int make_character_sets_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
for (; *field_num >= 0; field_num++)
{
field_info= &schema_table->fields_info[*field_num];
- LEX_CSTRING field_name= {field_info->field_name,
- strlen(field_info->field_name)};
Item_field *field= new (thd->mem_root) Item_field(thd, context,
- NullS, NullS, &field_name);
+ field_info->name());
if (field)
{
- field->set_name(thd, field_info->old_name,
- strlen(field_info->old_name),
- system_charset_info);
+ field->set_name(thd, field_info->old_name());
if (add_item_to_list(thd, field))
return 1;
}
@@ -8536,15 +8263,11 @@ int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
for (; *field_num >= 0; field_num++)
{
field_info= &schema_table->fields_info[*field_num];
- LEX_CSTRING field_name= {field_info->field_name,
- strlen(field_info->field_name)};
Item_field *field= new (thd->mem_root) Item_field(thd, context,
- NullS, NullS, &field_name);
+ field_info->name());
if (field)
{
- field->set_name(thd, field_info->old_name,
- strlen(field_info->old_name),
- system_charset_info);
+ field->set_name(thd, field_info->old_name());
if (add_item_to_list(thd, field))
return 1;
}
@@ -8961,7 +8684,7 @@ static my_bool run_hton_fill_schema_table(THD *thd, plugin_ref plugin,
struct run_hton_fill_schema_table_args *args=
(run_hton_fill_schema_table_args *) arg;
handlerton *hton= plugin_hton(plugin);
- if (hton->fill_is_table && hton->state == SHOW_OPTION_YES)
+ if (hton->fill_is_table)
hton->fill_is_table(hton, thd, args->tables, args->cond,
get_schema_table_idx(args->tables->schema_table));
return false;
@@ -9067,809 +8790,654 @@ int fill_key_cache_tables(THD *thd, TABLE_LIST *tables, COND *cond)
}
+namespace Show {
+
ST_FIELD_INFO schema_fields_info[]=
{
- {"CATALOG_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"SCHEMA_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Database",
- SKIP_OPEN_TABLE},
- {"DEFAULT_CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
- SKIP_OPEN_TABLE},
- {"DEFAULT_COLLATION_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
- SKIP_OPEN_TABLE},
- {"SQL_PATH", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("CATALOG_NAME", Catalog(), NOT_NULL),
+ Column("SCHEMA_NAME", Name(), NOT_NULL, "Database"),
+ Column("DEFAULT_CHARACTER_SET_NAME", CSName(), NOT_NULL),
+ Column("DEFAULT_COLLATION_NAME", CSName(), NOT_NULL),
+ Column("SQL_PATH", Varchar(FN_REFLEN), NULLABLE),
+ Column("SCHEMA_COMMENT", Varchar(DATABASE_COMMENT_MAXLEN), NOT_NULL),
+ CEnd()
};
ST_FIELD_INFO tables_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
- SKIP_OPEN_TABLE},
- {"TABLE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, "Engine", OPEN_FRM_ONLY},
- {"VERSION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Version", OPEN_FRM_ONLY},
- {"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format", OPEN_FULL_TABLE},
- {"TABLE_ROWS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", OPEN_FULL_TABLE},
- {"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", OPEN_FULL_TABLE},
- {"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", OPEN_FULL_TABLE},
- {"MAX_DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", OPEN_FULL_TABLE},
- {"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", OPEN_FULL_TABLE},
- {"DATA_FREE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_free", OPEN_FULL_TABLE},
- {"AUTO_INCREMENT", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Auto_increment", OPEN_FULL_TABLE},
- {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Create_time", OPEN_FULL_TABLE},
- {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Update_time", OPEN_FULL_TABLE},
- {"CHECK_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Check_time", OPEN_FULL_TABLE},
- {"TABLE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 1, "Collation",
- OPEN_FRM_ONLY},
- {"CHECKSUM", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Checksum", OPEN_FULL_TABLE},
- {"CREATE_OPTIONS", 2048, MYSQL_TYPE_STRING, 0, 1, "Create_options",
- OPEN_FULL_TABLE},
- {"TABLE_COMMENT", TABLE_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0,
- "Comment", OPEN_FRM_ONLY},
- {"MAX_INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_index_length", OPEN_FULL_TABLE},
- {"TEMPORARY", 1, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, "Temporary", OPEN_FRM_ONLY},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL),
+ Column("TABLE_NAME", Name(), NOT_NULL, "Name"),
+ Column("TABLE_TYPE", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("ENGINE", Name(), NULLABLE, "Engine", OPEN_FRM_ONLY),
+ Column("VERSION", ULonglong(), NULLABLE, "Version", OPEN_FRM_ONLY),
+ Column("ROW_FORMAT", Varchar(10), NULLABLE, "Row_format", OPEN_FULL_TABLE),
+ Column("TABLE_ROWS", ULonglong(), NULLABLE, "Rows", OPEN_FULL_TABLE),
+ Column("AVG_ROW_LENGTH", ULonglong(), NULLABLE, "Avg_row_length",
+ OPEN_FULL_TABLE),
+ Column("DATA_LENGTH", ULonglong(), NULLABLE, "Data_length",OPEN_FULL_TABLE),
+ Column("MAX_DATA_LENGTH", ULonglong(), NULLABLE, "Max_data_length",
+ OPEN_FULL_TABLE),
+ Column("INDEX_LENGTH", ULonglong(), NULLABLE, "Index_length",OPEN_FULL_TABLE),
+ Column("DATA_FREE", ULonglong(), NULLABLE, "Data_free", OPEN_FULL_TABLE),
+ Column("AUTO_INCREMENT", ULonglong(), NULLABLE, "Auto_increment",
+ OPEN_FULL_TABLE),
+ Column("CREATE_TIME", Datetime(0), NULLABLE, "Create_time",OPEN_FULL_TABLE),
+ Column("UPDATE_TIME", Datetime(0), NULLABLE, "Update_time",OPEN_FULL_TABLE),
+ Column("CHECK_TIME", Datetime(0), NULLABLE, "Check_time", OPEN_FULL_TABLE),
+ Column("TABLE_COLLATION", CSName(), NULLABLE, "Collation", OPEN_FRM_ONLY),
+ Column("CHECKSUM", ULonglong(), NULLABLE, "Checksum", OPEN_FULL_TABLE),
+ Column("CREATE_OPTIONS", Varchar(2048),NULLABLE, "Create_options",
+ OPEN_FULL_TABLE),
+ Column("TABLE_COMMENT", Varchar(TABLE_COMMENT_MAXLEN),
+ NOT_NULL, "Comment", OPEN_FRM_ONLY),
+ Column("MAX_INDEX_LENGTH",ULonglong(), NULLABLE, "Max_index_length",
+ OPEN_FULL_TABLE),
+ Column("TEMPORARY", Varchar(1), NULLABLE, "Temporary", OPEN_FRM_ONLY),
+ CEnd()
};
ST_FIELD_INFO columns_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Field",
- OPEN_FRM_ONLY},
- {"ORDINAL_POSITION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- MY_I_S_UNSIGNED, 0, OPEN_FRM_ONLY},
- {"COLUMN_DEFAULT", MAX_FIELD_VARCHARLENGTH, MYSQL_TYPE_STRING, 0,
- 1, "Default", OPEN_FRM_ONLY},
- {"IS_NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null", OPEN_FRM_ONLY},
- {"DATA_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"CHARACTER_MAXIMUM_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
- 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
- {"CHARACTER_OCTET_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
- 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
- {"NUMERIC_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
- 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
- {"NUMERIC_SCALE", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
- 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
- {"DATETIME_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
- 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
- {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FRM_ONLY},
- {"COLLATION_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 1, "Collation",
- OPEN_FRM_ONLY},
- {"COLUMN_TYPE", 65535, MYSQL_TYPE_STRING, 0, 0, "Type", OPEN_FRM_ONLY},
- {"COLUMN_KEY", 3, MYSQL_TYPE_STRING, 0, 0, "Key", OPEN_FRM_ONLY},
- {"EXTRA", 30, MYSQL_TYPE_STRING, 0, 0, "Extra", OPEN_FRM_ONLY},
- {"PRIVILEGES", 80, MYSQL_TYPE_STRING, 0, 0, "Privileges", OPEN_FRM_ONLY},
- {"COLUMN_COMMENT", COLUMN_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0,
- "Comment", OPEN_FRM_ONLY},
- {"IS_GENERATED", 6, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"GENERATION_EXPRESSION", MAX_FIELD_VARCHARLENGTH, MYSQL_TYPE_STRING, 0, 1,
- 0, OPEN_FRM_ONLY},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("TABLE_NAME", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("COLUMN_NAME", Name(), NOT_NULL, "Field", OPEN_FRM_ONLY),
+ Column("ORDINAL_POSITION", ULonglong(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("COLUMN_DEFAULT", Longtext(MAX_FIELD_VARCHARLENGTH),
+ NULLABLE, "Default",OPEN_FRM_ONLY),
+ Column("IS_NULLABLE", Yesno(), NOT_NULL, "Null", OPEN_FRM_ONLY),
+ Column("DATA_TYPE", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("CHARACTER_MAXIMUM_LENGTH",ULonglong(), NULLABLE, OPEN_FRM_ONLY),
+ Column("CHARACTER_OCTET_LENGTH", ULonglong(), NULLABLE, OPEN_FRM_ONLY),
+ Column("NUMERIC_PRECISION", ULonglong(), NULLABLE, OPEN_FRM_ONLY),
+ Column("NUMERIC_SCALE", ULonglong(), NULLABLE, OPEN_FRM_ONLY),
+ Column("DATETIME_PRECISION", ULonglong(), NULLABLE, OPEN_FRM_ONLY),
+ Column("CHARACTER_SET_NAME", CSName(), NULLABLE, OPEN_FRM_ONLY),
+ Column("COLLATION_NAME", CSName(), NULLABLE, "Collation", OPEN_FRM_ONLY),
+ Column("COLUMN_TYPE", Longtext(65535), NOT_NULL, "Type", OPEN_FRM_ONLY),
+ Column("COLUMN_KEY", Varchar(3), NOT_NULL, "Key", OPEN_FRM_ONLY),
+ Column("EXTRA", Varchar(30), NOT_NULL, "Extra", OPEN_FRM_ONLY),
+ Column("PRIVILEGES", Varchar(80), NOT_NULL, "Privileges", OPEN_FRM_ONLY),
+ Column("COLUMN_COMMENT", Varchar(COLUMN_COMMENT_MAXLEN), NOT_NULL, "Comment",
+ OPEN_FRM_ONLY),
+ Column("IS_GENERATED", Varchar(6), NOT_NULL, OPEN_FRM_ONLY),
+ Column("GENERATION_EXPRESSION", Longtext(MAX_FIELD_VARCHARLENGTH),
+ NULLABLE, OPEN_FRM_ONLY),
+ CEnd()
};
ST_FIELD_INFO charsets_fields_info[]=
{
- {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, "Charset",
- SKIP_OPEN_TABLE},
- {"DEFAULT_COLLATE_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "Default collation", SKIP_OPEN_TABLE},
- {"DESCRIPTION", 60, MYSQL_TYPE_STRING, 0, 0, "Description",
- SKIP_OPEN_TABLE},
- {"MAXLEN", 3, MYSQL_TYPE_LONGLONG, 0, 0, "Maxlen", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("CHARACTER_SET_NAME", CSName(), NOT_NULL, "Charset"),
+ Column("DEFAULT_COLLATE_NAME", CSName(), NOT_NULL, "Default collation"),
+ Column("DESCRIPTION", Varchar(60), NOT_NULL, "Description"),
+ Column("MAXLEN", SLonglong(3), NOT_NULL, "Maxlen"),
+ CEnd()
};
ST_FIELD_INFO collation_fields_info[]=
{
- {"COLLATION_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, "Collation",
- SKIP_OPEN_TABLE},
- {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, "Charset",
- SKIP_OPEN_TABLE},
- {"ID", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Id",
- SKIP_OPEN_TABLE},
- {"IS_DEFAULT", 3, MYSQL_TYPE_STRING, 0, 0, "Default", SKIP_OPEN_TABLE},
- {"IS_COMPILED", 3, MYSQL_TYPE_STRING, 0, 0, "Compiled", SKIP_OPEN_TABLE},
- {"SORTLEN", 3, MYSQL_TYPE_LONGLONG, 0, 0, "Sortlen", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("COLLATION_NAME", CSName(), NOT_NULL, "Collation"),
+ Column("CHARACTER_SET_NAME", CSName(), NOT_NULL, "Charset"),
+ Column("ID", SLonglong(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL, "Id"),
+ Column("IS_DEFAULT", Yesno(), NOT_NULL, "Default"),
+ Column("IS_COMPILED", Yesno(), NOT_NULL, "Compiled"),
+ Column("SORTLEN", SLonglong(3), NOT_NULL, "Sortlen"),
+ CEnd()
};
ST_FIELD_INFO applicable_roles_fields_info[]=
{
- {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"ROLE_NAME", USERNAME_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"IS_DEFAULT", 3, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("GRANTEE", Userhost(), NOT_NULL),
+ Column("ROLE_NAME", Varchar(USERNAME_CHAR_LENGTH), NOT_NULL),
+ Column("IS_GRANTABLE", Yesno(), NOT_NULL),
+ Column("IS_DEFAULT", Yesno(), NULLABLE),
+ CEnd()
};
ST_FIELD_INFO enabled_roles_fields_info[]=
{
- {"ROLE_NAME", USERNAME_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("ROLE_NAME", Varchar(USERNAME_CHAR_LENGTH), NULLABLE),
+ CEnd()
};
ST_FIELD_INFO engines_fields_info[]=
{
- {"ENGINE", 64, MYSQL_TYPE_STRING, 0, 0, "Engine", SKIP_OPEN_TABLE},
- {"SUPPORT", 8, MYSQL_TYPE_STRING, 0, 0, "Support", SKIP_OPEN_TABLE},
- {"COMMENT", 160, MYSQL_TYPE_STRING, 0, 0, "Comment", SKIP_OPEN_TABLE},
- {"TRANSACTIONS", 3, MYSQL_TYPE_STRING, 0, 1, "Transactions", SKIP_OPEN_TABLE},
- {"XA", 3, MYSQL_TYPE_STRING, 0, 1, "XA", SKIP_OPEN_TABLE},
- {"SAVEPOINTS", 3 ,MYSQL_TYPE_STRING, 0, 1, "Savepoints", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("ENGINE", Varchar(64), NOT_NULL, "Engine"),
+ Column("SUPPORT", Varchar(8), NOT_NULL, "Support"),
+ Column("COMMENT", Varchar(160), NOT_NULL, "Comment"),
+ Column("TRANSACTIONS", Varchar(3), NULLABLE, "Transactions"),
+ Column("XA", Varchar(3), NULLABLE, "XA"),
+ Column("SAVEPOINTS", Varchar(3), NULLABLE, "Savepoints"),
+ CEnd()
};
ST_FIELD_INFO events_fields_info[]=
{
- {"EVENT_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"EVENT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Db",
- SKIP_OPEN_TABLE},
- {"EVENT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
- SKIP_OPEN_TABLE},
- {"DEFINER", DEFINER_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, "Definer", SKIP_OPEN_TABLE},
- {"TIME_ZONE", 64, MYSQL_TYPE_STRING, 0, 0, "Time zone", SKIP_OPEN_TABLE},
- {"EVENT_BODY", 8, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"EVENT_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"EVENT_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, "Type", SKIP_OPEN_TABLE},
- {"EXECUTE_AT", 0, MYSQL_TYPE_DATETIME, 0, 1, "Execute at", SKIP_OPEN_TABLE},
- {"INTERVAL_VALUE", 256, MYSQL_TYPE_STRING, 0, 1, "Interval value",
- SKIP_OPEN_TABLE},
- {"INTERVAL_FIELD", 18, MYSQL_TYPE_STRING, 0, 1, "Interval field",
- SKIP_OPEN_TABLE},
- {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"STARTS", 0, MYSQL_TYPE_DATETIME, 0, 1, "Starts", SKIP_OPEN_TABLE},
- {"ENDS", 0, MYSQL_TYPE_DATETIME, 0, 1, "Ends", SKIP_OPEN_TABLE},
- {"STATUS", 18, MYSQL_TYPE_STRING, 0, 0, "Status", SKIP_OPEN_TABLE},
- {"ON_COMPLETION", 12, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 0, 0, SKIP_OPEN_TABLE},
- {"LAST_ALTERED", 0, MYSQL_TYPE_DATETIME, 0, 0, 0, SKIP_OPEN_TABLE},
- {"LAST_EXECUTED", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
- {"EVENT_COMMENT", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"ORIGINATOR", 10, MYSQL_TYPE_LONGLONG, 0, 0, "Originator", SKIP_OPEN_TABLE},
- {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "character_set_client", SKIP_OPEN_TABLE},
- {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "collation_connection", SKIP_OPEN_TABLE},
- {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "Database Collation", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ // QQ: shouldn't EVENT_CATALOG be Catalog() like in all other places?
+ Column("EVENT_CATALOG", Name(), NOT_NULL),
+ Column("EVENT_SCHEMA", Name(), NOT_NULL, "Db"),
+ Column("EVENT_NAME", Name(), NOT_NULL, "Name"),
+ Column("DEFINER", Definer(), NOT_NULL, "Definer"),
+ Column("TIME_ZONE", Varchar(64), NOT_NULL, "Time zone"),
+ Column("EVENT_BODY", Varchar(8), NOT_NULL),
+ Column("EVENT_DEFINITION", Longtext(65535), NOT_NULL),
+ Column("EVENT_TYPE", Varchar(9), NOT_NULL, "Type"),
+ Column("EXECUTE_AT", Datetime(0), NULLABLE, "Execute at"),
+ Column("INTERVAL_VALUE", Varchar(256),NULLABLE, "Interval value"),
+ Column("INTERVAL_FIELD", Varchar(18), NULLABLE, "Interval field"),
+ Column("SQL_MODE", SQLMode(), NOT_NULL),
+ Column("STARTS", Datetime(0), NULLABLE, "Starts"),
+ Column("ENDS", Datetime(0), NULLABLE, "Ends"),
+ Column("STATUS", Varchar(18), NOT_NULL, "Status"),
+ Column("ON_COMPLETION", Varchar(12), NOT_NULL),
+ Column("CREATED", Datetime(0), NOT_NULL),
+ Column("LAST_ALTERED", Datetime(0), NOT_NULL),
+ Column("LAST_EXECUTED", Datetime(0), NULLABLE),
+ Column("EVENT_COMMENT", Name(), NOT_NULL),
+ Column("ORIGINATOR", SLonglong(10),NOT_NULL,"Originator"),
+ Column("CHARACTER_SET_CLIENT", CSName(), NOT_NULL, "character_set_client"),
+ Column("COLLATION_CONNECTION", CSName(), NOT_NULL, "collation_connection"),
+ Column("DATABASE_COLLATION", CSName(), NOT_NULL, "Database Collation"),
+ CEnd()
};
ST_FIELD_INFO coll_charset_app_fields_info[]=
{
- {"COLLATION_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
- SKIP_OPEN_TABLE},
- {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
- SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("COLLATION_NAME", CSName(), NOT_NULL),
+ Column("CHARACTER_SET_NAME", CSName(), NOT_NULL),
+ CEnd()
};
ST_FIELD_INFO proc_fields_info[]=
{
- {"SPECIFIC_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"ROUTINE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"ROUTINE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Db",
- SKIP_OPEN_TABLE},
- {"ROUTINE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
- SKIP_OPEN_TABLE},
- {"ROUTINE_TYPE", 13, MYSQL_TYPE_STRING, 0, 0, "Type", SKIP_OPEN_TABLE},
- {"DATA_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"NUMERIC_PRECISION", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"NUMERIC_SCALE", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"DATETIME_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
- 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
- {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"DTD_IDENTIFIER", 65535, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"ROUTINE_BODY", 8, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"ROUTINE_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"EXTERNAL_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"EXTERNAL_LANGUAGE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- SKIP_OPEN_TABLE},
- {"PARAMETER_STYLE", 8, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"IS_DETERMINISTIC", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"SQL_DATA_ACCESS", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- SKIP_OPEN_TABLE},
- {"SQL_PATH", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, "Security_type",
- SKIP_OPEN_TABLE},
- {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 0, "Created", SKIP_OPEN_TABLE},
- {"LAST_ALTERED", 0, MYSQL_TYPE_DATETIME, 0, 0, "Modified", SKIP_OPEN_TABLE},
- {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"ROUTINE_COMMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Comment",
- SKIP_OPEN_TABLE},
- {"DEFINER", DEFINER_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, "Definer", SKIP_OPEN_TABLE},
- {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "character_set_client", SKIP_OPEN_TABLE},
- {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "collation_connection", SKIP_OPEN_TABLE},
- {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "Database Collation", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("SPECIFIC_NAME", Name(), NOT_NULL),
+ Column("ROUTINE_CATALOG", Catalog(), NOT_NULL),
+ Column("ROUTINE_SCHEMA", Name(), NOT_NULL, "Db"),
+ Column("ROUTINE_NAME", Name(), NOT_NULL, "Name"),
+ Column("ROUTINE_TYPE", Varchar(13),NOT_NULL, "Type"),
+ Column("DATA_TYPE", Name(), NOT_NULL),
+ Column("CHARACTER_MAXIMUM_LENGTH",SLong(21), NULLABLE),
+ Column("CHARACTER_OCTET_LENGTH", SLong(21), NULLABLE),
+ Column("NUMERIC_PRECISION", SLong(21), NULLABLE),
+ Column("NUMERIC_SCALE", SLong(21), NULLABLE),
+ Column("DATETIME_PRECISION", ULonglong(), NULLABLE, OPEN_FRM_ONLY),
+ Column("CHARACTER_SET_NAME", Varchar(64),NULLABLE),
+ Column("COLLATION_NAME", Varchar(64),NULLABLE),
+ Column("DTD_IDENTIFIER", Longtext(65535), NULLABLE),
+ Column("ROUTINE_BODY", Varchar(8), NOT_NULL),
+ Column("ROUTINE_DEFINITION", Longtext(65535), NULLABLE),
+ Column("EXTERNAL_NAME", Name(), NULLABLE),
+ Column("EXTERNAL_LANGUAGE", Name(), NULLABLE),
+ Column("PARAMETER_STYLE", Varchar(8), NOT_NULL),
+ Column("IS_DETERMINISTIC", Varchar(3), NOT_NULL),
+ Column("SQL_DATA_ACCESS", Name(), NOT_NULL),
+ Column("SQL_PATH", Name(), NULLABLE),
+ Column("SECURITY_TYPE", Varchar(7), NOT_NULL, "Security_type"),
+ Column("CREATED", Datetime(0), NOT_NULL, "Created"),
+ Column("LAST_ALTERED", Datetime(0), NOT_NULL, "Modified"),
+ Column("SQL_MODE", SQLMode(), NOT_NULL),
+ Column("ROUTINE_COMMENT", Longtext(65535), NOT_NULL, "Comment"),
+ Column("DEFINER", Definer(), NOT_NULL, "Definer"),
+ Column("CHARACTER_SET_CLIENT", CSName(), NOT_NULL, "character_set_client"),
+ Column("COLLATION_CONNECTION", CSName(), NOT_NULL, "collation_connection"),
+ Column("DATABASE_COLLATION", CSName(), NOT_NULL, "Database Collation"),
+ CEnd()
};
ST_FIELD_INFO stat_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table", OPEN_FRM_ONLY},
- {"NON_UNIQUE", 1, MYSQL_TYPE_LONGLONG, 0, 0, "Non_unique", OPEN_FRM_ONLY},
- {"INDEX_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"INDEX_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Key_name",
- OPEN_FRM_ONLY},
- {"SEQ_IN_INDEX", 2, MYSQL_TYPE_LONGLONG, 0, 0, "Seq_in_index", OPEN_FRM_ONLY},
- {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Column_name",
- OPEN_FRM_ONLY},
- {"COLLATION", 1, MYSQL_TYPE_STRING, 0, 1, "Collation", OPEN_FRM_ONLY},
- {"CARDINALITY", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 1,
- "Cardinality", OPEN_FULL_TABLE},
- {"SUB_PART", 3, MYSQL_TYPE_LONGLONG, 0, 1, "Sub_part", OPEN_FRM_ONLY},
- {"PACKED", 10, MYSQL_TYPE_STRING, 0, 1, "Packed", OPEN_FRM_ONLY},
- {"NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null", OPEN_FRM_ONLY},
- {"INDEX_TYPE", 16, MYSQL_TYPE_STRING, 0, 0, "Index_type", OPEN_FULL_TABLE},
- {"COMMENT", 16, MYSQL_TYPE_STRING, 0, 1, "Comment", OPEN_FRM_ONLY},
- {"INDEX_COMMENT", INDEX_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0,
- "Index_comment", OPEN_FRM_ONLY},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("TABLE_NAME", Name(), NOT_NULL, "Table", OPEN_FRM_ONLY),
+ Column("NON_UNIQUE", SLonglong(1),NOT_NULL, "Non_unique", OPEN_FRM_ONLY),
+ Column("INDEX_SCHEMA", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("INDEX_NAME", Name(), NOT_NULL, "Key_name", OPEN_FRM_ONLY),
+ Column("SEQ_IN_INDEX", SLonglong(2),NOT_NULL, "Seq_in_index",OPEN_FRM_ONLY),
+ Column("COLUMN_NAME", Name(), NOT_NULL, "Column_name", OPEN_FRM_ONLY),
+ Column("COLLATION", Varchar(1), NULLABLE, "Collation", OPEN_FRM_ONLY),
+ Column("CARDINALITY", SLonglong(), NULLABLE, "Cardinality", OPEN_FULL_TABLE),
+ Column("SUB_PART", SLonglong(3),NULLABLE, "Sub_part", OPEN_FRM_ONLY),
+ Column("PACKED", Varchar(10), NULLABLE, "Packed", OPEN_FRM_ONLY),
+ Column("NULLABLE", Varchar(3), NOT_NULL, "Null", OPEN_FRM_ONLY),
+ Column("INDEX_TYPE", Varchar(16), NOT_NULL, "Index_type", OPEN_FULL_TABLE),
+ Column("COMMENT", Varchar(16), NULLABLE, "Comment", OPEN_FRM_ONLY),
+ Column("INDEX_COMMENT", Varchar(INDEX_COMMENT_MAXLEN),
+ NOT_NULL, "Index_comment",OPEN_FRM_ONLY),
+ CEnd()
};
ST_FIELD_INFO view_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"VIEW_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"CHECK_OPTION", 8, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"IS_UPDATABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"DEFINER", DEFINER_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FRM_ONLY},
- {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FRM_ONLY},
- {"ALGORITHM", 10, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("TABLE_NAME", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("VIEW_DEFINITION", Longtext(65535), NOT_NULL, OPEN_FRM_ONLY),
+ Column("CHECK_OPTION", Varchar(8), NOT_NULL, OPEN_FRM_ONLY),
+ Column("IS_UPDATABLE", Yesno(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("DEFINER", Definer(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("SECURITY_TYPE", Varchar(7), NOT_NULL, OPEN_FRM_ONLY),
+ Column("CHARACTER_SET_CLIENT", CSName(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("COLLATION_CONNECTION", CSName(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("ALGORITHM", Varchar(10),NOT_NULL, OPEN_FRM_ONLY),
+ CEnd()
};
ST_FIELD_INFO user_privileges_fields_info[]=
{
- {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("GRANTEE", Userhost(), NOT_NULL),
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL),
+ Column("PRIVILEGE_TYPE", Name(), NOT_NULL),
+ Column("IS_GRANTABLE", Yesno(), NOT_NULL),
+ CEnd()
};
ST_FIELD_INFO schema_privileges_fields_info[]=
{
- {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("GRANTEE", Userhost(), NOT_NULL),
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL),
+ Column("PRIVILEGE_TYPE", Name(), NOT_NULL),
+ Column("IS_GRANTABLE", Yesno(), NOT_NULL),
+ CEnd()
};
ST_FIELD_INFO table_privileges_fields_info[]=
{
- {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("GRANTEE", Userhost(), NOT_NULL),
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL),
+ Column("TABLE_NAME", Name(), NOT_NULL),
+ Column("PRIVILEGE_TYPE", Name(), NOT_NULL),
+ Column("IS_GRANTABLE", Yesno(), NOT_NULL),
+ CEnd()
};
ST_FIELD_INFO column_privileges_fields_info[]=
{
- {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("GRANTEE", Userhost(), NOT_NULL),
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL),
+ Column("TABLE_NAME", Name(), NOT_NULL),
+ Column("COLUMN_NAME", Name(), NOT_NULL),
+ Column("PRIVILEGE_TYPE", Name(), NOT_NULL),
+ Column("IS_GRANTABLE", Yesno(), NOT_NULL),
+ CEnd()
};
ST_FIELD_INFO table_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_SCHEMA", 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},
- {"CONSTRAINT_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("CONSTRAINT_CATALOG", Catalog(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_TYPE", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ CEnd()
};
ST_FIELD_INFO key_column_usage_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_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"TABLE_SCHEMA", 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},
- {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"ORDINAL_POSITION", 10 ,MYSQL_TYPE_LONGLONG, 0, 0, 0, OPEN_FULL_TABLE},
- {"POSITION_IN_UNIQUE_CONSTRAINT", 10 ,MYSQL_TYPE_LONGLONG, 0, 1, 0,
- OPEN_FULL_TABLE},
- {"REFERENCED_TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FULL_TABLE},
- {"REFERENCED_TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FULL_TABLE},
- {"REFERENCED_COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FULL_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("CONSTRAINT_CATALOG", Catalog(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("COLUMN_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("ORDINAL_POSITION", SLonglong(10), NOT_NULL, OPEN_FULL_TABLE),
+ Column("POSITION_IN_UNIQUE_CONSTRAINT", SLonglong(10), NULLABLE, OPEN_FULL_TABLE),
+ Column("REFERENCED_TABLE_SCHEMA", Name(), NULLABLE, OPEN_FULL_TABLE),
+ Column("REFERENCED_TABLE_NAME", Name(), NULLABLE, OPEN_FULL_TABLE),
+ Column("REFERENCED_COLUMN_NAME", Name(), NULLABLE, OPEN_FULL_TABLE),
+ CEnd()
};
ST_FIELD_INFO table_names_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_NAME", NAME_CHAR_LEN + MYSQL50_TABLE_NAME_PREFIX_LENGTH,
- MYSQL_TYPE_STRING, 0, 0, "Tables_in_", SKIP_OPEN_TABLE},
- {"TABLE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_type",
- OPEN_FRM_ONLY},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL),
+ Column("TABLE_NAME", Varchar(NAME_CHAR_LEN + MYSQL50_TABLE_NAME_PREFIX_LENGTH),
+ NOT_NULL, "Tables_in_"),
+ Column("TABLE_TYPE", Name(), NOT_NULL, "Table_type", OPEN_FRM_ONLY),
+ CEnd()
};
ST_FIELD_INFO open_tables_fields_info[]=
{
- {"Database", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Database",
- SKIP_OPEN_TABLE},
- {"Table",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table", SKIP_OPEN_TABLE},
- {"In_use", 1, MYSQL_TYPE_LONGLONG, 0, 0, "In_use", SKIP_OPEN_TABLE},
- {"Name_locked", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Name_locked", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("Database", Name(), NOT_NULL, "Database"),
+ Column("Table", Name(), NOT_NULL, "Table"),
+ Column("In_use", SLonglong(1), NOT_NULL, "In_use"),
+ Column("Name_locked", SLonglong(4), NOT_NULL, "Name_locked"),
+ CEnd()
};
ST_FIELD_INFO triggers_fields_info[]=
{
- {"TRIGGER_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"TRIGGER_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"TRIGGER_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Trigger",
- OPEN_FRM_ONLY},
- {"EVENT_MANIPULATION", 6, MYSQL_TYPE_STRING, 0, 0, "Event", OPEN_FRM_ONLY},
- {"EVENT_OBJECT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FRM_ONLY},
- {"EVENT_OBJECT_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FRM_ONLY},
- {"EVENT_OBJECT_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table",
- OPEN_FRM_ONLY},
- {"ACTION_ORDER", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, OPEN_FRM_ONLY},
- {"ACTION_CONDITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FRM_ONLY},
- {"ACTION_STATEMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Statement",
- OPEN_FRM_ONLY},
- {"ACTION_ORIENTATION", 9, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"ACTION_TIMING", 6, MYSQL_TYPE_STRING, 0, 0, "Timing", OPEN_FRM_ONLY},
- {"ACTION_REFERENCE_OLD_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FRM_ONLY},
- {"ACTION_REFERENCE_NEW_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FRM_ONLY},
- {"ACTION_REFERENCE_OLD_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"ACTION_REFERENCE_NEW_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
+ Column("TRIGGER_CATALOG", Catalog(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("TRIGGER_SCHEMA", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("TRIGGER_NAME", Name(), NOT_NULL, "Trigger", OPEN_FRM_ONLY),
+ Column("EVENT_MANIPULATION", Varchar(6), NOT_NULL, "Event", OPEN_FRM_ONLY),
+ Column("EVENT_OBJECT_CATALOG", Catalog(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("EVENT_OBJECT_SCHEMA", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("EVENT_OBJECT_TABLE", Name(), NOT_NULL, "Table", OPEN_FRM_ONLY),
+ Column("ACTION_ORDER", SLonglong(4), NOT_NULL, OPEN_FRM_ONLY),
+ Column("ACTION_CONDITION", Longtext(65535), NULLABLE, OPEN_FRM_ONLY),
+ Column("ACTION_STATEMENT", Longtext(65535), NOT_NULL, "Statement",OPEN_FRM_ONLY),
+ Column("ACTION_ORIENTATION", Varchar(9), NOT_NULL, OPEN_FRM_ONLY),
+ Column("ACTION_TIMING", Varchar(6), NOT_NULL, "Timing", OPEN_FRM_ONLY),
+ Column("ACTION_REFERENCE_OLD_TABLE",Name(), NULLABLE, OPEN_FRM_ONLY),
+ Column("ACTION_REFERENCE_NEW_TABLE",Name(), NULLABLE, OPEN_FRM_ONLY),
+ Column("ACTION_REFERENCE_OLD_ROW",Varchar(3),NOT_NULL, OPEN_FRM_ONLY),
+ Column("ACTION_REFERENCE_NEW_ROW",Varchar(3),NOT_NULL, OPEN_FRM_ONLY),
/* 2 here indicates 2 decimals */
- {"CREATED", 2, MYSQL_TYPE_DATETIME, 0, 1, "Created", OPEN_FRM_ONLY},
- {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, "sql_mode", OPEN_FRM_ONLY},
- {"DEFINER", DEFINER_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, "Definer", OPEN_FRM_ONLY},
- {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "character_set_client", OPEN_FRM_ONLY},
- {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "collation_connection", OPEN_FRM_ONLY},
- {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "Database Collation", OPEN_FRM_ONLY},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("CREATED", Datetime(2), NULLABLE, "Created", OPEN_FRM_ONLY),
+ Column("SQL_MODE", SQLMode(), NOT_NULL, "sql_mode", OPEN_FRM_ONLY),
+ Column("DEFINER", Definer(), NOT_NULL, "Definer", OPEN_FRM_ONLY),
+ Column("CHARACTER_SET_CLIENT", CSName(), NOT_NULL, "character_set_client",
+ OPEN_FRM_ONLY),
+ Column("COLLATION_CONNECTION", CSName(), NOT_NULL, "collation_connection",
+ OPEN_FRM_ONLY),
+ Column("DATABASE_COLLATION", CSName(), NOT_NULL, "Database Collation",
+ OPEN_FRM_ONLY),
+ CEnd()
};
ST_FIELD_INFO partitions_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"TABLE_SCHEMA",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},
- {"PARTITION_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"SUBPARTITION_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FULL_TABLE},
- {"PARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
- {"SUBPARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
- {"PARTITION_METHOD", 18, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"SUBPARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"PARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"SUBPARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FULL_TABLE},
- {"PARTITION_DESCRIPTION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"TABLE_ROWS", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
- OPEN_FULL_TABLE},
- {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
- OPEN_FULL_TABLE},
- {"DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
- OPEN_FULL_TABLE},
- {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
- {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
- OPEN_FULL_TABLE},
- {"DATA_FREE", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
- OPEN_FULL_TABLE},
- {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, OPEN_FULL_TABLE},
- {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, OPEN_FULL_TABLE},
- {"CHECK_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, OPEN_FULL_TABLE},
- {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
- {"PARTITION_COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"NODEGROUP", 12 , MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"TABLESPACE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FULL_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("PARTITION_NAME", Name(), NULLABLE, OPEN_FULL_TABLE),
+ Column("SUBPARTITION_NAME", Name(), NULLABLE, OPEN_FULL_TABLE),
+ Column("PARTITION_ORDINAL_POSITION", ULonglong(), NULLABLE, OPEN_FULL_TABLE),
+ Column("SUBPARTITION_ORDINAL_POSITION",ULonglong(),NULLABLE, OPEN_FULL_TABLE),
+ Column("PARTITION_METHOD", Varchar(18), NULLABLE, OPEN_FULL_TABLE),
+ Column("SUBPARTITION_METHOD", Varchar(12), NULLABLE, OPEN_FULL_TABLE),
+ Column("PARTITION_EXPRESSION", Longtext(65535), NULLABLE, OPEN_FULL_TABLE),
+ Column("SUBPARTITION_EXPRESSION", Longtext(65535), NULLABLE, OPEN_FULL_TABLE),
+ Column("PARTITION_DESCRIPTION", Longtext(65535), NULLABLE, OPEN_FULL_TABLE),
+ Column("TABLE_ROWS", ULonglong(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("AVG_ROW_LENGTH", ULonglong(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("DATA_LENGTH", ULonglong(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("MAX_DATA_LENGTH", ULonglong(), NULLABLE, OPEN_FULL_TABLE),
+ Column("INDEX_LENGTH", ULonglong(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("DATA_FREE", ULonglong(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CREATE_TIME", Datetime(0), NULLABLE, OPEN_FULL_TABLE),
+ Column("UPDATE_TIME", Datetime(0), NULLABLE, OPEN_FULL_TABLE),
+ Column("CHECK_TIME", Datetime(0), NULLABLE, OPEN_FULL_TABLE),
+ Column("CHECKSUM", ULonglong(), NULLABLE, OPEN_FULL_TABLE),
+ Column("PARTITION_COMMENT", Varchar(80), NOT_NULL, OPEN_FULL_TABLE),
+ Column("NODEGROUP", Varchar(12), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLESPACE_NAME", Name(), NULLABLE, OPEN_FULL_TABLE),
+ CEnd()
};
ST_FIELD_INFO variables_fields_info[]=
{
- {"VARIABLE_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Variable_name",
- SKIP_OPEN_TABLE},
- {"VARIABLE_VALUE", 2048, MYSQL_TYPE_STRING, 0, 0, "Value", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("VARIABLE_NAME", Varchar(64), NOT_NULL, "Variable_name"),
+ Column("VARIABLE_VALUE", Varchar(2048), NOT_NULL, "Value"),
+ CEnd()
};
ST_FIELD_INFO sysvars_fields_info[]=
{
- {"VARIABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, 0},
- {"SESSION_VALUE", 2048, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0},
- {"GLOBAL_VALUE", 2048, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0},
- {"GLOBAL_VALUE_ORIGIN", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, 0},
- {"DEFAULT_VALUE", 2048, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0},
- {"VARIABLE_SCOPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, 0},
- {"VARIABLE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, 0},
- {"VARIABLE_COMMENT", TABLE_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0, 0, 0},
- {"NUMERIC_MIN_VALUE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0},
- {"NUMERIC_MAX_VALUE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0},
- {"NUMERIC_BLOCK_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0},
- {"ENUM_VALUE_LIST", 65535, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0},
- {"READ_ONLY", 3, MYSQL_TYPE_STRING, 0, 0, 0, 0},
- {"COMMAND_LINE_ARGUMENT", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
+ Column("VARIABLE_NAME", Name(), NOT_NULL),
+ Column("SESSION_VALUE", Varchar(2048), NULLABLE),
+ Column("GLOBAL_VALUE", Varchar(2048), NULLABLE),
+ Column("GLOBAL_VALUE_ORIGIN", Name(), NOT_NULL),
+ Column("DEFAULT_VALUE", Varchar(2048), NULLABLE),
+ Column("VARIABLE_SCOPE", Name(), NOT_NULL),
+ Column("VARIABLE_TYPE", Name(), NOT_NULL),
+ Column("VARIABLE_COMMENT", Varchar(TABLE_COMMENT_MAXLEN), NOT_NULL),
+ Column("NUMERIC_MIN_VALUE", Varchar(MY_INT64_NUM_DECIMAL_DIGITS), NULLABLE),
+ Column("NUMERIC_MAX_VALUE", Varchar(MY_INT64_NUM_DECIMAL_DIGITS), NULLABLE),
+ Column("NUMERIC_BLOCK_SIZE", Varchar(MY_INT64_NUM_DECIMAL_DIGITS), NULLABLE),
+ Column("ENUM_VALUE_LIST", Longtext(65535), NULLABLE),
+ Column("READ_ONLY", Yesno(), NOT_NULL),
+ Column("COMMAND_LINE_ARGUMENT",Name(), NULLABLE),
+ Column("GLOBAL_VALUE_PATH", Varchar(2048), NULLABLE),
+ CEnd()
};
ST_FIELD_INFO processlist_fields_info[]=
{
- {"ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Id", SKIP_OPEN_TABLE},
- {"USER", USERNAME_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, "User",
- SKIP_OPEN_TABLE},
- {"HOST", LIST_PROCESS_HOST_LEN, MYSQL_TYPE_STRING, 0, 0, "Host",
- SKIP_OPEN_TABLE},
- {"DB", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, "Db", SKIP_OPEN_TABLE},
- {"COMMAND", 16, MYSQL_TYPE_STRING, 0, 0, "Command", SKIP_OPEN_TABLE},
- {"TIME", 7, MYSQL_TYPE_LONG, 0, 0, "Time", SKIP_OPEN_TABLE},
- {"STATE", 64, MYSQL_TYPE_STRING, 0, 1, "State", SKIP_OPEN_TABLE},
- {"INFO", PROCESS_LIST_INFO_WIDTH, MYSQL_TYPE_STRING, 0, 1, "Info",
- SKIP_OPEN_TABLE},
- {"TIME_MS", 100 * (MY_INT64_NUM_DECIMAL_DIGITS + 1) + 3, MYSQL_TYPE_DECIMAL,
- 0, 0, "Time_ms", SKIP_OPEN_TABLE},
- {"STAGE", 2, MYSQL_TYPE_TINY, 0, 0, "Stage", SKIP_OPEN_TABLE},
- {"MAX_STAGE", 2, MYSQL_TYPE_TINY, 0, 0, "Max_stage", SKIP_OPEN_TABLE},
- {"PROGRESS", 703, MYSQL_TYPE_DECIMAL, 0, 0, "Progress",
- SKIP_OPEN_TABLE},
- {"MEMORY_USED", 7, MYSQL_TYPE_LONGLONG, 0, 0, "Memory_used", SKIP_OPEN_TABLE},
- {"MAX_MEMORY_USED", 7, MYSQL_TYPE_LONGLONG, 0, 0, "Max_memory_used", SKIP_OPEN_TABLE},
- {"EXAMINED_ROWS", 7, MYSQL_TYPE_LONG, 0, 0, "Examined_rows", SKIP_OPEN_TABLE},
- {"QUERY_ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, SKIP_OPEN_TABLE},
- {"INFO_BINARY", PROCESS_LIST_INFO_WIDTH, MYSQL_TYPE_BLOB, 0, 1,
- "Info_binary", SKIP_OPEN_TABLE},
- {"TID", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Tid", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("ID", SLonglong(4), NOT_NULL, "Id"),
+ Column("USER", Varchar(USERNAME_CHAR_LENGTH), NOT_NULL, "User"),
+ Column("HOST", Varchar(LIST_PROCESS_HOST_LEN),NOT_NULL, "Host"),
+ Column("DB", Name(), NULLABLE, "Db"),
+ Column("COMMAND", Varchar(16), NOT_NULL, "Command"),
+ Column("TIME", SLong(7), NOT_NULL, "Time"),
+ Column("STATE", Varchar(64), NULLABLE, "State"),
+ Column("INFO", Longtext(PROCESS_LIST_INFO_WIDTH),
+ NULLABLE, "Info"),
+ Column("TIME_MS", Decimal(100 * (MY_INT64_NUM_DECIMAL_DIGITS + 1) + 3),
+ NOT_NULL, "Time_ms"),
+ Column("STAGE", STiny(2), NOT_NULL, "Stage"),
+ Column("MAX_STAGE", STiny(2), NOT_NULL, "Max_stage"),
+ Column("PROGRESS", Decimal(703), NOT_NULL, "Progress"),
+ Column("MEMORY_USED", SLonglong(7), NOT_NULL, "Memory_used"),
+ Column("MAX_MEMORY_USED",SLonglong(7), NOT_NULL, "Max_memory_used"),
+ Column("EXAMINED_ROWS", SLong(7), NOT_NULL, "Examined_rows"),
+ Column("QUERY_ID", SLonglong(4), NOT_NULL),
+ Column("INFO_BINARY",Blob(PROCESS_LIST_INFO_WIDTH),NULLABLE, "Info_binary"),
+ Column("TID", SLonglong(4), NOT_NULL, "Tid"),
+ CEnd()
};
ST_FIELD_INFO plugin_fields_info[]=
{
- {"PLUGIN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
- SKIP_OPEN_TABLE},
- {"PLUGIN_VERSION", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"PLUGIN_STATUS", 16, MYSQL_TYPE_STRING, 0, 0, "Status", SKIP_OPEN_TABLE},
- {"PLUGIN_TYPE", 80, MYSQL_TYPE_STRING, 0, 0, "Type", SKIP_OPEN_TABLE},
- {"PLUGIN_TYPE_VERSION", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"PLUGIN_LIBRARY", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, "Library",
- SKIP_OPEN_TABLE},
- {"PLUGIN_LIBRARY_VERSION", 20, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"PLUGIN_AUTHOR", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"PLUGIN_DESCRIPTION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"PLUGIN_LICENSE", 80, MYSQL_TYPE_STRING, 0, 0, "License", SKIP_OPEN_TABLE},
- {"LOAD_OPTION", 64, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"PLUGIN_MATURITY", 12, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"PLUGIN_AUTH_VERSION", 80, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("PLUGIN_NAME", Name(), NOT_NULL, "Name"),
+ Column("PLUGIN_VERSION", Varchar(20), NOT_NULL),
+ Column("PLUGIN_STATUS", Varchar(16), NOT_NULL, "Status"),
+ Column("PLUGIN_TYPE", Varchar(80), NOT_NULL, "Type"),
+ Column("PLUGIN_TYPE_VERSION", Varchar(20), NOT_NULL),
+ Column("PLUGIN_LIBRARY", Name(), NULLABLE, "Library"),
+ Column("PLUGIN_LIBRARY_VERSION", Varchar(20), NULLABLE),
+ Column("PLUGIN_AUTHOR", Name(), NULLABLE),
+ Column("PLUGIN_DESCRIPTION", Longtext(65535), NULLABLE),
+ Column("PLUGIN_LICENSE", Varchar(80), NOT_NULL, "License"),
+ Column("LOAD_OPTION", Varchar(64), NOT_NULL),
+ Column("PLUGIN_MATURITY", Varchar(12), NOT_NULL),
+ Column("PLUGIN_AUTH_VERSION", Varchar(80), NULLABLE),
+ CEnd()
};
ST_FIELD_INFO files_fields_info[]=
{
- {"FILE_ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, SKIP_OPEN_TABLE},
- {"FILE_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"FILE_TYPE", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLESPACE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- SKIP_OPEN_TABLE},
- {"TABLE_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"LOGFILE_GROUP_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- SKIP_OPEN_TABLE},
- {"LOGFILE_GROUP_NUMBER", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"FULLTEXT_KEYS", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"DELETED_ROWS", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"UPDATE_COUNT", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"FREE_EXTENTS", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"TOTAL_EXTENTS", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"EXTENT_SIZE", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, SKIP_OPEN_TABLE},
- {"INITIAL_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
- {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
- {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
- {"CREATION_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
- {"LAST_UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
- {"LAST_ACCESS_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
- {"RECOVER_TIME", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"TRANSACTION_COUNTER", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"VERSION", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Version", SKIP_OPEN_TABLE},
- {"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format", SKIP_OPEN_TABLE},
- {"TABLE_ROWS", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", SKIP_OPEN_TABLE},
- {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", SKIP_OPEN_TABLE},
- {"DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", SKIP_OPEN_TABLE},
- {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", SKIP_OPEN_TABLE},
- {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", SKIP_OPEN_TABLE},
- {"DATA_FREE", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_free", SKIP_OPEN_TABLE},
- {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Create_time", SKIP_OPEN_TABLE},
- {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Update_time", SKIP_OPEN_TABLE},
- {"CHECK_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Check_time", SKIP_OPEN_TABLE},
- {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Checksum", SKIP_OPEN_TABLE},
- {"STATUS", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"EXTRA", 255, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("FILE_ID", SLonglong(4), NOT_NULL),
+ Column("FILE_NAME", Varchar(FN_REFLEN),NULLABLE),
+ Column("FILE_TYPE", Varchar(20), NOT_NULL),
+ Column("TABLESPACE_NAME", Name(), NULLABLE),
+ Column("TABLE_CATALOG", Name(), NOT_NULL),
+ Column("TABLE_SCHEMA", Name(), NULLABLE),
+ Column("TABLE_NAME", Name(), NULLABLE),
+ Column("LOGFILE_GROUP_NAME", Name(), NULLABLE),
+ Column("LOGFILE_GROUP_NUMBER",SLonglong(4), NULLABLE),
+ Column("ENGINE", Name(), NOT_NULL),
+ Column("FULLTEXT_KEYS", Name(), NULLABLE),
+ Column("DELETED_ROWS", SLonglong(4), NULLABLE),
+ Column("UPDATE_COUNT", SLonglong(4), NULLABLE),
+ Column("FREE_EXTENTS", SLonglong(4), NULLABLE),
+ Column("TOTAL_EXTENTS", SLonglong(4), NULLABLE),
+ Column("EXTENT_SIZE", SLonglong(4), NOT_NULL),
+ Column("INITIAL_SIZE", ULonglong(), NULLABLE),
+ Column("MAXIMUM_SIZE", ULonglong(), NULLABLE),
+ Column("AUTOEXTEND_SIZE", ULonglong(), NULLABLE),
+ Column("CREATION_TIME", Datetime(0), NULLABLE),
+ Column("LAST_UPDATE_TIME", Datetime(0), NULLABLE),
+ Column("LAST_ACCESS_TIME", Datetime(0), NULLABLE),
+ Column("RECOVER_TIME", SLonglong(4), NULLABLE),
+ Column("TRANSACTION_COUNTER", SLonglong(4), NULLABLE),
+ Column("VERSION", ULonglong(), NULLABLE, "Version"),
+ Column("ROW_FORMAT", Varchar(10), NULLABLE, "Row_format"),
+ Column("TABLE_ROWS", ULonglong(), NULLABLE, "Rows"),
+ Column("AVG_ROW_LENGTH", ULonglong(), NULLABLE, "Avg_row_length"),
+ Column("DATA_LENGTH", ULonglong(), NULLABLE, "Data_length"),
+ Column("MAX_DATA_LENGTH", ULonglong(), NULLABLE, "Max_data_length"),
+ Column("INDEX_LENGTH", ULonglong(), NULLABLE, "Index_length"),
+ Column("DATA_FREE", ULonglong(), NULLABLE, "Data_free"),
+ Column("CREATE_TIME", Datetime(0), NULLABLE, "Create_time"),
+ Column("UPDATE_TIME", Datetime(0), NULLABLE, "Update_time"),
+ Column("CHECK_TIME", Datetime(0), NULLABLE, "Check_time"),
+ Column("CHECKSUM", ULonglong(), NULLABLE, "Checksum"),
+ Column("STATUS", Varchar(20), NOT_NULL),
+ Column("EXTRA", Varchar(255), NULLABLE),
+ CEnd()
};
+}; // namespace Show
+
+
void init_fill_schema_files_row(TABLE* table)
{
int i;
- for(i=0; files_fields_info[i].field_name!=NULL; i++)
+ for(i=0; !Show::files_fields_info[i].end_marker(); i++)
table->field[i]->set_null();
table->field[IS_FILES_STATUS]->set_notnull();
table->field[IS_FILES_STATUS]->store("NORMAL", 6, system_charset_info);
}
+
+namespace Show {
+
ST_FIELD_INFO referential_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},
- {"UNIQUE_CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {"UNIQUE_CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {"UNIQUE_CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0,
- MY_I_S_MAYBE_NULL, 0, OPEN_FULL_TABLE},
- {"MATCH_OPTION", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"UPDATE_RULE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"DELETE_RULE", 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},
- {"REFERENCED_TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("CONSTRAINT_CATALOG", Catalog(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("UNIQUE_CONSTRAINT_CATALOG", Catalog(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("UNIQUE_CONSTRAINT_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("UNIQUE_CONSTRAINT_NAME", Name(), NULLABLE, OPEN_FULL_TABLE),
+ Column("MATCH_OPTION", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("UPDATE_RULE", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("DELETE_RULE", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("REFERENCED_TABLE_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ CEnd()
};
ST_FIELD_INFO parameters_fields_info[]=
{
- {"SPECIFIC_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"SPECIFIC_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {"SPECIFIC_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 0, 0, OPEN_FULL_TABLE},
- {"PARAMETER_MODE", 5, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"PARAMETER_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"DATA_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE},
- {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE},
- {"NUMERIC_PRECISION", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE},
- {"NUMERIC_SCALE", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE},
- {"DATETIME_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
- 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
- {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"DTD_IDENTIFIER", 65535, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"ROUTINE_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}
+ Column("SPECIFIC_CATALOG", Catalog(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("SPECIFIC_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("SPECIFIC_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("ORDINAL_POSITION", SLong(21), NOT_NULL, OPEN_FULL_TABLE),
+ Column("PARAMETER_MODE", Varchar(5), NULLABLE, OPEN_FULL_TABLE),
+ Column("PARAMETER_NAME", Name(), NULLABLE, OPEN_FULL_TABLE),
+ Column("DATA_TYPE", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CHARACTER_MAXIMUM_LENGTH",SLong(21), NULLABLE, OPEN_FULL_TABLE),
+ Column("CHARACTER_OCTET_LENGTH", SLong(21), NULLABLE, OPEN_FULL_TABLE),
+ Column("NUMERIC_PRECISION", SLong(21), NULLABLE, OPEN_FULL_TABLE),
+ Column("NUMERIC_SCALE", SLong(21), NULLABLE, OPEN_FULL_TABLE),
+ Column("DATETIME_PRECISION", ULonglong(), NULLABLE, OPEN_FRM_ONLY),
+ Column("CHARACTER_SET_NAME", Varchar(64), NULLABLE, OPEN_FULL_TABLE),
+ Column("COLLATION_NAME", Varchar(64), NULLABLE, OPEN_FULL_TABLE),
+ Column("DTD_IDENTIFIER", Longtext(65535), NOT_NULL, OPEN_FULL_TABLE),
+ Column("ROUTINE_TYPE", Varchar(9), NOT_NULL, OPEN_FULL_TABLE),
+ CEnd()
};
ST_FIELD_INFO tablespaces_fields_info[]=
{
- {"TABLESPACE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- SKIP_OPEN_TABLE},
- {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLESPACE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL,
- 0, SKIP_OPEN_TABLE},
- {"LOGFILE_GROUP_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL,
- 0, SKIP_OPEN_TABLE},
- {"EXTENT_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
- MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE},
- {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
- MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE},
- {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
- MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE},
- {"NODEGROUP_ID", 21, MYSQL_TYPE_LONGLONG, 0,
- MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE},
- {"TABLESPACE_COMMENT", 2048, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0,
- SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("TABLESPACE_NAME", Name(), NOT_NULL),
+ Column("ENGINE", Name(), NOT_NULL),
+ Column("TABLESPACE_TYPE", Name(), NULLABLE),
+ Column("LOGFILE_GROUP_NAME", Name(), NULLABLE),
+ Column("EXTENT_SIZE", ULonglong(), NULLABLE),
+ Column("AUTOEXTEND_SIZE", ULonglong(), NULLABLE),
+ Column("MAXIMUM_SIZE", ULonglong(), NULLABLE),
+ Column("NODEGROUP_ID", ULonglong(), NULLABLE),
+ Column("TABLESPACE_COMMENT", Varchar(2048), NULLABLE),
+ CEnd()
};
ST_FIELD_INFO keycache_fields_info[]=
{
- {"KEY_CACHE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"SEGMENTS", 3, MYSQL_TYPE_LONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED) , 0, SKIP_OPEN_TABLE},
- {"SEGMENT_NUMBER", 3, MYSQL_TYPE_LONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
- {"FULL_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
- {"BLOCK_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE },
- {"USED_BLOCKS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), "Key_blocks_used", SKIP_OPEN_TABLE},
- {"UNUSED_BLOCKS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), "Key_blocks_unused", SKIP_OPEN_TABLE},
- {"DIRTY_BLOCKS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), "Key_blocks_not_flushed", SKIP_OPEN_TABLE},
- {"READ_REQUESTS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), "Key_read_requests", SKIP_OPEN_TABLE},
- {"READS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), "Key_reads", SKIP_OPEN_TABLE},
- {"WRITE_REQUESTS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), "Key_write_requests", SKIP_OPEN_TABLE},
- {"WRITES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), "Key_writes", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("KEY_CACHE_NAME",Varchar(NAME_LEN),NOT_NULL),
+ Column("SEGMENTS", ULong(3), NULLABLE),
+ Column("SEGMENT_NUMBER", ULong(3), NULLABLE),
+ Column("FULL_SIZE", ULonglong(), NOT_NULL),
+ Column("BLOCK_SIZE", ULonglong(), NOT_NULL),
+ Column("USED_BLOCKS", ULonglong(), NOT_NULL, "Key_blocks_used"),
+ Column("UNUSED_BLOCKS", ULonglong(), NOT_NULL, "Key_blocks_unused"),
+ Column("DIRTY_BLOCKS", ULonglong(), NOT_NULL, "Key_blocks_not_flushed"),
+ Column("READ_REQUESTS", ULonglong(), NOT_NULL, "Key_read_requests"),
+ Column("READS", ULonglong(), NOT_NULL, "Key_reads"),
+ Column("WRITE_REQUESTS", ULonglong(), NOT_NULL, "Key_write_requests"),
+ Column("WRITES", ULonglong(), NOT_NULL, "Key_writes"),
+ CEnd()
};
ST_FIELD_INFO show_explain_fields_info[]=
{
- /* field_name, length, type, value, field_flags, old_name*/
- {"id", 3, MYSQL_TYPE_LONGLONG, 0 /*value*/, MY_I_S_MAYBE_NULL, "id",
- SKIP_OPEN_TABLE},
- {"select_type", 19, MYSQL_TYPE_STRING, 0 /*value*/, 0, "select_type",
- SKIP_OPEN_TABLE},
- {"table", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0 /*value*/, MY_I_S_MAYBE_NULL,
- "table", SKIP_OPEN_TABLE},
- {"type", 15, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, "type", SKIP_OPEN_TABLE},
- {"possible_keys", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/,
- MY_I_S_MAYBE_NULL, "possible_keys", SKIP_OPEN_TABLE},
- {"key", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/,
- MY_I_S_MAYBE_NULL, "key", SKIP_OPEN_TABLE},
- {"key_len", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/,
- MY_I_S_MAYBE_NULL, "key_len", SKIP_OPEN_TABLE},
- {"ref", NAME_CHAR_LEN*MAX_REF_PARTS, MYSQL_TYPE_STRING, 0/*value*/,
- MY_I_S_MAYBE_NULL, "ref", SKIP_OPEN_TABLE},
- {"rows", 10, MYSQL_TYPE_LONGLONG, 0/*value*/, MY_I_S_MAYBE_NULL, "rows",
- SKIP_OPEN_TABLE},
- {"Extra", 255, MYSQL_TYPE_STRING, 0/*value*/, 0 /*flags*/, "Extra",
- SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("id", SLonglong(3), NULLABLE, "id"),
+ Column("select_type", Varchar(19), NOT_NULL, "select_type"),
+ Column("table", Name(), NULLABLE, "table"),
+ Column("type", Varchar(15), NULLABLE, "type"),
+ Column("possible_keys",Varchar(NAME_CHAR_LEN*MAX_KEY), NULLABLE, "possible_keys"),
+ Column("key", Varchar(NAME_CHAR_LEN*MAX_KEY), NULLABLE, "key"),
+ Column("key_len", Varchar(NAME_CHAR_LEN*MAX_KEY), NULLABLE, "key_len"),
+ Column("ref", Varchar(NAME_CHAR_LEN*MAX_REF_PARTS),NULLABLE, "ref"),
+ Column("rows", SLonglong(10), NULLABLE, "rows"),
+ Column("Extra", Varchar(255), NOT_NULL, "Extra"),
+ CEnd()
};
-#ifdef HAVE_SPATIAL
-ST_FIELD_INFO geometry_columns_fields_info[]=
-{
- {"F_TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"F_TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"F_TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"F_GEOMETRY_COLUMN", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Field",
- OPEN_FRM_ONLY},
- {"G_TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"G_TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"G_TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"G_GEOMETRY_COLUMN", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Field",
- OPEN_FRM_ONLY},
- {"STORAGE_TYPE", 2, MYSQL_TYPE_TINY, 0, 0, 0, OPEN_FRM_ONLY},
- {"GEOMETRY_TYPE", 7, MYSQL_TYPE_LONG, 0, 0, 0, OPEN_FRM_ONLY},
- {"COORD_DIMENSION", 2, MYSQL_TYPE_TINY, 0, 0, 0, OPEN_FRM_ONLY},
- {"MAX_PPR", 2, MYSQL_TYPE_TINY, 0, 0, 0, OPEN_FRM_ONLY},
- {"SRID", 5, MYSQL_TYPE_SHORT, 0, 0, 0, OPEN_FRM_ONLY},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
-};
-
-
-ST_FIELD_INFO spatial_ref_sys_fields_info[]=
+ST_FIELD_INFO check_constraints_fields_info[]=
{
- {"SRID", 5, MYSQL_TYPE_SHORT, 0, 0, 0, SKIP_OPEN_TABLE},
- {"AUTH_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"AUTH_SRID", 5, MYSQL_TYPE_LONG, 0, 0, 0, SKIP_OPEN_TABLE},
- {"SRTEXT", 2048, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
+ Column("CONSTRAINT_CATALOG", Catalog(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CHECK_CLAUSE", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ CEnd()
};
-#endif /*HAVE_SPATIAL*/
+}; // namespace Show
-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},
- {"TABLE_NAME", 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},
- {"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}
-};
+
+namespace Show {
/** For creating fields of information_schema.OPTIMIZER_TRACE */
extern ST_FIELD_INFO optimizer_trace_info[];
+} //namespace Show
+
/*
Description of ST_FIELD_INFO in table.h
@@ -9879,108 +9447,102 @@ extern ST_FIELD_INFO optimizer_trace_info[];
ST_SCHEMA_TABLE schema_tables[]=
{
- {"ALL_PLUGINS", plugin_fields_info, 0,
+ {"ALL_PLUGINS", Show::plugin_fields_info, 0,
fill_all_plugins, make_old_format, 0, 5, -1, 0, 0},
- {"APPLICABLE_ROLES", applicable_roles_fields_info, 0,
+ {"APPLICABLE_ROLES", Show::applicable_roles_fields_info, 0,
fill_schema_applicable_roles, 0, 0, -1, -1, 0, 0},
- {"CHARACTER_SETS", charsets_fields_info, 0,
+ {"CHARACTER_SETS", Show::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,
+ {"CHECK_CONSTRAINTS", Show::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,
+ {"COLLATIONS", Show::collation_fields_info, 0,
fill_schema_collation, make_old_format, 0, -1, -1, 0, 0},
- {"COLLATION_CHARACTER_SET_APPLICABILITY", coll_charset_app_fields_info,
+ {"COLLATION_CHARACTER_SET_APPLICABILITY", Show::coll_charset_app_fields_info,
0, fill_schema_coll_charset_app, 0, 0, -1, -1, 0, 0},
- {"COLUMNS", columns_fields_info, 0,
+ {"COLUMNS", Show::columns_fields_info, 0,
get_all_tables, make_columns_old_format, get_schema_column_record, 1, 2, 0,
OPTIMIZE_I_S_TABLE|OPEN_VIEW_FULL},
- {"COLUMN_PRIVILEGES", column_privileges_fields_info, 0,
+ {"COLUMN_PRIVILEGES", Show::column_privileges_fields_info, 0,
fill_schema_column_privileges, 0, 0, -1, -1, 0, 0},
- {"ENABLED_ROLES", enabled_roles_fields_info, 0,
+ {"ENABLED_ROLES", Show::enabled_roles_fields_info, 0,
fill_schema_enabled_roles, 0, 0, -1, -1, 0, 0},
- {"ENGINES", engines_fields_info, 0,
+ {"ENGINES", Show::engines_fields_info, 0,
fill_schema_engines, make_old_format, 0, -1, -1, 0, 0},
#ifdef HAVE_EVENT_SCHEDULER
- {"EVENTS", events_fields_info, 0,
+ {"EVENTS", Show::events_fields_info, 0,
Events::fill_schema_events, make_old_format, 0, -1, -1, 0, 0},
#else
- {"EVENTS", events_fields_info, 0,
+ {"EVENTS", Show::events_fields_info, 0,
0, make_old_format, 0, -1, -1, 0, 0},
#endif
- {"EXPLAIN", show_explain_fields_info, 0, fill_show_explain,
+ {"EXPLAIN", Show::show_explain_fields_info, 0, fill_show_explain,
make_old_format, 0, -1, -1, TRUE /*hidden*/ , 0},
- {"FILES", files_fields_info, 0,
+ {"FILES", Show::files_fields_info, 0,
hton_fill_schema_table, 0, 0, -1, -1, 0, 0},
- {"GLOBAL_STATUS", variables_fields_info, 0,
+ {"GLOBAL_STATUS", Show::variables_fields_info, 0,
fill_status, make_old_format, 0, 0, -1, 0, 0},
- {"GLOBAL_VARIABLES", variables_fields_info, 0,
+ {"GLOBAL_VARIABLES", Show::variables_fields_info, 0,
fill_variables, make_old_format, 0, 0, -1, 0, 0},
- {"KEY_CACHES", keycache_fields_info, 0,
+ {"KEY_CACHES", Show::keycache_fields_info, 0,
fill_key_cache_tables, 0, 0, -1,-1, 0, 0},
- {"KEY_COLUMN_USAGE", key_column_usage_fields_info, 0,
+ {"KEY_COLUMN_USAGE", Show::key_column_usage_fields_info, 0,
get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0,
OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
- {"OPEN_TABLES", open_tables_fields_info, 0,
+ {"OPEN_TABLES", Show::open_tables_fields_info, 0,
fill_open_tables, make_old_format, 0, -1, -1, 1, 0},
- {"OPTIMIZER_TRACE", optimizer_trace_info, 0,
+ {"OPTIMIZER_TRACE", Show::optimizer_trace_info, 0,
fill_optimizer_trace_info, NULL, NULL, -1, -1, false, 0},
- {"PARAMETERS", parameters_fields_info, 0,
+ {"PARAMETERS", Show::parameters_fields_info, 0,
fill_schema_proc, 0, 0, -1, -1, 0, 0},
- {"PARTITIONS", partitions_fields_info, 0,
+ {"PARTITIONS", Show::partitions_fields_info, 0,
get_all_tables, 0, get_schema_partitions_record, 1, 2, 0,
OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
- {"PLUGINS", plugin_fields_info, 0,
+ {"PLUGINS", Show::plugin_fields_info, 0,
fill_plugins, make_old_format, 0, -1, -1, 0, 0},
- {"PROCESSLIST", processlist_fields_info, 0,
+ {"PROCESSLIST", Show::processlist_fields_info, 0,
fill_schema_processlist, make_old_format, 0, -1, -1, 0, 0},
- {"PROFILING", query_profile_statistics_info, 0,
+ {"PROFILING", Show::query_profile_statistics_info, 0,
fill_query_profile_statistics_info, make_profile_table_for_show,
NULL, -1, -1, false, 0},
- {"REFERENTIAL_CONSTRAINTS", referential_constraints_fields_info,
+ {"REFERENTIAL_CONSTRAINTS", Show::referential_constraints_fields_info,
0, get_all_tables, 0, get_referential_constraints_record,
1, 9, 0, OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
- {"ROUTINES", proc_fields_info, 0,
+ {"ROUTINES", Show::proc_fields_info, 0,
fill_schema_proc, make_proc_old_format, 0, -1, -1, 0, 0},
- {"SCHEMATA", schema_fields_info, 0,
+ {"SCHEMATA", Show::schema_fields_info, 0,
fill_schema_schemata, make_schemata_old_format, 0, 1, -1, 0, 0},
- {"SCHEMA_PRIVILEGES", schema_privileges_fields_info, 0,
+ {"SCHEMA_PRIVILEGES", Show::schema_privileges_fields_info, 0,
fill_schema_schema_privileges, 0, 0, -1, -1, 0, 0},
- {"SESSION_STATUS", variables_fields_info, 0,
+ {"SESSION_STATUS", Show::variables_fields_info, 0,
fill_status, make_old_format, 0, 0, -1, 0, 0},
- {"SESSION_VARIABLES", variables_fields_info, 0,
+ {"SESSION_VARIABLES", Show::variables_fields_info, 0,
fill_variables, make_old_format, 0, 0, -1, 0, 0},
- {"STATISTICS", stat_fields_info, 0,
+ {"STATISTICS", Show::stat_fields_info, 0,
get_all_tables, make_old_format, get_schema_stat_record, 1, 2, 0,
OPEN_TABLE_ONLY|OPTIMIZE_I_S_TABLE},
- {"SYSTEM_VARIABLES", sysvars_fields_info, 0,
+ {"SYSTEM_VARIABLES", Show::sysvars_fields_info, 0,
fill_sysvars, make_old_format, 0, 0, -1, 0, 0},
- {"TABLES", tables_fields_info, 0,
+ {"TABLES", Show::tables_fields_info, 0,
get_all_tables, make_old_format, get_schema_tables_record, 1, 2, 0,
OPTIMIZE_I_S_TABLE},
- {"TABLESPACES", tablespaces_fields_info, 0,
+ {"TABLESPACES", Show::tablespaces_fields_info, 0,
hton_fill_schema_table, 0, 0, -1, -1, 0, 0},
- {"TABLE_CONSTRAINTS", table_constraints_fields_info, 0,
+ {"TABLE_CONSTRAINTS", Show::table_constraints_fields_info, 0,
get_all_tables, 0, get_schema_constraints_record, 3, 4, 0,
OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
- {"TABLE_NAMES", table_names_fields_info, 0,
+ {"TABLE_NAMES", Show::table_names_fields_info, 0,
get_all_tables, make_table_names_old_format, 0, 1, 2, 1, OPTIMIZE_I_S_TABLE},
- {"TABLE_PRIVILEGES", table_privileges_fields_info, 0,
+ {"TABLE_PRIVILEGES", Show::table_privileges_fields_info, 0,
fill_schema_table_privileges, 0, 0, -1, -1, 0, 0},
- {"TRIGGERS", triggers_fields_info, 0,
+ {"TRIGGERS", Show::triggers_fields_info, 0,
get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0,
OPEN_TRIGGER_ONLY|OPTIMIZE_I_S_TABLE},
- {"USER_PRIVILEGES", user_privileges_fields_info, 0,
+ {"USER_PRIVILEGES", Show::user_privileges_fields_info, 0,
fill_schema_user_privileges, 0, 0, -1, -1, 0, 0},
- {"VIEWS", view_fields_info, 0,
+ {"VIEWS", Show::view_fields_info, 0,
get_all_tables, 0, get_schema_views_record, 1, 2, 0,
OPEN_VIEW_ONLY|OPTIMIZE_I_S_TABLE},
-#ifdef HAVE_SPATIAL
- {"GEOMETRY_COLUMNS", geometry_columns_fields_info, 0,
- get_all_tables, make_columns_old_format, get_geometry_column_record,
- 1, 2, 0, OPTIMIZE_I_S_TABLE|OPEN_VIEW_FULL},
- {"SPATIAL_REF_SYS", spatial_ref_sys_fields_info, 0,
- fill_spatial_ref_sys, make_old_format, 0, -1, -1, 0, 0},
-#endif /*HAVE_SPATIAL*/
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};
@@ -9990,7 +9552,8 @@ int initialize_schema_table(st_plugin_int *plugin)
ST_SCHEMA_TABLE *schema_table;
DBUG_ENTER("initialize_schema_table");
- if (!(schema_table= (ST_SCHEMA_TABLE *)my_malloc(sizeof(ST_SCHEMA_TABLE),
+ if (!(schema_table= (ST_SCHEMA_TABLE *)my_malloc(key_memory_ST_SCHEMA_TABLE,
+ sizeof(ST_SCHEMA_TABLE),
MYF(MY_WME | MY_ZEROFILL))))
DBUG_RETURN(1);
/* Historical Requirement */
@@ -10013,8 +9576,8 @@ int initialize_schema_table(st_plugin_int *plugin)
}
if (!schema_table->old_format)
- for (ST_FIELD_INFO *f= schema_table->fields_info; f->field_name; f++)
- if (f->old_name && f->old_name[0])
+ for (ST_FIELD_INFO *f= schema_table->fields_info; !f->end_marker(); f++)
+ if (f->old_name().str && f->old_name().str[0])
{
schema_table->old_format= make_old_format;
break;
@@ -10138,7 +9701,7 @@ static bool show_create_trigger_impl(THD *thd, Trigger *trigger)
Item_datetime_literal *tmp= (new (mem_root)
Item_datetime_literal(thd, &zero_time, 2));
- tmp->set_name(thd, STRING_WITH_LEN("Created"), system_charset_info);
+ tmp->set_name(thd, Lex_cstring(STRING_WITH_LEN("Created")));
fields.push_back(tmp, mem_root);
if (p->send_result_set_metadata(&fields,
@@ -10351,15 +9914,15 @@ public:
~IS_internal_schema_access()
{}
- ACL_internal_access_result check(ulong want_access,
- ulong *save_priv) const;
+ ACL_internal_access_result check(privilege_t want_access,
+ privilege_t *save_priv) const;
const ACL_internal_table_access *lookup(const char *name) const;
};
ACL_internal_access_result
-IS_internal_schema_access::check(ulong want_access,
- ulong *save_priv) const
+IS_internal_schema_access::check(privilege_t want_access,
+ privilege_t *save_priv) const
{
want_access &= ~SELECT_ACL;
@@ -10367,7 +9930,7 @@ IS_internal_schema_access::check(ulong want_access,
We don't allow any simple privileges but SELECT_ACL on
the information_schema database.
*/
- if (unlikely(want_access & DB_ACLS))
+ if (unlikely((want_access & DB_ACLS) != NO_ACL))
return ACL_INTERNAL_ACCESS_DENIED;
/* Always grant SELECT for the information schema. */
@@ -10392,99 +9955,6 @@ void initialize_information_schema_acl()
&is_internal_schema_access);
}
-#ifdef WITH_PARTITION_STORAGE_ENGINE
-/*
- Convert a string in character set in column character set format
- to utf8 character set if possible, the utf8 character set string
- will later possibly be converted to character set used by client.
- Thus we attempt conversion from column character set to both
- utf8 and to character set client.
-
- Examples of strings that should fail conversion to utf8 are unassigned
- characters as e.g. 0x81 in cp1250 (Windows character set for for countries
- like Czech and Poland). Example of string that should fail conversion to
- character set on client (e.g. if this is latin1) is 0x2020 (daggger) in
- ucs2.
-
- If the conversion fails we will as a fall back convert the string to
- hex encoded format. The caller of the function can also ask for hex
- encoded format of output string unconditionally.
-
- SYNOPSIS
- get_cs_converted_string_value()
- thd Thread object
- input_str Input string in cs character set
- output_str Output string to be produced in utf8
- cs Character set of input string
- use_hex Use hex string unconditionally
-
-
- RETURN VALUES
- No return value
-*/
-
-static void get_cs_converted_string_value(THD *thd,
- String *input_str,
- String *output_str,
- CHARSET_INFO *cs,
- bool use_hex)
-{
-
- output_str->length(0);
- if (input_str->length() == 0)
- {
- output_str->append("''");
- return;
- }
- if (!use_hex)
- {
- String try_val;
- uint try_conv_error= 0;
-
- try_val.copy(input_str->ptr(), input_str->length(), cs,
- thd->variables.character_set_client, &try_conv_error);
- if (likely(!try_conv_error))
- {
- String val;
- uint conv_error= 0;
-
- val.copy(input_str->ptr(), input_str->length(), cs,
- system_charset_info, &conv_error);
- if (likely(!conv_error))
- {
- append_unescaped(output_str, val.ptr(), val.length());
- return;
- }
- }
- /* We had a conversion error, use hex encoded string for safety */
- }
- {
- const uchar *ptr;
- uint i, len;
- char buf[3];
-
- output_str->append("_");
- output_str->append(cs->csname);
- output_str->append(" ");
- output_str->append("0x");
- len= input_str->length();
- ptr= (uchar*)input_str->ptr();
- for (i= 0; i < len; i++)
- {
- uint high, low;
-
- high= (*ptr) >> 4;
- low= (*ptr) & 0x0F;
- buf[0]= _dig_vec_upper[high];
- buf[1]= _dig_vec_upper[low];
- buf[2]= 0;
- output_str->append((const char*)buf);
- ptr++;
- }
- }
- return;
-}
-#endif
/**
Dumps a text description of a thread, its security context
diff --git a/sql/sql_show.h b/sql/sql_show.h
index 39cbc35230a..80588cda8b5 100644
--- a/sql/sql_show.h
+++ b/sql/sql_show.h
@@ -76,10 +76,19 @@ typedef struct system_status_var STATUS_VAR;
#define IS_FILES_EXTRA 37
typedef enum { WITHOUT_DB_NAME, WITH_DB_NAME } enum_with_db_name;
+
+int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond);
+
int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
Table_specification_st *create_info_arg,
enum_with_db_name with_db_name);
+int show_create_table_ex(THD *thd, TABLE_LIST *table_list,
+ const char * forced_db, const char *forced_name,
+ String *packet,
+ Table_specification_st *create_info_arg,
+ enum_with_db_name with_db_name);
+
int copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table);
bool append_identifier(THD *thd, String *packet, const char *name, size_t length);
@@ -110,6 +119,7 @@ bool append_definer(THD *thd, String *buffer, const LEX_CSTRING *definer_user,
const LEX_CSTRING *definer_host);
int add_status_vars(SHOW_VAR *list);
void remove_status_vars(SHOW_VAR *list);
+ulonglong get_status_vars_version(void);
void init_status_vars();
void free_status_vars();
void reset_status_vars();
@@ -117,9 +127,7 @@ bool show_create_trigger(THD *thd, const sp_name *trg_name);
void view_store_options(THD *thd, TABLE_LIST *table, String *buff);
void init_fill_schema_files_row(TABLE* table);
-bool schema_table_store_record(THD *thd, TABLE *table);
void initialize_information_schema_acl();
-COND *make_cond_for_info_schema(THD *thd, COND *cond, TABLE_LIST *table);
ST_SCHEMA_TABLE *find_schema_table(THD *thd, const LEX_CSTRING *table_name,
bool *in_plugin);
diff --git a/sql/sql_signal.cc b/sql/sql_signal.cc
index 320a954711a..115f5fa4347 100644
--- a/sql/sql_signal.cc
+++ b/sql/sql_signal.cc
@@ -1,4 +1,5 @@
/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2009, 2020, 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
@@ -104,7 +105,7 @@ static bool assign_fixed_string(MEM_ROOT *mem_root,
src_cs= src->charset();
src_len= src->length();
src_end= src_str + src_len;
- numchars= src_cs->cset->numchars(src_cs, src_str, src_end);
+ numchars= src_cs->numchars(src_str, src_end);
if (numchars <= max_char)
{
@@ -114,7 +115,7 @@ static bool assign_fixed_string(MEM_ROOT *mem_root,
else
{
numchars= max_char;
- to_copy= dst_cs->cset->charpos(dst_cs, src_str, src_end, numchars);
+ to_copy= dst_cs->charpos(src_str, src_end, numchars);
truncated= true;
}
@@ -151,7 +152,7 @@ static int assign_condition_item(MEM_ROOT *mem_root, const char* name, THD *thd,
Item *set, String *ci)
{
char str_buff[(64+1)*4]; /* Room for a null terminated UTF8 String 64 */
- String str_value(str_buff, sizeof(str_buff), & my_charset_utf8_bin);
+ String str_value(str_buff, sizeof(str_buff), & my_charset_utf8mb3_bin);
String *str;
bool truncated;
@@ -164,7 +165,7 @@ static int assign_condition_item(MEM_ROOT *mem_root, const char* name, THD *thd,
}
str= set->val_str(& str_value);
- truncated= assign_fixed_string(mem_root, & my_charset_utf8_bin, 64, ci, str);
+ truncated= assign_fixed_string(mem_root, & my_charset_utf8mb3_bin, 64, ci, str);
if (truncated)
{
if (thd->is_strict_mode())
@@ -260,7 +261,7 @@ int Sql_cmd_common_signal::eval_signal_informations(THD *thd, Sql_condition *con
bool truncated;
String utf8_text;
str= set->val_str(& str_value);
- truncated= assign_fixed_string(thd->mem_root, & my_charset_utf8_bin,
+ truncated= assign_fixed_string(thd->mem_root, & my_charset_utf8mb3_bin,
MYSQL_ERRMSG_SIZE,
& utf8_text, str);
if (truncated)
diff --git a/sql/sql_sort.h b/sql/sql_sort.h
index 7abbc808632..5b3f5a67d17 100644
--- a/sql/sql_sort.h
+++ b/sql/sql_sort.h
@@ -2,6 +2,7 @@
#define SQL_SORT_INCLUDED
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2020, 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
@@ -19,10 +20,8 @@
#include "my_base.h" /* ha_rows */
#include <my_sys.h> /* qsort2_cmp */
#include "queues.h"
+#include "sql_class.h"
-typedef struct st_buffpek BUFFPEK;
-
-struct SORT_FIELD;
class Field;
struct TABLE;
@@ -64,21 +63,476 @@ struct BUFFPEK_COMPARE_CONTEXT
};
+/**
+ Descriptor for a merge chunk to be sort-merged.
+ A merge chunk is a sequence of pre-sorted records, written to a
+ temporary file. A Merge_chunk instance describes where this chunk is stored
+ in the file, and where it is located when it is in memory.
+
+ It is a POD because
+ - we read/write them from/to files.
+
+ We have accessors (getters/setters) for all struct members.
+ */
+
+struct Merge_chunk {
+public:
+ my_off_t file_position() const { return m_file_position; }
+ void set_file_position(my_off_t val) { m_file_position= val; }
+ void advance_file_position(my_off_t val) { m_file_position+= val; }
+
+ uchar *buffer_start() { return m_buffer_start; }
+ const uchar *buffer_end() const { return m_buffer_end; }
+
+ void set_buffer(uchar *start, uchar *end)
+ {
+ m_buffer_start= start;
+ m_buffer_end= end;
+ }
+ void set_buffer_start(uchar *start)
+ {
+ m_buffer_start= start;
+ }
+ void set_buffer_end(uchar *end)
+ {
+ DBUG_ASSERT(m_buffer_end == NULL || end <= m_buffer_end);
+ m_buffer_end= end;
+ }
+
+ void init_current_key() { m_current_key= m_buffer_start; }
+ uchar *current_key() { return m_current_key; }
+ void advance_current_key(uint val) { m_current_key+= val; }
+
+ void decrement_rowcount(ha_rows val) { m_rowcount-= val; }
+ void set_rowcount(ha_rows val) { m_rowcount= val; }
+ ha_rows rowcount() const { return m_rowcount; }
+
+ ha_rows mem_count() const { return m_mem_count; }
+ void set_mem_count(ha_rows val) { m_mem_count= val; }
+ ha_rows decrement_mem_count() { return --m_mem_count; }
+
+ ha_rows max_keys() const { return m_max_keys; }
+ void set_max_keys(ha_rows val) { m_max_keys= val; }
+
+ size_t buffer_size() const { return m_buffer_end - m_buffer_start; }
+
+ /**
+ Tries to merge *this with *mc, returns true if successful.
+ The assumption is that *this is no longer in use,
+ and the space it has been allocated can be handed over to a
+ buffer which is adjacent to it.
+ */
+ bool merge_freed_buff(Merge_chunk *mc) const
+ {
+ if (mc->m_buffer_end == m_buffer_start)
+ {
+ mc->m_buffer_end= m_buffer_end;
+ mc->m_max_keys+= m_max_keys;
+ return true;
+ }
+ else if (mc->m_buffer_start == m_buffer_end)
+ {
+ mc->m_buffer_start= m_buffer_start;
+ mc->m_max_keys+= m_max_keys;
+ return true;
+ }
+ return false;
+ }
+
+ /// The current key for this chunk
+ uchar *m_current_key= nullptr;
+ /// Current position in the file to be sorted.
+ my_off_t m_file_position= 0;
+ /// Start of main-memory buffer for this chunk.
+ uchar *m_buffer_start= nullptr;
+ /// End of main-memory buffer for this chunk.
+ uchar *m_buffer_end= nullptr;
+ /// Number of unread rows in this chunk.
+ ha_rows m_rowcount= 0;
+ /// Number of rows in the main-memory buffer.
+ ha_rows m_mem_count= 0;
+ /// If we have fixed-size rows: max number of rows in buffer.
+ ha_rows m_max_keys= 0;
+};
+
+typedef Bounds_checked_array<SORT_ADDON_FIELD> Addon_fields_array;
+typedef Bounds_checked_array<SORT_FIELD> Sort_keys_array;
+
+/**
+ This class wraps information about usage of addon fields.
+ An Addon_fields object is used both during packing of data in the filesort
+ buffer, and later during unpacking in 'Filesort_info::unpack_addon_fields'.
+
+ @see documentation for the Sort_addon_field struct.
+ @see documentation for get_addon_fields()
+ */
+class Addon_fields {
+public:
+ Addon_fields(Addon_fields_array arr)
+ : m_field_descriptors(arr),
+ m_addon_buf(),
+ m_addon_buf_length(),
+ m_using_packed_addons(false)
+ {
+ DBUG_ASSERT(!arr.is_null());
+ }
+
+ SORT_ADDON_FIELD *begin() { return m_field_descriptors.begin(); }
+ SORT_ADDON_FIELD *end() { return m_field_descriptors.end(); }
+
+ /// rr_unpack_from_tempfile needs an extra buffer when unpacking.
+ uchar *allocate_addon_buf(uint sz)
+ {
+ m_addon_buf= (uchar *)my_malloc(PSI_INSTRUMENT_ME, sz, MYF(MY_WME | MY_THREAD_SPECIFIC));
+ if (m_addon_buf)
+ m_addon_buf_length= sz;
+ return m_addon_buf;
+ }
+
+ void free_addon_buff()
+ {
+ my_free(m_addon_buf);
+ m_addon_buf= NULL;
+ m_addon_buf_length= 0;
+ }
+
+ uchar *get_addon_buf() { return m_addon_buf; }
+ uint get_addon_buf_length() const { return m_addon_buf_length; }
+
+ void set_using_packed_addons(bool val)
+ {
+ m_using_packed_addons= val;
+ }
+
+ bool using_packed_addons() const
+ {
+ return m_using_packed_addons;
+ }
+
+ static bool can_pack_addon_fields(uint record_length)
+ {
+ return (record_length <= (0xFFFF));
+ }
+
+ /**
+ @returns Total number of bytes used for packed addon fields.
+ the size of the length field + size of null bits + sum of field sizes.
+ */
+ static uint read_addon_length(uchar *p)
+ {
+ return size_of_length_field + uint2korr(p);
+ }
+
+ /**
+ Stores the number of bytes used for packed addon fields.
+ */
+ static void store_addon_length(uchar *p, uint sz)
+ {
+ // We actually store the length of everything *after* the length field.
+ int2store(p, sz - size_of_length_field);
+ }
+
+ static const uint size_of_length_field= 2;
+
+private:
+ Addon_fields_array m_field_descriptors;
+
+ uchar *m_addon_buf; ///< Buffer for unpacking addon fields.
+ uint m_addon_buf_length; ///< Length of the buffer.
+ bool m_using_packed_addons; ///< Are we packing the addon fields?
+};
+
+/**
+ This class wraps information about usage of sort keys.
+ A Sort_keys object is used both during packing of data in the filesort
+ buffer, and later during unpacking in 'Filesort_info::unpack_addon_fields'.
+
+ @see SORT_FIELD struct.
+*/
+
+class Sort_keys :public Sql_alloc,
+ public Sort_keys_array
+{
+public:
+ Sort_keys(SORT_FIELD* arr, size_t count):
+ Sort_keys_array(arr, count),
+ m_using_packed_sortkeys(false),
+ size_of_packable_fields(0),
+ sort_length(0)
+ {
+ DBUG_ASSERT(!is_null());
+ }
+
+ bool using_packed_sortkeys() const
+ { return m_using_packed_sortkeys; }
+
+ void set_using_packed_sortkeys(bool val)
+ {
+ m_using_packed_sortkeys= val;
+ }
+ void set_size_of_packable_fields(uint len)
+ {
+ size_of_packable_fields= len;
+ }
+
+ uint get_size_of_packable_fields()
+ {
+ return size_of_packable_fields;
+ }
+
+ void set_sort_length(uint len)
+ {
+ sort_length= len;
+ }
+
+ uint get_sort_length()
+ {
+ return sort_length;
+ }
+
+ static void store_sortkey_length(uchar *p, uint sz)
+ {
+ int4store(p, sz - size_of_length_field);
+ }
+
+ static uint read_sortkey_length(uchar *p)
+ {
+ return size_of_length_field + uint4korr(p);
+ }
+
+ void increment_size_of_packable_fields(uint len)
+ {
+ size_of_packable_fields+= len;
+ }
+
+ void increment_original_sort_length(uint len)
+ {
+ sort_length+= len;
+ }
+
+ static const uint size_of_length_field= 4;
+
+private:
+ bool m_using_packed_sortkeys; // Are we packing sort keys
+ uint size_of_packable_fields; // Total length bytes for packable columns
+
+ /*
+ The length that would be needed if we stored non-packed mem-comparable
+ images of fields?
+ */
+ uint sort_length;
+};
+
+
+/**
+PACKED SORT KEYS
+
+Description
+
+In this optimization where we would like the pack the values of the sort key
+inside the sort buffer for each record.
+
+Contents:
+1. Background
+1.1 Implementation details
+2. Solution : Packed Sort Keys
+2.1 Packed key format
+2.2 Which format to use
+3. Special cases
+3.1 Handling very long strings
+3.2 Handling for long binary strings
+3.3 Handling very long strings with Packed sort keys
+4. Sort key columns in addon_fields
+
+1. Background
+Before this optimization of using packed sort keys, filesort() sorted the
+data using mem-comparable keys.
+
+That is, if we wanted to sort by
+
+ ORDER BY col1, col2, ... colN
+then the filesort code would for each row generate one "Sort Key"
+and then sort the rows by their Sort Keys.
+
+The Sort Keys are mem-comparable (that is, are compared by memcmp()) and
+they are of FIXED SIZE. The sort key has the same length regardless of
+what value it represents. This causes INEFFICIENT MEMORY USAGE.
+
+1.1 Implementation details
+
+make_sortkey() is the function that produces a sort key
+from a record.
+
+The function treats Field and Item objects differently.
+
+class Field has:
+
+a) void make_sort_key(uchar *buff, uint length);
+ make_sort_key is a non-virtual function which handles encoding of
+ SQL null values.
+
+b) virtual void sort_string(uchar *buff,uint length)=0;
+ sort_string produces mem-comparable image of the field value
+ for each datatype.
+
+For Items, Type_handler has a virtual function:
+
+ virtual void make_sort_key(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const= 0;
+ which various datatypes overload.
+
+
+2. SOLUTION: PACKED SORT KEYS
+
+Note that one can have mem-comparable keys are that are not fixed-size.
+MyRocks uses such encoding for example.
+
+However for this optimization it was decided to store the original
+(non-mem-comparable) values instead and use a datatype-aware
+key comparison function.
+
+2.1 Packed key format
+The keys are stored in a new variable-size data format called "packed".
+
+The format is as follows:
+
+ <sort_key_length><packed_value_1><packed_value2> ....... <packed_valueN>
+
+ format for a n-part sort key
+
+<sort_key_length> is the length of the whole key.
+Each packed value is encoded as follows:
+
+ <null_byte=0> // This is a an SQL NULL
+ [<null_byte=1>] <packed_value> // this a non-NULL value
+null_byte is present if the field/item is NULLable.
+SQL NULL is encoded as just one NULL-indicator byte. The value itself is omitted.
+
+The format of the packed_value depends on the datatype.
+For "non-packable" datatypes it is just their mem-comparable form, as before.
+
+The "packable" datatypes are currently variable-length strings and the
+packed format for them is (for binary blobs, see a note below):
+
+<length> <string>
+2.2 Which format to use
+
+The advantage of Packed Key Format is potential space savings for
+variable-length fields.
+
+The disadvantages are:
+
+a) It may actually take more space, because of sort_key_length and
+ length fields.
+b) The comparison function is more expensive.
+
+Currently the logic is: use Packed Key Format if we would save 128 or more
+bytes when constructing a sort key from values that have empty string
+for each packable component.
+
+3. SPECIAL CASES
+3.1 HANDLING VERY LONG STRINGS
+the size of sort key part was limited by @@max_sort_length variable.
+It is defined as:
+
+The number of bytes to use when sorting data values. The server uses only the
+first max_sort_length bytes of each value and ignores the rest.
+
+3.2 HANDLING VERY LONG BINARY STRINGS
+Long binary strings receive special treatment. A sort key for the long
+binary string is truncated at max_sort_length bytes like described above,
+but then a "suffix" is appended which contains the total length of the
+value before the truncation.
+
+3.3 HANDLING VERY LONG STRINGS WITH PACKED SORT KEY
+Truncating multi-byte string at N bytes is not safe because one can cut in the
+middle of a character. One is tempted to solve this by discarding the partial
+character but that's also not a good idea as in some collations multiple
+characters may produce one weight (this is called "contraction").
+
+This combination of circumstances:
+
+The string value is very long, so truncation is necessary
+The collation is "complex", so truncation is dangerous
+is deemed to be relatively rare so it was decided to just use
+the non-packed sort keys in this case.
+
+4. SORT KEY COLUMNS IN ADDON FIELDS
+Currently, each sort key column is actually stored twice
+1. as part of the sort key
+2. in the addon_fields
+This made total sense when sort key stored the mem-comparable image
+(from which one cannot restore the original value in general case).
+But since we now store the original value, we could also remove it from the
+addon_fields and further save space. This is still a limitation and needs
+to be fixed later
+
+@see Sort_keys
+
+**/
+
+/**
+ The sort record format may use one of two formats for the non-sorted part of
+ the record:
+
+ 1. Use the rowid
+
+ |<sort_key>| <rowid> |
+ / / ref_length /
+
+ 2. Use "addon fields"
+
+ |<sort_key>|<null bits>|<field a><field b>...|
+ / / addon_length /
+
+ The packed format for "addon fields"
+
+ |<sort_key>|<length>|<null bits>|<field a><field b>...|
+ / / addon_length /
+
+ <sort_key> The key may use one of the two formats:
+ A. fixed-size mem-comparable form. The record is always
+ sort_length bytes long.
+ B. "PackedKeyFormat" - the records are variable-size.
+
+ <key> Fields are fixed-size, specially encoded with
+ Field::make_sort_key() so we can do byte-by-byte compare.
+
+ <length> Contains the *actual* packed length (after packing) of
+ everything after the sort keys.
+ The size of the length field is 2 bytes,
+ which should cover most use cases: addon data <= 65535 bytes.
+ This is the same as max record size in MySQL.
+ <null bits> One bit for each nullable field, indicating whether the field
+ is null or not. May have size zero if no fields are nullable.
+ <field xx> Are stored with field->pack(), and retrieved with
+ field->unpack(). Addon fields within a record are stored
+ consecutively, with no "holes" or padding. They will have zero
+ size for NULL values.
+
+*/
+
class Sort_param {
public:
uint rec_length; // Length of sorted records.
uint sort_length; // Length of sorted columns.
uint ref_length; // Length of record ref.
+ uint addon_length; // Length of addon_fields
uint res_length; // Length of records in final sorted file/buffer.
uint max_keys_per_buffer; // Max keys / buffer.
uint min_dupl_count;
ha_rows max_rows; // Select limit, or HA_POS_ERROR if unlimited.
ha_rows examined_rows; // Number of examined rows.
TABLE *sort_form; // For quicker make_sortkey.
- SORT_FIELD *local_sortorder;
- SORT_FIELD *end;
- SORT_ADDON_FIELD *addon_field; // Descriptors for companion fields.
- LEX_STRING addon_buf; // Buffer & length of added packed fields.
+ /**
+ ORDER BY list with some precalculated info for filesort.
+ Array is created and owned by a Filesort instance.
+ */
+ Bounds_checked_array<SORT_FIELD> local_sortorder;
+ Addon_fields *addon_fields; // Descriptors for companion fields.
+ Sort_keys *sort_keys;
+ bool using_pq;
uchar *unique_buff;
bool not_killable;
@@ -89,25 +543,138 @@ public:
Sort_param()
{
- memset(this, 0, sizeof(*this));
+ memset(reinterpret_cast<void*>(this), 0, sizeof(*this));
}
void init_for_filesort(uint sortlen, TABLE *table,
ha_rows maxrows, bool sort_positions);
+ /// Enables the packing of addons if possible.
+ void try_to_pack_addons(ulong max_length_for_sort_data);
+
+ /// Are we packing the "addon fields"?
+ bool using_packed_addons() const
+ {
+ DBUG_ASSERT(m_using_packed_addons ==
+ (addon_fields != NULL &&
+ addon_fields->using_packed_addons()));
+ return m_using_packed_addons;
+ }
+
+ bool using_packed_sortkeys() const
+ {
+ DBUG_ASSERT(m_using_packed_sortkeys ==
+ (sort_keys != NULL && sort_keys->using_packed_sortkeys()));
+ return m_using_packed_sortkeys;
+ }
+
+ /// Are we using "addon fields"?
+ bool using_addon_fields() const
+ {
+ return addon_fields != NULL;
+ }
+
+ uint32 get_result_length(uchar *plen)
+ {
+ if (!m_using_packed_addons)
+ return res_length;
+ return Addon_fields::read_addon_length(plen);
+ }
+
+ uint32 get_addon_length(uchar *plen)
+ {
+ if (using_packed_addons())
+ return Addon_fields::read_addon_length(plen);
+ else
+ return addon_length;
+ }
+
+ uint32 get_sort_length(uchar *plen)
+ {
+ if (using_packed_sortkeys())
+ return Sort_keys::read_sortkey_length(plen) +
+ /*
+ when addon fields are not present, then the sort_length also
+ includes the res_length. For packed keys here we add
+ the res_length
+ */
+ (using_addon_fields() ? 0: res_length);
+ else
+ return sort_length;
+ }
+
+ uint get_record_length(uchar *plen)
+ {
+ if (m_packed_format)
+ {
+ uint sort_len= get_sort_length(plen);
+ return sort_len + get_addon_length(plen + sort_len);
+ }
+ else
+ return rec_length;
+ }
+
+ /**
+ Getter for record length and result length.
+ @param record_start Pointer to record.
+ @param [out] recl Store record length here.
+ @param [out] resl Store result length here.
+ */
+ void get_rec_and_res_len(uchar *record_start, uint *recl, uint *resl)
+ {
+ if (m_packed_format)
+ {
+ uint sort_len= get_sort_length(record_start);
+ uint addon_len= get_addon_length(record_start + sort_len);
+ *recl= sort_len + addon_len;
+ *resl= using_addon_fields() ? addon_len : res_length;
+ }
+ else
+ {
+ *recl= rec_length;
+ *resl= res_length;
+ }
+ }
+
+ void try_to_pack_sortkeys();
+
+ qsort2_cmp get_compare_function() const
+ {
+ return using_packed_sortkeys() ?
+ get_packed_keys_compare_ptr() :
+ get_ptr_compare(sort_length);
+ }
+ void* get_compare_argument(size_t *sort_len) const
+ {
+ return using_packed_sortkeys() ?
+ (void*) this :
+ (void*) sort_len;
+ }
+
+ bool is_packed_format() const
+ {
+ return m_packed_format;
+ }
+
+private:
+ uint m_packable_length;
+ bool m_using_packed_addons; ///< caches the value of using_packed_addons()
+ /* caches the value of using_packed_sortkeys() */
+ bool m_using_packed_sortkeys;
+ bool m_packed_format;
};
+typedef Bounds_checked_array<uchar> Sort_buffer;
-int merge_many_buff(Sort_param *param, uchar *sort_buffer,
- BUFFPEK *buffpek,
- uint *maxbuffer, IO_CACHE *t_file);
-ulong read_to_buffer(IO_CACHE *fromfile,BUFFPEK *buffpek,
- uint sort_length);
+int merge_many_buff(Sort_param *param, Sort_buffer sort_buffer,
+ Merge_chunk *buffpek, uint *maxbuffer, IO_CACHE *t_file);
+ulong read_to_buffer(IO_CACHE *fromfile, Merge_chunk *buffpek,
+ Sort_param *param, bool packing_format);
bool merge_buffers(Sort_param *param,IO_CACHE *from_file,
- IO_CACHE *to_file, uchar *sort_buffer,
- BUFFPEK *lastbuff,BUFFPEK *Fb,
- BUFFPEK *Tb,int flag);
-int merge_index(Sort_param *param, uchar *sort_buffer,
- BUFFPEK *buffpek, uint maxbuffer,
- IO_CACHE *tempfile, IO_CACHE *outfile);
-void reuse_freed_buff(QUEUE *queue, BUFFPEK *reuse, uint key_length);
+ IO_CACHE *to_file, Sort_buffer sort_buffer,
+ Merge_chunk *lastbuff, Merge_chunk *Fb,
+ Merge_chunk *Tb, int flag);
+int merge_index(Sort_param *param, Sort_buffer sort_buffer,
+ Merge_chunk *buffpek, uint maxbuffer,
+ IO_CACHE *tempfile, IO_CACHE *outfile);
+void reuse_freed_buff(QUEUE *queue, Merge_chunk *reuse, uint key_length);
#endif /* SQL_SORT_INCLUDED */
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index a94fb1196b4..55e8e52c052 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -1432,7 +1432,7 @@ public:
*/
bool init(uint n_keyparts)
{
- if (!(rowid_buf= (uchar*)my_malloc(rowid_size, MYF(0))))
+ if (!(rowid_buf= (uchar*)my_malloc(PSI_INSTRUMENT_ME, rowid_size, MYF(0))))
return true;
if (open_cached_file(&io_cache, mysql_tmpdir, TEMP_PREFIX,
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 483eb4fcbec..2fc6ae0ad7d 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2016, MariaDB
+ Copyright (c) 2016, 2020, 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
@@ -41,8 +41,8 @@ bool Binary_string::real_alloc(size_t length)
if (Alloced_length < arg_length)
{
free();
- if (!(Ptr=(char*) my_malloc(arg_length,MYF(MY_WME |
- (thread_specific ?
+ if (!(Ptr=(char*) my_malloc(PSI_INSTRUMENT_ME,
+ arg_length,MYF(MY_WME | (thread_specific ?
MY_THREAD_SPECIFIC : 0)))))
return TRUE;
DBUG_ASSERT(length < UINT_MAX32);
@@ -92,13 +92,13 @@ bool Binary_string::realloc_raw(size_t alloc_length)
return TRUE; /* Overflow */
if (alloced)
{
- if (!(new_ptr= (char*) my_realloc(Ptr,len,
+ if (!(new_ptr= (char*) my_realloc(PSI_INSTRUMENT_ME, Ptr,len,
MYF(MY_WME |
(thread_specific ?
MY_THREAD_SPECIFIC : 0)))))
return TRUE; // Signal error
}
- else if ((new_ptr= (char*) my_malloc(len,
+ else if ((new_ptr= (char*) my_malloc(PSI_INSTRUMENT_ME, len,
MYF(MY_WME |
(thread_specific ?
MY_THREAD_SPECIFIC : 0)))))
@@ -125,7 +125,7 @@ bool String::set_int(longlong num, bool unsigned_flag, CHARSET_INFO *cs)
if (alloc(l))
return TRUE;
- str_length=(uint32) (cs->cset->longlong10_to_str)(cs,Ptr,l,base,num);
+ str_length=(uint32) (cs->longlong10_to_str)(Ptr,l,base,num);
set_charset(cs);
return FALSE;
}
@@ -777,6 +777,29 @@ void Static_binary_string::qs_append(ulonglong i)
str_length+= (int) (end-buff);
}
+
+bool Binary_string::copy_printable_hhhh(CHARSET_INFO *to_cs,
+ CHARSET_INFO *from_cs,
+ const char *from,
+ size_t from_length)
+{
+ DBUG_ASSERT(from_length < UINT_MAX32);
+ uint errors;
+ uint one_escaped_char_length= MY_CS_PRINTABLE_CHAR_LENGTH * to_cs->mbminlen;
+ uint one_char_length= MY_MAX(one_escaped_char_length, to_cs->mbmaxlen);
+ ulonglong bytes_needed= from_length * one_char_length;
+ if (bytes_needed >= UINT_MAX32 || alloc((size_t) bytes_needed))
+ return true;
+ str_length= my_convert_using_func(Ptr, Alloced_length, to_cs,
+ my_wc_to_printable_generic,
+ from, from_length,
+ from_cs,
+ from_cs->cset->mb_wc,
+ &errors);
+ return false;
+}
+
+
/*
Compare strings according to collation, without end space.
@@ -798,9 +821,8 @@ void Static_binary_string::qs_append(ulonglong i)
int sortcmp(const String *s,const String *t, CHARSET_INFO *cs)
{
- return cs->coll->strnncollsp(cs,
- (uchar *) s->ptr(),s->length(),
- (uchar *) t->ptr(),t->length());
+ return cs->strnncollsp(s->ptr(), s->length(),
+ t->ptr(), t->length());
}
@@ -1076,8 +1098,8 @@ String_copier::well_formed_copy(CHARSET_INFO *to_cs,
my_charset_same(from_cs, to_cs))
{
m_cannot_convert_error_pos= NULL;
- return (uint) to_cs->cset->copy_fix(to_cs, to, to_length, from, from_length,
- nchars, this);
+ return (uint) to_cs->copy_fix(to, to_length, from, from_length,
+ nchars, this);
}
return (uint) my_convert_fix(to_cs, to, to_length, from_cs, from, from_length,
nchars, this, this);
@@ -1214,3 +1236,25 @@ bool String::append_semi_hex(const char *s, uint len, CHARSET_INFO *cs)
str_length+= nbytes;
return false;
}
+
+// Shrink the buffer, but only if it is allocated on the heap.
+void Binary_string::shrink(size_t arg_length)
+{
+ if (!is_alloced())
+ return;
+ if (ALIGN_SIZE(arg_length + 1) < Alloced_length)
+ {
+ char* new_ptr;
+ if (!(new_ptr = (char*)my_realloc(STRING_PSI_MEMORY_KEY, Ptr, arg_length,
+ MYF(thread_specific ? MY_THREAD_SPECIFIC : 0))))
+ {
+ Alloced_length = 0;
+ real_alloc(arg_length);
+ }
+ else
+ {
+ Ptr = new_ptr;
+ Alloced_length = (uint32)arg_length;
+ }
+ }
+}
diff --git a/sql/sql_string.h b/sql/sql_string.h
index aad5314a973..4eeac0a8a82 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -3,7 +3,7 @@
/*
Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2008, 2019, MariaDB Corporation.
+ Copyright (c) 2008, 2020, 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
@@ -30,6 +30,13 @@
#include "sql_list.h"
class String;
+#ifdef MYSQL_SERVER
+extern PSI_memory_key key_memory_String_value;
+#define STRING_PSI_MEMORY_KEY key_memory_String_value
+#else
+#define STRING_PSI_MEMORY_KEY PSI_NOT_INSTRUMENTED
+#endif
+
typedef struct st_io_cache IO_CACHE;
typedef struct st_mem_root MEM_ROOT;
@@ -60,7 +67,7 @@ class Well_formed_prefix_status: public String_copy_status
public:
Well_formed_prefix_status(CHARSET_INFO *cs,
const char *str, const char *end, size_t nchars)
- { cs->cset->well_formed_char_length(cs, str, end, nchars, this); }
+ { cs->well_formed_char_length(str, end, nchars, this); }
};
@@ -137,20 +144,26 @@ public:
Charset(CHARSET_INFO *cs) :m_charset(cs) { }
CHARSET_INFO *charset() const { return m_charset; }
+ bool use_mb() const { return m_charset->use_mb(); }
uint mbminlen() const { return m_charset->mbminlen; }
uint mbmaxlen() const { return m_charset->mbmaxlen; }
+ bool is_good_for_ft() const
+ {
+ // Binary and UCS2/UTF16/UTF32 are not supported
+ return m_charset != &my_charset_bin && m_charset->mbminlen == 1;
+ }
size_t numchars(const char *str, const char *end) const
{
- return m_charset->cset->numchars(m_charset, str, end);
+ return m_charset->numchars(str, end);
}
size_t lengthsp(const char *str, size_t length) const
{
- return m_charset->cset->lengthsp(m_charset, str, length);
+ return m_charset->lengthsp(str, length);
}
size_t charpos(const char *str, const char *end, size_t pos) const
{
- return m_charset->cset->charpos(m_charset, str, end, pos);
+ return m_charset->charpos(str, end, pos);
}
void set_charset(CHARSET_INFO *charset_arg)
{
@@ -519,6 +532,15 @@ public:
bool copy(const char *s, size_t arg_length); // Allocate new string
bool copy_or_move(const char *s,size_t arg_length);
+ /**
+ Convert a string to a printable format.
+ All non-convertable and control characters are replaced to 5-character
+ sequences '\hhhh'.
+ */
+ bool copy_printable_hhhh(CHARSET_INFO *to_cs,
+ CHARSET_INFO *from_cs,
+ const char *from, size_t from_length);
+
bool append_ulonglong(ulonglong val);
bool append_longlong(longlong val);
@@ -531,6 +553,10 @@ public:
q_append(s, size);
return false;
}
+ bool append(const LEX_CSTRING &s)
+ {
+ return append(s.str, s.length);
+ }
bool append(const Binary_string &s)
{
return append(s.ptr(), s.length());
@@ -640,28 +666,8 @@ public:
return realloc_with_extra(arg_length);
}
// Shrink the buffer, but only if it is allocated on the heap.
- inline void shrink(size_t arg_length)
- {
- if (!is_alloced())
- return;
- if (ALIGN_SIZE(arg_length+1) < Alloced_length)
- {
- char *new_ptr;
- if (unlikely(!(new_ptr=(char*)
- my_realloc(Ptr,
- arg_length,MYF((thread_specific ?
- MY_THREAD_SPECIFIC : 0))))))
- {
- Alloced_length= 0;
- real_alloc(arg_length);
- }
- else
- {
- Ptr= new_ptr;
- Alloced_length= (uint32) arg_length;
- }
- }
- }
+ void shrink(size_t arg_length);
+
void move(Binary_string &s)
{
set_alloced(s.Ptr, s.str_length, s.Alloced_length);
@@ -835,6 +841,15 @@ public:
bool copy_aligned(const char *s, size_t arg_length, size_t offset,
CHARSET_INFO *cs);
bool set_or_copy_aligned(const char *s, size_t arg_length, CHARSET_INFO *cs);
+ bool can_be_safely_converted_to(CHARSET_INFO *tocs) const
+ {
+ if (charset() == &my_charset_bin)
+ return Well_formed_prefix(tocs, ptr(), length()).length() == length();
+ String try_val;
+ uint try_conv_error= 0;
+ try_val.copy(ptr(), length(), charset(), tocs, &try_conv_error);
+ return try_conv_error == 0;
+ }
bool copy(const char*s, size_t arg_length, CHARSET_INFO *csfrom,
CHARSET_INFO *csto, uint *errors);
bool copy(const String *str, CHARSET_INFO *tocs, uint *errors)
@@ -869,6 +884,14 @@ public:
{
return Binary_string::append_hex((const char*)src, srclen);
}
+ bool append_introducer_and_hex(CHARSET_INFO *cs, const LEX_CSTRING &str)
+ {
+ return
+ append(STRING_WITH_LEN("_")) ||
+ append(cs->csname) ||
+ append(STRING_WITH_LEN(" 0x")) ||
+ append_hex(str.str, (uint32) str.length);
+ }
bool append(IO_CACHE* file, uint32 arg_length)
{
return Binary_string::append(file, arg_length);
@@ -908,6 +931,10 @@ public:
// Append with optional character set conversion from cs to charset()
bool append(const char *s, size_t arg_length, CHARSET_INFO *cs);
+ bool append(const LEX_CSTRING &s, CHARSET_INFO *cs)
+ {
+ return append(s.str, s.length, cs);
+ }
void strip_sp();
friend int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
@@ -1004,6 +1031,15 @@ public:
};
+template<size_t buff_sz>
+class BinaryStringBuffer : public Binary_string
+{
+ char buff[buff_sz];
+public:
+ BinaryStringBuffer() : Binary_string(buff, buff_sz) { length(0); }
+};
+
+
class String_space: public String
{
public:
@@ -1019,7 +1055,7 @@ static inline bool check_if_only_end_space(CHARSET_INFO *cs,
const char *str,
const char *end)
{
- return str+ cs->cset->scan(cs, str, end, MY_SEQ_SPACES) == end;
+ return str + cs->scan(str, end, MY_SEQ_SPACES) == end;
}
int append_query_string(CHARSET_INFO *csinfo, String *to,
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 619c3fe2654..2d4ff71d0c1 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2019, Oracle and/or its affiliates.
- Copyright (c) 2010, 2019, MariaDB
+ Copyright (c) 2010, 2020, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -28,7 +28,7 @@
#include "sql_base.h" // lock_table_names
#include "lock.h" // mysql_unlock_tables
#include "strfunc.h" // find_type2, find_set
-#include "sql_truncate.h" // regenerate_locked_table
+#include "sql_truncate.h" // regenerate_locked_table
#include "sql_partition.h" // mem_alloc_error,
// partition_info
// NOT_A_PARTITION_ID
@@ -132,7 +132,7 @@ static char* add_identifier(THD* thd, char *to_p, const char * end_p,
*(to_p++)= (char) quote;
while (*conv_name && (end_p - to_p - 1) > 0)
{
- int length= my_charlen(system_charset_info, conv_name, conv_name_end);
+ int length= system_charset_info->charlen(conv_name, conv_name_end);
if (length <= 0)
length= 1;
if (length == 1 && *conv_name == (char) quote)
@@ -1127,8 +1127,8 @@ static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry)
ddl_log_entry->tmp_name));
handler_name.str= (char*)ddl_log_entry->handler_name;
handler_name.length= strlen(ddl_log_entry->handler_name);
- init_sql_alloc(&mem_root, "execute_ddl_log_action", TABLE_ALLOC_BLOCK_SIZE,
- 0, MYF(MY_THREAD_SPECIFIC));
+ init_sql_alloc(key_memory_gdl, &mem_root, TABLE_ALLOC_BLOCK_SIZE, 0,
+ MYF(MY_THREAD_SPECIFIC));
if (!strcmp(ddl_log_entry->handler_name, reg_ext))
frm_action= TRUE;
else
@@ -1162,7 +1162,7 @@ static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry)
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
strxmov(to_path, ddl_log_entry->name, par_ext, NullS);
- (void) mysql_file_delete(key_file_partition, to_path, MYF(MY_WME));
+ (void) mysql_file_delete(key_file_partition_ddl_log, to_path, MYF(MY_WME));
#endif
}
else
@@ -1200,7 +1200,7 @@ static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry)
#ifdef WITH_PARTITION_STORAGE_ENGINE
strxmov(to_path, ddl_log_entry->name, par_ext, NullS);
strxmov(from_path, ddl_log_entry->from_name, par_ext, NullS);
- (void) mysql_file_rename(key_file_partition, from_path, to_path, MYF(MY_WME));
+ (void) mysql_file_rename(key_file_partition_ddl_log, from_path, to_path, MYF(MY_WME));
#endif
}
else
@@ -1297,7 +1297,7 @@ static bool get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY **active_entry,
if (global_ddl_log.first_free == NULL)
{
- if (!(used_entry= (DDL_LOG_MEMORY_ENTRY*)my_malloc(
+ if (!(used_entry= (DDL_LOG_MEMORY_ENTRY*)my_malloc(key_memory_DDL_LOG_MEMORY_ENTRY,
sizeof(DDL_LOG_MEMORY_ENTRY), MYF(MY_WME))))
{
sql_print_error("Failed to allocate memory for ddl log free list");
@@ -2443,6 +2443,16 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
{
char *end;
int frm_delete_error= 0;
+
+#ifdef WITH_WSREP
+ if (WSREP(thd) &&
+ !wsrep_should_replicate_ddl(thd, table_type->db_type))
+ {
+ error= 1;
+ goto err;
+ }
+#endif
+
/*
It could happen that table's share in the table definition cache
is the only thing that keeps the engine plugin loaded
@@ -2470,8 +2480,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
table->table= 0;
}
else
- tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db.str, table->table_name.str,
- false);
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db.str,
+ table->table_name.str);
/* Check that we have an exclusive lock on the table to be dropped. */
DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db.str,
@@ -2743,7 +2753,8 @@ bool log_drop_table(THD *thd, const LEX_CSTRING *db_name,
*/
bool quick_rm_table(THD *thd, handlerton *base, const LEX_CSTRING *db,
- const LEX_CSTRING *table_name, uint flags, const char *table_path)
+ const LEX_CSTRING *table_name, uint flags,
+ const char *table_path)
{
char path[FN_REFLEN + 1];
int error= 0;
@@ -2751,11 +2762,13 @@ bool quick_rm_table(THD *thd, handlerton *base, const LEX_CSTRING *db,
size_t path_length= table_path ?
(strxnmov(path, sizeof(path) - 1, table_path, reg_ext, NullS) - path) :
- build_table_filename(path, sizeof(path)-1, db->str, table_name->str, reg_ext, flags);
- if (mysql_file_delete(key_file_frm, path, MYF(0)))
- error= 1; /* purecov: inspected */
+ build_table_filename(path, sizeof(path)-1, db->str, table_name->str,
+ reg_ext, flags);
+ if (!(flags & NO_FRM_RENAME))
+ if (mysql_file_delete(key_file_frm, path, MYF(0)))
+ error= 1; /* purecov: inspected */
path[path_length - reg_ext_length]= '\0'; // Remove reg_ext
- if (flags & NO_HA_TABLE)
+ if ((flags & (NO_HA_TABLE | NO_PAR_TABLE)) == NO_HA_TABLE)
{
handler *file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base);
if (!file)
@@ -2861,7 +2874,7 @@ static int sort_keys(KEY *a, KEY *b)
*/
bool check_duplicates_in_interval(const char *set_or_name,
- const char *name, TYPELIB *typelib,
+ const char *name, const TYPELIB *typelib,
CHARSET_INFO *cs, unsigned int *dup_val_count)
{
TYPELIB tmp= *typelib;
@@ -2925,12 +2938,11 @@ bool Column_definition::prepare_stage2_typelib(const char *type_name,
}
-uint Column_definition::pack_flag_numeric(uint dec) const
+uint Column_definition::pack_flag_numeric() const
{
return (FIELDFLAG_NUMBER |
(flags & UNSIGNED_FLAG ? 0 : FIELDFLAG_DECIMAL) |
- (flags & ZEROFILL_FLAG ? FIELDFLAG_ZEROFILL : 0) |
- (dec << FIELDFLAG_DEC_SHIFT));
+ (flags & ZEROFILL_FLAG ? FIELDFLAG_ZEROFILL : 0));
}
@@ -3226,8 +3238,7 @@ bool Column_definition::prepare_stage1_check_typelib_default()
}
else /* MYSQL_TYPE_ENUM */
{
- def->length(charset->cset->lengthsp(charset,
- def->ptr(), def->length()));
+ def->length(charset->lengthsp(def->ptr(), def->length()));
not_found= !find_type2(interval, def->ptr(), def->length(), charset);
}
}
@@ -3333,7 +3344,7 @@ static Create_field * add_hash_field(THD * thd, List<Create_field> *create_list,
}
}
cf->field_name= field_name;
- cf->set_handler(&type_handler_longlong);
+ cf->set_handler(&type_handler_slonglong);
key_info->algorithm= HA_KEY_ALG_LONG_HASH;
create_list->push_back(cf,thd->mem_root);
return cf;
@@ -3351,6 +3362,63 @@ mysql_add_invisible_index(THD *thd, List<Key> *key_list,
key_list->push_back(key, thd->mem_root);
return key;
}
+
+
+bool Type_handler_string::Key_part_spec_init_ft(Key_part_spec *part,
+ const Column_definition &def)
+ const
+{
+ /*
+ Set length to 0. It's set to the real column width later for CHAR.
+ It has to be the correct col width for CHAR, as its data are not
+ prefixed with length (unlike blobs).
+ */
+ part->length= 0;
+ return !Charset(def.charset).is_good_for_ft();
+}
+
+
+bool Type_handler_varchar::Key_part_spec_init_ft(Key_part_spec *part,
+ const Column_definition &def)
+ const
+{
+ part->length= 0;
+ return !Charset(def.charset).is_good_for_ft();
+}
+
+
+bool
+Type_handler_blob_common::Key_part_spec_init_ft(Key_part_spec *part,
+ const Column_definition &def)
+ const
+{
+ /*
+ Set keyseg length to 1 for blobs.
+ It's ignored in ft code: the data length is taken from the length prefix.
+ */
+ part->length= 1;
+ return !Charset(def.charset).is_good_for_ft();
+}
+
+
+static bool
+key_add_part_check_null(const handler *file, KEY *key_info,
+ const Column_definition *sql_field,
+ const Key_part_spec *column)
+{
+ if (!(sql_field->flags & NOT_NULL_FLAG))
+ {
+ key_info->flags|= HA_NULL_PART_KEY;
+ if (!(file->ha_table_flags() & HA_NULL_IN_KEY))
+ {
+ my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name.str);
+ return true;
+ }
+ }
+ return false;
+}
+
+
/*
Preparation for table creation
@@ -3401,12 +3469,12 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
DBUG_EXECUTE_IF("test_pseudo_invisible",{
mysql_add_invisible_field(thd, &alter_info->create_list,
- "invisible", &type_handler_long, INVISIBLE_SYSTEM,
+ "invisible", &type_handler_slong, INVISIBLE_SYSTEM,
new (thd->mem_root)Item_int(thd, 9));
});
DBUG_EXECUTE_IF("test_completely_invisible",{
mysql_add_invisible_field(thd, &alter_info->create_list,
- "invisible", &type_handler_long, INVISIBLE_FULL,
+ "invisible", &type_handler_slong, INVISIBLE_FULL,
new (thd->mem_root)Item_int(thd, 9));
});
DBUG_EXECUTE_IF("test_invisible_index",{
@@ -3419,11 +3487,10 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
LEX_CSTRING* connect_string = &create_info->connect_string;
if (connect_string->length != 0 &&
connect_string->length > CONNECT_STRING_MAXLEN &&
- (system_charset_info->cset->charpos(system_charset_info,
- connect_string->str,
- (connect_string->str +
- connect_string->length),
- CONNECT_STRING_MAXLEN)
+ (system_charset_info->charpos(connect_string->str,
+ (connect_string->str +
+ connect_string->length),
+ CONNECT_STRING_MAXLEN)
< connect_string->length))
{
my_error(ER_WRONG_STRING_LENGTH, MYF(0),
@@ -3893,136 +3960,92 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
cols2.rewind();
- if (key->type == Key::FULLTEXT)
- {
- if ((sql_field->real_field_type() != MYSQL_TYPE_STRING &&
- sql_field->real_field_type() != MYSQL_TYPE_VARCHAR &&
- !f_is_blob(sql_field->pack_flag)) ||
- sql_field->charset == &my_charset_bin ||
- sql_field->charset->mbminlen > 1 || // ucs2 doesn't work yet
- (ft_key_charset && sql_field->charset != ft_key_charset))
- {
- my_error(ER_BAD_FT_COLUMN, MYF(0), column->field_name.str);
- DBUG_RETURN(-1);
- }
- ft_key_charset=sql_field->charset;
- /*
- for fulltext keys keyseg length is 1 for blobs (it's ignored in ft
- code anyway, and 0 (set to column width later) for char's. it has
- to be correct col width for char's, as char data are not prefixed
- with length (unlike blobs, where ft code takes data length from a
- data prefix, ignoring column->length).
- */
- column->length= MY_TEST(f_is_blob(sql_field->pack_flag));
- }
- else
- {
- column->length*= sql_field->charset->mbmaxlen;
+ switch(key->type) {
- if (key->type == Key::SPATIAL)
+ case Key::FULLTEXT:
+ if (sql_field->type_handler()->Key_part_spec_init_ft(column,
+ *sql_field) ||
+ (ft_key_charset && sql_field->charset != ft_key_charset))
{
- if (column->length)
- {
- my_error(ER_WRONG_SUB_KEY, MYF(0));
- DBUG_RETURN(TRUE);
- }
- if (!f_is_geom(sql_field->pack_flag))
- {
- my_error(ER_WRONG_ARGUMENTS, MYF(0), "SPATIAL INDEX");
- DBUG_RETURN(TRUE);
- }
+ my_error(ER_BAD_FT_COLUMN, MYF(0), column->field_name.str);
+ DBUG_RETURN(-1);
}
+ ft_key_charset= sql_field->charset;
+ break;
- if (f_is_blob(sql_field->pack_flag) ||
- (f_is_geom(sql_field->pack_flag) && key->type != Key::SPATIAL))
+ case Key::SPATIAL:
+ if (sql_field->type_handler()->Key_part_spec_init_spatial(column,
+ *sql_field) ||
+ sql_field->check_vcol_for_key(thd))
+ DBUG_RETURN(TRUE);
+ if (!(sql_field->flags & NOT_NULL_FLAG))
{
- if (!(file->ha_table_flags() & HA_CAN_INDEX_BLOBS))
- {
- my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name.str,
- file->table_type());
- DBUG_RETURN(TRUE);
- }
- if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type ==
- Field::GEOM_POINT)
- column->length= MAX_LEN_GEOM_POINT_FIELD;
- if (!column->length)
- {
- if (key->type == Key::UNIQUE)
- is_hash_field_needed= true;
- else if (key->type == Key::MULTIPLE)
- column->length= file->max_key_length() + 1;
- else
- {
- my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name.str);
- DBUG_RETURN(TRUE);
- }
- }
+ my_message(ER_SPATIAL_CANT_HAVE_NULL,
+ ER_THD(thd, ER_SPATIAL_CANT_HAVE_NULL), MYF(0));
+ DBUG_RETURN(TRUE);
}
-#ifdef HAVE_SPATIAL
- if (key->type == Key::SPATIAL)
- {
- if (!column->length)
- {
- /*
- 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
- Lately we'll extend this code to support more dimensions
- */
- column->length= 4*sizeof(double);
- }
- }
-#endif
+ break;
+
+ case Key::PRIMARY:
if (sql_field->vcol_info)
{
- if (key->type == Key::PRIMARY)
- {
- my_error(ER_PRIMARY_KEY_BASED_ON_GENERATED_COLUMN, MYF(0));
- DBUG_RETURN(TRUE);
- }
- if (sql_field->vcol_info->flags & VCOL_NOT_STRICTLY_DETERMINISTIC)
- {
- /* use check_expression() to report an error */
- check_expression(sql_field->vcol_info, &sql_field->field_name,
- VCOL_GENERATED_STORED);
- DBUG_ASSERT(thd->is_error());
- DBUG_RETURN(TRUE);
- }
+ my_error(ER_PRIMARY_KEY_BASED_ON_GENERATED_COLUMN, MYF(0));
+ DBUG_RETURN(TRUE);
}
- if (!(sql_field->flags & NOT_NULL_FLAG))
- {
- if (key->type == Key::PRIMARY)
- {
- /* Implicitly set primary key fields to NOT NULL for ISO conf. */
- sql_field->flags|= NOT_NULL_FLAG;
- sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
- null_fields--;
- }
- else
- {
- key_info->flags|= HA_NULL_PART_KEY;
- if (!(file->ha_table_flags() & HA_NULL_IN_KEY))
- {
- my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name.str);
- DBUG_RETURN(TRUE);
- }
- if (key->type == Key::SPATIAL)
- {
- my_message(ER_SPATIAL_CANT_HAVE_NULL,
- ER_THD(thd, ER_SPATIAL_CANT_HAVE_NULL), MYF(0));
- DBUG_RETURN(TRUE);
- }
- }
- }
- if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
- {
- if (column_nr == 0 || (file->ha_table_flags() & HA_AUTO_PART_KEY))
- auto_increment--; // Field is used
- }
+ if (sql_field->type_handler()->Key_part_spec_init_primary(column,
+ *sql_field,
+ file))
+ DBUG_RETURN(TRUE);
+ if (!(sql_field->flags & NOT_NULL_FLAG))
+ {
+ /* Implicitly set primary key fields to NOT NULL for ISO conf. */
+ sql_field->flags|= NOT_NULL_FLAG;
+ sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
+ null_fields--;
+ }
+ break;
+
+ case Key::MULTIPLE:
+ if (sql_field->type_handler()->Key_part_spec_init_multiple(column,
+ *sql_field,
+ file) ||
+ sql_field->check_vcol_for_key(thd) ||
+ key_add_part_check_null(file, key_info, sql_field, column))
+ DBUG_RETURN(TRUE);
+ break;
+
+ case Key::FOREIGN_KEY:
+ if (sql_field->type_handler()->Key_part_spec_init_foreign(column,
+ *sql_field,
+ file) ||
+ sql_field->check_vcol_for_key(thd) ||
+ key_add_part_check_null(file, key_info, sql_field, column))
+ DBUG_RETURN(TRUE);
+ break;
+
+ case Key::UNIQUE:
+ if (sql_field->type_handler()->Key_part_spec_init_unique(column,
+ *sql_field, file,
+ &is_hash_field_needed) ||
+ sql_field->check_vcol_for_key(thd) ||
+ key_add_part_check_null(file, key_info, sql_field, column))
+ DBUG_RETURN(TRUE);
+ break;
+ }
+
+ if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
+ {
+ DBUG_ASSERT(key->type != Key::FULLTEXT);
+ DBUG_ASSERT(key->type != Key::SPATIAL);
+ if (column_nr == 0 || (file->ha_table_flags() & HA_AUTO_PART_KEY))
+ auto_increment--; // Field is used
}
key_part_info->fieldnr= field;
key_part_info->offset= (uint16) sql_field->offset;
key_part_info->key_type=sql_field->pack_flag;
- uint key_part_length= sql_field->key_length;
+ uint key_part_length= sql_field->type_handler()->
+ calc_key_length(*sql_field);
if (column->length)
{
@@ -4115,19 +4138,14 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
/* Use packed keys for long strings on the first column */
if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) &&
!((create_info->table_options & HA_OPTION_NO_PACK_KEYS)) &&
- (key_part_length >= KEY_DEFAULT_PACK_LENGTH &&
- (sql_field->real_field_type() == MYSQL_TYPE_STRING ||
- sql_field->real_field_type() == MYSQL_TYPE_VARCHAR ||
- f_is_blob(sql_field->pack_flag))) && !is_hash_field_needed)
- {
- if ((column_nr == 0 && f_is_blob(sql_field->pack_flag)) ||
- sql_field->real_field_type() == MYSQL_TYPE_VARCHAR)
- key_info->flags|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
- else
- key_info->flags|= HA_PACK_KEY;
+ (key_part_length >= KEY_DEFAULT_PACK_LENGTH) &&
+ !is_hash_field_needed)
+ {
+ key_info->flags|= sql_field->type_handler()->KEY_pack_flags(column_nr);
}
/* Check if the key segment is partial, set the key flag accordingly */
- if (key_part_length != sql_field->key_length &&
+ if (key_part_length != sql_field->type_handler()->
+ calc_key_length(*sql_field) &&
key_part_length != sql_field->type_handler()->max_octet_length())
key_info->flags|= HA_KEY_HAS_PART_KEY_SEG;
@@ -4392,8 +4410,9 @@ bool validate_comment_length(THD *thd, LEX_CSTRING *comment, size_t max_len,
uint err_code, const char *name)
{
DBUG_ENTER("validate_comment_length");
- size_t tmp_len= my_charpos(system_charset_info, comment->str,
- comment->str + comment->length, max_len);
+ size_t tmp_len= system_charset_info->charpos(comment->str,
+ comment->str + comment->length,
+ max_len);
if (tmp_len < comment->length)
{
if (thd->is_strict_mode())
@@ -4489,7 +4508,7 @@ bool Column_definition::prepare_blob_field(THD *thd)
set_handler(Type_handler::blob_type_handler((uint) length));
pack_length= type_handler()->calc_pack_length(0);
}
- length= key_length= 0;
+ length= 0;
}
DBUG_RETURN(0);
}
@@ -5538,7 +5557,8 @@ mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db,
{
if (rename_file_ext(from,to,reg_ext))
error= my_errno;
- (void) file->ha_create_partitioning_metadata(to, from, CHF_RENAME_FLAG);
+ if (!(flags & NO_PAR_TABLE))
+ (void) file->ha_create_partitioning_metadata(to, from, CHF_RENAME_FLAG);
}
else if (!file || likely(!(error=file->ha_rename_table(from_base, to_base))))
{
@@ -5562,7 +5582,6 @@ mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db,
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);
@@ -5663,6 +5682,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
local_create_info.init(create_info->create_like_options());
local_create_info.db_type= src_table->table->s->db_type();
local_create_info.row_type= src_table->table->s->row_type;
+ local_create_info.alter_info= &local_alter_info;
if (mysql_prepare_alter_table(thd, src_table->table, &local_create_info,
&local_alter_info, &local_alter_ctx))
goto err;
@@ -5840,8 +5860,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
goto err;
/*
- As the reference table is temporary and may not exist on slave, we must
- force the ENGINE to be present into CREATE TABLE.
+ As the reference table is temporary and may not exist on slave, we
+ must force the ENGINE to be present into CREATE TABLE.
*/
create_info->used_fields|= HA_CREATE_USED_ENGINE;
@@ -6147,7 +6167,7 @@ drop_create_field:
for (f_ptr=table->field; *f_ptr; f_ptr++)
{
if (my_strcasecmp(system_charset_info,
- acol->name, (*f_ptr)->field_name.str) == 0)
+ acol->name.str, (*f_ptr)->field_name.str) == 0)
break;
}
if (unlikely(*f_ptr == NULL))
@@ -6155,7 +6175,7 @@ drop_create_field:
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_BAD_FIELD_ERROR,
ER_THD(thd, ER_BAD_FIELD_ERROR),
- acol->name, table->s->table_name.str);
+ acol->name.str, table->s->table_name.str);
it.remove();
if (alter_info->alter_list.is_empty())
{
@@ -7562,11 +7582,10 @@ static bool mysql_inplace_alter_table(THD *thd,
{
Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN | MYSQL_OPEN_IGNORE_KILLED);
handlerton *db_type= table->s->db_type();
- MDL_ticket *mdl_ticket= table->mdl_ticket;
Alter_info *alter_info= ha_alter_info->alter_info;
bool reopen_tables= false;
bool res;
-
+ handlerton *hton;
DBUG_ENTER("mysql_inplace_alter_table");
/* Downgrade DDL lock while we are waiting for exclusive lock below */
@@ -7629,8 +7648,7 @@ static bool mysql_inplace_alter_table(THD *thd,
goto cleanup;
tdc_remove_table(thd, TDC_RT_REMOVE_NOT_OWN_KEEP_SHARE,
- table->s->db.str, table->s->table_name.str,
- false);
+ table->s->db.str, table->s->table_name.str);
}
/*
@@ -7773,6 +7791,28 @@ static bool mysql_inplace_alter_table(THD *thd,
}
}
+ /* Notify the engine that the table definition has changed */
+
+ hton= table->file->ht;
+ if (hton->notify_tabledef_changed)
+ {
+ char db_buff[FN_REFLEN], table_buff[FN_REFLEN];
+ LEX_CSTRING tmp_db, tmp_table;
+ tmp_db.str= db_buff;
+ tmp_table.str= table_buff;
+ tmp_db.length= tablename_to_filename(table_list->db.str,
+ db_buff, sizeof(db_buff));
+ tmp_table.length= tablename_to_filename(table_list->table_name.str,
+ table_buff, sizeof(table_buff));
+ if ((hton->notify_tabledef_changed)(hton, &tmp_db, &tmp_table,
+ table->s->frm_image,
+ &table->s->tabledef_version))
+ {
+ my_error(HA_ERR_INCOMPATIBLE_DEFINITION, MYF(0));
+ DBUG_RETURN(true);
+ }
+ }
+
close_all_tables_for_name(thd, table->s,
alter_ctx->is_table_renamed() ?
HA_EXTRA_PREPARE_FOR_RENAME :
@@ -7797,30 +7837,12 @@ static bool mysql_inplace_alter_table(THD *thd,
DBUG_RETURN(true);
}
- table_list->mdl_request.ticket= mdl_ticket;
- if (open_table(thd, table_list, &ot_ctx))
- DBUG_RETURN(true);
-
- /*
- Tell the handler that the changed frm is on disk and table
- has been re-opened
- */
- table_list->table->file->ha_notify_table_changed();
-
- /*
- We might be going to reopen table down on the road, so we have to
- restore state of the TABLE object which we used for obtaining of
- handler object to make it usable for later reopening.
- */
- close_thread_table(thd, &thd->open_tables);
- table_list->table= NULL;
-
// Rename altered table if requested.
if (alter_ctx->is_table_renamed())
{
// Remove TABLE and TABLE_SHARE for old name from TDC.
tdc_remove_table(thd, TDC_RT_REMOVE_ALL,
- alter_ctx->db.str, alter_ctx->table_name.str, false);
+ alter_ctx->db.str, alter_ctx->table_name.str);
if (mysql_rename_table(db_type, &alter_ctx->db, &alter_ctx->table_name,
&alter_ctx->new_db, &alter_ctx->new_alias, 0))
@@ -7968,6 +7990,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
List<Create_field> new_create_list;
/* New key definitions are added here */
List<Key> new_key_list;
+ List<Alter_rename_key> rename_key_list(alter_info->alter_rename_key_list);
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
List_iterator<Create_field> def_it(alter_info->create_list);
List_iterator<Alter_column> alter_it(alter_info->alter_list);
@@ -8108,24 +8131,6 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
continue;
}
- /*
- If we are doing a rename of a column, update all references in virtual
- column expressions, constraints and defaults to use the new column name
- */
- if (alter_info->flags & ALTER_RENAME_COLUMN)
- {
- if (field->vcol_info)
- field->vcol_info->expr->walk(&Item::rename_fields_processor, 1,
- &column_rename_param);
- if (field->check_constraint)
- field->check_constraint->expr->walk(&Item::rename_fields_processor, 1,
- &column_rename_param);
- if (field->default_value)
- field->default_value->expr->walk(&Item::rename_fields_processor, 1,
- &column_rename_param);
- table->m_needs_reopen= 1; // because new column name is on thd->mem_root
- }
-
/* Check if field is changed */
def_it.rewind();
while ((def=def_it++))
@@ -8199,19 +8204,61 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
while ((alter=alter_it++))
{
if (!my_strcasecmp(system_charset_info,field->field_name.str,
- alter->name))
+ alter->name.str))
break;
}
if (alter)
{
- if ((def->default_value= alter->default_value))
- def->flags&= ~NO_DEFAULT_VALUE_FLAG;
+ if (alter->is_rename())
+ {
+ def->change= alter->name;
+ def->field_name= alter->new_name;
+ column_rename_param.fields.push_back(def);
+ }
else
- def->flags|= NO_DEFAULT_VALUE_FLAG;
+ {
+ if ((def->default_value= alter->default_value))
+ def->flags&= ~NO_DEFAULT_VALUE_FLAG;
+ else
+ def->flags|= NO_DEFAULT_VALUE_FLAG;
+ }
alter_it.remove();
}
}
}
+
+ /*
+ If we are doing a rename of a column, update all references in virtual
+ column expressions, constraints and defaults to use the new column name
+ */
+ if (alter_info->flags & ALTER_RENAME_COLUMN)
+ {
+ alter_it.rewind();
+ Alter_column *alter;
+ while ((alter=alter_it++))
+ {
+ if (alter->is_rename())
+ {
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), alter->name.str,
+ table->s->table_name.str);
+ goto err;
+ }
+ }
+ for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
+ {
+ if (field->vcol_info)
+ field->vcol_info->expr->walk(&Item::rename_fields_processor, 1,
+ &column_rename_param);
+ if (field->check_constraint)
+ field->check_constraint->expr->walk(&Item::rename_fields_processor, 1,
+ &column_rename_param);
+ if (field->default_value)
+ field->default_value->expr->walk(&Item::rename_fields_processor, 1,
+ &column_rename_param);
+ }
+ table->m_needs_reopen= 1; // because new column name is on thd->mem_root
+ }
+
dropped_sys_vers_fields &= VERS_SYSTEM_FIELD;
if ((dropped_sys_vers_fields ||
alter_info->flags & ALTER_DROP_PERIOD) &&
@@ -8265,15 +8312,11 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
flag to allow ALTER TABLE only if the table to be altered is empty.
*/
- if ((def->real_field_type() == MYSQL_TYPE_DATE ||
- def->real_field_type() == MYSQL_TYPE_NEWDATE ||
- def->real_field_type() == MYSQL_TYPE_DATETIME ||
- def->real_field_type() == MYSQL_TYPE_DATETIME2) &&
- !alter_ctx->datetime_field &&
- !(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
- thd->variables.sql_mode & MODE_NO_ZERO_DATE)
- {
- alter_ctx->datetime_field= def;
+ if (!alter_ctx->implicit_default_value_error_field &&
+ !(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
+ def->type_handler()->validate_implicit_default_value(thd, *def))
+ {
+ alter_ctx->implicit_default_value_error_field= def;
alter_ctx->error_if_not_empty= TRUE;
}
if (!def->after.str)
@@ -8331,7 +8374,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
while ((alter=alter_it++))
{
if (!my_strcasecmp(system_charset_info,def->field_name.str,
- alter->name))
+ alter->name.str))
break;
}
if (alter)
@@ -8346,7 +8389,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
if (unlikely(alter_info->alter_list.elements))
{
my_error(ER_BAD_FIELD_ERROR, MYF(0),
- alter_info->alter_list.head()->name, table->s->table_name.str);
+ alter_info->alter_list.head()->name.str, table->s->table_name.str);
goto err;
}
if (unlikely(!new_create_list.elements))
@@ -8396,6 +8439,39 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
continue;
}
+ /* If this index is to stay in the table check if it has to be renamed. */
+ List_iterator<Alter_rename_key> rename_key_it(rename_key_list);
+ Alter_rename_key *rename_key;
+
+ while ((rename_key= rename_key_it++))
+ {
+ if (!my_strcasecmp(system_charset_info, key_name, rename_key->old_name.str))
+ {
+ if (!my_strcasecmp(system_charset_info, key_name, primary_key_name))
+ {
+ my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), rename_key->old_name.str);
+ goto err;
+ }
+ else if (!my_strcasecmp(system_charset_info, rename_key->new_name.str,
+ primary_key_name))
+ {
+ my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), rename_key->new_name.str);
+ goto err;
+ }
+
+ key_name= rename_key->new_name.str;
+ rename_key_it.remove();
+ /*
+ If the user has explicitly renamed the key, we should no longer
+ treat it as generated. Otherwise this key might be automatically
+ dropped by mysql_prepare_create_table() and this will confuse
+ code in fill_alter_inplace_info().
+ */
+ key_info->flags&= ~HA_GENERATED_KEY;
+ break;
+ }
+ }
+
if (key_info->algorithm == HA_KEY_ALG_LONG_HASH)
{
setup_keyinfo_hash(key_info);
@@ -8722,6 +8798,13 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
}
}
+ if (rename_key_list.elements)
+ {
+ my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), rename_key_list.head()->old_name.str,
+ table->s->table_name.str);
+ goto err;
+ }
+
if (!create_info->comment.str)
{
create_info->comment.str= table->s->comment.str;
@@ -9114,8 +9197,8 @@ static bool fk_prepare_copy_alter_table(THD *thd, TABLE *table,
ref_table= tbuf;
}
- mdl_request.init(MDL_key::TABLE, ref_db, ref_table, MDL_SHARED_NO_WRITE,
- MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&mdl_request, MDL_key::TABLE, ref_db, ref_table,
+ MDL_SHARED_NO_WRITE, MDL_TRANSACTION);
if (thd->mdl_context.acquire_lock(&mdl_request,
thd->variables.lock_wait_timeout))
DBUG_RETURN(true);
@@ -9386,6 +9469,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
Alter_info *alter_info,
uint order_num, ORDER *order, bool ignore)
{
+ bool engine_changed;
DBUG_ENTER("mysql_alter_table");
/*
@@ -9444,6 +9528,17 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
&alter_prelocking_strategy);
thd->open_options&= ~HA_OPEN_FOR_ALTER;
+#ifdef WITH_WSREP
+ if (WSREP(thd) &&
+ (thd->lex->sql_command == SQLCOM_ALTER_TABLE ||
+ thd->lex->sql_command == SQLCOM_CREATE_INDEX ||
+ thd->lex->sql_command == SQLCOM_DROP_INDEX) &&
+ !wsrep_should_replicate_ddl(thd, table_list->table->s->db_type()->db_type))
+ DBUG_RETURN(true);
+#endif
+
+ DEBUG_SYNC(thd, "alter_table_after_open_tables");
+
TABLE *table= table_list->table;
bool versioned= table && table->versioned();
@@ -9528,9 +9623,9 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
MDL_request_list mdl_requests;
MDL_request target_db_mdl_request;
- target_mdl_request.init(MDL_key::TABLE,
- alter_ctx.new_db.str, alter_ctx.new_name.str,
- MDL_EXCLUSIVE, MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&target_mdl_request, MDL_key::TABLE,
+ alter_ctx.new_db.str, alter_ctx.new_name.str,
+ MDL_EXCLUSIVE, MDL_TRANSACTION);
mdl_requests.push_front(&target_mdl_request);
/*
@@ -9540,9 +9635,9 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
*/
if (alter_ctx.is_database_changed())
{
- target_db_mdl_request.init(MDL_key::SCHEMA, alter_ctx.new_db.str, "",
- MDL_INTENTION_EXCLUSIVE,
- MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&target_db_mdl_request, MDL_key::SCHEMA,
+ alter_ctx.new_db.str, "", MDL_INTENTION_EXCLUSIVE,
+ MDL_TRANSACTION);
mdl_requests.push_front(&target_db_mdl_request);
}
@@ -9789,8 +9884,7 @@ do_continue:;
bool fast_alter_partition= false;
{
if (prep_alter_part_table(thd, table, alter_info, create_info,
- &alter_ctx, &partition_changed,
- &fast_alter_partition))
+ &partition_changed, &fast_alter_partition))
{
DBUG_RETURN(true);
}
@@ -10190,7 +10284,7 @@ do_continue:;
if (table->s->tmp_table != NO_TMP_TABLE)
{
/* in case of alter temp table send the tracker in OK packet */
- SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
+ thd->session_tracker.state_change.mark_as_changed(thd);
}
/*
@@ -10273,6 +10367,23 @@ do_continue:;
}
/*
+ Check if file names for the engine are unique. If we change engine
+ and file names are unique then we don't need to rename the original
+ table to a temporary name during the rename phase
+
+ File names are unique if engine changed and
+ - Either new or old engine does not store the table in files
+ - Neither old or new engine uses files from another engine
+ The above is mainly true for the sequence and the partition engine.
+ */
+ engine_changed= ((new_table->file->ht != table->file->ht) &&
+ (((!(new_table->file->ha_table_flags() & HA_FILE_BASED) ||
+ !(table->file->ha_table_flags() & HA_FILE_BASED))) ||
+ (!(table->file->ha_table_flags() & HA_REUSES_FILE_NAMES) &&
+ !(new_table->file->ha_table_flags() &
+ HA_REUSES_FILE_NAMES))));
+
+ /*
Close the intermediate table that will be the new table, but do
not delete it! Even though MERGE tables do not have their children
attached here it is safe to call THD::drop_temporary_table().
@@ -10315,23 +10426,39 @@ do_continue:;
/*
Rename the old table to temporary name to have a backup in case
anything goes wrong while renaming the new table.
+ We only have to do this if name of the table is not changed.
+ If we are changing to use another table handler, we don't
+ have to do the rename as the table names will not interfer.
*/
char backup_name_buff[FN_LEN];
LEX_CSTRING backup_name;
backup_name.str= backup_name_buff;
- backup_name.length= my_snprintf(backup_name_buff, sizeof(backup_name_buff),
- "%s2-%lx-%lx", tmp_file_prefix,
+ DBUG_PRINT("info", ("is_table_renamed: %d engine_changed: %d",
+ alter_ctx.is_table_renamed(), engine_changed));
+
+ if (!alter_ctx.is_table_renamed())
+ {
+ backup_name.length= my_snprintf(backup_name_buff, sizeof(backup_name_buff),
+ "%s2-%lx-%lx", tmp_file_prefix,
current_pid, (long) thd->thread_id);
- if (lower_case_table_names)
- my_casedn_str(files_charset_info, backup_name_buff);
- if (mysql_rename_table(old_db_type, &alter_ctx.db, &alter_ctx.table_name,
- &alter_ctx.db, &backup_name, FN_TO_IS_TMP))
+ if (lower_case_table_names)
+ my_casedn_str(files_charset_info, backup_name_buff);
+ if (mysql_rename_table(old_db_type, &alter_ctx.db, &alter_ctx.table_name,
+ &alter_ctx.db, &backup_name,
+ FN_TO_IS_TMP |
+ (engine_changed ? NO_HA_TABLE | NO_PAR_TABLE : 0)))
+ {
+ // Rename to temporary name failed, delete the new table, abort ALTER.
+ (void) quick_rm_table(thd, new_db_type, &alter_ctx.new_db,
+ &alter_ctx.tmp_name, FN_IS_TMP);
+ goto err_with_mdl;
+ }
+ }
+ else
{
- // Rename to temporary name failed, delete the new table, abort ALTER.
- (void) quick_rm_table(thd, new_db_type, &alter_ctx.new_db,
- &alter_ctx.tmp_name, FN_IS_TMP);
- goto err_with_mdl;
+ /* The original table is the backup */
+ backup_name= alter_ctx.table_name;
}
// Rename the new table to the correct name.
@@ -10343,10 +10470,15 @@ do_continue:;
(void) quick_rm_table(thd, new_db_type, &alter_ctx.new_db,
&alter_ctx.tmp_name, FN_IS_TMP);
- // Restore the backup of the original table to the old name.
- (void) mysql_rename_table(old_db_type, &alter_ctx.db, &backup_name,
- &alter_ctx.db, &alter_ctx.alias,
- FN_FROM_IS_TMP | NO_FK_CHECKS);
+ if (!alter_ctx.is_table_renamed())
+ {
+ // Restore the backup of the original table to the old name.
+ (void) mysql_rename_table(old_db_type, &alter_ctx.db, &backup_name,
+ &alter_ctx.db, &alter_ctx.alias,
+ FN_FROM_IS_TMP | NO_FK_CHECKS |
+ (engine_changed ? NO_HA_TABLE | NO_PAR_TABLE :
+ 0));
+ }
goto err_with_mdl;
}
@@ -10366,7 +10498,9 @@ do_continue:;
// Restore the backup of the original table to the old name.
(void) mysql_rename_table(old_db_type, &alter_ctx.db, &backup_name,
&alter_ctx.db, &alter_ctx.alias,
- FN_FROM_IS_TMP | NO_FK_CHECKS);
+ FN_FROM_IS_TMP | NO_FK_CHECKS |
+ (engine_changed ? NO_HA_TABLE | NO_PAR_TABLE :
+ 0));
goto err_with_mdl;
}
rename_table_in_stat_tables(thd, &alter_ctx.db, &alter_ctx.alias,
@@ -10374,7 +10508,19 @@ do_continue:;
}
// ALTER TABLE succeeded, delete the backup of the old table.
- if (quick_rm_table(thd, old_db_type, &alter_ctx.db, &backup_name, FN_IS_TMP))
+ error= quick_rm_table(thd, old_db_type, &alter_ctx.db, &backup_name,
+ FN_IS_TMP |
+ (engine_changed ? NO_HA_TABLE | NO_PAR_TABLE: 0));
+ if (engine_changed)
+ {
+ /* the .frm file was removed but not the original table */
+ error|= quick_rm_table(thd, old_db_type, &alter_ctx.db,
+ &alter_ctx.table_name,
+ NO_FRM_RENAME |
+ (engine_changed ? 0 : FN_IS_TMP));
+ }
+
+ if (error)
{
/*
The fact that deletion of the backup failed is not critical
@@ -10421,6 +10567,7 @@ end_temporary:
DBUG_RETURN(false);
err_new_table_cleanup:
+ DBUG_PRINT("error", ("err_new_table_cleanup"));
my_free(const_cast<uchar*>(frm.str));
/*
No default value was provided for a DATE/DATETIME field, the
@@ -10431,30 +10578,8 @@ err_new_table_cleanup:
if (unlikely(alter_ctx.error_if_not_empty &&
thd->get_stmt_da()->current_row_for_warning()))
{
- const char *f_val= "0000-00-00";
- const char *f_type= "date";
- switch (alter_ctx.datetime_field->real_field_type())
- {
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_NEWDATE:
- break;
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_DATETIME2:
- f_val= "0000-00-00 00:00:00";
- f_type= "datetime";
- break;
- default:
- /* Shouldn't get here. */
- DBUG_ASSERT(0);
- }
- bool save_abort_on_warning= thd->abort_on_warning;
- thd->abort_on_warning= true;
- thd->push_warning_truncated_value_for_field(Sql_condition::WARN_LEVEL_WARN,
- f_type, f_val,
- new_table->s,
- alter_ctx.datetime_field->
- field_name.str);
- thd->abort_on_warning= save_abort_on_warning;
+ Abort_on_warning_instant_set aws(thd, true);
+ alter_ctx.report_implicit_default_value_error(thd, new_table->s);
}
if (new_table)
@@ -10470,11 +10595,16 @@ err_new_table_cleanup:
DBUG_RETURN(true);
err_with_mdl_after_alter:
+ DBUG_PRINT("error", ("err_with_mdl_after_alter"));
/* the table was altered. binlog the operation */
DBUG_ASSERT(!(mysql_bin_log.is_open() &&
thd->is_current_stmt_binlog_format_row() &&
(create_info->tmp_table())));
- write_bin_log(thd, true, thd->query(), thd->query_length());
+ /*
+ We can't reset error as we will return 'true' below and the server
+ expects that error is set
+ */
+ write_bin_log(thd, FALSE, thd->query(), thd->query_length());
err_with_mdl:
/*
@@ -10606,6 +10736,8 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
to->file->extra(HA_EXTRA_PREPARE_FOR_ALTER_TABLE);
to->file->ha_start_bulk_insert(from->file->stats.records,
ignore ? 0 : HA_CREATE_UNIQUE_INDEX_BY_SORT);
+ mysql_stage_set_work_estimated(thd->m_stage_progress_psi, from->file->stats.records);
+
List_iterator<Create_field> it(create);
Create_field *def;
copy_end=copy;
@@ -10657,14 +10789,12 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
to->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
- bool save_abort_on_warning= thd->abort_on_warning;
- thd->abort_on_warning= false;
+ Abort_on_warning_instant_set aws(thd, false);
my_snprintf(warn_buff, sizeof(warn_buff),
"ORDER BY ignored as there is a user-defined clustered index"
" in the table '%-.192s'", from->s->table_name.str);
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
warn_buff);
- thd->abort_on_warning= save_abort_on_warning;
}
else
{
@@ -10708,7 +10838,6 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
from->file->column_bitmaps_signal();
- THD_STAGE_INFO(thd, stage_copy_to_tmp_table);
/* Tell handler that we have values for all columns in the to table */
to->use_all_columns();
/* Add virtual columns to vcol_set to ensure they are updated */
@@ -10854,7 +10983,11 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
}
}
else
+ {
+ DEBUG_SYNC(thd, "copy_data_between_tables_before");
found_count++;
+ mysql_stage_set_work_completed(thd->m_stage_progress_psi, found_count);
+ }
thd->get_stmt_da()->inc_current_row_for_warning();
}
@@ -10947,6 +11080,7 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy)
bzero((char*) &create_info, sizeof(create_info));
create_info.row_type=ROW_TYPE_NOT_USED;
create_info.default_table_charset=default_charset_info;
+ create_info.alter_info= &alter_info;
/* Force alter table to recreate table */
alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
@@ -11226,6 +11360,13 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
goto end_with_restore_list;
}
+ /*
+ Since CREATE_INFO is not full without Alter_info, it is better to pass them
+ as a signle parameter. TODO: remove alter_info argument where create_info is
+ passed.
+ */
+ create_info.alter_info= &alter_info;
+
/* Check privileges */
if ((res= create_table_precheck(thd, select_tables, create_table)))
goto end_with_restore_list;
@@ -11444,7 +11585,8 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
(!thd->is_current_stmt_binlog_format_row() ||
!create_info.tmp_table()))
{
- WSREP_TO_ISOLATION_BEGIN(create_table->db.str, create_table->table_name.str, NULL);
+ WSREP_TO_ISOLATION_BEGIN_CREATE(create_table->db.str, create_table->table_name.str,
+ create_table, &create_info);
}
/* Regular CREATE TABLE */
res= mysql_create_table(thd, create_table, &create_info, &alter_info);
@@ -11458,7 +11600,7 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
ON then send session state notification in OK packet */
if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
{
- SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
+ thd->session_tracker.state_change.mark_as_changed(thd);
}
my_ok(thd);
}
diff --git a/sql/sql_table.h b/sql/sql_table.h
index 35bff0873ea..ae05fe05c5d 100644
--- a/sql/sql_table.h
+++ b/sql/sql_table.h
@@ -118,8 +118,6 @@ enum enum_explain_filename_mode
EXPLAIN_PARTITIONS_AS_COMMENT
};
-/* Maximum length of GEOM_POINT Field */
-#define MAX_LEN_GEOM_POINT_FIELD 25
/* depends on errmsg.txt Database `db`, Table `t` ... */
#define EXPLAIN_FILENAME_MAX_EXTRA_LENGTH 63
@@ -140,6 +138,8 @@ static const uint NO_HA_TABLE= 1 << 4;
static const uint SKIP_SYMDIR_ACCESS= 1 << 5;
/** Don't check foreign key constraints while renaming table */
static const uint NO_FK_CHECKS= 1 << 6;
+/* Don't delete .par table in quick_rm_table() */
+static const uint NO_PAR_TABLE= 1 << 7;
uint filename_to_tablename(const char *from, char *to, size_t to_length,
bool stay_quiet = false);
diff --git a/sql/sql_tablespace.cc b/sql/sql_tablespace.cc
index d912fabe8c8..bfbaf185243 100644
--- a/sql/sql_tablespace.cc
+++ b/sql/sql_tablespace.cc
@@ -32,7 +32,7 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info)
If the user haven't defined an engine, this will fallback to using the
default storage engine.
*/
- if (hton == NULL || hton->state != SHOW_OPTION_YES)
+ if (hton == NULL)
{
hton= ha_default_handlerton(thd);
if (ts_info->storage_engine != 0)
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index a3506687a72..e353c2a6b46 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -88,9 +88,8 @@ static my_bool print_cached_tables_callback(TDC_element *element,
while ((entry= it++))
{
THD *in_use= entry->in_use;
- printf("%-14.14s %-32s%6lu%8ld%6d %s\n",
+ printf("%-14.14s %-32s%8ld%6d %s\n",
entry->s->db.str, entry->s->table_name.str,
- (ulong) element->version,
in_use ? (long) in_use->thread_id : (long) 0,
entry->db_stat ? 1 : 0,
in_use ? lock_descriptions[(int)entry->reginfo.lock_type] :
@@ -110,8 +109,6 @@ static void print_cached_tables(void)
tdc_iterate(0, (my_hash_walk_action) print_cached_tables_callback, NULL, true);
- printf("\nCurrent refresh version: %ld\n",
- (long) tdc_refresh_version());
fflush(stdout);
/* purecov: end */
return;
@@ -469,7 +466,8 @@ static void display_table_locks(void)
void *saved_base;
DYNAMIC_ARRAY saved_table_locks;
- (void) my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO),
+ (void) my_init_dynamic_array(key_memory_locked_thread_list,
+ &saved_table_locks, sizeof(TABLE_LOCK_INFO),
tc_records() + 20, 50, MYF(0));
mysql_mutex_lock(&THR_LOCK_lock);
for (list= thr_lock_thread_list; list; list= list_rest(list))
diff --git a/sql/sql_time.cc b/sql/sql_time.cc
index 9584dfd5f63..c08e54bed87 100644
--- a/sql/sql_time.cc
+++ b/sql/sql_time.cc
@@ -338,9 +338,9 @@ to_ascii(CHARSET_INFO *cs,
const char *srcend= src + src_length;
char *dst0= dst, *dstend= dst + dst_length - 1;
while (dst < dstend &&
- (cnvres= (cs->cset->mb_wc)(cs, &wc,
- (const uchar*) src,
- (const uchar*) srcend)) > 0 &&
+ (cnvres= cs->mb_wc(&wc,
+ (const uchar*) src,
+ (const uchar*) srcend)) > 0 &&
wc < 128)
{
src+= cnvres;
@@ -734,9 +734,7 @@ bool parse_date_time_format(timestamp_type format_type,
this. If separators are used, they must be between each part
*/
if (format_length == 6 && !need_p &&
- !my_strnncoll(&my_charset_bin,
- (const uchar *) format, 6,
- (const uchar *) format_str, 6))
+ !my_charset_bin.strnncoll(format, 6, format_str, 6))
return 0;
if (separator_map == (1 | 2))
{
@@ -757,9 +755,9 @@ bool parse_date_time_format(timestamp_type format_type,
Between DATE and TIME we also allow space as separator
*/
if ((format_length == 12 && !need_p &&
- !my_strnncoll(&my_charset_bin,
- (const uchar *) format, 12,
- (const uchar*) known_date_time_formats[INTERNAL_FORMAT].datetime_format,
+ !my_charset_bin.strnncoll(
+ format, 12,
+ known_date_time_formats[INTERNAL_FORMAT].datetime_format,
12)) ||
(separators == 5 && separator_map == (1 | 2 | 8 | 16)))
return 0;
@@ -832,7 +830,8 @@ DATE_TIME_FORMAT *date_time_format_copy(THD *thd, DATE_TIME_FORMAT *format)
if (thd)
new_format= (DATE_TIME_FORMAT *) thd->alloc(length);
else
- new_format= (DATE_TIME_FORMAT *) my_malloc(length, MYF(MY_WME));
+ new_format= (DATE_TIME_FORMAT *) my_malloc(key_memory_DATE_TIME_FORMAT,
+ length, MYF(MY_WME));
if (new_format)
{
/* Put format string after current pos */
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 5802d2c811e..5b8ae46d33f 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -30,11 +30,11 @@
#include "sql_table.h" // build_table_filename,
// check_n_cut_mysql50_prefix
#include "sql_db.h" // get_default_db_collation
-#include "sql_acl.h" // *_ACL
#include "sql_handler.h" // mysql_ha_rm_tables
#include "sp_cache.h" // sp_invalidate_cache
#include <mysys_err.h>
#include "debug_sync.h"
+#include "mysql/psi/mysql_sp.h"
/*************************************************************************/
@@ -440,7 +440,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
*/
if (!trust_function_creators &&
(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) &&
- !(thd->security_ctx->master_access & SUPER_ACL))
+ !(thd->security_ctx->master_access & PRIV_LOG_BIN_TRUSTED_SP_CREATOR))
{
my_error(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, MYF(0));
DBUG_RETURN(TRUE);
@@ -463,7 +463,8 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
*/
thd->lex->sql_command= backup.sql_command;
- if (opt_readonly && !(thd->security_ctx->master_access & SUPER_ACL) &&
+ if (opt_readonly &&
+ !(thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY) &&
!thd->slave_thread)
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
@@ -507,9 +508,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
goto end;
}
-#ifdef WITH_WSREP
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, tables);
-#endif
/* We should have only one table in table list. */
DBUG_ASSERT(tables->next_global == 0);
@@ -550,6 +549,12 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
}
table= tables->table;
+#ifdef WITH_WSREP
+ if (WSREP(thd) &&
+ !wsrep_should_replicate_ddl(thd, table->s->db_type()->db_type))
+ goto wsrep_error_label;
+#endif
+
/* Later on we will need it to downgrade the lock */
mdl_ticket= table->mdl_ticket;
@@ -620,7 +625,13 @@ end:
thd->lex->restore_backup_query_tables_list(&backup);
if (!result)
+ {
my_ok(thd);
+ /* Drop statistics for this stored program from performance schema. */
+ MYSQL_DROP_SP(SP_TYPE_TRIGGER,
+ thd->lex->spname->m_db.str, static_cast<uint>(thd->lex->spname->m_db.length),
+ thd->lex->spname->m_name.str, static_cast<uint>(thd->lex->spname->m_name.length));
+ }
DBUG_RETURN(result);
#ifdef WITH_WSREP
@@ -1550,6 +1561,10 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *db,
trigger->definer= *trg_definer;
}
+ sp->m_sp_share= MYSQL_GET_SP_SHARE(SP_TYPE_TRIGGER,
+ sp->m_db.str, static_cast<uint>(sp->m_db.length),
+ sp->m_name.str, static_cast<uint>(sp->m_name.length));
+
#ifndef DBUG_OFF
/*
Let us check that we correctly update trigger definitions when we
@@ -1809,8 +1824,8 @@ bool Table_triggers_list::drop_all_triggers(THD *thd, const LEX_CSTRING *db,
DBUG_ENTER("Triggers::drop_all_triggers");
table.reset();
- init_sql_alloc(&table.mem_root, "Triggers::drop_all_triggers", 8192, 0,
- MYF(0));
+ init_sql_alloc(key_memory_Table_trigger_dispatcher,
+ &table.mem_root, 8192, 0, MYF(0));
if (Table_triggers_list::check_n_load(thd, db, name, &table, 1))
{
@@ -1842,6 +1857,9 @@ bool Table_triggers_list::drop_all_triggers(THD *thd, const LEX_CSTRING *db,
*/
result= 1;
}
+ /* Drop statistics for this stored program from performance schema. */
+ MYSQL_DROP_SP(SP_TYPE_TRIGGER, db->str, static_cast<uint>(db->length),
+ trigger->name.str, static_cast<uint>(trigger->name.length));
}
}
}
@@ -2061,8 +2079,8 @@ bool Table_triggers_list::change_table_name(THD *thd, const LEX_CSTRING *db,
DBUG_ENTER("Triggers::change_table_name");
table.reset();
- init_sql_alloc(&table.mem_root, "Triggers::change_table_name", 8192, 0,
- MYF(0));
+ init_sql_alloc(key_memory_Table_trigger_dispatcher,
+ &table.mem_root, 8192, 0, MYF(0));
/*
This method interfaces the mysql server code protected by
diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc
index bfcdda6e0e9..a47822e43ca 100644
--- a/sql/sql_truncate.cc
+++ b/sql/sql_truncate.cc
@@ -303,6 +303,12 @@ bool Sql_cmd_truncate_table::lock_table(THD *thd, TABLE_LIST *table_ref,
versioned= table->versioned();
hton= table->file->ht;
+#ifdef WITH_WSREP
+ if (WSREP(thd) &&
+ !wsrep_should_replicate_ddl(thd, hton->db_type))
+ DBUG_RETURN(TRUE);
+#endif
+
table_ref->mdl_request.ticket= table->mdl_ticket;
}
else
@@ -320,6 +326,15 @@ bool Sql_cmd_truncate_table::lock_table(THD *thd, TABLE_LIST *table_ref,
versioned= share->versioned;
sequence= share->table_type == TABLE_TYPE_SEQUENCE;
hton= share->db_type();
+#ifdef WITH_WSREP
+ if (WSREP(thd) &&
+ hton != view_pseudo_hton &&
+ !wsrep_should_replicate_ddl(thd, hton->db_type))
+ {
+ tdc_release_share(share);
+ DBUG_RETURN(TRUE);
+ }
+#endif
tdc_release_share(share);
@@ -361,7 +376,7 @@ bool Sql_cmd_truncate_table::lock_table(THD *thd, TABLE_LIST *table_ref,
{
/* Table is already locked exclusively. Remove cached instances. */
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table_ref->db.str,
- table_ref->table_name.str, FALSE);
+ table_ref->table_name.str);
}
DBUG_RETURN(FALSE);
@@ -417,9 +432,10 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
#ifdef WITH_WSREP
if (WSREP(thd) &&
- wsrep_to_isolation_begin(thd, table_ref->db.str, table_ref->table_name.str, 0))
- DBUG_RETURN(TRUE);
+ wsrep_to_isolation_begin(thd, table_ref->db.str, table_ref->table_name.str, NULL))
+ DBUG_RETURN(TRUE);
#endif /* WITH_WSREP */
+
if (lock_table(thd, table_ref, &hton_can_recreate))
DBUG_RETURN(TRUE);
diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc
index 5265d254a05..678dd81709e 100644
--- a/sql/sql_tvc.cc
+++ b/sql/sql_tvc.cc
@@ -386,9 +386,10 @@ bool table_value_constr::exec(SELECT_LEX *sl)
while ((elem= li++))
{
- if (send_records >= sl->master_unit()->select_limit_cnt)
+ if (send_records >= sl->master_unit()->lim.get_select_limit())
break;
- int rc= result->send_data(*elem);
+ int rc=
+ result->send_data_with_check(*elem, sl->master_unit(), send_records);
if (!rc)
send_records++;
else if (rc > 0)
@@ -647,7 +648,7 @@ st_select_lex *wrap_tvc(THD *thd, st_select_lex *tvc_sl,
wrapper_sl->set_linkage(tvc_sl->get_linkage());
wrapper_sl->parsing_place= SELECT_LIST;
item= new (thd->mem_root) Item_field(thd, &wrapper_sl->context,
- NULL, NULL, &star_clex_str);
+ star_clex_str);
if (item == NULL || add_item_to_list(thd, item))
goto err;
(wrapper_sl->with_wild)++;
@@ -751,6 +752,7 @@ st_select_lex *wrap_tvc_with_tail(THD *thd, st_select_lex *tvc_sl)
{
wrapper_sl->master_unit()->union_distinct= wrapper_sl;
}
+ wrapper_sl->distinct= tvc_sl->distinct;
thd->lex->current_select= wrapper_sl;
return wrapper_sl;
}
@@ -905,7 +907,7 @@ Item *Item_func_in::in_predicate_to_in_subs_transformer(THD *thd,
sq_select= lex->current_select;
sq_select->parsing_place= SELECT_LIST;
item= new (thd->mem_root) Item_field(thd, &sq_select->context,
- NULL, NULL, &star_clex_str);
+ star_clex_str);
if (item == NULL || add_item_to_list(thd, item))
goto err;
(sq_select->with_wild)++;
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index f1f6ecfb046..cbf620e85d1 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2015,2019 MariaDB
+ Copyright (c) 2015,2020 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
@@ -16,118 +16,230 @@
#include "mariadb.h"
#include "sql_type.h"
+#include "sql_type_geom.h"
#include "sql_const.h"
#include "sql_class.h"
#include "sql_time.h"
#include "item.h"
#include "log.h"
#include "tztime.h"
-
-Type_handler_row type_handler_row;
-
-Type_handler_null type_handler_null;
-
-Type_handler_bool type_handler_bool;
-Type_handler_tiny type_handler_tiny;
-Type_handler_short type_handler_short;
-Type_handler_long type_handler_long;
-Type_handler_int24 type_handler_int24;
-Type_handler_longlong type_handler_longlong;
-Type_handler_longlong type_handler_ulonglong; // Only used for CAST() for now
-Type_handler_vers_trx_id type_handler_vers_trx_id;
-Type_handler_float type_handler_float;
-Type_handler_double type_handler_double;
-Type_handler_bit type_handler_bit;
-
-Type_handler_olddecimal type_handler_olddecimal;
-Type_handler_newdecimal type_handler_newdecimal;
-
-Type_handler_year type_handler_year;
-Type_handler_year type_handler_year2;
-Type_handler_time type_handler_time;
-Type_handler_date type_handler_date;
-Type_handler_timestamp type_handler_timestamp;
-Type_handler_timestamp2 type_handler_timestamp2;
-Type_handler_datetime type_handler_datetime;
-Type_handler_time2 type_handler_time2;
-Type_handler_newdate type_handler_newdate;
-Type_handler_datetime2 type_handler_datetime2;
-
-Type_handler_enum type_handler_enum;
-Type_handler_set type_handler_set;
-
-Type_handler_string type_handler_string;
-Type_handler_var_string type_handler_var_string;
-Type_handler_varchar type_handler_varchar;
-Type_handler_hex_hybrid type_handler_hex_hybrid;
-static Type_handler_varchar_compressed type_handler_varchar_compressed;
-
-Type_handler_tiny_blob type_handler_tiny_blob;
-Type_handler_medium_blob type_handler_medium_blob;
-Type_handler_long_blob type_handler_long_blob;
-Type_handler_blob type_handler_blob;
-static Type_handler_blob_compressed type_handler_blob_compressed;
+#include <mysql/plugin_data_type.h>
+
+
+const DTCollation &DTCollation_numeric::singleton()
+{
+ static const DTCollation_numeric tmp;
+ return tmp;
+}
+
+Named_type_handler<Type_handler_row> type_handler_row("row");
+
+Named_type_handler<Type_handler_null> type_handler_null("null");
+
+Named_type_handler<Type_handler_bool> type_handler_bool("boolean");
+Named_type_handler<Type_handler_tiny> type_handler_stiny("tinyint");
+Named_type_handler<Type_handler_short> type_handler_sshort("smallint");
+Named_type_handler<Type_handler_long> type_handler_slong("int");
+Named_type_handler<Type_handler_int24> type_handler_sint24("mediumint");
+Named_type_handler<Type_handler_longlong> type_handler_slonglong("bigint");
+Named_type_handler<Type_handler_utiny> type_handler_utiny("tiny unsigned");
+Named_type_handler<Type_handler_ushort> type_handler_ushort("smallint unsigned");
+Named_type_handler<Type_handler_ulong> type_handler_ulong("int unsigned");
+Named_type_handler<Type_handler_uint24> type_handler_uint24("mediumint unsigned");
+Named_type_handler<Type_handler_ulonglong> type_handler_ulonglong("bigint unsigned");
+Named_type_handler<Type_handler_vers_trx_id> type_handler_vers_trx_id("bigint unsigned");
+Named_type_handler<Type_handler_float> type_handler_float("float");
+Named_type_handler<Type_handler_double> type_handler_double("double");
+Named_type_handler<Type_handler_bit> type_handler_bit("bit");
+
+Named_type_handler<Type_handler_olddecimal> type_handler_olddecimal("decimal");
+Named_type_handler<Type_handler_newdecimal> type_handler_newdecimal("decimal");
+
+Named_type_handler<Type_handler_year> type_handler_year("year");
+Named_type_handler<Type_handler_year> type_handler_year2("year");
+Named_type_handler<Type_handler_time> type_handler_time("time");
+Named_type_handler<Type_handler_date> type_handler_date("date");
+Named_type_handler<Type_handler_timestamp> type_handler_timestamp("timestamp");
+Named_type_handler<Type_handler_timestamp2> type_handler_timestamp2("timestamp");
+Named_type_handler<Type_handler_datetime> type_handler_datetime("datetime");
+Named_type_handler<Type_handler_time2> type_handler_time2("time");
+Named_type_handler<Type_handler_newdate> type_handler_newdate("date");
+Named_type_handler<Type_handler_datetime2> type_handler_datetime2("datetime");
+
+Named_type_handler<Type_handler_enum> type_handler_enum("enum");
+Named_type_handler<Type_handler_set> type_handler_set("set");
+
+Named_type_handler<Type_handler_string> type_handler_string("char");
+Named_type_handler<Type_handler_var_string> type_handler_var_string("varchar");
+Named_type_handler<Type_handler_varchar> type_handler_varchar("varchar");
+Named_type_handler<Type_handler_hex_hybrid> type_handler_hex_hybrid("hex_hybrid");
+Named_type_handler<Type_handler_varchar_compressed> type_handler_varchar_compressed("varchar");
+
+Named_type_handler<Type_handler_tiny_blob> type_handler_tiny_blob("tinyblob");
+Named_type_handler<Type_handler_medium_blob> type_handler_medium_blob("mediumblob");
+Named_type_handler<Type_handler_long_blob> type_handler_long_blob("longblob");
+Named_type_handler<Type_handler_blob> type_handler_blob("blob");
+Named_type_handler<Type_handler_blob_compressed> type_handler_blob_compressed("blob");
Type_handler_interval_DDhhmmssff type_handler_interval_DDhhmmssff;
+Vers_type_timestamp vers_type_timestamp;
+Vers_type_trx vers_type_trx;
+
+/***************************************************************************/
+
+
+
+class Type_collection_std: public Type_collection
+{
+public:
+ const Type_handler *handler_by_name(const LEX_CSTRING &name) const override
+ {
+ return NULL;
+ }
+ const Type_handler *aggregate_for_result(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return Type_handler::aggregate_for_result_traditional(a, b);
+ }
+ const Type_handler *aggregate_for_comparison(const Type_handler *a,
+ const Type_handler *b)
+ const override;
+ const Type_handler *aggregate_for_min_max(const Type_handler *a,
+ const Type_handler *b)
+ const override;
+ const Type_handler *aggregate_for_num_op(const Type_handler *a,
+ const Type_handler *b)
+ const override;
+};
+
+
+static Type_collection_std type_collection_std;
+
+const Type_collection *Type_handler::type_collection() const
+{
+ return &type_collection_std;
+}
+
+
+bool Type_handler::is_traditional_scalar_type() const
+{
+ return type_collection() == &type_collection_std;
+}
+
+
+class Type_collection_row: public Type_collection
+{
+public:
+ bool init(Type_handler_data *data) override
+ {
+ return false;
+ }
+ const Type_handler *handler_by_name(const LEX_CSTRING &name) const override
+ {
+ return NULL;
+ }
+ const Type_handler *aggregate_for_result(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return NULL;
+ }
+ const Type_handler *aggregate_for_comparison(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ DBUG_ASSERT(a == &type_handler_row);
+ DBUG_ASSERT(b == &type_handler_row);
+ return &type_handler_row;
+ }
+ const Type_handler *aggregate_for_min_max(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return NULL;
+ }
+ const Type_handler *aggregate_for_num_op(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return NULL;
+ }
+};
+
+
+static Type_collection_row type_collection_row;
+
+const Type_collection *Type_handler_row::type_collection() const
+{
+ return &type_collection_row;
+}
+
+
+bool Type_handler_data::init()
+{
#ifdef HAVE_SPATIAL
-Type_handler_geometry type_handler_geometry;
+ return type_collection_geometry.init(this);
#endif
+ return false;
+}
-bool Type_handler_data::init()
+const Type_handler *
+Type_handler::handler_by_name(THD *thd, const LEX_CSTRING &name)
{
+ plugin_ref plugin;
+ if ((plugin= my_plugin_lock_by_name(thd, &name, MariaDB_DATA_TYPE_PLUGIN)))
+ {
+ /*
+ Data type plugins do not maintain ref_count yet.
+ For now we have only mandatory built-in plugins
+ and dynamic plugins for test purposes.
+ It should be safe to unlock the plugin immediately.
+ */
+ const Type_handler *ph= reinterpret_cast<st_mariadb_data_type*>
+ (plugin_decl(plugin)->info)->type_handler;
+ plugin_unlock(thd, plugin);
+ return ph;
+ }
+
#ifdef HAVE_SPATIAL
+ const Type_handler *ha= type_collection_geometry.handler_by_name(name);
+ if (ha)
+ return ha;
+#endif
+ return NULL;
+}
+
#ifndef DBUG_OFF
- if (m_type_aggregator_non_commutative_test.add(&type_handler_geometry,
- &type_handler_geometry,
- &type_handler_geometry) ||
- m_type_aggregator_non_commutative_test.add(&type_handler_geometry,
- &type_handler_varchar,
- &type_handler_long_blob))
- return true;
+static const Type_handler *frm_data_type_info_emulate(const LEX_CSTRING &name)
+{
+ if (Name(STRING_WITH_LEN("xchar")).eq(name))
+ return &type_handler_string;
+ if (Name(STRING_WITH_LEN("xblob")).eq(name))
+ return &type_handler_blob;
+ return NULL;
+}
#endif
- return
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_null,
- &type_handler_geometry) ||
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_geometry,
- &type_handler_geometry) ||
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_hex_hybrid,
- &type_handler_long_blob) ||
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_tiny_blob,
- &type_handler_long_blob) ||
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_blob,
- &type_handler_long_blob) ||
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_medium_blob,
- &type_handler_long_blob) ||
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_long_blob,
- &type_handler_long_blob) ||
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_varchar,
- &type_handler_long_blob) ||
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_string,
- &type_handler_long_blob) ||
- m_type_aggregator_for_comparison.add(&type_handler_geometry,
- &type_handler_geometry,
- &type_handler_geometry) ||
- m_type_aggregator_for_comparison.add(&type_handler_geometry,
- &type_handler_null,
- &type_handler_geometry) ||
- m_type_aggregator_for_comparison.add(&type_handler_geometry,
- &type_handler_long_blob,
- &type_handler_long_blob);
-#endif
- return false;
+
+const Type_handler *
+Type_handler::handler_by_name_or_error(THD *thd, const LEX_CSTRING &name)
+{
+ const Type_handler *h= handler_by_name(thd, name);
+ DBUG_EXECUTE_IF("emulate_handler_by_name_or_error_failure", h= NULL;);
+ if (!h)
+ {
+ DBUG_EXECUTE_IF("frm_data_type_info_emulate",
+ if ((h= frm_data_type_info_emulate(name)))
+ return h;
+ );
+ my_error(ER_UNKNOWN_DATA_TYPE, MYF(0),
+ ErrConvString(name.str, name.length, system_charset_info).ptr());
+ }
+ return h;
}
@@ -1017,7 +1129,7 @@ Datetime_truncation_not_needed::Datetime_truncation_not_needed(THD *thd, Item *i
/********************************************************************/
-uint Type_std_attributes::count_max_decimals(Item **item, uint nitems)
+uint Type_numeric_attributes::find_max_decimals(Item **item, uint nitems)
{
uint res= 0;
for (uint i= 0; i < nitems; i++)
@@ -1026,55 +1138,61 @@ uint Type_std_attributes::count_max_decimals(Item **item, uint nitems)
}
-/**
- Set max_length/decimals of function if function is fixed point and
- result length/precision depends on argument ones.
-*/
-
-void Type_std_attributes::count_decimal_length(Item **item, uint nitems)
+uint Type_numeric_attributes::count_unsigned(Item **item, uint nitems)
{
- int max_int_part= 0;
- decimals= 0;
- unsigned_flag= 1;
- for (uint i=0 ; i < nitems ; i++)
+ uint res= 0;
+ for (uint i= 0 ; i < nitems ; i++)
{
- set_if_bigger(decimals, item[i]->decimals);
- set_if_bigger(max_int_part, item[i]->decimal_int_part());
- set_if_smaller(unsigned_flag, item[i]->unsigned_flag);
+ if (item[i]->unsigned_flag)
+ res++;
}
- int precision= MY_MIN(max_int_part + decimals, DECIMAL_MAX_PRECISION);
- fix_char_length(my_decimal_precision_to_length_no_truncation(precision,
- (uint8) decimals,
- unsigned_flag));
+ return res;
}
-/**
- Set max_length of if it is maximum length of its arguments.
-*/
-
-void Type_std_attributes::count_only_length(Item **item, uint nitems)
+uint32 Type_numeric_attributes::find_max_char_length(Item **item, uint nitems)
{
uint32 char_length= 0;
- unsigned_flag= 0;
for (uint i= 0; i < nitems ; i++)
- {
set_if_bigger(char_length, item[i]->max_char_length());
- set_if_bigger(unsigned_flag, item[i]->unsigned_flag);
- }
- fix_char_length(char_length);
+ return char_length;
}
-void Type_std_attributes::count_octet_length(Item **item, uint nitems)
+uint32 Type_numeric_attributes::find_max_octet_length(Item **item, uint nitems)
{
- max_length= 0;
- unsigned_flag= 0;
+ uint32 octet_length= 0;
for (uint i= 0; i < nitems ; i++)
- {
- set_if_bigger(max_length, item[i]->max_length);
- set_if_bigger(unsigned_flag, item[i]->unsigned_flag);
- }
+ set_if_bigger(octet_length, item[i]->max_length);
+ return octet_length;
+}
+
+
+int Type_numeric_attributes::find_max_decimal_int_part(Item **item, uint nitems)
+{
+ int max_int_part= 0;
+ for (uint i=0 ; i < nitems ; i++)
+ set_if_bigger(max_int_part, item[i]->decimal_int_part());
+ return max_int_part;
+}
+
+
+/**
+ Set max_length/decimals of function if function is fixed point and
+ result length/precision depends on argument ones.
+*/
+
+void
+Type_numeric_attributes::aggregate_numeric_attributes_decimal(Item **item,
+ uint nitems,
+ bool unsigned_arg)
+{
+ int max_int_part= find_max_decimal_int_part(item, nitems);
+ decimals= find_max_decimals(item, nitems);
+ int precision= MY_MIN(max_int_part + decimals, DECIMAL_MAX_PRECISION);
+ max_length= my_decimal_precision_to_length_no_truncation(precision,
+ (uint8) decimals,
+ unsigned_flag);
}
@@ -1083,7 +1201,9 @@ void Type_std_attributes::count_octet_length(Item **item, uint nitems)
result length/precision depends on argument ones.
*/
-void Type_std_attributes::count_real_length(Item **items, uint nitems)
+void
+Type_numeric_attributes::aggregate_numeric_attributes_real(Item **items,
+ uint nitems)
{
uint32 length= 0;
decimals= 0;
@@ -1122,16 +1242,17 @@ void Type_std_attributes::count_real_length(Item **items, uint nitems)
@retval False on success, true on error.
*/
-bool Type_std_attributes::count_string_length(const char *func_name,
- Item **items, uint nitems)
+bool Type_std_attributes::aggregate_attributes_string(const char *func_name,
+ Item **items, uint nitems)
{
if (agg_arg_charsets_for_string_result(collation, func_name,
items, nitems, 1))
return true;
if (collation.collation == &my_charset_bin)
- count_octet_length(items, nitems);
+ max_length= find_max_octet_length(items, nitems);
else
- count_only_length(items, nitems);
+ fix_char_length(find_max_char_length(items, nitems));
+ unsigned_flag= false;
decimals= max_length ? NOT_FIXED_DEC : 0;
return false;
}
@@ -1278,7 +1399,7 @@ Type_handler::get_handler_by_cmp_type(Item_result type)
{
switch (type) {
case REAL_RESULT: return &type_handler_double;
- case INT_RESULT: return &type_handler_longlong;
+ case INT_RESULT: return &type_handler_slonglong;
case DECIMAL_RESULT: return &type_handler_newdecimal;
case STRING_RESULT: return &type_handler_long_blob;
case TIME_RESULT: return &type_handler_datetime;
@@ -1289,6 +1410,37 @@ Type_handler::get_handler_by_cmp_type(Item_result type)
}
+/*
+ If we have a mixture of:
+ - a MariaDB standard (built-in permanent) data type, and
+ - a non-standard (optionally compiled or pluggable) data type,
+ then we ask the type collection of the non-standard type to aggregate
+ the mixture.
+ The standard type collection type_collection_std knows nothing
+ about non-standard types, while non-standard type collections
+ know everything about standard data types.
+*/
+const Type_collection *
+Type_handler::type_collection_for_aggregation(const Type_handler *h0,
+ const Type_handler *h1)
+{
+ const Type_collection *c0= h0->type_collection();
+ const Type_collection *c1= h1->type_collection();
+ if (c0 == c1)
+ return c0;
+ if (c0 == &type_collection_std)
+ return c1;
+ if (c1 == &type_collection_std)
+ return c0;
+ /*
+ A mixture of two non-standard collections.
+ The caller code will continue to aggregate through
+ the type aggregators in Type_handler_data.
+ */
+ return NULL;
+}
+
+
Type_handler_hybrid_field_type::Type_handler_hybrid_field_type()
:m_type_handler(&type_handler_double)
{
@@ -1310,66 +1462,149 @@ uint Type_handler_time::m_hires_bytes[MAX_DATETIME_PRECISION + 1]=
{ 3, 4, 4, 5, 5, 5, 6 };
/***************************************************************************/
-const Name Type_handler_row::m_name_row(STRING_WITH_LEN("row"));
-
-const Name Type_handler_null::m_name_null(STRING_WITH_LEN("null"));
-
-const Name
- Type_handler_string::m_name_char(STRING_WITH_LEN("char")),
- Type_handler_var_string::m_name_var_string(STRING_WITH_LEN("varchar")),
- Type_handler_varchar::m_name_varchar(STRING_WITH_LEN("varchar")),
- Type_handler_hex_hybrid::m_name_hex_hybrid(STRING_WITH_LEN("hex_hybrid")),
- Type_handler_tiny_blob::m_name_tinyblob(STRING_WITH_LEN("tinyblob")),
- Type_handler_medium_blob::m_name_mediumblob(STRING_WITH_LEN("mediumblob")),
- Type_handler_long_blob::m_name_longblob(STRING_WITH_LEN("longblob")),
- Type_handler_blob::m_name_blob(STRING_WITH_LEN("blob"));
-
-const Name
- Type_handler_enum::m_name_enum(STRING_WITH_LEN("enum")),
- Type_handler_set::m_name_set(STRING_WITH_LEN("set"));
-
-const Name
- Type_handler_bool::m_name_bool(STRING_WITH_LEN("boolean")),
- Type_handler_tiny::m_name_tiny(STRING_WITH_LEN("tinyint")),
- Type_handler_short::m_name_short(STRING_WITH_LEN("smallint")),
- Type_handler_long::m_name_int(STRING_WITH_LEN("int")),
- Type_handler_longlong::m_name_longlong(STRING_WITH_LEN("bigint")),
- Type_handler_int24::m_name_mediumint(STRING_WITH_LEN("mediumint")),
- Type_handler_year::m_name_year(STRING_WITH_LEN("year")),
- Type_handler_bit::m_name_bit(STRING_WITH_LEN("bit"));
-
-const Name
- Type_handler_float::m_name_float(STRING_WITH_LEN("float")),
- Type_handler_double::m_name_double(STRING_WITH_LEN("double"));
-
-const Name
- Type_handler_olddecimal::m_name_decimal(STRING_WITH_LEN("decimal")),
- Type_handler_newdecimal::m_name_decimal(STRING_WITH_LEN("decimal"));
-
-const Name
- Type_handler_time_common::m_name_time(STRING_WITH_LEN("time")),
- Type_handler_date_common::m_name_date(STRING_WITH_LEN("date")),
- Type_handler_datetime_common::m_name_datetime(STRING_WITH_LEN("datetime")),
- Type_handler_timestamp_common::m_name_timestamp(STRING_WITH_LEN("timestamp"));
-
-const Name
- Type_handler::m_version_default(STRING_WITH_LEN("")),
- Type_handler::m_version_mariadb53(STRING_WITH_LEN("mariadb-5.3")),
- Type_handler::m_version_mysql56(STRING_WITH_LEN("mysql-5.6"));
-
-
-const Type_limits_int
- Type_handler_tiny::m_limits_sint8= Type_limits_sint8(),
- Type_handler_tiny::m_limits_uint8= Type_limits_uint8(),
- Type_handler_short::m_limits_sint16= Type_limits_sint16(),
- Type_handler_short::m_limits_uint16= Type_limits_uint16(),
- Type_handler_int24::m_limits_sint24= Type_limits_sint24(),
- Type_handler_int24::m_limits_uint24= Type_limits_uint24(),
- Type_handler_long::m_limits_sint32= Type_limits_sint32(),
- Type_handler_long::m_limits_uint32= Type_limits_uint32(),
- Type_handler_longlong::m_limits_sint64= Type_limits_sint64(),
- Type_handler_longlong::m_limits_uint64= Type_limits_uint64();
+const Name Type_handler::version() const
+{
+ static const Name ver(STRING_WITH_LEN(""));
+ return ver;
+}
+
+const Name & Type_handler::version_mariadb53()
+{
+ static const Name ver(STRING_WITH_LEN("mariadb-5.3"));
+ return ver;
+}
+
+const Name & Type_handler::version_mysql56()
+{
+ static const Name ver(STRING_WITH_LEN("mysql-5.6"));
+ return ver;
+}
+
+
+/***************************************************************************/
+
+const Type_limits_int *Type_handler_tiny::type_limits_int() const
+{
+ static const Type_limits_sint8 limits_sint8;
+ return &limits_sint8;
+}
+
+const Type_limits_int *Type_handler_utiny::type_limits_int() const
+{
+ static const Type_limits_uint8 limits_uint8;
+ return &limits_uint8;
+}
+
+const Type_limits_int *Type_handler_short::type_limits_int() const
+{
+ static const Type_limits_sint16 limits_sint16;
+ return &limits_sint16;
+}
+
+const Type_limits_int *Type_handler_ushort::type_limits_int() const
+{
+ static const Type_limits_uint16 limits_uint16;
+ return &limits_uint16;
+}
+
+const Type_limits_int *Type_handler_int24::type_limits_int() const
+{
+ static const Type_limits_sint24 limits_sint24;
+ return &limits_sint24;
+}
+
+const Type_limits_int *Type_handler_uint24::type_limits_int() const
+{
+ static const Type_limits_uint24 limits_uint24;
+ return &limits_uint24;
+}
+
+const Type_limits_int *Type_handler_long::type_limits_int() const
+{
+ static const Type_limits_sint32 limits_sint32;
+ return &limits_sint32;
+}
+
+const Type_limits_int *Type_handler_ulong::type_limits_int() const
+{
+ static const Type_limits_uint32 limits_uint32;
+ return &limits_uint32;
+}
+
+const Type_limits_int *Type_handler_longlong::type_limits_int() const
+{
+ static const Type_limits_sint64 limits_sint64;
+ return &limits_sint64;
+}
+
+const Type_limits_int *Type_handler_ulonglong::type_limits_int() const
+{
+ static const Type_limits_uint64 limits_uint64;
+ return &limits_uint64;
+}
+
+
+/***************************************************************************/
+const Type_handler *Type_handler_bool::type_handler_signed() const
+{
+ return &type_handler_bool;
+}
+
+const Type_handler *Type_handler_bool::type_handler_unsigned() const
+{
+ return &type_handler_bool;
+}
+
+const Type_handler *Type_handler_tiny::type_handler_signed() const
+{
+ return &type_handler_stiny;
+}
+
+const Type_handler *Type_handler_tiny::type_handler_unsigned() const
+{
+ return &type_handler_utiny;
+}
+
+const Type_handler *Type_handler_short::type_handler_signed() const
+{
+ return &type_handler_sshort;
+}
+
+const Type_handler *Type_handler_short::type_handler_unsigned() const
+{
+ return &type_handler_ushort;
+}
+
+const Type_handler *Type_handler_int24::type_handler_signed() const
+{
+ return &type_handler_sint24;
+}
+
+const Type_handler *Type_handler_int24::type_handler_unsigned() const
+{
+ return &type_handler_uint24;
+}
+
+const Type_handler *Type_handler_long::type_handler_signed() const
+{
+ return &type_handler_slong;
+}
+
+const Type_handler *Type_handler_long::type_handler_unsigned() const
+{
+ return &type_handler_ulong;
+}
+
+const Type_handler *Type_handler_longlong::type_handler_signed() const
+{
+ return &type_handler_slonglong;
+}
+
+const Type_handler *Type_handler_longlong::type_handler_unsigned() const
+{
+ return &type_handler_ulonglong;
+}
/***************************************************************************/
@@ -1381,7 +1616,7 @@ const Type_handler *Type_handler_null::type_handler_for_comparison() const
const Type_handler *Type_handler_int_result::type_handler_for_comparison() const
{
- return &type_handler_longlong;
+ return &type_handler_slonglong;
}
@@ -1450,7 +1685,7 @@ const Type_handler *Type_handler_typelib::type_handler_for_item_field() const
const Type_handler *Type_handler_typelib::cast_to_int_type_handler() const
{
- return &type_handler_longlong;
+ return &type_handler_slonglong;
}
@@ -1459,29 +1694,35 @@ const Type_handler *Type_handler_typelib::cast_to_int_type_handler() const
bool
Type_handler_hybrid_field_type::aggregate_for_result(const Type_handler *other)
{
- if (m_type_handler->is_traditional_type() && other->is_traditional_type())
- {
- m_type_handler=
- Type_handler::aggregate_for_result_traditional(m_type_handler, other);
- return false;
- }
- other= type_handler_data->
- m_type_aggregator_for_result.find_handler(m_type_handler, other);
- if (!other)
+ const Type_handler *hres;
+ const Type_collection *c;
+ if (!(c= Type_handler::type_collection_for_aggregation(m_type_handler, other)) ||
+ !(hres= c->aggregate_for_result(m_type_handler, other)))
+ hres= type_handler_data->
+ m_type_aggregator_for_result.find_handler(m_type_handler, other);
+ if (!hres)
return true;
- m_type_handler= other;
+ m_type_handler= hres;
return false;
}
const Type_handler *
-Type_handler::type_handler_long_or_longlong(uint max_char_length)
+Type_handler::type_handler_long_or_longlong(uint max_char_length,
+ bool unsigned_flag)
{
+ if (unsigned_flag)
+ {
+ if (max_char_length <= MY_INT32_NUM_DECIMAL_DIGITS - 2)
+ return &type_handler_ulong;
+ return &type_handler_ulonglong;
+ }
if (max_char_length <= MY_INT32_NUM_DECIMAL_DIGITS - 2)
- return &type_handler_long;
- return &type_handler_longlong;
+ return &type_handler_slong;
+ return &type_handler_slonglong;
}
+
/*
This method is called for CASE (and its abbreviations) and LEAST/GREATEST
when data type aggregation returned LONGLONG and there were some BIT
@@ -1492,8 +1733,8 @@ const Type_handler *
Type_handler::bit_and_int_mixture_handler(uint max_char_length)
{
if (max_char_length <= MY_INT32_NUM_DECIMAL_DIGITS)
- return &type_handler_long;
- return &type_handler_longlong;
+ return &type_handler_slong;
+ return &type_handler_slonglong;
}
@@ -1555,9 +1796,9 @@ Type_handler_hybrid_field_type::aggregate_for_result(const char *funcname,
{
bit_and_non_bit_mixture_found= true;
if (type_handler() == &type_handler_bit)
- set_handler(&type_handler_longlong); // BIT + non-BIT
+ set_handler(&type_handler_slonglong); // BIT + non-BIT
else
- cur= &type_handler_longlong; // non-BIT + BIT
+ cur= &type_handler_slonglong; // non-BIT + BIT
}
if (aggregate_for_result(cur))
{
@@ -1566,7 +1807,7 @@ Type_handler_hybrid_field_type::aggregate_for_result(const char *funcname,
return true;
}
}
- if (bit_and_non_bit_mixture_found && type_handler() == &type_handler_longlong)
+ if (bit_and_non_bit_mixture_found && type_handler() == &type_handler_slonglong)
set_handler(Type_handler::bit_and_int_mixture_handler(max_display_length));
return false;
}
@@ -1585,37 +1826,42 @@ Type_handler_hybrid_field_type::aggregate_for_comparison(const Type_handler *h)
{
DBUG_ASSERT(m_type_handler == m_type_handler->type_handler_for_comparison());
DBUG_ASSERT(h == h->type_handler_for_comparison());
+ const Type_handler *hres;
+ const Type_collection *c;
+ if (!(c= Type_handler::type_collection_for_aggregation(m_type_handler, h)) ||
+ !(hres= c->aggregate_for_comparison(m_type_handler, h)))
+ hres= type_handler_data->
+ m_type_aggregator_for_comparison.find_handler(m_type_handler, h);
+ if (!hres)
+ return true;
+ m_type_handler= hres;
+ DBUG_ASSERT(m_type_handler == m_type_handler->type_handler_for_comparison());
+ return false;
+}
- if (!m_type_handler->is_traditional_type() ||
- !h->is_traditional_type())
- {
- h= type_handler_data->
- m_type_aggregator_for_comparison.find_handler(m_type_handler, h);
- if (!h)
- return true;
- m_type_handler= h;
- DBUG_ASSERT(m_type_handler == m_type_handler->type_handler_for_comparison());
- return false;
- }
- Item_result a= cmp_type();
- Item_result b= h->cmp_type();
+const Type_handler *
+Type_collection_std::aggregate_for_comparison(const Type_handler *ha,
+ const Type_handler *hb) const
+{
+ Item_result a= ha->cmp_type();
+ Item_result b= hb->cmp_type();
if (a == STRING_RESULT && b == STRING_RESULT)
- m_type_handler= &type_handler_long_blob;
- else if (a == INT_RESULT && b == INT_RESULT)
- m_type_handler= &type_handler_longlong;
- else if (a == ROW_RESULT || b == ROW_RESULT)
- m_type_handler= &type_handler_row;
- else if (a == TIME_RESULT || b == TIME_RESULT)
+ return &type_handler_long_blob;
+ if (a == INT_RESULT && b == INT_RESULT)
+ return &type_handler_slonglong;
+ if (a == ROW_RESULT || b == ROW_RESULT)
+ return &type_handler_row;
+ if (a == TIME_RESULT || b == TIME_RESULT)
{
if ((a == TIME_RESULT) + (b == TIME_RESULT) == 1)
{
/*
We're here if there's only one temporal data type:
either m_type_handler or h.
+ Temporal types bit non-temporal types.
*/
- if (b == TIME_RESULT)
- m_type_handler= h; // Temporal types bit non-temporal types
+ const Type_handler *res= b == TIME_RESULT ? hb : ha;
/*
Compare TIMESTAMP to a non-temporal type as DATETIME.
This is needed to make queries with fuzzy dates work:
@@ -1623,9 +1869,9 @@ Type_handler_hybrid_field_type::aggregate_for_comparison(const Type_handler *h)
WHERE
ts BETWEEN '0000-00-00' AND '2010-00-01 00:00:00';
*/
- if (m_type_handler->type_handler_for_native_format() ==
- &type_handler_timestamp2)
- m_type_handler= &type_handler_datetime;
+ if (res->type_handler_for_native_format() == &type_handler_timestamp2)
+ return &type_handler_datetime;
+ return res;
}
else
{
@@ -1637,19 +1883,15 @@ Type_handler_hybrid_field_type::aggregate_for_comparison(const Type_handler *h)
to print DATE constants using proper format:
'YYYY-MM-DD' rather than 'YYYY-MM-DD 00:00:00'.
*/
- if (m_type_handler->field_type() != h->field_type())
- m_type_handler= &type_handler_datetime;
+ if (ha->field_type() != hb->field_type())
+ return &type_handler_datetime;
+ return ha;
}
}
- else if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
- (b == INT_RESULT || b == DECIMAL_RESULT))
- {
- m_type_handler= &type_handler_newdecimal;
- }
- else
- m_type_handler= &type_handler_double;
- DBUG_ASSERT(m_type_handler == m_type_handler->type_handler_for_comparison());
- return false;
+ if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
+ (b == INT_RESULT || b == DECIMAL_RESULT))
+ return &type_handler_newdecimal;
+ return &type_handler_double;
}
@@ -1665,12 +1907,12 @@ Type_handler_hybrid_field_type::aggregate_for_comparison(const Type_handler *h)
bool
Type_handler_hybrid_field_type::aggregate_for_min_max(const Type_handler *h)
{
- if (!m_type_handler->is_traditional_type() ||
- !h->is_traditional_type())
+ const Type_handler *hres;
+ const Type_collection *c;
+ if (!(c= Type_handler::type_collection_for_aggregation(m_type_handler, h))||
+ !(hres= c->aggregate_for_min_max(m_type_handler, h)))
{
/*
- If at least one data type is non-traditional,
- do aggregation for result immediately.
For now we suppose that these two expressions:
- LEAST(type1, type2)
- COALESCE(type1, type2)
@@ -1678,79 +1920,74 @@ Type_handler_hybrid_field_type::aggregate_for_min_max(const Type_handler *h)
if type1 and/or type2 are non-traditional.
This may change in the future.
*/
- h= type_handler_data->
- m_type_aggregator_for_result.find_handler(m_type_handler, h);
- if (!h)
- return true;
- m_type_handler= h;
- return false;
+ hres= type_handler_data->
+ m_type_aggregator_for_result.find_handler(m_type_handler, h);
}
+ if (!hres)
+ return true;
+ m_type_handler= hres;
+ return false;
+}
+
- Item_result a= cmp_type();
- Item_result b= h->cmp_type();
+const Type_handler *
+Type_collection_std::aggregate_for_min_max(const Type_handler *ha,
+ const Type_handler *hb) const
+{
+ Item_result a= ha->cmp_type();
+ Item_result b= hb->cmp_type();
DBUG_ASSERT(a != ROW_RESULT); // Disallowed by check_cols() in fix_fields()
DBUG_ASSERT(b != ROW_RESULT); // Disallowed by check_cols() in fix_fields()
if (a == STRING_RESULT && b == STRING_RESULT)
- m_type_handler=
- Type_handler::aggregate_for_result_traditional(m_type_handler, h);
- else if (a == INT_RESULT && b == INT_RESULT)
+ return Type_collection_std::aggregate_for_result(ha, hb);
+ if (a == INT_RESULT && b == INT_RESULT)
{
// BIT aggregates with non-BIT as BIGINT
- if (m_type_handler != h)
+ if (ha != hb)
{
- if (m_type_handler == &type_handler_bit)
- m_type_handler= &type_handler_longlong;
- else if (h == &type_handler_bit)
- h= &type_handler_longlong;
+ if (ha == &type_handler_bit)
+ ha= &type_handler_slonglong;
+ else if (hb == &type_handler_bit)
+ hb= &type_handler_slonglong;
}
- m_type_handler=
- Type_handler::aggregate_for_result_traditional(m_type_handler, h);
+ return Type_collection_std::aggregate_for_result(ha, hb);
}
- else if (a == TIME_RESULT || b == TIME_RESULT)
+ if (a == TIME_RESULT || b == TIME_RESULT)
{
- if ((m_type_handler->type_handler_for_native_format() ==
- &type_handler_timestamp2) +
- (h->type_handler_for_native_format() ==
- &type_handler_timestamp2) == 1)
+ if ((ha->type_handler_for_native_format() == &type_handler_timestamp2) +
+ (hb->type_handler_for_native_format() == &type_handler_timestamp2) == 1)
{
/*
Handle LEAST(TIMESTAMP, non-TIMESTAMP) as DATETIME,
to make sure fuzzy dates work in this context:
LEAST('2001-00-00', timestamp_field)
*/
- m_type_handler= &type_handler_datetime2;
+ return &type_handler_datetime2;
}
- else if ((a == TIME_RESULT) + (b == TIME_RESULT) == 1)
+ if ((a == TIME_RESULT) + (b == TIME_RESULT) == 1)
{
/*
We're here if there's only one temporal data type:
either m_type_handler or h.
+ Temporal types bit non-temporal types.
*/
- if (b == TIME_RESULT)
- m_type_handler= h; // Temporal types bit non-temporal types
+ return (b == TIME_RESULT) ? hb : ha;
}
- else
- {
- /*
- We're here if both m_type_handler and h are temporal data types.
- */
- m_type_handler=
- Type_handler::aggregate_for_result_traditional(m_type_handler, h);
- }
- }
- else if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
- (b == INT_RESULT || b == DECIMAL_RESULT))
- {
- m_type_handler= &type_handler_newdecimal;
+ /*
+ We're here if both m_type_handler and h are temporal data types.
+ */
+ return Type_collection_std::aggregate_for_result(ha, hb);
}
- else
+ if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
+ (b == INT_RESULT || b == DECIMAL_RESULT))
{
- // Preserve FLOAT if two FLOATs, set to DOUBLE otherwise.
- if (m_type_handler != &type_handler_float || h != &type_handler_float)
- m_type_handler= &type_handler_double;
+ return &type_handler_newdecimal;
}
- return false;
+ // Preserve FLOAT if two FLOATs, set to DOUBLE otherwise.
+ if (ha == &type_handler_float && hb == &type_handler_float)
+ return &type_handler_float;
+ return &type_handler_double;
}
@@ -1759,15 +1996,12 @@ Type_handler_hybrid_field_type::aggregate_for_min_max(const char *funcname,
Item **items, uint nitems)
{
bool bit_and_non_bit_mixture_found= false;
- uint32 max_display_length;
// LEAST/GREATEST require at least two arguments
DBUG_ASSERT(nitems > 1);
set_handler(items[0]->type_handler());
- max_display_length= items[0]->max_display_length();
for (uint i= 1; i < nitems; i++)
{
const Type_handler *cur= items[i]->type_handler();
- set_if_bigger(max_display_length, items[i]->max_display_length());
// Check if BIT + non-BIT, or non-BIT + BIT
bit_and_non_bit_mixture_found|= (m_type_handler == &type_handler_bit) !=
(cur == &type_handler_bit);
@@ -1778,15 +2012,20 @@ Type_handler_hybrid_field_type::aggregate_for_min_max(const char *funcname,
return true;
}
}
- if (bit_and_non_bit_mixture_found && type_handler() == &type_handler_longlong)
+ if (bit_and_non_bit_mixture_found && type_handler() == &type_handler_slonglong)
+ {
+ uint32 max_display_length= items[0]->max_display_length();
+ for (uint i= 1; i < nitems; i++)
+ set_if_bigger(max_display_length, items[i]->max_display_length());
set_handler(Type_handler::bit_and_int_mixture_handler(max_display_length));
+ }
return false;
}
const Type_handler *
-Type_handler::aggregate_for_num_op_traditional(const Type_handler *h0,
- const Type_handler *h1)
+Type_collection_std::aggregate_for_num_op(const Type_handler *h0,
+ const Type_handler *h1) const
{
Item_result r0= h0->cmp_type();
Item_result r1= h1->cmp_type();
@@ -1802,7 +2041,7 @@ Type_handler::aggregate_for_num_op_traditional(const Type_handler *h0,
return &type_handler_newdecimal;
DBUG_ASSERT(r0 == INT_RESULT && r1 == INT_RESULT);
- return &type_handler_longlong;
+ return &type_handler_slonglong;
}
@@ -1827,17 +2066,14 @@ Type_handler_hybrid_field_type::aggregate_for_num_op(const Type_aggregator *agg,
const Type_handler *h1)
{
const Type_handler *hres;
- if (h0->is_traditional_type() && h1->is_traditional_type())
- {
- set_handler(Type_handler::aggregate_for_num_op_traditional(h0, h1));
- return false;
- }
- if ((hres= agg->find_handler(h0, h1)))
- {
- set_handler(hres);
- return false;
- }
- return true;
+ const Type_collection *c;
+ if (!(c= Type_handler::type_collection_for_aggregation(h0, h1)) ||
+ !(hres= c->aggregate_for_num_op(h0, h1)))
+ hres= agg->find_handler(h0, h1);
+ if (!hres)
+ return true;
+ m_type_handler= hres;
+ return false;
}
@@ -1849,11 +2085,11 @@ Type_handler::get_handler_by_field_type(enum_field_types type)
switch (type) {
case MYSQL_TYPE_DECIMAL: return &type_handler_olddecimal;
case MYSQL_TYPE_NEWDECIMAL: return &type_handler_newdecimal;
- case MYSQL_TYPE_TINY: return &type_handler_tiny;
- case MYSQL_TYPE_SHORT: return &type_handler_short;
- case MYSQL_TYPE_LONG: return &type_handler_long;
- case MYSQL_TYPE_LONGLONG: return &type_handler_longlong;
- case MYSQL_TYPE_INT24: return &type_handler_int24;
+ case MYSQL_TYPE_TINY: return &type_handler_stiny;
+ case MYSQL_TYPE_SHORT: return &type_handler_sshort;
+ case MYSQL_TYPE_LONG: return &type_handler_slong;
+ case MYSQL_TYPE_LONGLONG: return &type_handler_slonglong;
+ case MYSQL_TYPE_INT24: return &type_handler_sint24;
case MYSQL_TYPE_YEAR: return &type_handler_year;
case MYSQL_TYPE_BIT: return &type_handler_bit;
case MYSQL_TYPE_FLOAT: return &type_handler_float;
@@ -1904,11 +2140,11 @@ Type_handler::get_handler_by_real_type(enum_field_types type)
switch (type) {
case MYSQL_TYPE_DECIMAL: return &type_handler_olddecimal;
case MYSQL_TYPE_NEWDECIMAL: return &type_handler_newdecimal;
- case MYSQL_TYPE_TINY: return &type_handler_tiny;
- case MYSQL_TYPE_SHORT: return &type_handler_short;
- case MYSQL_TYPE_LONG: return &type_handler_long;
- case MYSQL_TYPE_LONGLONG: return &type_handler_longlong;
- case MYSQL_TYPE_INT24: return &type_handler_int24;
+ case MYSQL_TYPE_TINY: return &type_handler_stiny;
+ case MYSQL_TYPE_SHORT: return &type_handler_sshort;
+ case MYSQL_TYPE_LONG: return &type_handler_slong;
+ case MYSQL_TYPE_LONGLONG: return &type_handler_slonglong;
+ case MYSQL_TYPE_INT24: return &type_handler_sint24;
case MYSQL_TYPE_YEAR: return &type_handler_year;
case MYSQL_TYPE_BIT: return &type_handler_bit;
case MYSQL_TYPE_FLOAT: return &type_handler_float;
@@ -1921,13 +2157,7 @@ Type_handler::get_handler_by_real_type(enum_field_types type)
case MYSQL_TYPE_LONG_BLOB: return &type_handler_long_blob;
case MYSQL_TYPE_BLOB: return &type_handler_blob;
case MYSQL_TYPE_BLOB_COMPRESSED: return &type_handler_blob_compressed;
- case MYSQL_TYPE_VAR_STRING:
- /*
- VAR_STRING is actually a field_type(), not a real_type(),
- but it's used around the code in real_type() context.
- We should clean up the code and add DBUG_ASSERT(0) here.
- */
- return &type_handler_string;
+ case MYSQL_TYPE_VAR_STRING: return &type_handler_var_string;
case MYSQL_TYPE_STRING: return &type_handler_string;
case MYSQL_TYPE_ENUM: return &type_handler_enum;
case MYSQL_TYPE_SET: return &type_handler_set;
@@ -1946,8 +2176,7 @@ Type_handler::get_handler_by_real_type(enum_field_types type)
case MYSQL_TYPE_DATETIME2: return &type_handler_datetime2;
case MYSQL_TYPE_NEWDATE: return &type_handler_newdate;
};
- DBUG_ASSERT(0);
- return &type_handler_string;
+ return NULL;
}
@@ -2016,7 +2245,8 @@ Type_handler_int_result::make_num_distinct_aggregator_field(MEM_ROOT *mem_root,
/***********************************************************************/
-Field *Type_handler_tiny::make_conversion_table_field(TABLE *table,
+Field *Type_handler_tiny::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
@@ -2027,84 +2257,91 @@ Field *Type_handler_tiny::make_conversion_table_field(TABLE *table,
using conversions so it should be true also when using conversions.
*/
bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
- return new (table->in_use->mem_root)
+ return new (root)
Field_tiny(NULL, 4 /*max_length*/, (uchar *) "", 1, Field::NONE,
&empty_clex_str, 0/*zerofill*/, unsigned_flag);
}
-Field *Type_handler_short::make_conversion_table_field(TABLE *table,
+Field *Type_handler_short::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
- return new (table->in_use->mem_root)
+ return new (root)
Field_short(NULL, 6 /*max_length*/, (uchar *) "", 1, Field::NONE,
&empty_clex_str, 0/*zerofill*/, unsigned_flag);
}
-Field *Type_handler_int24::make_conversion_table_field(TABLE *table,
+Field *Type_handler_int24::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
- return new (table->in_use->mem_root)
+ return new (root)
Field_medium(NULL, 9 /*max_length*/, (uchar *) "", 1, Field::NONE,
&empty_clex_str, 0/*zerofill*/, unsigned_flag);
}
-Field *Type_handler_long::make_conversion_table_field(TABLE *table,
+Field *Type_handler_long::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
- return new (table->in_use->mem_root)
+ return new (root)
Field_long(NULL, 11 /*max_length*/, (uchar *) "", 1, Field::NONE,
&empty_clex_str, 0/*zerofill*/, unsigned_flag);
}
-Field *Type_handler_longlong::make_conversion_table_field(TABLE *table,
+Field *Type_handler_longlong::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
- return new (table->in_use->mem_root)
+ return new (root)
Field_longlong(NULL, 20 /*max_length*/,(uchar *) "", 1, Field::NONE,
&empty_clex_str, 0/*zerofill*/, unsigned_flag);
}
-Field *Type_handler_float::make_conversion_table_field(TABLE *table,
+Field *Type_handler_float::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_float(NULL, 12 /*max_length*/, (uchar *) "", 1, Field::NONE,
&empty_clex_str, 0/*dec*/, 0/*zerofill*/, 0/*unsigned_flag*/);
}
-Field *Type_handler_double::make_conversion_table_field(TABLE *table,
+Field *Type_handler_double::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_double(NULL, 22 /*max_length*/, (uchar *) "", 1, Field::NONE,
&empty_clex_str, 0/*dec*/, 0/*zerofill*/, 0/*unsigned_flag*/);
}
-Field *Type_handler_newdecimal::make_conversion_table_field(TABLE *table,
+Field *Type_handler_newdecimal::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
@@ -2113,13 +2350,14 @@ Field *Type_handler_newdecimal::make_conversion_table_field(TABLE *table,
uint8 decimals= metadata & 0x00ff;
uint32 max_length= my_decimal_precision_to_length(precision, decimals, false);
DBUG_ASSERT(decimals <= DECIMAL_MAX_SCALE);
- return new (table->in_use->mem_root)
+ return new (root)
Field_new_decimal(NULL, max_length, (uchar *) "", 1, Field::NONE,
&empty_clex_str, decimals, 0/*zerofill*/, 0/*unsigned*/);
}
-Field *Type_handler_olddecimal::make_conversion_table_field(TABLE *table,
+Field *Type_handler_olddecimal::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
@@ -2136,153 +2374,169 @@ Field *Type_handler_olddecimal::make_conversion_table_field(TABLE *table,
}
-Field *Type_handler_year::make_conversion_table_field(TABLE *table,
+Field *Type_handler_year::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new(table->in_use->mem_root)
+ return new(root)
Field_year(NULL, 4, (uchar *) "", 1, Field::NONE, &empty_clex_str);
}
-Field *Type_handler_null::make_conversion_table_field(TABLE *table,
+Field *Type_handler_null::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new(table->in_use->mem_root)
+ return new(root)
Field_null(NULL, 0, Field::NONE, &empty_clex_str, target->charset());
}
-Field *Type_handler_timestamp::make_conversion_table_field(TABLE *table,
+Field *Type_handler_timestamp::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new_Field_timestamp(table->in_use->mem_root, NULL, (uchar *) "", 1,
- Field::NONE, &empty_clex_str, table->s, target->decimals());
+ return new_Field_timestamp(root, NULL, (uchar *) "", 1,
+ Field::NONE, &empty_clex_str,
+ table->s, target->decimals());
}
-Field *Type_handler_timestamp2::make_conversion_table_field(TABLE *table,
+Field *Type_handler_timestamp2::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new(table->in_use->mem_root)
+ return new(root)
Field_timestampf(NULL, (uchar *) "", 1, Field::NONE,
&empty_clex_str, table->s, metadata);
}
-Field *Type_handler_newdate::make_conversion_table_field(TABLE *table,
+Field *Type_handler_newdate::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new(table->in_use->mem_root)
+ return new(root)
Field_newdate(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str);
}
-Field *Type_handler_date::make_conversion_table_field(TABLE *table,
+Field *Type_handler_date::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new(table->in_use->mem_root)
+ return new(root)
Field_date(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str);
}
-Field *Type_handler_time::make_conversion_table_field(TABLE *table,
+Field *Type_handler_time::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new_Field_time(table->in_use->mem_root, NULL, (uchar *) "", 1,
+ return new_Field_time(root, NULL, (uchar *) "", 1,
Field::NONE, &empty_clex_str, target->decimals());
}
-Field *Type_handler_time2::make_conversion_table_field(TABLE *table,
+Field *Type_handler_time2::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new(table->in_use->mem_root)
+ return new(root)
Field_timef(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str, metadata);
}
-Field *Type_handler_datetime::make_conversion_table_field(TABLE *table,
+Field *Type_handler_datetime::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new_Field_datetime(table->in_use->mem_root, NULL, (uchar *) "", 1,
+ return new_Field_datetime(root, NULL, (uchar *) "", 1,
Field::NONE, &empty_clex_str, target->decimals());
}
-Field *Type_handler_datetime2::make_conversion_table_field(TABLE *table,
+Field *Type_handler_datetime2::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new(table->in_use->mem_root)
+ return new(root)
Field_datetimef(NULL, (uchar *) "", 1,
Field::NONE, &empty_clex_str, metadata);
}
-Field *Type_handler_bit::make_conversion_table_field(TABLE *table,
+Field *Type_handler_bit::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
DBUG_ASSERT((metadata & 0xff) <= 7);
uint32 max_length= 8 * (metadata >> 8U) + (metadata & 0x00ff);
- return new(table->in_use->mem_root)
+ return new(root)
Field_bit_as_char(NULL, max_length, (uchar *) "", 1,
Field::NONE, &empty_clex_str);
}
-Field *Type_handler_string::make_conversion_table_field(TABLE *table,
+Field *Type_handler_string::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
/* This is taken from Field_string::unpack. */
uint32 max_length= (((metadata >> 4) & 0x300) ^ 0x300) + (metadata & 0x00ff);
- return new(table->in_use->mem_root)
+ return new(root)
Field_string(NULL, max_length, (uchar *) "", 1,
Field::NONE, &empty_clex_str, target->charset());
}
-Field *Type_handler_varchar::make_conversion_table_field(TABLE *table,
+Field *Type_handler_varchar::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
DBUG_ASSERT(HA_VARCHAR_PACKLENGTH(metadata) <= MAX_FIELD_VARCHARLENGTH);
- return new(table->in_use->mem_root)
+ return new(root)
Field_varstring(NULL, metadata, HA_VARCHAR_PACKLENGTH(metadata),
(uchar *) "", 1, Field::NONE, &empty_clex_str,
table->s, target->charset());
}
-Field *Type_handler_varchar_compressed::make_conversion_table_field(TABLE *table,
+Field *Type_handler_varchar_compressed::make_conversion_table_field(
+ MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new(table->in_use->mem_root)
+ return new(root)
Field_varstring_compressed(NULL, metadata,
HA_VARCHAR_PACKLENGTH(metadata),
(uchar *) "", 1, Field::NONE,
@@ -2293,7 +2547,9 @@ Field *Type_handler_varchar_compressed::make_conversion_table_field(TABLE *table
-Field *Type_handler_blob_compressed::make_conversion_table_field(TABLE *table,
+Field *Type_handler_blob_compressed::make_conversion_table_field(
+ MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
@@ -2301,7 +2557,7 @@ Field *Type_handler_blob_compressed::make_conversion_table_field(TABLE *table,
uint pack_length= metadata & 0x00ff;
if (pack_length < 1 || pack_length > 4)
return NULL; // Broken binary log?
- return new(table->in_use->mem_root)
+ return new(root)
Field_blob_compressed(NULL, (uchar *) "", 1, Field::NONE,
&empty_clex_str,
table->s, pack_length, target->charset(),
@@ -2309,43 +2565,15 @@ Field *Type_handler_blob_compressed::make_conversion_table_field(TABLE *table,
}
-#ifdef HAVE_SPATIAL
-const Name Type_handler_geometry::m_name_geometry(STRING_WITH_LEN("geometry"));
-
-
-const Type_handler *Type_handler_geometry::type_handler_for_comparison() const
-{
- return &type_handler_geometry;
-}
-
-
-Field *Type_handler_geometry::make_conversion_table_field(TABLE *table,
- uint metadata,
- const Field *target)
- const
-{
- DBUG_ASSERT(target->type() == MYSQL_TYPE_GEOMETRY);
- /*
- We do not do not update feature_gis statistics here:
- status_var_increment(target->table->in_use->status_var.feature_gis);
- as this is only a temporary field.
- The statistics was already incremented when "target" was created.
- */
- return new(table->in_use->mem_root)
- Field_geom(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str, table->s, 4,
- ((const Field_geom*) target)->geom_type,
- ((const Field_geom*) target)->srid);
-}
-#endif
-
-Field *Type_handler_enum::make_conversion_table_field(TABLE *table,
+Field *Type_handler_enum::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
DBUG_ASSERT(target->type() == MYSQL_TYPE_STRING);
DBUG_ASSERT(target->real_type() == MYSQL_TYPE_ENUM);
- return new(table->in_use->mem_root)
+ return new(root)
Field_enum(NULL, target->field_length,
(uchar *) "", 1, Field::NONE, &empty_clex_str,
metadata & 0x00ff/*pack_length()*/,
@@ -2353,14 +2581,15 @@ Field *Type_handler_enum::make_conversion_table_field(TABLE *table,
}
-Field *Type_handler_set::make_conversion_table_field(TABLE *table,
+Field *Type_handler_set::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
DBUG_ASSERT(target->type() == MYSQL_TYPE_STRING);
DBUG_ASSERT(target->real_type() == MYSQL_TYPE_SET);
- return new(table->in_use->mem_root)
+ return new(root)
Field_set(NULL, target->field_length,
(uchar *) "", 1, Field::NONE, &empty_clex_str,
metadata & 0x00ff/*pack_length()*/,
@@ -2368,6 +2597,28 @@ Field *Type_handler_set::make_conversion_table_field(TABLE *table,
}
+Field *Type_handler_enum::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ const Typelib *typelib= def.typelib();
+ DBUG_ASSERT(typelib);
+ /*
+ Assume I_S columns don't have non-ASCII characters in names.
+ If we eventually want to, Typelib::max_char_length() must be implemented.
+ */
+ return new (root)
+ Field_enum(addr.ptr(), (uint32) typelib->max_octet_length(),
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name,
+ get_enum_pack_length(typelib->count),
+ typelib, system_charset_info);
+
+}
+
+
/*************************************************************************/
bool Type_handler::
@@ -2379,6 +2630,108 @@ bool Type_handler::
/*************************************************************************/
+
+bool
+Type_handler::Column_definition_set_attributes(THD *thd,
+ Column_definition *def,
+ const Lex_field_type_st &attr,
+ CHARSET_INFO *cs,
+ column_definition_type_t type)
+ const
+{
+ def->charset= cs;
+ def->set_length_and_dec(attr);
+ return false;
+}
+
+
+/*
+ In sql_mode=ORACLE, real size of VARCHAR and CHAR with no length
+ in SP parameters is fixed at runtime with the length of real args.
+ Let's translate VARCHAR to VARCHAR(4000) for return value.
+
+ Since Oracle 9, maximum size for VARCHAR in PL/SQL is 32767.
+
+ In MariaDB the limit for VARCHAR is 65535 bytes.
+ We could translate VARCHAR with no length to VARCHAR(65535), but
+ it would mean that for multi-byte character sets we'd have to translate
+ VARCHAR to MEDIUMTEXT, to guarantee 65535 characters.
+
+ Also we could translate VARCHAR to VARCHAR(16383), where 16383 is
+ the maximum possible length in characters in case of mbmaxlen=4
+ (e.g. utf32, utf16, utf8mb4). However, we'll have character sets with
+ mbmaxlen=5 soon (e.g. gb18030).
+*/
+
+bool
+Type_handler_string::Column_definition_set_attributes(
+ THD *thd,
+ Column_definition *def,
+ const Lex_field_type_st &attr,
+ CHARSET_INFO *cs,
+ column_definition_type_t type)
+ const
+{
+ Type_handler::Column_definition_set_attributes(thd, def, attr, cs, type);
+ if (attr.length())
+ return false;
+ switch (type) {
+ case COLUMN_DEFINITION_ROUTINE_PARAM:
+ case COLUMN_DEFINITION_FUNCTION_RETURN:
+ if (thd->variables.sql_mode & MODE_ORACLE)
+ {
+ // See Type_handler_varchar::Column_definition_set_attributes()
+ def->length= def->decimals= 2000;
+ def->set_handler(&type_handler_varchar);
+ return false;
+ }
+ break;
+ case COLUMN_DEFINITION_ROUTINE_LOCAL:
+ case COLUMN_DEFINITION_TABLE_FIELD:
+ break;
+ }
+ def->length= 1;
+ return false;
+}
+
+
+bool
+Type_handler_varchar::Column_definition_set_attributes(
+ THD *thd,
+ Column_definition *def,
+ const Lex_field_type_st &attr,
+ CHARSET_INFO *cs,
+ column_definition_type_t type)
+ const
+{
+ Type_handler::Column_definition_set_attributes(thd, def, attr, cs, type);
+ if (attr.length())
+ return false;
+ switch (type) {
+ case COLUMN_DEFINITION_ROUTINE_PARAM:
+ case COLUMN_DEFINITION_FUNCTION_RETURN:
+ if (thd->variables.sql_mode & MODE_ORACLE)
+ {
+ /*
+ Type_handler_varchar::adjust_spparam_type() tests "decimals"
+ to detect if the formal parameter length needs to be adjusted to
+ the actual parameter length. Non-zero decimals means that the length
+ was set implicitly to the default value and needs to be adjusted.
+ */
+ def->length= def->decimals= 4000;
+ return false;
+ }
+ break;
+ case COLUMN_DEFINITION_ROUTINE_LOCAL:
+ case COLUMN_DEFINITION_TABLE_FIELD:
+ break;
+ }
+ thd->parse_error();
+ return true;
+}
+
+
+/*************************************************************************/
bool Type_handler_null::
Column_definition_fix_attributes(Column_definition *def) const
{
@@ -2458,14 +2811,6 @@ bool Type_handler_blob_common::
return def->check_length(ER_TOO_BIG_DISPLAYWIDTH, MAX_FIELD_BLOBLENGTH);
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Column_definition_fix_attributes(Column_definition *def) const
-{
- def->flags|= BLOB_FLAG;
- return false;
-}
-#endif
bool Type_handler_year::
Column_definition_fix_attributes(Column_definition *def) const
@@ -2539,15 +2884,6 @@ bool Type_handler_bit::
/*************************************************************************/
-void Type_handler_blob_common::
- Column_definition_reuse_fix_attributes(THD *thd,
- Column_definition *def,
- const Field *field) const
-{
- DBUG_ASSERT(def->key_length == 0);
-}
-
-
void Type_handler_typelib::
Column_definition_reuse_fix_attributes(THD *thd,
Column_definition *def,
@@ -2558,18 +2894,6 @@ void Type_handler_typelib::
}
-#ifdef HAVE_SPATIAL
-void Type_handler_geometry::
- Column_definition_reuse_fix_attributes(THD *thd,
- Column_definition *def,
- const Field *field) const
-{
- def->geom_type= ((Field_geom*) field)->geom_type;
- def->srid= ((Field_geom*) field)->srid;
-}
-#endif
-
-
void Type_handler_year::
Column_definition_reuse_fix_attributes(THD *thd,
Column_definition *def,
@@ -2679,20 +3003,6 @@ bool Type_handler_string_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Column_definition_prepare_stage1(THD *thd,
- MEM_ROOT *mem_root,
- Column_definition *def,
- handler *file,
- ulonglong table_flags) const
-{
- def->create_length_to_internal_length_string();
- return def->prepare_blob_field(thd);
-}
-#endif
-
-
/*************************************************************************/
bool Type_handler::
@@ -2795,8 +3105,7 @@ bool Type_handler::
Column_definition_prepare_stage2_legacy_num(Column_definition *def,
enum_field_types type) const
{
- def->pack_flag= def->pack_flag_numeric(def->decimals) |
- f_settype((uint) type);
+ def->pack_flag= def->pack_flag_numeric() | f_settype((uint) type);
return false;
}
@@ -2812,7 +3121,8 @@ bool Type_handler::
*/
if (dec >= FLOATING_POINT_DECIMALS)
dec= FLOATING_POINT_DECIMALS;
- def->pack_flag= def->pack_flag_numeric(dec) | f_settype((uint) type);
+ def->decimals= dec;
+ def->pack_flag= def->pack_flag_numeric() | f_settype((uint) type);
return false;
}
@@ -2821,7 +3131,7 @@ bool Type_handler_newdecimal::
handler *file,
ulonglong table_flags) const
{
- def->pack_flag= def->pack_flag_numeric(def->decimals);
+ def->pack_flag= def->pack_flag_numeric();
return false;
}
@@ -2833,21 +3143,6 @@ bool Type_handler_blob_common::
return def->prepare_stage2_blob(file, table_flags, FIELDFLAG_BLOB);
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Column_definition_prepare_stage2(Column_definition *def,
- handler *file,
- ulonglong table_flags) const
-{
- if (!(table_flags & HA_CAN_GEOMETRY))
- {
- my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "GEOMETRY");
- return true;
- }
- return def->prepare_stage2_blob(file, table_flags, FIELDFLAG_GEOM);
-}
-#endif
-
bool Type_handler_varchar::
Column_definition_prepare_stage2(Column_definition *def,
handler *file,
@@ -2903,6 +3198,93 @@ bool Type_handler_bit::
return false;
}
+
+/*************************************************************************/
+bool Type_handler::Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return false;
+}
+
+
+bool Type_handler::Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *has_field_needed) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return false;
+}
+
+
+bool Type_handler::Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return false;
+}
+
+
+bool Type_handler::Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return false;
+}
+
+
+bool Type_handler::Key_part_spec_init_spatial(Key_part_spec *part,
+ const Column_definition &def)
+ const
+{
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "SPATIAL INDEX");
+ return true;
+}
+
+
+bool Type_handler_blob_common::Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return part->check_primary_key_for_blob(file);
+}
+
+
+bool Type_handler_blob_common::Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *hash_field_needed) const
+{
+ if (!(part->length*= def.charset->mbmaxlen))
+ *hash_field_needed= true;
+ return part->check_key_for_blob(file);
+}
+
+
+bool Type_handler_blob_common::Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return part->init_multiple_key_for_blob(file);
+}
+
+
+bool Type_handler_blob_common::Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return part->check_foreign_key_for_blob(file);
+}
+
+
+
/*************************************************************************/
uint32 Type_handler_time::calc_pack_length(uint32 length) const
@@ -2961,13 +3343,6 @@ uint32 Type_handler_long_blob::calc_pack_length(uint32 length) const
return 4 + portable_sizeof_char_ptr;
}
-#ifdef HAVE_SPATIAL
-uint32 Type_handler_geometry::calc_pack_length(uint32 length) const
-{
- return 4 + portable_sizeof_char_ptr;
-}
-#endif
-
uint32 Type_handler_newdecimal::calc_pack_length(uint32 length) const
{
abort(); // This shouldn't happen
@@ -2988,87 +3363,83 @@ uint32 Type_handler_enum::calc_pack_length(uint32 length) const
/*************************************************************************/
-Field *Type_handler::make_and_init_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const
+uint Type_handler::calc_key_length(const Column_definition &def) const
{
- Field *field= make_table_field(name, addr, attr, table);
- if (field)
- field->init(table);
- return field;
+ DBUG_ASSERT(def.pack_length == calc_pack_length((uint32) def.length));
+ return def.pack_length;
}
-
-Field *Type_handler_tiny::make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const
+uint Type_handler_bit::calc_key_length(const Column_definition &def) const
{
- return new (table->in_use->mem_root)
- Field_tiny(addr.ptr(), attr.max_char_length(),
- addr.null_ptr(), addr.null_bit(),
- Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag);
+ if (f_bit_as_char(def.pack_flag))
+ return def.pack_length;
+ /* We need one extra byte to store the bits we save among the null bits */
+ return def.pack_length + MY_TEST(def.length & 7);
}
-
-Field *Type_handler_short::make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const
-
+uint Type_handler_newdecimal::calc_key_length(const Column_definition &def) const
{
- return new (table->in_use->mem_root)
- Field_short(addr.ptr(), attr.max_char_length(),
- addr.null_ptr(), addr.null_bit(),
- Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag);
+ return def.pack_length;
}
-
-Field *Type_handler_int24::make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const
+uint
+Type_handler_string_result::calc_key_length(const Column_definition &def) const
{
- return new (table->in_use->mem_root)
- Field_medium(addr.ptr(), attr.max_char_length(),
- addr.null_ptr(), addr.null_bit(),
- Field::NONE, name,
- 0/*zerofill*/, attr.unsigned_flag);
+ return (uint) def.length;
}
+uint Type_handler_enum::calc_key_length(const Column_definition &def) const
+{
+ DBUG_ASSERT(def.interval);
+ return get_enum_pack_length(def.interval->count);
+}
-Field *Type_handler_long::make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const
+uint Type_handler_set::calc_key_length(const Column_definition &def) const
{
- return new (table->in_use->mem_root)
- Field_long(addr.ptr(), attr.max_char_length(),
- addr.null_ptr(), addr.null_bit(),
- Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag);
+ DBUG_ASSERT(def.interval);
+ return get_set_pack_length(def.interval->count);
}
+uint Type_handler_blob_common::calc_key_length(const Column_definition &def) const
+{
+ return 0;
+}
-Field *Type_handler_longlong::make_table_field(const LEX_CSTRING *name,
+/*************************************************************************/
+Field *Type_handler::make_and_init_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new (table->in_use->mem_root)
- Field_longlong(addr.ptr(), attr.max_char_length(),
- addr.null_ptr(), addr.null_bit(),
- Field::NONE, name,
- 0/*zerofill*/, attr.unsigned_flag);
+ Field *field= make_table_field(root, name, addr, attr, table->s);
+ if (field)
+ field->init(table);
+ return field;
}
-Field *Type_handler_vers_trx_id::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_int_result::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+{
+ DBUG_ASSERT(is_unsigned() == attr.unsigned_flag);
+ Column_definition_attributes dattr(attr);
+ return make_table_field_from_def(share, root, name, addr,
+ Bit_addr(), &dattr, 0);
+}
+
+
+Field *Type_handler_vers_trx_id::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
- return new (table->in_use->mem_root)
+ DBUG_ASSERT(is_unsigned() == attr.unsigned_flag);
+ return new (root)
Field_vers_trx_id(addr.ptr(), attr.max_char_length(),
addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
@@ -3076,37 +3447,25 @@ Field *Type_handler_vers_trx_id::make_table_field(const LEX_CSTRING *name,
}
-Field *Type_handler_float::make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const
-{
- return new (table->in_use->mem_root)
- Field_float(addr.ptr(), attr.max_char_length(),
- addr.null_ptr(), addr.null_bit(),
- Field::NONE, name,
- (uint8) attr.decimals, 0/*zerofill*/, attr.unsigned_flag);
-}
-
-
-Field *Type_handler_double::make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const
+Field *
+Type_handler_real_result::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
{
- return new (table->in_use->mem_root)
- Field_double(addr.ptr(), attr.max_char_length(),
- addr.null_ptr(), addr.null_bit(),
- Field::NONE, name,
- (uint8) attr.decimals, 0/*zerofill*/, attr.unsigned_flag);
+ Column_definition_attributes dattr(attr);
+ return make_table_field_from_def(share, root, name, addr,
+ Bit_addr(), &dattr, 0);
}
Field *
-Type_handler_olddecimal::make_table_field(const LEX_CSTRING *name,
+Type_handler_olddecimal::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
/*
Currently make_table_field() is used for Item purpose only.
@@ -3116,19 +3475,18 @@ Type_handler_olddecimal::make_table_field(const LEX_CSTRING *name,
in make_field() in field.cc, to open old tables with old decimal.
*/
DBUG_ASSERT(0);
- return new (table->in_use->mem_root)
- Field_decimal(addr.ptr(), attr.max_length,
- addr.null_ptr(), addr.null_bit(),
- Field::NONE, name, (uint8) attr.decimals,
- 0/*zerofill*/,attr.unsigned_flag);
+ Column_definition_attributes dattr(attr);
+ return make_table_field_from_def(share, root, name, addr,
+ Bit_addr(), &dattr, 0);
}
Field *
-Type_handler_newdecimal::make_table_field(const LEX_CSTRING *name,
+Type_handler_newdecimal::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
uint8 dec= (uint8) attr.decimals;
uint8 intg= (uint8) (attr.decimal_precision() - dec);
@@ -3164,81 +3522,74 @@ Type_handler_newdecimal::make_table_field(const LEX_CSTRING *name,
/* Corrected value fits. */
len= required_length;
}
- return new (table->in_use->mem_root)
+ return new (root)
Field_new_decimal(addr.ptr(), len, addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
dec, 0/*zerofill*/, attr.unsigned_flag);
}
-Field *Type_handler_year::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_null::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
-{
- return new (table->in_use->mem_root)
- Field_year(addr.ptr(), attr.max_length,
- addr.null_ptr(), addr.null_bit(),
- Field::NONE, name);
-}
-
-
-Field *Type_handler_null::make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_null(addr.ptr(), attr.max_length,
Field::NONE, name, attr.collation.collation);
}
-Field *Type_handler_timestamp::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_timestamp::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
- return new_Field_timestamp(table->in_use->mem_root,
+ return new_Field_timestamp(root,
addr.ptr(), addr.null_ptr(), addr.null_bit(),
- Field::NONE, name, table->s, attr.decimals);
+ Field::NONE, name, share, attr.decimals);
}
-Field *Type_handler_timestamp2::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_timestamp2::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
/*
Will be changed to "new Field_timestampf" when we reuse
make_table_field() for make_field() purposes in field.cc.
*/
- return new_Field_timestamp(table->in_use->mem_root,
+ return new_Field_timestamp(root,
addr.ptr(), addr.null_ptr(), addr.null_bit(),
- Field::NONE, name, table->s, attr.decimals);
+ Field::NONE, name, share, attr.decimals);
}
-Field *Type_handler_newdate::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_newdate::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_newdate(addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name);
}
-Field *Type_handler_date::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_date::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
/*
@@ -3246,28 +3597,30 @@ Field *Type_handler_date::make_table_field(const LEX_CSTRING *name,
for make_field() in field.cc
*/
DBUG_ASSERT(0);
- return new (table->in_use->mem_root)
+ return new (root)
Field_date(addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name);
}
-Field *Type_handler_time::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_time::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
- return new_Field_time(table->in_use->mem_root,
+ return new_Field_time(root,
addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, attr.decimals);
}
-Field *Type_handler_time2::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_time2::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
@@ -3275,159 +3628,153 @@ Field *Type_handler_time2::make_table_field(const LEX_CSTRING *name,
Will be changed to "new Field_timef" when we reuse
make_table_field() for make_field() purposes in field.cc.
*/
- return new_Field_time(table->in_use->mem_root,
+ return new_Field_time(root,
addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, attr.decimals);
}
-Field *Type_handler_datetime::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_datetime::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
- return new_Field_datetime(table->in_use->mem_root,
+ return new_Field_datetime(root,
addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, attr.decimals);
}
-Field *Type_handler_datetime2::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_datetime2::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
/*
Will be changed to "new Field_datetimef" when we reuse
make_table_field() for make_field() purposes in field.cc.
*/
- return new_Field_datetime(table->in_use->mem_root,
+ return new_Field_datetime(root,
addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, attr.decimals);
}
-Field *Type_handler_bit::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_bit::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_bit_as_char(addr.ptr(), attr.max_length,
addr.null_ptr(), addr.null_bit(),
Field::NONE, name);
}
-Field *Type_handler_string::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_string::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_string(addr.ptr(), attr.max_length,
addr.null_ptr(), addr.null_bit(),
Field::NONE, name, attr.collation);
}
-Field *Type_handler_varchar::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_varchar::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
DBUG_ASSERT(HA_VARCHAR_PACKLENGTH(attr.max_length) <=
MAX_FIELD_VARCHARLENGTH);
- return new (table->in_use->mem_root)
+ return new (root)
Field_varstring(addr.ptr(), attr.max_length,
HA_VARCHAR_PACKLENGTH(attr.max_length),
addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
- table->s, attr.collation);
+ share, attr.collation);
}
-Field *Type_handler_tiny_blob::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_tiny_blob::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
- Field::NONE, name, table->s,
+ Field::NONE, name, share,
1, attr.collation);
}
-Field *Type_handler_blob::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_blob::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
- Field::NONE, name, table->s,
+ Field::NONE, name, share,
2, attr.collation);
}
Field *
-Type_handler_medium_blob::make_table_field(const LEX_CSTRING *name,
+Type_handler_medium_blob::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
- Field::NONE, name, table->s,
+ Field::NONE, name, share,
3, attr.collation);
}
-Field *Type_handler_long_blob::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_long_blob::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
- Field::NONE, name, table->s,
+ Field::NONE, name, share,
4, attr.collation);
}
-
-#ifdef HAVE_SPATIAL
-Field *Type_handler_geometry::make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const
-{
- return new (table->in_use->mem_root)
- Field_geom(addr.ptr(), addr.null_ptr(), addr.null_bit(),
- Field::NONE, name, table->s, 4,
- (Field::geometry_type) attr.uint_geometry_type(),
- 0);
-}
-#endif
-
-
-Field *Type_handler_enum::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_enum::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
- TYPELIB *typelib= attr.get_typelib();
+ const TYPELIB *typelib= attr.get_typelib();
DBUG_ASSERT(typelib);
- return new (table->in_use->mem_root)
+ return new (root)
Field_enum(addr.ptr(), attr.max_length,
addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
@@ -3436,15 +3783,16 @@ Field *Type_handler_enum::make_table_field(const LEX_CSTRING *name,
}
-Field *Type_handler_set::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_set::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const
{
- TYPELIB *typelib= attr.get_typelib();
+ const TYPELIB *typelib= attr.get_typelib();
DBUG_ASSERT(typelib);
- return new (table->in_use->mem_root)
+ return new (root)
Field_set(addr.ptr(), attr.max_length,
addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
@@ -3452,6 +3800,198 @@ Field *Type_handler_set::make_table_field(const LEX_CSTRING *name,
attr.collation);
}
+
+/*************************************************************************/
+
+Field *Type_handler_float::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_float(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name,
+ (uint8) NOT_FIXED_DEC,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_double::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_double(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name,
+ (uint8) NOT_FIXED_DEC,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_decimal_result::make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ uint dec= def.decimal_scale();
+ uint prec= def.decimal_precision();
+ DBUG_ASSERT(dec <= DECIMAL_MAX_SCALE);
+ uint32 len= my_decimal_precision_to_length(prec, dec, def.unsigned_flag());
+ return new (root)
+ Field_new_decimal(addr.ptr(), len, addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name,
+ (uint8) dec, 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_blob_common::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ if (show_field)
+ {
+ return new (root)
+ Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name, table->s,
+ length_bytes(),
+ &my_charset_bin);
+ }
+ else
+ return new (root)
+ Field_null(addr.ptr(), 0, Field::NONE, &name, &my_charset_bin);
+}
+
+
+Field *Type_handler_varchar::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ DBUG_ASSERT(def.char_length());
+ LEX_CSTRING name= def.name();
+ uint32 octet_length= (uint32) def.char_length() * 3;
+ if (octet_length > MAX_FIELD_VARCHARLENGTH)
+ {
+ Field *field= new (root)
+ Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(), Field::NONE,
+ &name, table->s, 4, system_charset_info);
+ if (field)
+ field->field_length= octet_length;
+ return field;
+ }
+ else if (show_field)
+ {
+ return new (root)
+ Field_varstring(addr.ptr(), octet_length,
+ HA_VARCHAR_PACKLENGTH(octet_length),
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name,
+ table->s, system_charset_info);
+ }
+ else
+ return new (root)
+ Field_null(addr.ptr(), 0, Field::NONE, &name, system_charset_info);
+}
+
+
+Field *Type_handler_tiny::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_tiny(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(), Field::NONE, &name,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_short::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_short(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(), Field::NONE, &name,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_long::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_long(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(), Field::NONE, &name,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_longlong::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_longlong(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(), Field::NONE, &name,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_date_common::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_newdate(addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name);
+}
+
+
+Field *Type_handler_time_common::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new_Field_time(root,
+ addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name, def.fsp());
+}
+
+
+Field *Type_handler_datetime_common::make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root) Field_datetimef(addr.ptr(),
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name, def.fsp());
+}
+
+
/*************************************************************************/
/*
@@ -3507,13 +4047,6 @@ uint32 Type_handler_bit::max_display_length(const Item *item) const
return item->max_length;
}
-
-uint32 Type_handler_general_purpose_int::max_display_length(const Item *item)
- const
-{
- return type_limits_int_by_unsigned_flag(item->unsigned_flag)->char_length();
-}
-
/*************************************************************************/
uint32
@@ -3544,7 +4077,7 @@ uint32
Type_handler_general_purpose_int::Item_decimal_notation_int_digits(
const Item *item) const
{
- return type_limits_int_by_unsigned_flag(item->unsigned_flag)->precision();
+ return type_limits_int()->precision();
}
/*************************************************************************/
@@ -3770,7 +4303,7 @@ bool Type_handler_string_result::
the query should return only the row with 'oe'.
It should not return 'o-umlaut', because 'o-umlaut' does not match
the right part of the condition: a='oe'
- ('o-umlaut' is not equal to 'oe' in utf8_general_ci,
+ ('o-umlaut' is not equal to 'oe' in utf8mb3_general_ci,
which is the collation of the field "a").
If we change the right part from:
@@ -3911,11 +4444,14 @@ bool Type_handler_int_result::
{
// Convert a mixture of signed and unsigned int to decimal
handler->set_handler(&type_handler_newdecimal);
- func->aggregate_attributes_decimal(items, nitems);
+ func->aggregate_attributes_decimal(items, nitems, false);
return false;
}
}
func->aggregate_attributes_int(items, nitems);
+ handler->set_handler(func->unsigned_flag ?
+ handler->type_handler()->type_handler_unsigned() :
+ handler->type_handler()->type_handler_signed());
return false;
}
@@ -3939,7 +4475,8 @@ bool Type_handler_decimal_result::
Type_all_attributes *func,
Item **items, uint nitems) const
{
- func->aggregate_attributes_decimal(items, nitems);
+ uint unsigned_count= func->count_unsigned(items, nitems);
+ func->aggregate_attributes_decimal(items, nitems, unsigned_count == nitems);
return false;
}
@@ -3967,10 +4504,10 @@ bool Type_handler_typelib::
Type_all_attributes *func,
Item **items, uint nitems) const
{
- TYPELIB *typelib= NULL;
+ const TYPELIB *typelib= NULL;
for (uint i= 0; i < nitems; i++)
{
- TYPELIB *typelib2;
+ const TYPELIB *typelib2;
if ((typelib2= items[i]->get_typelib()))
{
if (typelib)
@@ -4053,29 +4590,6 @@ bool Type_handler_timestamp_common::
return false;
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_hybrid_func_fix_attributes(THD *thd,
- const char *func_name,
- Type_handler_hybrid_field_type *handler,
- Type_all_attributes *func,
- Item **items, uint nitems) const
-{
- DBUG_ASSERT(nitems > 0);
- Type_geometry_attributes gattr(items[0]->type_handler(), items[0]);
- for (uint i= 1; i < nitems; i++)
- gattr.join(items[i]);
- func->set_geometry_type(gattr.get_geometry_type());
- func->collation.set(&my_charset_bin);
- func->unsigned_flag= false;
- func->decimals= 0;
- func->max_length= (uint32) UINT_MAX32;
- func->set_maybe_null(true);
- return false;
-}
-#endif
-
-
/*************************************************************************/
bool Type_handler::
@@ -4210,7 +4724,15 @@ bool Type_handler_real_result::
bool Type_handler_int_result::
Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
{
- return func->fix_length_and_dec_numeric(&type_handler_longlong);
+ /*
+ "this" is equal func->args[0]->type_handler() here, e.g. for MIN()/MAX().
+ func->unsigned_flag is not reliably set yet.
+ It will be set by the call below (copied from args[0]).
+ */
+ const Type_handler *h= is_unsigned()
+ ? (Type_handler *)&type_handler_ulonglong
+ : (Type_handler *)&type_handler_slonglong;
+ return func->fix_length_and_dec_numeric(h);
}
@@ -4293,13 +4815,6 @@ bool Type_handler_string_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_sum_sum_fix_length_and_dec(Item_sum_sum *item) const
-{
- return Item_func_or_sum_illegal_param("sum");
-}
-#endif
/*************************************************************************/
@@ -4344,13 +4859,6 @@ bool Type_handler_string_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_sum_avg_fix_length_and_dec(Item_sum_avg *item) const
-{
- return Item_func_or_sum_illegal_param("avg");
-}
-#endif
/*************************************************************************/
@@ -4395,15 +4903,6 @@ bool Type_handler_string_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_sum_variance_fix_length_and_dec(Item_sum_variance *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-#endif
-
-
/*************************************************************************/
bool Type_handler_real_result::Item_val_bool(Item *item) const
@@ -5098,9 +5597,8 @@ cmp_item *Type_handler_timestamp_common::make_cmp_item(THD *thd,
static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y)
{
- return cs->coll->strnncollsp(cs,
- (uchar *) x->ptr(),x->length(),
- (uchar *) y->ptr(),y->length());
+ return cs->strnncollsp(x->ptr(), x->length(),
+ y->ptr(), y->length());
}
in_vector *Type_handler_string_result::make_in_vector(THD *thd,
@@ -5706,14 +6204,6 @@ bool Type_handler_string_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_func_round_fix_length_and_dec(Item_func_round *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-#endif
-
/***************************************************************************/
bool Type_handler_row::
@@ -5764,14 +6254,6 @@ bool Type_handler_string_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-#endif
-
/***************************************************************************/
bool Type_handler_row::
@@ -5822,14 +6304,6 @@ bool Type_handler_string_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-#endif
-
/***************************************************************************/
bool Type_handler_row::
@@ -5880,15 +6354,6 @@ bool Type_handler_string_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-#endif
-
-
/***************************************************************************/
bool Type_handler::
@@ -6038,78 +6503,6 @@ bool Type_handler::
}
-#ifdef HAVE_SPATIAL
-
-bool Type_handler_geometry::
- Item_func_signed_fix_length_and_dec(Item_func_signed *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-
-
-bool Type_handler_geometry::
- Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-
-
-bool Type_handler_geometry::
- Item_double_typecast_fix_length_and_dec(Item_double_typecast *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-
-
-bool Type_handler_geometry::
- Item_float_typecast_fix_length_and_dec(Item_float_typecast *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-
-
-bool Type_handler_geometry::
- Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-
-
-bool Type_handler_geometry::
- Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) const
-{
- if (item->cast_charset() != &my_charset_bin)
- return Item_func_or_sum_illegal_param(item); // CAST(geom AS CHAR)
- item->fix_length_and_dec_str();
- return false; // CAST(geom AS BINARY)
-}
-
-
-bool Type_handler_geometry::
- Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-
-
-
-bool Type_handler_geometry::
- Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-
-
-bool Type_handler_geometry::
- Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item)
- const
-{
- return Item_func_or_sum_illegal_param(item);
-
-}
-
-#endif /* HAVE_SPATIAL */
-
/***************************************************************************/
bool Type_handler_row::
@@ -6728,21 +7121,6 @@ bool Type_handler_temporal_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_param_set_from_value(THD *thd,
- Item_param *param,
- const Type_all_attributes *attr,
- const st_value *val) const
-{
- param->unsigned_flag= false;
- param->setup_conversion_blob(thd);
- param->set_geometry_type(attr->uint_geometry_type());
- return param->set_str(val->m_string.ptr(), val->m_string.length(),
- &my_charset_bin, &my_charset_bin);
-}
-#endif
-
/***************************************************************************/
bool Type_handler_null::
@@ -6910,10 +7288,10 @@ Item *Type_handler_string_result::
String *result= item->val_str(&tmp);
if (item->null_value)
return new (thd->mem_root) Item_null(thd, item->name.str);
- uint length= result->length();
- char *tmp_str= thd->strmake(result->ptr(), length);
- return new (thd->mem_root) Item_string(thd, item->name.str,
- tmp_str, length, result->charset());
+ LEX_CSTRING value;
+ thd->make_lex_string(&value, result->ptr(), result->length());
+ return new (thd->mem_root) Item_string(thd, item->name, value,
+ result->charset());
}
@@ -7263,7 +7641,8 @@ void Type_handler_datetime_common::Item_param_set_param_func(Item_param *param,
param->set_param_datetime(pos, len);
}
-Field *Type_handler_blob_common::make_conversion_table_field(TABLE *table,
+Field *Type_handler_blob_common::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
@@ -7271,7 +7650,7 @@ Field *Type_handler_blob_common::make_conversion_table_field(TABLE *table,
uint pack_length= metadata & 0x00ff;
if (pack_length < 1 || pack_length > 4)
return NULL; // Broken binary log?
- return new(table->in_use->mem_root)
+ return new(root)
Field_blob(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str,
table->s, pack_length, target->charset());
}
@@ -7301,15 +7680,6 @@ void Type_handler_typelib::Item_param_set_param_func(Item_param *param,
}
-#ifdef HAVE_SPATIAL
-void Type_handler_geometry::Item_param_set_param_func(Item_param *param,
- uchar **pos,
- ulong len) const
-{
- param->set_null(); // Not possible type code in the client-server protocol
-}
-#endif
-
/***************************************************************************/
Field *Type_handler_row::
@@ -7332,11 +7702,12 @@ Field *Type_handler_olddecimal::
const Column_definition_attributes *attr,
uint32 flags) const
{
+ DBUG_ASSERT(f_decimals(attr->pack_flag) == 0);
return new (mem_root)
Field_decimal(rec.ptr(), (uint32) attr->length,
rec.null_ptr(), rec.null_bit(),
attr->unireg_check, name,
- f_decimals(attr->pack_flag),
+ (uint8) attr->decimals,
f_is_zerofill(attr->pack_flag) != 0,
f_is_dec(attr->pack_flag) == 0);
}
@@ -7349,11 +7720,12 @@ Field *Type_handler_newdecimal::
const Column_definition_attributes *attr,
uint32 flags) const
{
+ DBUG_ASSERT(f_decimals(attr->pack_flag) == 0);
return new (mem_root)
Field_new_decimal(rec.ptr(), (uint32) attr->length,
rec.null_ptr(), rec.null_bit(),
attr->unireg_check, name,
- f_decimals(attr->pack_flag),
+ (uint8) attr->decimals,
f_is_zerofill(attr->pack_flag) != 0,
f_is_dec(attr->pack_flag) == 0);
}
@@ -7366,7 +7738,8 @@ Field *Type_handler_float::
const Column_definition_attributes *attr,
uint32 flags) const
{
- int decimals= f_decimals(attr->pack_flag);
+ DBUG_ASSERT(f_decimals(attr->pack_flag) == 0);
+ uint decimals= attr->decimals;
if (decimals == FLOATING_POINT_DECIMALS)
decimals= NOT_FIXED_DEC;
return new (mem_root)
@@ -7385,7 +7758,8 @@ Field *Type_handler_double::
const Column_definition_attributes *attr,
uint32 flags) const
{
- int decimals= f_decimals(attr->pack_flag);
+ DBUG_ASSERT(f_decimals(attr->pack_flag) == 0);
+ uint decimals= attr->decimals;
if (decimals == FLOATING_POINT_DECIMALS)
decimals= NOT_FIXED_DEC;
return new (mem_root)
@@ -7489,6 +7863,7 @@ Field *Type_handler_timestamp::
const Column_definition_attributes *attr,
uint32 flags) const
{
+ DBUG_ASSERT(attr->decimals == attr->temporal_dec(MAX_DATETIME_WIDTH));
return new_Field_timestamp(mem_root,
rec.ptr(), rec.null_ptr(), rec.null_bit(),
attr->unireg_check, name, share,
@@ -7503,6 +7878,7 @@ Field *Type_handler_timestamp2::
const Column_definition_attributes *attr,
uint32 flags) const
{
+ DBUG_ASSERT(attr->decimals == attr->temporal_dec(MAX_DATETIME_WIDTH));
return new (mem_root)
Field_timestampf(rec.ptr(), rec.null_ptr(), rec.null_bit(),
attr->unireg_check,
@@ -7556,6 +7932,7 @@ Field *Type_handler_time::
const Column_definition_attributes *attr,
uint32 flags) const
{
+ DBUG_ASSERT(attr->decimals == attr->temporal_dec(MIN_TIME_WIDTH));
return new_Field_time(mem_root, rec.ptr(), rec.null_ptr(), rec.null_bit(),
attr->unireg_check, name,
attr->temporal_dec(MIN_TIME_WIDTH));
@@ -7569,6 +7946,7 @@ Field *Type_handler_time2::
const Column_definition_attributes *attr,
uint32 flags) const
{
+ DBUG_ASSERT(attr->decimals == attr->temporal_dec(MIN_TIME_WIDTH));
return new (mem_root)
Field_timef(rec.ptr(), rec.null_ptr(), rec.null_bit(),
attr->unireg_check, name,
@@ -7583,6 +7961,7 @@ Field *Type_handler_datetime::
const Column_definition_attributes *attr,
uint32 flags) const
{
+ DBUG_ASSERT(attr->decimals == attr->temporal_dec(MAX_DATETIME_WIDTH));
return new_Field_datetime(mem_root, rec.ptr(), rec.null_ptr(), rec.null_bit(),
attr->unireg_check, name,
attr->temporal_dec(MAX_DATETIME_WIDTH));
@@ -7596,6 +7975,7 @@ Field *Type_handler_datetime2::
const Column_definition_attributes *attr,
uint32 flags) const
{
+ DBUG_ASSERT(attr->decimals == attr->temporal_dec(MAX_DATETIME_WIDTH));
return new (mem_root)
Field_datetimef(rec.ptr(), rec.null_ptr(), rec.null_bit(),
attr->unireg_check, name,
@@ -7633,21 +8013,6 @@ Field *Type_handler_bit::
}
-#ifdef HAVE_SPATIAL
-Field *Type_handler_geometry::
- make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
- const LEX_CSTRING *name,
- const Record_addr &rec, const Bit_addr &bit,
- const Column_definition_attributes *attr,
- uint32 flags) const
-{
- status_var_increment(current_thd->status_var.feature_gis);
- return new (mem_root)
- Field_geom(rec.ptr(), rec.null_ptr(), rec.null_bit(),
- attr->unireg_check, name, share,
- attr->pack_flag_to_pack_length(), attr->geom_type, attr->srid);
-}
-#endif
Field *Type_handler_string::
@@ -7745,16 +8110,110 @@ void Type_handler::
}
-#ifdef HAVE_SPATIAL
-void Type_handler_geometry::
+void Type_handler_real_result::
Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
uchar *buff) const
{
- def->frm_pack_basic(buff);
- buff[11]= 0;
- buff[14]= (uchar) def->geom_type;
+ def->frm_pack_numeric_with_dec(buff);
+}
+
+
+void Type_handler_decimal_result::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ def->frm_pack_numeric_with_dec(buff);
+}
+
+
+void Type_handler_int_result::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
+ DBUG_ASSERT(def->decimals == 0);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_date_common::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
+ DBUG_ASSERT(def->decimals == 0);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_bit::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_TREAT_BIT_AS_CHAR) == 0);
+ DBUG_ASSERT(def->decimals == 0);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_blob_common::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_BLOB) == 0);
+ DBUG_ASSERT(def->decimals == 0 ||
+ def->decimals == NOT_FIXED_DEC);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_null::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
+ DBUG_ASSERT(def->decimals == NOT_FIXED_DEC);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_string_result::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
+ DBUG_ASSERT(def->decimals == 0 || def->decimals == NOT_FIXED_DEC);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_enum::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_INTERVAL) == 0);
+ DBUG_ASSERT(def->decimals == 0);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_set::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_BITFIELD) == 0);
+ DBUG_ASSERT(def->decimals == 0);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_temporal_result::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
}
-#endif
/***************************************************************************/
@@ -7771,89 +8230,60 @@ bool Type_handler::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
+bool Type_handler_real_result::
Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
TABLE_SHARE *share,
const uchar *buffer,
LEX_CUSTRING *gis_options)
const
{
- uint gis_opt_read, gis_length, gis_decimals;
- Field_geom::storage_type st_type;
- attr->frm_unpack_basic(buffer);
- // charset and geometry_type share the same byte in frm
- attr->geom_type= (Field::geometry_type) buffer[14];
- gis_opt_read= gis_field_options_read(gis_options->str,
- gis_options->length,
- &st_type, &gis_length,
- &gis_decimals, &attr->srid);
- gis_options->str+= gis_opt_read;
- gis_options->length-= gis_opt_read;
- return false;
+ return attr->frm_unpack_numeric_with_dec(share, buffer);
}
-#endif
-/***************************************************************************/
-bool Type_handler::Vers_history_point_resolve_unit(THD *thd,
- Vers_history_point *point)
- const
-{
- /*
- Disallow using non-relevant data types in history points.
- Even expressions with explicit TRANSACTION or TIMESTAMP units.
- */
- point->bad_expression_data_type_error(name().ptr());
- return true;
-}
-
-
-bool Type_handler_typelib::
- Vers_history_point_resolve_unit(THD *thd,
- Vers_history_point *point) const
-{
- /*
- ENUM/SET have dual type properties (string and numeric).
- Require explicit CAST to avoid ambiguity.
- */
- point->bad_expression_data_type_error(name().ptr());
- return true;
-}
-
-
-bool Type_handler_general_purpose_int::
- Vers_history_point_resolve_unit(THD *thd,
- Vers_history_point *point) const
+bool Type_handler_decimal_result::
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const
{
- return point->resolve_unit_trx_id(thd);
+ return attr->frm_unpack_numeric_with_dec(share, buffer);
}
-bool Type_handler_bit::
- Vers_history_point_resolve_unit(THD *thd,
- Vers_history_point *point) const
+bool Type_handler_time_common::
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const
{
- return point->resolve_unit_trx_id(thd);
+ return attr->frm_unpack_temporal_with_dec(share, MIN_TIME_WIDTH, buffer);
}
-bool Type_handler_temporal_result::
- Vers_history_point_resolve_unit(THD *thd,
- Vers_history_point *point) const
+bool Type_handler_datetime_common::
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const
{
- return point->resolve_unit_timestamp(thd);
+ return attr->frm_unpack_temporal_with_dec(share, MAX_DATETIME_WIDTH, buffer);
}
-bool Type_handler_general_purpose_string::
- Vers_history_point_resolve_unit(THD *thd,
- Vers_history_point *point) const
+bool Type_handler_timestamp_common::
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const
{
- return point->resolve_unit_timestamp(thd);
+ return attr->frm_unpack_temporal_with_dec(share, MAX_DATETIME_WIDTH, buffer);
}
-/***************************************************************************/
bool Type_handler_null::Item_const_eq(const Item_const *a,
const Item_const *b,
@@ -7932,14 +8362,7 @@ Type_handler_temporal_result::Item_const_eq(const Item_const *a,
const Type_handler *
Type_handler_hex_hybrid::cast_to_int_type_handler() const
{
- return &type_handler_longlong;
-}
-
-
-const Type_handler *
-Type_handler_hex_hybrid::type_handler_for_system_time() const
-{
- return &type_handler_longlong;
+ return &type_handler_ulonglong;
}
@@ -8346,6 +8769,233 @@ Type_handler_timestamp_common::Item_param_val_native(THD *thd,
}
+/***************************************************************************/
+
+bool Type_handler::validate_implicit_default_value(THD *thd,
+ const Column_definition &def) const
+{
+ DBUG_EXECUTE_IF("validate_implicit_default_value_error", return true;);
+ return false;
+}
+
+
+bool Type_handler_date_common::validate_implicit_default_value(THD *thd,
+ const Column_definition &def) const
+{
+ return thd->variables.sql_mode & MODE_NO_ZERO_DATE;
+}
+
+
+bool Type_handler_datetime_common::validate_implicit_default_value(THD *thd,
+ const Column_definition &def) const
+{
+ return thd->variables.sql_mode & MODE_NO_ZERO_DATE;
+}
+
+
+/***************************************************************************/
+
+const Name & Type_handler_row::default_value() const
+{
+ DBUG_ASSERT(0);
+ static Name def(STRING_WITH_LEN(""));
+ return def;
+}
+
+const Name & Type_handler_numeric::default_value() const
+{
+ static Name def(STRING_WITH_LEN("0"));
+ return def;
+}
+
+const Name & Type_handler_string_result::default_value() const
+{
+ static Name def(STRING_WITH_LEN(""));
+ return def;
+}
+
+const Name & Type_handler_time_common::default_value() const
+{
+ static Name def(STRING_WITH_LEN("00:00:00"));
+ return def;
+}
+
+const Name & Type_handler_date_common::default_value() const
+{
+ static Name def(STRING_WITH_LEN("0000-00-00"));
+ return def;
+}
+
+const Name & Type_handler_datetime_common::default_value() const
+{
+ static Name def(STRING_WITH_LEN("0000-00-00 00:00:00"));
+ return def;
+}
+
+const Name & Type_handler_timestamp_common::default_value() const
+{
+ static Name def(STRING_WITH_LEN("0000-00-00 00:00:00"));
+ return def;
+}
+
+/***************************************************************************/
+
+bool Type_handler::Column_definition_data_type_info_image(Binary_string *to,
+ const Column_definition &def)
+ const
+{
+ // Have *some* columns write type info (let's use string fields as an example)
+ DBUG_EXECUTE_IF("frm_data_type_info_emulate",
+ if (cmp_type() == STRING_RESULT)
+ return to->append("x", 1) ||
+ to->append(name().lex_cstring()););
+ if (type_collection() != &type_collection_std)
+ return to->append(name().lex_cstring());
+ return false;
+}
+
+
+/***************************************************************************/
+
+void
+Type_handler::partition_field_type_not_allowed(const LEX_CSTRING &field_name)
+{
+ my_error(ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD, MYF(0),
+ field_name.str);
+}
+
+
+bool
+Type_handler::partition_field_check_result_type(Item *item,
+ Item_result expected_type)
+{
+ if (item->result_type() != expected_type)
+ {
+ my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
+ return TRUE;
+ }
+ return false;
+}
+
+
+bool
+Type_handler_blob_common::partition_field_check(const LEX_CSTRING &field_name,
+ Item *item_expr) const
+{
+ my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR, MYF(0));
+ return true;
+}
+
+
+bool
+Type_handler_general_purpose_int::partition_field_append_value(
+ String *str,
+ Item *item_expr,
+ CHARSET_INFO *field_cs,
+ partition_value_print_mode_t mode)
+ const
+{
+ DBUG_ASSERT(item_expr->cmp_type() == INT_RESULT);
+ StringBuffer<21> tmp;
+ longlong value= item_expr->val_int();
+ tmp.set(value, system_charset_info);
+ return str->append(tmp);
+}
+
+
+/*
+ Append an Item value to a String using a desired mode.
+
+ @param [OUT] str The string to append the value to.
+ @param item_expr The item to get the value from
+ @param field_cs The character set of the value owner field.
+ @param mode The mode.
+ @retval true on error
+ @retval false on success
+
+ The value is added using system_charset_info (no matter what mode is).
+
+ (1) If mode is equal to PARTITION_VALUE_PRINT_MODE_FRM,
+ the value is appended as a pure ASCII string in the format '_latin1 0xdf',
+ i.e. a character set introducer followed by a hex hybrid.
+
+ Before appending, we value is first converted to field_cs.
+ a) If the conversion succeeds, the value is printed in its field_cs
+ represenation.
+ b) If the conversion fails, the value is printed without conversion,
+ using the original character set introducer followed by the original
+ string hex representation.
+ In this case, open_table_from_share() will later notice that
+ the value cannot be actually stored to the field, and report
+ the error. So here we don't need to report errors such as
+ ER_PARTITION_FUNCTION_IS_NOT_ALLOWED.
+
+ (2) If the mode is equal to PARTITION_VALUE_PRINT_SHOW,
+ then the value is needed for:
+ - SHOW CREATE TABLE, or
+ - the PARTITION_DESCRIPTION column in a
+ INFORMATION_SCHEMA.PARTITION query.
+
+ The value generated here will be later sent to the client and
+ therefore will be converted to the client character set in the protocol.
+
+ We try to generate the value as a simple quoted utf8 string without
+ introducers (e.g. 'utf8-string') when possible, to make it:
+ - as human readable as possible
+ - but still safe for mysqldump purposes.
+
+ Simple quoted utf8 string is generated when these two conditions are true
+ at the same time:
+ a) The value can be safely converted to utf8,
+ so we can return it without data loss from this function.
+ b) The value can be safely converted to the client character set,
+ so we can convert it later without data loss to the client character
+ set in the protocol.
+
+ If one of the conditions fail, the value is returned using
+ PARTITION_VALUE_PRINT_MODE_FRM representation. See (1).
+*/
+bool Type_handler::partition_field_append_value(
+ String *str,
+ Item *item_expr,
+ CHARSET_INFO *field_cs,
+ partition_value_print_mode_t mode)
+ const
+{
+ DBUG_ASSERT(cmp_type() != INT_RESULT);
+ StringBuffer<MAX_KEY_LENGTH> buf;
+ String *res;
+
+ if (!(res= item_expr->val_str(&buf)))
+ return str->append(STRING_WITH_LEN("NULL"), system_charset_info);
+
+ if (!res->length())
+ return str->append(STRING_WITH_LEN("''"), system_charset_info);
+
+ if (mode == PARTITION_VALUE_PRINT_MODE_FRM ||
+ !res->can_be_safely_converted_to(current_thd->
+ variables.character_set_client) ||
+ !res->can_be_safely_converted_to(system_charset_info))
+ {
+ StringBuffer<64> buf2;
+ uint cnverr2= 0;
+ buf2.copy(res->ptr(), res->length(), res->charset(), field_cs, &cnverr2);
+ if (!cnverr2)
+ return str->append_introducer_and_hex(buf2.charset(), buf2.lex_cstring());
+ return str->append_introducer_and_hex(res->charset(), res->lex_cstring());
+ }
+
+ StringBuffer<64> val(system_charset_info);
+ uint cnverr= 0;
+ val.copy(res->ptr(), res->length(), res->charset(),
+ system_charset_info, &cnverr);
+ append_unescaped(str, val.ptr(), val.length());
+ return false;
+}
+
+
+/***************************************************************************/
+
LEX_CSTRING Charset::collation_specific_name() const
{
/*
@@ -8391,3 +9041,16 @@ Charset::eq_collation_specific_names(CHARSET_INFO *cs) const
LEX_CSTRING name1= Charset(cs).collation_specific_name();
return name0.length && !cmp(&name0, &name1);
}
+
+int initialize_data_type_plugin(st_plugin_int *plugin)
+{
+ st_mariadb_data_type *data= (st_mariadb_data_type*) plugin->plugin->info;
+ data->type_handler->set_name(Name(plugin->name));
+ if (plugin->plugin->init && plugin->plugin->init(NULL))
+ {
+ sql_print_error("Plugin '%s' init function returned error.",
+ plugin->name.str);
+ return 1;
+ }
+ return 0;
+}
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 2be651a2f2f..c3a6a5f4ff5 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -2,6 +2,7 @@
#define SQL_TYPE_H_INCLUDED
/*
Copyright (c) 2015 MariaDB Foundation.
+ Copyright (c) 2015, 2020, 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
@@ -22,15 +23,21 @@
#include "mysqld.h"
+#include "lex_string.h"
#include "sql_array.h"
#include "sql_const.h"
#include "sql_time.h"
+#include "sql_type_string.h"
#include "sql_type_real.h"
#include "compat56.h"
+C_MODE_START
+#include <ma_dyncol.h>
+C_MODE_END
class Field;
class Column_definition;
class Column_definition_attributes;
+class Key_part_spec;
class Item;
class Item_const;
class Item_literal;
@@ -69,6 +76,7 @@ class Item_func_div;
class Item_func_mod;
class cmp_item;
class in_vector;
+class Type_handler_data;
class Type_handler_hybrid_field_type;
class Sort_param;
class Arg_comparator;
@@ -79,8 +87,13 @@ class handler;
struct Schema_specification_st;
struct TABLE;
struct SORT_FIELD_ATTR;
+struct SORT_FIELD;
class Vers_history_point;
class Virtual_column_info;
+class Conv_source;
+class ST_FIELD_INFO;
+class Type_collection;
+class Create_func;
#define my_charset_numeric my_charset_latin1
@@ -110,6 +123,133 @@ enum scalar_comparison_op
};
+enum partition_value_print_mode_t
+{
+ PARTITION_VALUE_PRINT_MODE_SHOW= 0,
+ PARTITION_VALUE_PRINT_MODE_FRM= 1
+};
+
+
+enum column_definition_type_t
+{
+ COLUMN_DEFINITION_TABLE_FIELD,
+ COLUMN_DEFINITION_ROUTINE_PARAM,
+ COLUMN_DEFINITION_ROUTINE_LOCAL,
+ COLUMN_DEFINITION_FUNCTION_RETURN
+};
+
+
+class Send_field_extended_metadata
+{
+ LEX_CSTRING m_attr[MARIADB_FIELD_ATTR_LAST+1];
+public:
+ Send_field_extended_metadata()
+ {
+ bzero(this, sizeof(*this));
+ }
+ bool set_data_type_name(const LEX_CSTRING &str)
+ {
+ m_attr[MARIADB_FIELD_ATTR_DATA_TYPE_NAME]= str;
+ return false;
+ }
+ bool set_format_name(const LEX_CSTRING &str)
+ {
+ m_attr[MARIADB_FIELD_ATTR_FORMAT_NAME]= str;
+ return false;
+ }
+ bool has_extended_metadata() const
+ {
+ for (uint i= 0; i <= MARIADB_FIELD_ATTR_LAST; i++)
+ {
+ if (m_attr[i].str)
+ return true;
+ }
+ return false;
+ }
+ const LEX_CSTRING &attr(uint i) const
+ {
+ DBUG_ASSERT(i <= MARIADB_FIELD_ATTR_LAST);
+ return m_attr[i];
+ }
+};
+
+
+class Data_type_statistics
+{
+public:
+ uint m_uneven_bit_length;
+ uint m_fixed_string_total_length;
+ uint m_fixed_string_count;
+ uint m_variable_string_total_length;
+ uint m_variable_string_count;
+ uint m_blob_count;
+ Data_type_statistics()
+ :m_uneven_bit_length(0),
+ m_fixed_string_total_length(0),
+ m_fixed_string_count(0),
+ m_variable_string_total_length(0),
+ m_variable_string_count(0),
+ m_blob_count(0)
+ { }
+ uint string_count() const
+ {
+ return m_fixed_string_count + m_variable_string_count;
+ }
+ uint string_total_length() const
+ {
+ return m_fixed_string_total_length + m_variable_string_total_length;
+ }
+};
+
+
+class Typelib: public TYPELIB
+{
+public:
+ Typelib(uint count, const char **type_names, unsigned int *type_lengths)
+ {
+ TYPELIB::count= count;
+ TYPELIB::name= "";
+ TYPELIB::type_names= type_names;
+ TYPELIB::type_lengths= type_lengths;
+ }
+ uint max_octet_length() const
+ {
+ uint max_length= 0;
+ for (uint i= 0; i < TYPELIB::count; i++)
+ {
+ const uint length= TYPELIB::type_lengths[i];
+ set_if_bigger(max_length, length);
+ }
+ return max_length;
+ }
+};
+
+
+template<uint sz>
+class TypelibBuffer: public Typelib
+{
+ const char *m_type_names[sz + 1];
+ uint m_type_lengths[sz + 1];
+public:
+ TypelibBuffer(uint count, const LEX_CSTRING *values)
+ :Typelib(count, m_type_names, m_type_lengths)
+ {
+ DBUG_ASSERT(sz >= count);
+ for (uint i= 0; i < count; i++)
+ {
+ DBUG_ASSERT(values[i].str != NULL);
+ m_type_names[i]= values[i].str;
+ m_type_lengths[i]= (uint) values[i].length;
+ }
+ m_type_names[sz]= NullS; // End marker
+ m_type_lengths[sz]= 0; // End marker
+ }
+ TypelibBuffer(const LEX_CSTRING *values)
+ :TypelibBuffer(sz, values)
+ { }
+};
+
+
class Native: public Binary_string
{
public:
@@ -581,7 +721,7 @@ public:
if (m_error)
return true;
to_hh24mmssff(ltime, MYSQL_TIMESTAMP_TIME);
- ltime->hour+= to_days_abs() * 24;
+ ltime->hour+= static_cast<unsigned>(to_days_abs() * 24);
return adjust_time_range_with_warn(thd, ltime, decimals);
}
bool to_datetime(MYSQL_TIME *ltime) const
@@ -766,7 +906,8 @@ protected:
my_decimal *to_decimal(my_decimal *to) const;
static double to_double(bool negate, ulonglong num, ulong frac)
{
- double d= (double) num + frac / (double) TIME_SECOND_PART_FACTOR;
+ double d= static_cast<double>(num) + static_cast<double>(frac) /
+ TIME_SECOND_PART_FACTOR;
return negate ? -d : d;
}
longlong to_packed() const { return ::pack_time(this); }
@@ -894,7 +1035,7 @@ protected:
{
return ::check_date(this, flags, warn);
}
- void time_hhmmssff_set_max(ulong max_hour)
+ void time_hhmmssff_set_max(uint max_hour)
{
hour= max_hour;
minute= TIME_MAX_MINUTE;
@@ -2631,9 +2772,7 @@ public:
{ }
void set(const DTCollation &dt)
{
- collation= dt.collation;
- derivation= dt.derivation;
- repertoire= dt.repertoire;
+ *this= dt;
}
void set(CHARSET_INFO *collation_arg, Derivation derivation_arg)
{
@@ -2649,12 +2788,6 @@ public:
derivation= derivation_arg;
repertoire= repertoire_arg;
}
- void set_numeric()
- {
- collation= &my_charset_numeric;
- derivation= DERIVATION_NUMERIC;
- repertoire= MY_REPERTOIRE_NUMERIC;
- }
void set(CHARSET_INFO *collation_arg)
{
collation= collation_arg;
@@ -2679,15 +2812,25 @@ public:
default: return "UNKNOWN";
}
}
- int sortcmp(const String *s, const String *t) const
+ int sortcmp(const Binary_string *s, const Binary_string *t) const
{
- return collation->coll->strnncollsp(collation,
- (uchar *) s->ptr(), s->length(),
- (uchar *) t->ptr(), t->length());
+ return collation->strnncollsp(s->ptr(), s->length(),
+ t->ptr(), t->length());
}
};
+class DTCollation_numeric: public DTCollation
+{
+public:
+ DTCollation_numeric()
+ :DTCollation(charset_info(), DERIVATION_NUMERIC, MY_REPERTOIRE_NUMERIC)
+ { }
+ static const CHARSET_INFO *charset_info() { return &my_charset_numeric; }
+ static const DTCollation & singleton();
+};
+
+
static inline uint32
char_to_byte_length_safe(size_t char_length_arg, uint32 mbmaxlen_arg)
{
@@ -2695,38 +2838,87 @@ char_to_byte_length_safe(size_t char_length_arg, uint32 mbmaxlen_arg)
return tmp > UINT_MAX32 ? (uint32) UINT_MAX32 : static_cast<uint32>(tmp);
}
-/**
- A class to store type attributes for the standard data types.
- Does not include attributes for the extended data types
- such as ENUM, SET, GEOMETRY.
-*/
-class Type_std_attributes
+
+class Type_numeric_attributes
{
public:
- DTCollation collation;
- uint decimals;
+ static uint count_unsigned(Item **item, uint nitems);
+ static uint32 find_max_char_length(Item **item, uint nitems);
+ static uint32 find_max_octet_length(Item **item, uint nitems);
+ static int find_max_decimal_int_part(Item **item, uint nitems);
+ static uint find_max_decimals(Item **item, uint nitems);
+public:
/*
The maximum value length in characters multiplied by collation->mbmaxlen.
Almost always it's the maximum value length in bytes.
*/
uint32 max_length;
+ uint decimals;
bool unsigned_flag;
- Type_std_attributes()
- :collation(&my_charset_bin, DERIVATION_COERCIBLE),
- decimals(0), max_length(0), unsigned_flag(false)
+public:
+ Type_numeric_attributes()
+ :max_length(0), decimals(0), unsigned_flag(false)
{ }
- Type_std_attributes(const Type_std_attributes *other)
- :collation(other->collation),
- decimals(other->decimals),
- max_length(other->max_length),
- unsigned_flag(other->unsigned_flag)
+ Type_numeric_attributes(uint32 max_length_arg, uint decimals_arg,
+ bool unsigned_flag_arg)
+ :max_length(max_length_arg),
+ decimals(decimals_arg),
+ unsigned_flag(unsigned_flag_arg)
{ }
- Type_std_attributes(uint32 max_length_arg, uint decimals_arg,
- bool unsigned_flag_arg, const DTCollation &dtc)
- :collation(dtc),
- decimals(decimals_arg),
- max_length(max_length_arg),
- unsigned_flag(unsigned_flag_arg)
+protected:
+ void aggregate_numeric_attributes_real(Item **item, uint nitems);
+ void aggregate_numeric_attributes_decimal(Item **item, uint nitems,
+ bool unsigned_arg);
+};
+
+
+
+class Type_temporal_attributes: public Type_numeric_attributes
+{
+public:
+ Type_temporal_attributes(uint int_part_length, uint dec, bool unsigned_arg)
+ :Type_numeric_attributes(int_part_length + (dec ? 1 : 0),
+ MY_MIN(dec, TIME_SECOND_PART_DIGITS),
+ unsigned_arg)
+ {
+ max_length+= decimals;
+ }
+};
+
+
+class Type_temporal_attributes_not_fixed_dec: public Type_numeric_attributes
+{
+public:
+ Type_temporal_attributes_not_fixed_dec(uint32 int_part_length, uint dec,
+ bool unsigned_flag)
+ :Type_numeric_attributes(int_part_length, dec, unsigned_flag)
+ {
+ if (decimals == NOT_FIXED_DEC)
+ max_length+= TIME_SECOND_PART_DIGITS + 1;
+ else if (decimals)
+ {
+ set_if_smaller(decimals, TIME_SECOND_PART_DIGITS);
+ max_length+= decimals + 1;
+ }
+ }
+};
+
+
+/**
+ A class to store type attributes for the standard data types.
+ Does not include attributes for the extended data types
+ such as ENUM, SET, GEOMETRY.
+*/
+class Type_std_attributes: public Type_numeric_attributes
+{
+public:
+ DTCollation collation;
+ Type_std_attributes()
+ :collation(&my_charset_bin, DERIVATION_COERCIBLE)
+ { }
+ Type_std_attributes(const Type_numeric_attributes &nattr,
+ const DTCollation &dtc)
+ :Type_numeric_attributes(nattr), collation(dtc)
{ }
void set(const Type_std_attributes *other)
{
@@ -2736,6 +2928,10 @@ public:
{
*this= other;
}
+ void set(const Type_numeric_attributes &nattr, const DTCollation &dtc)
+ {
+ *this= Type_std_attributes(nattr, dtc);
+ }
uint32 max_char_length() const
{ return max_length / collation.collation->mbmaxlen; }
void fix_length_and_charset(uint32 max_char_length_arg, CHARSET_INFO *cs)
@@ -2748,41 +2944,11 @@ public:
max_length= char_to_byte_length_safe(max_char_length_arg,
collation.collation->mbmaxlen);
}
- void fix_char_length_temporal_not_fixed_dec(uint int_part_length, uint dec)
- {
- uint char_length= int_part_length;
- if ((decimals= dec))
- {
- if (decimals == NOT_FIXED_DEC)
- char_length+= TIME_SECOND_PART_DIGITS + 1;
- else
- {
- set_if_smaller(decimals, TIME_SECOND_PART_DIGITS);
- char_length+= decimals + 1;
- }
- }
- fix_char_length(char_length);
- }
- void fix_attributes_temporal_not_fixed_dec(uint int_part_length, uint dec)
- {
- collation.set_numeric();
- unsigned_flag= 0;
- fix_char_length_temporal_not_fixed_dec(int_part_length, dec);
- }
- void fix_attributes_time_not_fixed_dec(uint dec)
- {
- fix_attributes_temporal_not_fixed_dec(MIN_TIME_WIDTH, dec);
- }
- void fix_attributes_datetime_not_fixed_dec(uint dec)
- {
- fix_attributes_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec);
- }
- void fix_attributes_temporal(uint int_part_length, uint dec)
+ void fix_attributes_temporal(uint32 int_part_length, uint dec)
{
- collation.set_numeric();
- unsigned_flag= 0;
- decimals= MY_MIN(dec, TIME_SECOND_PART_DIGITS);
- max_length= decimals + int_part_length + (dec ? 1 : 0);
+ *this= Type_std_attributes(
+ Type_temporal_attributes(int_part_length, dec, false),
+ DTCollation_numeric());
}
void fix_attributes_date()
{
@@ -2797,38 +2963,31 @@ public:
fix_attributes_temporal(MAX_DATETIME_WIDTH, dec);
}
- void count_only_length(Item **item, uint nitems);
- void count_octet_length(Item **item, uint nitems);
- void count_real_length(Item **item, uint nitems);
- void count_decimal_length(Item **item, uint nitems);
- bool count_string_length(const char *func_name, Item **item, uint nitems);
- uint count_max_decimals(Item **item, uint nitems);
-
void aggregate_attributes_int(Item **items, uint nitems)
{
- collation.set_numeric();
- count_only_length(items, nitems);
+ collation= DTCollation_numeric();
+ fix_char_length(find_max_char_length(items, nitems));
+ unsigned_flag= count_unsigned(items, nitems) > 0;
decimals= 0;
}
void aggregate_attributes_real(Item **items, uint nitems)
{
- collation.set_numeric();
- count_real_length(items, nitems);
+ collation= DTCollation_numeric();
+ aggregate_numeric_attributes_real(items, nitems);
}
- void aggregate_attributes_decimal(Item **items, uint nitems)
+ void aggregate_attributes_decimal(Item **items, uint nitems,
+ bool unsigned_arg)
{
- collation.set_numeric();
- count_decimal_length(items, nitems);
+ collation= DTCollation_numeric();
+ aggregate_numeric_attributes_decimal(items, nitems,
+ (unsigned_flag= unsigned_arg));
}
bool aggregate_attributes_string(const char *func_name,
- Item **item, uint nitems)
- {
- return count_string_length(func_name, item, nitems);
- }
+ Item **item, uint nitems);
void aggregate_attributes_temporal(uint int_part_length,
Item **item, uint nitems)
{
- fix_attributes_temporal(int_part_length, count_max_decimals(item, nitems));
+ fix_attributes_temporal(int_part_length, find_max_decimals(item, nitems));
}
bool agg_item_collations(DTCollation &c, const char *name,
@@ -2932,23 +3091,15 @@ public:
Type_all_attributes()
:Type_std_attributes()
{ }
- Type_all_attributes(const Type_all_attributes *other)
+ Type_all_attributes(const Type_all_attributes &other)
:Type_std_attributes(other)
{ }
virtual ~Type_all_attributes() {}
virtual void set_maybe_null(bool maybe_null_arg)= 0;
// Returns total number of decimal digits
virtual uint decimal_precision() const= 0;
- /*
- Field::geometry_type is not visible here.
- Let's use an "uint" wrapper for now. Later when we move Field_geom
- into a plugin, this method will be replaced to some generic
- datatype indepented method.
- */
- virtual uint uint_geometry_type() const= 0;
- virtual void set_geometry_type(uint type)= 0;
- virtual TYPELIB *get_typelib() const= 0;
- virtual void set_typelib(TYPELIB *typelib)= 0;
+ virtual const TYPELIB *get_typelib() const= 0;
+ virtual void set_typelib(const TYPELIB *typelib)= 0;
};
@@ -3007,8 +3158,19 @@ public:
LEX_CSTRING::str= str_arg;
LEX_CSTRING::length= length_arg;
}
+ Name(const LEX_CSTRING &lcs)
+ {
+ LEX_CSTRING::str= lcs.str;
+ LEX_CSTRING::length= lcs.length;
+ }
const char *ptr() const { return LEX_CSTRING::str; }
uint length() const { return (uint) LEX_CSTRING::length; }
+ const LEX_CSTRING &lex_cstring() const { return *this; }
+ bool eq(const LEX_CSTRING &other) const
+ {
+ return !system_charset_info->strnncoll(LEX_CSTRING::str, LEX_CSTRING::length,
+ other.str, other.length);
+ }
};
@@ -3040,7 +3202,7 @@ public:
{ }
uchar *ptr() const { return m_ptr; }
uchar offs() const { return m_offs; }
- uchar bit() const { return m_ptr ? ((uchar) 1) << m_offs : 0; }
+ uchar bit() const { return static_cast<uchar>(m_ptr ? 1U << m_offs : 0); }
void inc()
{
DBUG_ASSERT(m_ptr);
@@ -3144,12 +3306,63 @@ public:
};
+enum vers_kind_t
+{
+ VERS_UNDEFINED= 0,
+ VERS_TIMESTAMP,
+ VERS_TRX_ID
+};
+
+
+class Vers_type_handler
+{
+protected:
+ Vers_type_handler() {}
+public:
+ virtual ~Vers_type_handler() {}
+ virtual vers_kind_t kind() const
+ {
+ DBUG_ASSERT(0);
+ return VERS_UNDEFINED;
+ }
+ virtual bool check_sys_fields(const LEX_CSTRING &table_name,
+ const Column_definition *row_start,
+ const Column_definition *row_end) const= 0;
+};
+
+
+class Vers_type_timestamp: public Vers_type_handler
+{
+public:
+ virtual vers_kind_t kind() const
+ {
+ return VERS_TIMESTAMP;
+ }
+ bool check_sys_fields(const LEX_CSTRING &table_name,
+ const Column_definition *row_start,
+ const Column_definition *row_end) const;
+};
+extern Vers_type_timestamp vers_type_timestamp;
+
+
+class Vers_type_trx: public Vers_type_handler
+{
+public:
+ virtual vers_kind_t kind() const
+ {
+ return VERS_TRX_ID;
+ }
+ bool check_sys_fields(const LEX_CSTRING &table_name,
+ const Column_definition *row_start,
+ const Column_definition *row_end) const;
+};
+extern MYSQL_PLUGIN_IMPORT Vers_type_trx vers_type_trx;
+
+
class Type_handler
{
+ Name m_name;
protected:
- static const Name m_version_default;
- static const Name m_version_mysql56;
- static const Name m_version_mariadb53;
String *print_item_value_csstr(THD *thd, Item *item, String *str) const;
String *print_item_value_temporal(THD *thd, Item *item, String *str,
const Name &type_name, String *buf) const;
@@ -3157,10 +3370,16 @@ protected:
bool maybe_null, bool null_value,
bool unsigned_flag,
longlong value) const;
- bool
- Item_func_or_sum_illegal_param(const char *name) const;
- bool
- Item_func_or_sum_illegal_param(const Item_func_or_sum *) const;
+ void store_sort_key_longlong(uchar *to, bool unsigned_flag,
+ longlong value) const;
+
+ uint make_packed_sort_key_longlong(uchar *to, bool maybe_null,
+ bool null_value, bool unsigned_flag,
+ longlong value,
+ const SORT_FIELD_ATTR *sort_field) const;
+
+ bool Item_func_or_sum_illegal_param(const char *name) const;
+ bool Item_func_or_sum_illegal_param(const Item_func_or_sum *) const;
bool check_null(const Item *item, st_value *value) const;
bool Item_send_str(Item *item, Protocol *protocol, st_value *buf) const;
bool Item_send_tiny(Item *item, Protocol *protocol, st_value *buf) const;
@@ -3183,11 +3402,15 @@ protected:
enum_field_types type)
const;
public:
+ static const Type_handler *handler_by_name(THD *thd, const LEX_CSTRING &name);
+ static const Type_handler *handler_by_name_or_error(THD *thd,
+ const LEX_CSTRING &name);
static const Type_handler *odbc_literal_type_handler(const LEX_CSTRING *str);
static const Type_handler *blob_type_handler(uint max_octet_length);
static const Type_handler *string_type_handler(uint max_octet_length);
static const Type_handler *bit_and_int_mixture_handler(uint max_char_len);
- static const Type_handler *type_handler_long_or_longlong(uint max_char_len);
+ static const Type_handler *type_handler_long_or_longlong(uint max_char_len,
+ bool unsigned_flag);
/**
Return a string type handler for Item
If too_big_for_varchar() returns a BLOB variant, according to length.
@@ -3200,24 +3423,26 @@ public:
static const Type_handler *get_handler_by_field_type(enum_field_types type);
static const Type_handler *get_handler_by_real_type(enum_field_types type);
static const Type_handler *get_handler_by_cmp_type(Item_result type);
- static const Type_handler *get_handler_by_result_type(Item_result type)
- {
- /*
- As result_type() returns STRING_RESULT for temporal Items,
- type should never be equal to TIME_RESULT here.
- */
- DBUG_ASSERT(type != TIME_RESULT);
- return get_handler_by_cmp_type(type);
- }
+ static const Type_collection *
+ type_collection_for_aggregation(const Type_handler *h1,
+ const Type_handler *h2);
+ virtual const Type_collection *type_collection() const;
static const
Type_handler *aggregate_for_result_traditional(const Type_handler *h1,
const Type_handler *h2);
- static const
- Type_handler *aggregate_for_num_op_traditional(const Type_handler *h1,
- const Type_handler *h2);
-
- virtual const Name name() const= 0;
- virtual const Name version() const { return m_version_default; }
+ static void partition_field_type_not_allowed(const LEX_CSTRING &field_name);
+ static bool partition_field_check_result_type(Item *item,
+ Item_result expected_type);
+ static const Name & version_mysql56();
+ static const Name & version_mariadb53();
+
+ void set_name(Name n) { DBUG_ASSERT(!m_name.ptr()); m_name= n; }
+ const Name name() const { return m_name; }
+ virtual const Name version() const;
+ virtual const Name &default_value() const= 0;
+ virtual uint32 flags() const { return 0; }
+ virtual ulong KEY_pack_flags(uint column_nr) const { return 0; }
+ bool is_unsigned() const { return flags() & UNSIGNED_FLAG; }
virtual enum_field_types field_type() const= 0;
virtual enum_field_types real_field_type() const { return field_type(); }
/**
@@ -3239,7 +3464,7 @@ public:
*/
virtual enum_field_types traditional_merge_field_type() const
{
- DBUG_ASSERT(is_traditional_type());
+ DBUG_ASSERT(is_traditional_scalar_type());
return field_type();
}
virtual enum_field_types type_code_for_protocol() const
@@ -3247,8 +3472,15 @@ public:
return field_type();
}
virtual protocol_send_type_t protocol_send_type() const= 0;
+ virtual bool Item_append_extended_type_info(Send_field_extended_metadata *to,
+ const Item *item) const
+ {
+ return false;
+ }
virtual Item_result result_type() const= 0;
virtual Item_result cmp_type() const= 0;
+ virtual enum_dynamic_column_type
+ dyncol_type(const Type_all_attributes *attr) const= 0;
virtual enum_mysql_timestamp_type mysql_timestamp_type() const
{
return MYSQL_TIMESTAMP_ERROR;
@@ -3263,6 +3495,16 @@ public:
{
return false;
}
+ /*
+ If operations such as:
+ UPDATE t1 SET binary_string_field=this_type_field;
+ should store this_type_field->val_native() rather than
+ this_type_field->val_str().
+ */
+ virtual bool convert_to_binary_using_val_native() const
+ {
+ return false;
+ }
virtual bool is_timestamp_type() const
{
return false;
@@ -3329,10 +3571,25 @@ public:
{
return this;
}
- virtual const Type_handler *type_handler_for_system_time() const
+ virtual const Type_handler *type_handler_unsigned() const
+ {
+ return this;
+ }
+ virtual const Type_handler *type_handler_signed() const
{
return this;
}
+ virtual bool partition_field_check(const LEX_CSTRING &field_name,
+ Item *item_expr) const
+ {
+ partition_field_type_not_allowed(field_name);
+ return true;
+ }
+ virtual bool partition_field_append_value(String *str,
+ Item *item_expr,
+ CHARSET_INFO *field_cs,
+ partition_value_print_mode_t mode)
+ const;
virtual int
stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const= 0;
virtual CHARSET_INFO *charset_for_protocol(const Item *item) const;
@@ -3344,15 +3601,13 @@ public:
{
return false;
}
+ Type_handler() : m_name(0,0) {}
virtual ~Type_handler() {}
/**
- Determines MariaDB traditional data types that always present
+ Determines MariaDB traditional scalar data types that always present
in the server.
*/
- virtual bool is_traditional_type() const
- {
- return true;
- }
+ bool is_traditional_scalar_type() const;
virtual bool is_scalar_type() const { return true; }
virtual bool can_return_int() const { return true; }
virtual bool can_return_decimal() const { return true; }
@@ -3405,9 +3660,13 @@ public:
This information is not available in the binary log, so
we assume that these fields are the same on the master and on the slave.
*/
- virtual Field *make_conversion_table_field(TABLE *TABLE,
+ virtual Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target) const= 0;
+ virtual void show_binlog_type(const Conv_source &src, const Field &dst,
+ String *str) const;
+ virtual uint32 max_display_length_for_field(const Conv_source &src) const= 0;
/*
Performs the final data type validation for a UNION element,
after the regular "aggregation for result" was done.
@@ -3416,6 +3675,19 @@ public:
{
return false;
}
+ virtual uint Column_definition_gis_options_image(uchar *buff,
+ const Column_definition &def)
+ const
+ {
+ return 0;
+ }
+ virtual bool Column_definition_data_type_info_image(Binary_string *to,
+ const Column_definition &def)
+ const;
+ // Check if the implicit default value is Ok in the current sql_mode
+ virtual bool validate_implicit_default_value(THD *thd,
+ const Column_definition &def)
+ const;
// Automatic upgrade, e.g. for ALTER TABLE t1 FORCE
virtual void Column_definition_implicit_upgrade(Column_definition *c) const
{ }
@@ -3423,6 +3695,13 @@ public:
virtual bool Column_definition_validate_check_constraint(THD *thd,
Column_definition *c)
const;
+ // Set attributes in the parser
+ virtual bool Column_definition_set_attributes(THD *thd,
+ Column_definition *def,
+ const Lex_field_type_st &attr,
+ CHARSET_INFO *cs,
+ column_definition_type_t type)
+ const;
// Fix attributes after the parser
virtual bool Column_definition_fix_attributes(Column_definition *c) const= 0;
/*
@@ -3464,14 +3743,45 @@ public:
virtual bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
ulonglong table_flags) const= 0;
- virtual Field *make_table_field(const LEX_CSTRING *name,
+ virtual bool Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const;
+ virtual bool Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *has_key_needed) const;
+ virtual bool Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const;
+ virtual bool Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const;
+ virtual bool Key_part_spec_init_spatial(Key_part_spec *part,
+ const Column_definition &def) const;
+ virtual bool Key_part_spec_init_ft(Key_part_spec *part,
+ const Column_definition &def) const
+ {
+ return true; // Error
+ }
+ virtual Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const= 0;
- Field *make_and_init_table_field(const LEX_CSTRING *name,
+ TABLE_SHARE *share) const= 0;
+ Field *make_and_init_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ virtual Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+ {
+ DBUG_ASSERT(0);
+ return NULL;
+ }
virtual Field *
make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
@@ -3483,22 +3793,40 @@ public:
virtual void
Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
uchar *buff) const;
+ virtual const Type_handler *type_handler_frm_unpack(const uchar *buffer) const
+ {
+ return this;
+ }
virtual bool
Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
TABLE_SHARE *share,
const uchar *buffer,
LEX_CUSTRING *gis_options) const;
- virtual void make_sort_key(uchar *to, Item *item,
- const SORT_FIELD_ATTR *sort_field,
- Sort_param *param) const= 0;
- virtual void sortlength(THD *thd,
+ /*
+ Create a fixed size key part for a sort key
+ */
+ virtual void make_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const= 0;
+
+ /*
+ create a compact size key part for a sort key
+ */
+ virtual uint make_packed_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const=0;
+
+ virtual void sort_length(THD *thd,
const Type_std_attributes *item,
SORT_FIELD_ATTR *attr) const= 0;
+ virtual bool is_packable() const { return false; }
+
virtual uint32 max_display_length(const Item *item) const= 0;
virtual uint32 Item_decimal_notation_int_digits(const Item *item) const { return 0; }
virtual uint32 calc_pack_length(uint32 length) const= 0;
+ virtual uint calc_key_length(const Column_definition &def) const;
virtual void Item_update_null_value(Item *item) 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 {}
@@ -3581,6 +3909,10 @@ public:
Item *src,
const Item *cmp) const= 0;
virtual Item_cache *Item_get_cache(THD *thd, const Item *item) const= 0;
+ virtual Item *make_constructor_item(THD *thd, List<Item> *args) const
+ {
+ return NULL;
+ }
/**
A builder for literals with data type name prefix, e.g.:
TIME'00:00:00', DATE'2001-01-01', TIMESTAMP'2001-01-01 00:00:00'.
@@ -3610,7 +3942,6 @@ public:
virtual Item *create_typecast_item(THD *thd, Item *item,
const Type_cast_attributes &attr) const
{
- DBUG_ASSERT(0);
return NULL;
}
virtual Item_copy *create_item_copy(THD *thd, Item *item) const;
@@ -3758,8 +4089,7 @@ public:
virtual bool
Item_func_mod_fix_length_and_dec(Item_func_mod *func) const= 0;
- virtual bool
- Vers_history_point_resolve_unit(THD *thd, Vers_history_point *point) const;
+ virtual const Vers_type_handler *vers() const { return NULL; }
};
@@ -3768,67 +4098,82 @@ public:
*/
class Type_handler_row: public Type_handler
{
- static const Name m_name_row;
public:
virtual ~Type_handler_row() {}
- const Name name() const { return m_name_row; }
- bool is_scalar_type() const { return false; }
- bool can_return_int() const { return false; }
- bool can_return_decimal() const { return false; }
- bool can_return_real() const { return false; }
- bool can_return_str() const { return false; }
- bool can_return_text() const { return false; }
- bool can_return_date() const { return false; }
- bool can_return_time() const { return false; }
- enum_field_types field_type() const
+ const Name &default_value() const override;
+ bool validate_implicit_default_value(THD *thd,
+ const Column_definition &def) const
+ override
+ {
+ DBUG_ASSERT(0);
+ return true;
+ }
+ const Type_collection *type_collection() const override;
+ bool is_scalar_type() const override { return false; }
+ bool can_return_int() const override { return false; }
+ bool can_return_decimal() const override { return false; }
+ bool can_return_real() const override { return false; }
+ bool can_return_str() const override { return false; }
+ bool can_return_text() const override { return false; }
+ bool can_return_date() const override { return false; }
+ bool can_return_time() const override { return false; }
+ enum_field_types field_type() const override
{
DBUG_ASSERT(0);
return MYSQL_TYPE_NULL;
};
- protocol_send_type_t protocol_send_type() const
+ protocol_send_type_t protocol_send_type() const override
{
DBUG_ASSERT(0);
return PROTOCOL_SEND_STRING;
}
- Item_result result_type() const
+ Item_result result_type() const override
{
return ROW_RESULT;
}
- Item_result cmp_type() const
+ Item_result cmp_type() const override
{
return ROW_RESULT;
}
- const Type_handler *type_handler_for_comparison() const;
- int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ DBUG_ASSERT(0);
+ return DYN_COL_NULL;
+ }
+ const Type_handler *type_handler_for_comparison() const override;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const override
{
DBUG_ASSERT(0);
return 0;
}
bool subquery_type_allows_materialization(const Item *inner,
- const Item *outer) const
+ const Item *outer) const override
{
DBUG_ASSERT(0);
return false;
}
- Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const
+ Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const override
{
DBUG_ASSERT(0);
return NULL;
}
- Field *make_conversion_table_field(TABLE *TABLE,
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
- const Field *target) const
+ const Field *target) const override
{
DBUG_ASSERT(0);
return NULL;
}
- bool Column_definition_fix_attributes(Column_definition *c) const
+ bool Column_definition_fix_attributes(Column_definition *c) const override
{
return false;
}
void Column_definition_reuse_fix_attributes(THD *thd,
Column_definition *c,
- const Field *field) const
+ const Field *field)
+ const override
{
DBUG_ASSERT(0);
}
@@ -3836,26 +4181,27 @@ public:
MEM_ROOT *mem_root,
Column_definition *c,
handler *file,
- ulonglong table_flags) const;
+ ulonglong table_flags) const override;
bool Column_definition_redefine_stage1(Column_definition *def,
const Column_definition *dup,
const handler *file,
const Schema_specification_st *schema)
- const
+ const override
{
DBUG_ASSERT(0);
return true;
}
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{
return false;
}
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE_SHARE *share) const override
{
DBUG_ASSERT(0);
return NULL;
@@ -3866,145 +4212,162 @@ public:
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
- void make_sort_key(uchar *to, Item *item,
- const SORT_FIELD_ATTR *sort_field,
- Sort_param *param) const
+ uint32 flags) const override;
+ void make_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const override
+ {
+ DBUG_ASSERT(0);
+ }
+ uint make_packed_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const override
{
DBUG_ASSERT(0);
+ return 0;
}
- void sortlength(THD *thd, const Type_std_attributes *item,
- SORT_FIELD_ATTR *attr) const
+ void sort_length(THD *thd, const Type_std_attributes *item,
+ SORT_FIELD_ATTR *attr) const override
{
DBUG_ASSERT(0);
}
- uint32 max_display_length(const Item *item) const
+ uint32 max_display_length(const Item *item) const override
{
DBUG_ASSERT(0);
return 0;
}
- uint32 calc_pack_length(uint32 length) const
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ {
+ DBUG_ASSERT(0);
+ return 0;
+ }
+ uint32 calc_pack_length(uint32 length) const override
{
DBUG_ASSERT(0);
return 0;
}
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
- Item *a, Item *b) const;
- uint Item_decimal_precision(const Item *item) const
+ Item *a, Item *b) const override;
+ uint Item_decimal_precision(const Item *item) const override
{
DBUG_ASSERT(0);
return DECIMAL_MAX_PRECISION;
}
- bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
- const st_value *value) const;
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ const st_value *value) const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
DBUG_ASSERT(0);
return true;
}
- void Item_update_null_value(Item *item) const;
- int Item_save_in_field(Item *item, Field *field, bool no_conversions) const
+ void Item_update_null_value(Item *item) const override;
+ int Item_save_in_field(Item *item, Field *field, bool no_conversions)
+ const override
{
DBUG_ASSERT(0);
return 1;
}
- String *print_item_value(THD *thd, Item *item, String *str) const;
+ String *print_item_value(THD *thd, Item *item, String *str) const override;
bool can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
Item_bool_func2 *source,
- Item *source_expr, Item *source_const) const
+ Item *source_expr, Item *source_const)
+ const override
{
DBUG_ASSERT(0);
return false;
}
- Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
- Item_copy *create_item_copy(THD *thd, Item *item) const
+ Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp)
+ const override;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
+ Item_copy *create_item_copy(THD *thd, Item *item) const override
{
DBUG_ASSERT(0);
return NULL;
}
- bool set_comparator_func(Arg_comparator *cmp) const;
+ bool set_comparator_func(Arg_comparator *cmp) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- Item **items, uint nitems) const
+ Item **items, uint nitems)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
+ bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const
+ bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const
+ bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const
+ bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_val_bool(Item *item) const
+ bool Item_val_bool(Item *item) const override
{
DBUG_ASSERT(0);
return false;
}
void Item_get_date(THD *thd, Item *item,
Temporal::Warn *warn, MYSQL_TIME *ltime,
- date_mode_t fuzzydate) const
+ date_mode_t fuzzydate) const override
{
DBUG_ASSERT(0);
set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
}
- longlong Item_val_int_signed_typecast(Item *item) const
+ longlong Item_val_int_signed_typecast(Item *item) const override
{
DBUG_ASSERT(0);
return 0;
}
- longlong Item_val_int_unsigned_typecast(Item *item) const
+ longlong Item_val_int_unsigned_typecast(Item *item) const override
{
DBUG_ASSERT(0);
return 0;
}
- String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const
+ String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str)
+ const override
{
DBUG_ASSERT(0);
return NULL;
}
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
- String *) const
+ String *) const override
{
DBUG_ASSERT(0);
return NULL;
}
double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
- const
+ const override
{
DBUG_ASSERT(0);
return 0.0;
}
longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
- const
+ const override
{
DBUG_ASSERT(0);
return 0;
}
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
- my_decimal *) const
+ my_decimal *) const override
{
DBUG_ASSERT(0);
return NULL;
@@ -4013,105 +4376,116 @@ public:
Item_func_hybrid_field_type *,
Temporal::Warn *,
MYSQL_TIME *ltime,
- date_mode_t fuzzydate) const
+ date_mode_t fuzzydate)
+ const override
{
DBUG_ASSERT(0);
set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
}
- String *Item_func_min_max_val_str(Item_func_min_max *, String *) const
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override
{
DBUG_ASSERT(0);
return NULL;
}
- double Item_func_min_max_val_real(Item_func_min_max *) const
+ double Item_func_min_max_val_real(Item_func_min_max *) const override
{
DBUG_ASSERT(0);
return 0;
}
- longlong Item_func_min_max_val_int(Item_func_min_max *) const
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const override
{
DBUG_ASSERT(0);
return 0;
}
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
- my_decimal *) const
+ my_decimal *) const override
{
DBUG_ASSERT(0);
return NULL;
}
bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
- MYSQL_TIME *, date_mode_t fuzzydate) const
+ MYSQL_TIME *, date_mode_t fuzzydate)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_func_between_fix_length_and_dec(Item_func_between *func) const
+ bool Item_func_between_fix_length_and_dec(Item_func_between *func)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- longlong Item_func_between_val_int(Item_func_between *func) const;
- cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
- in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs) const;
- bool Item_func_in_fix_comparator_compatible_types(THD *thd,
- Item_func_in *) const;
- bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
- bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
- bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
- bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
+ longlong Item_func_between_val_int(Item_func_between *func) const override;
+ cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
+ in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs)
+ const override;
+ bool Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *)
+ const override;
+ bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
+ bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const override;
+ bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override;
+ bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override;
- bool Item_func_signed_fix_length_and_dec(Item_func_signed *) const
+ bool Item_func_signed_fix_length_and_dec(Item_func_signed *) const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *) const
+ bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *) const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *) const
+ bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *) const
+ bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *) const
+ bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const
+ bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *) const
+ bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *) const
+ bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *) const
+ bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const;
- bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const;
- bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
- bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
- bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
+ bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override;
+ bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override;
+ bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override;
+ bool Item_func_div_fix_length_and_dec(Item_func_div *) const override;
+ bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override;
};
@@ -4121,20 +4495,23 @@ public:
class Type_handler_numeric: public Type_handler
{
public:
- String *print_item_value(THD *thd, Item *item, String *str) 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;
+ const Name &default_value() const override;
+ String *print_item_value(THD *thd, Item *item, String *str) const override;
+ double Item_func_min_max_val_real(Item_func_min_max *) const override;
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const override;
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
- my_decimal *) const;
+ my_decimal *) const override;
bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
- MYSQL_TIME *, date_mode_t fuzzydate) const;
+ MYSQL_TIME *, date_mode_t fuzzydate)
+ const override;
virtual ~Type_handler_numeric() { }
bool can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
Item_bool_func2 *source,
- Item *source_expr, Item *source_const) const;
- bool Item_func_between_fix_length_and_dec(Item_func_between *func) const;
- bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const;
+ Item *source_expr, Item *source_const)
+ const override;
+ bool Item_func_between_fix_length_and_dec(Item_func_between *func) const override;
+ bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const override;
};
@@ -4143,187 +4520,253 @@ public:
class Type_handler_real_result: public Type_handler_numeric
{
public:
- Item_result result_type() const { return REAL_RESULT; }
- Item_result cmp_type() const { return REAL_RESULT; }
+ Item_result result_type() const override{ return REAL_RESULT; }
+ Item_result cmp_type() const override { return REAL_RESULT; }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ return DYN_COL_DOUBLE;
+ }
virtual ~Type_handler_real_result() {}
- const Type_handler *type_handler_for_comparison() const;
+ const Type_handler *type_handler_for_comparison() const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const override;
void Column_definition_reuse_fix_attributes(THD *thd,
Column_definition *c,
- const Field *field) const;
- int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
+ const Field *field)
+ const override;
+ void
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+ uchar *buff) const override;
+ bool
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const override;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
+ const override;
bool subquery_type_allows_materialization(const Item *inner,
- const Item *outer) const;
- void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field,
- Sort_param *param) const;
- void sortlength(THD *thd,
- const Type_std_attributes *item,
- SORT_FIELD_ATTR *attr) const;
+ const Item *outer)
+ const override;
+ void make_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const override;
+ uint make_packed_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const override;
+ void sort_length(THD *thd,
+ const Type_std_attributes *item,
+ SORT_FIELD_ATTR *attr) const override;
bool Item_const_eq(const Item_const *a, const Item_const *b,
- bool binary_cmp) const;
+ bool binary_cmp) const override;
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(THD *thd, Item *item, st_value *value) const;
+ Item *a, Item *b) const override;
+ uint Item_decimal_precision(const Item *item) const override;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
- const st_value *value) const;
- void Item_update_null_value(Item *item) const;
- int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
- Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
- bool set_comparator_func(Arg_comparator *cmp) const;
+ const st_value *value) const override;
+ void Item_update_null_value(Item *item) const override;
+ int Item_save_in_field(Item *item, Field *field, bool no_conversions)
+ const override;
+ Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp)
+ const override;
+ bool set_comparator_func(Arg_comparator *cmp) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- Item **items, uint nitems) const;
+ Item **items, uint nitems)
+ const override;
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_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;
+ Item **items, uint nitems)
+ const override;
+ bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override;
+ bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override;
+ bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override;
+ bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override;
+ bool Item_func_signed_fix_length_and_dec(Item_func_signed *item)
+ const override;
+ bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item)
+ const override;
+ bool Item_val_bool(Item *item) const override;
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;
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const override;
+ longlong Item_val_int_signed_typecast(Item *item) const override;
+ longlong Item_val_int_unsigned_typecast(Item *item) const override;
+ String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str)
+ const override;
double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
- const;
+ const override;
longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
- const;
+ const override;
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
- my_decimal *) const;
+ my_decimal *) const override;
void Item_func_hybrid_field_type_get_date(THD *,
Item_func_hybrid_field_type *,
Temporal::Warn *,
MYSQL_TIME *,
- date_mode_t fuzzydate) const;
- longlong Item_func_between_val_int(Item_func_between *func) const;
- cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
- in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
- bool Item_func_in_fix_comparator_compatible_types(THD *thd,
- Item_func_in *) const;
-
- bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
- bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
- bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
- bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
- bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const;
- bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const;
- bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
- bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
- bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
+ date_mode_t fuzzydate)
+ const override;
+ longlong Item_func_between_val_int(Item_func_between *func) const override;
+ cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
+ in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs)
+ const override;
+ bool Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *)
+ const override;
+
+ bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
+ bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const override;
+ bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override;
+ bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override;
+ bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override;
+ bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override;
+ bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override;
+ bool Item_func_div_fix_length_and_dec(Item_func_div *) const override;
+ bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override;
};
class Type_handler_decimal_result: public Type_handler_numeric
{
public:
- protocol_send_type_t protocol_send_type() const
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_STRING;
}
- Item_result result_type() const { return DECIMAL_RESULT; }
- Item_result cmp_type() const { return DECIMAL_RESULT; }
+ Item_result result_type() const override { return DECIMAL_RESULT; }
+ Item_result cmp_type() const override { return DECIMAL_RESULT; }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *) const
+ override
+ {
+ return DYN_COL_DECIMAL;
+ }
virtual ~Type_handler_decimal_result() {};
- const Type_handler *type_handler_for_comparison() const;
- int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const
+ const Type_handler *type_handler_for_comparison() const override;
+ int stored_field_cmp_to_item(THD *, Field *field, Item *item) const override
{
VDec item_val(item);
return item_val.is_null() ? 0 : my_decimal(field).cmp(item_val.ptr());
}
bool subquery_type_allows_materialization(const Item *inner,
- const Item *outer) const;
- Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const;
- void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field,
- Sort_param *param) const;
- void sortlength(THD *thd,
- const Type_std_attributes *item,
- SORT_FIELD_ATTR *attr) const;
- uint32 max_display_length(const Item *item) const;
- uint32 Item_decimal_notation_int_digits(const Item *item) const;
+ const Item *outer) const override;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
+ Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *)
+ const override;
+ void make_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const override;
+ uint make_packed_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const override;
+ void
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+ uchar *buff) const override;
+ bool
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const override;
+ void sort_length(THD *thd,
+ const Type_std_attributes *item,
+ SORT_FIELD_ATTR *attr) const override;
+ uint32 max_display_length(const Item *item) const override;
+ uint32 Item_decimal_notation_int_digits(const Item *item) const override;
Item *create_typecast_item(THD *thd, Item *item,
- const Type_cast_attributes &attr) const;
+ const Type_cast_attributes &attr) const override;
bool Item_const_eq(const Item_const *a, const Item_const *b,
- bool binary_cmp) const;
+ bool binary_cmp) const override;
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
- Item *a, Item *b) const
+ Item *a, Item *b) const override
{
VDec va(a), vb(b);
return va.ptr() && vb.ptr() && !va.cmp(vb);
}
- uint Item_decimal_precision(const Item *item) const;
- bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
+ uint Item_decimal_precision(const Item *item) const override;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
- const st_value *value) const;
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ const st_value *value) const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_str(item, protocol, buf);
}
- void Item_update_null_value(Item *item) const;
- int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
- Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
- bool set_comparator_func(Arg_comparator *cmp) const;
+ void Item_update_null_value(Item *item) const override;
+ int Item_save_in_field(Item *item, Field *field, bool no_conversions) const
+ override;
+ Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const
+ override;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
+ bool set_comparator_func(Arg_comparator *cmp) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- 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
+ Item **items, uint nitems)
+ const override;
+ bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const override;
+ bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override;
+ bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override;
+ bool Item_sum_variance_fix_length_and_dec(Item_sum_variance*) const override;
+ bool Item_val_bool(Item *item) const override
{
return VDec(item).to_bool();
}
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
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const override;
+ longlong Item_val_int_signed_typecast(Item *item) const override;
+ longlong Item_val_int_unsigned_typecast(Item *item) const override
{
return VDec(item).to_longlong(true);
}
- String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const;
+ String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str)
+ const override;
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
- String *) const;
+ String *) const override;
double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
- const;
+ const override;
longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
- const;
+ const override;
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
- my_decimal *) const;
+ my_decimal *) const override;
void Item_func_hybrid_field_type_get_date(THD *,
Item_func_hybrid_field_type *,
Temporal::Warn *,
MYSQL_TIME *,
- 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;
- in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
- bool Item_func_in_fix_comparator_compatible_types(THD *thd,
- Item_func_in *) const;
- bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
- bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
- bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
- bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
- bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const;
- bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const;
- bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
- bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
- bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
+ date_mode_t fuzzydate)
+ const override;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *)
+ const override;
+ longlong Item_func_between_val_int(Item_func_between *func) const override;
+ cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
+ in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs)
+ const override;
+ bool Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *)
+ const override;
+ bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
+ bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override;
+ bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override;
+ bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override;
+ bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override;
+ bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override;
+ bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override;
+ bool Item_func_div_fix_length_and_dec(Item_func_div *) const override;
+ bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override;
};
@@ -4455,93 +4898,121 @@ public:
class Type_handler_int_result: public Type_handler_numeric
{
public:
- Item_result result_type() const { return INT_RESULT; }
- Item_result cmp_type() const { return INT_RESULT; }
- bool is_order_clause_position_type() const { return true; }
- bool is_limit_clause_valid_type() const { return true; }
+ Item_result result_type() const override { return INT_RESULT; }
+ Item_result cmp_type() const override { return INT_RESULT; }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr) const override
+ {
+ return attr->unsigned_flag ? DYN_COL_UINT : DYN_COL_INT;
+ }
+ bool is_order_clause_position_type() const override { return true; }
+ bool is_limit_clause_valid_type() const override { return true; }
virtual ~Type_handler_int_result() {}
- const Type_handler *type_handler_for_comparison() const;
- int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
+ const Type_handler *type_handler_for_comparison() const override;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const override;
bool subquery_type_allows_materialization(const Item *inner,
- const Item *outer) const;
- Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const;
- void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field,
- Sort_param *param) const;
- void sortlength(THD *thd,
- const Type_std_attributes *item,
- SORT_FIELD_ATTR *attr) const;
+ const Item *outer) const override;
+ Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const override;
+ void make_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const override;
+ uint make_packed_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const override;
+ void
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+ uchar *buff) const override;
+ void sort_length(THD *thd,
+ const Type_std_attributes *item,
+ SORT_FIELD_ATTR *attr) const override;
bool Item_const_eq(const Item_const *a, const Item_const *b,
- bool binary_cmp) const;
+ bool binary_cmp) const override;
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(THD *thd, Item *item, st_value *value) const;
+ Item *a, Item *b) const override;
+ uint Item_decimal_precision(const Item *item) const override;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
- const st_value *value) const;
- void Item_update_null_value(Item *item) const;
- int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
- Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
- bool set_comparator_func(Arg_comparator *cmp) const;
+ const st_value *value) const override;
+ void Item_update_null_value(Item *item) const override;
+ int Item_save_in_field(Item *item, Field *field, bool no_conversions) const override;
+ Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const override;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
+ bool set_comparator_func(Arg_comparator *cmp) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- 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;
+ Item **items, uint nitems) const override;
+ bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override;
+ bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override;
+ bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override;
+ bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override;
+ bool Item_val_bool(Item *item) const override;
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;
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const override;
+ longlong Item_val_int_signed_typecast(Item *item) const override;
+ longlong Item_val_int_unsigned_typecast(Item *item) const override;
+ String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const override;
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
- String *) const;
+ String *) const override;
double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
- const;
+ const override;
longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
- const;
+ const override;
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
- my_decimal *) const;
+ my_decimal *) const override;
void Item_func_hybrid_field_type_get_date(THD *,
Item_func_hybrid_field_type *,
Temporal::Warn *,
MYSQL_TIME *,
- 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;
- in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
+ date_mode_t fuzzydate) const override;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override;
+ longlong Item_func_between_val_int(Item_func_between *func) const override;
+ cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
+ in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const override;
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
- Item_func_in *) const;
- bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
- bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
- bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
- bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
- bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const;
- bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const;
- bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
- bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
- bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
-
+ Item_func_in *) const override;
+ bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
+ bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const override;
+ bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override;
+ bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override;
+ bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override;
+ bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override;
+ bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override;
+ bool Item_func_div_fix_length_and_dec(Item_func_div *) const override;
+ bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override;
+ const Vers_type_handler *vers() const override { return &vers_type_trx; }
};
class Type_handler_general_purpose_int: public Type_handler_int_result
{
public:
- bool type_can_have_auto_increment_attribute() const { return true; }
- virtual const Type_limits_int *
- type_limits_int_by_unsigned_flag(bool unsigned_flag) const= 0;
- uint32 max_display_length(const Item *item) const;
- uint32 Item_decimal_notation_int_digits(const Item *item) const;
- bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p) const;
+ bool type_can_have_auto_increment_attribute() const override { return true; }
+ virtual const Type_limits_int *type_limits_int() const= 0;
+ uint32 max_display_length(const Item *item) const override
+ {
+ return type_limits_int()->char_length();
+ }
+ uint32 Item_decimal_notation_int_digits(const Item *item) const override;
+ bool partition_field_check(const LEX_CSTRING &field_name,
+ Item *item_expr) const override
+ {
+ return partition_field_check_result_type(item_expr, INT_RESULT);
+ }
+ bool partition_field_append_value(String *str,
+ Item *item_expr,
+ CHARSET_INFO *field_cs,
+ partition_value_print_mode_t)
+ const override;
+ const Vers_type_handler *vers() const override { return &vers_type_trx; }
};
@@ -4551,69 +5022,78 @@ protected:
uint Item_decimal_scale_with_seconds(const Item *item) const;
uint Item_divisor_precision_increment_with_seconds(const Item *) const;
public:
- Item_result result_type() const { return STRING_RESULT; }
- Item_result cmp_type() const { return TIME_RESULT; }
+ Item_result result_type() const override { return STRING_RESULT; }
+ Item_result cmp_type() const override { return TIME_RESULT; }
virtual ~Type_handler_temporal_result() {}
- void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field,
- Sort_param *param) const;
- void sortlength(THD *thd,
- const Type_std_attributes *item,
- SORT_FIELD_ATTR *attr) const;
+ void
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+ uchar *buff) const override;
+ void make_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const override;
+ uint make_packed_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const override;
+ void sort_length(THD *thd,
+ const Type_std_attributes *item,
+ SORT_FIELD_ATTR *attr) const override;
bool Item_const_eq(const Item_const *a, const Item_const *b,
- bool binary_cmp) const;
+ bool binary_cmp) const override;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
- const st_value *value) const;
- uint32 max_display_length(const Item *item) const;
- uint32 Item_decimal_notation_int_digits(const Item *item) const;
+ const st_value *value) const override;
+ uint32 max_display_length(const Item *item) const override;
+ uint32 Item_decimal_notation_int_digits(const Item *item) const override;
bool can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
Item_bool_func2 *source,
- Item *source_expr, Item *source_const) const;
+ Item *source_expr, Item *source_const)
+ const override;
bool subquery_type_allows_materialization(const Item *inner,
- const Item *outer) const;
+ const Item *outer) const override;
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;
+ Item **items, uint nitems)
+ const override;
+ bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const override;
+ bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override;
+ bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override;
+ bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *)const override;
+ bool Item_val_bool(Item *item) const override;
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;
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const override;
+ longlong Item_val_int_signed_typecast(Item *item) const override;
+ longlong Item_val_int_unsigned_typecast(Item *item) const override;
+ String *Item_func_hex_val_str_ascii(Item_func_hex *, String *)const override;
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
- String *) const;
+ String *) const override;
double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
- const;
+ const override;
longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
- const;
+ const override;
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
- my_decimal *) const;
+ my_decimal *) const override;
void Item_func_hybrid_field_type_get_date(THD *,
Item_func_hybrid_field_type *,
Temporal::Warn *,
MYSQL_TIME *,
- date_mode_t fuzzydate) const;
+ date_mode_t) const override;
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;
- bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
- bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
- bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
- bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
- bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const;
- bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const;
- bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
- bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
- bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
- bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p) const;
+ MYSQL_TIME *, date_mode_t) const override;
+ bool Item_func_between_fix_length_and_dec(Item_func_between *)const override;
+ bool Item_func_in_fix_comparator_compatible_types(THD *, Item_func_in *)
+ const override;
+ bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
+ bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *)const override;
+ bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override;
+ bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override;
+ bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override;
+ bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override;
+ bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override;
+ bool Item_func_div_fix_length_and_dec(Item_func_div *) const override;
+ bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override;
+ const Vers_type_handler *vers() const override { return &vers_type_timestamp; }
};
@@ -4621,143 +5101,173 @@ class Type_handler_string_result: public Type_handler
{
uint Item_temporal_precision(THD *thd, Item *item, bool is_time) const;
public:
- protocol_send_type_t protocol_send_type() const
+ const Name &default_value() const override;
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_STRING;
}
- Item_result result_type() const { return STRING_RESULT; }
- Item_result cmp_type() const { return STRING_RESULT; }
- CHARSET_INFO *charset_for_protocol(const Item *item) const;
+ Item_result result_type() const override { return STRING_RESULT; }
+ Item_result cmp_type() const override { return STRING_RESULT; }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *) const
+ override
+ {
+ return DYN_COL_STRING;
+ }
+ CHARSET_INFO *charset_for_protocol(const Item *item) const override;
virtual ~Type_handler_string_result() {}
- const Type_handler *type_handler_for_comparison() const;
- int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
+ const Type_handler *type_handler_for_comparison() const override;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const
+ override;
const Type_handler *
type_handler_adjusted_to_max_octet_length(uint max_octet_length,
- CHARSET_INFO *cs) const;
- void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field,
- Sort_param *param) const;
- void sortlength(THD *thd,
- const Type_std_attributes *item,
- SORT_FIELD_ATTR *attr) const;
- bool union_element_finalize(const Item * item) const;
+ CHARSET_INFO *cs) const override;
+ void make_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const override;
+ uint make_packed_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const override;
+ void sort_length(THD *thd,
+ const Type_std_attributes *item,
+ SORT_FIELD_ATTR *attr) const override;
+ bool is_packable()const override { return true; }
+ bool union_element_finalize(const Item * item) const override;
+ uint calc_key_length(const Column_definition &def) const override;
bool Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *c,
handler *file,
- ulonglong table_flags) const;
+ ulonglong table_flags) const override;
bool Column_definition_redefine_stage1(Column_definition *def,
const Column_definition *dup,
const handler *file,
const Schema_specification_st *schema)
- const;
- uint32 max_display_length(const Item *item) const;
-/*
+ const override;
+ void
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+ uchar *buff) const override;
+ uint32 max_display_length(const Item *item) const override;
+ /*
The next method returns 309 for long stringified doubles in scientific
notation, e.g. FORMAT('1e308', 2).
-*/
- uint32 Item_decimal_notation_int_digits(const Item *item) const { return 309; }
+ */
+ uint32 Item_decimal_notation_int_digits(const Item *item) const override
+ { return 309; }
bool Item_const_eq(const Item_const *a, const Item_const *b,
- bool binary_cmp) const;
+ bool binary_cmp) const override;
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
- Item *a, Item *b) const;
- uint Item_time_precision(THD *thd, Item *item) const
+ Item *a, Item *b) const override;
+ uint Item_time_precision(THD *thd, Item *item) const override
{
return Item_temporal_precision(thd, item, true);
}
- uint Item_datetime_precision(THD *thd, Item *item) const
+ uint Item_datetime_precision(THD *thd, Item *item) const override
{
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(THD *thd, Item *item, st_value *value) const;
- void Item_param_setup_conversion(THD *thd, Item_param *) const;
+ uint Item_decimal_precision(const Item *item) const override;
+ void Item_update_null_value(Item *item) const override;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override;
+ void Item_param_setup_conversion(THD *thd, Item_param *) const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
- const st_value *value) const;
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ const st_value *value) const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_str(item, protocol, buf);
}
- int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
- String *print_item_value(THD *thd, Item *item, String *str) const
+ int Item_save_in_field(Item *item, Field *field, bool no_conversions) const
+ override;
+ String *print_item_value(THD *thd, Item *item, String *str) const override
{
return print_item_value_csstr(thd, item, str);
}
bool can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
Item_bool_func2 *source,
- Item *source_expr, Item *source_const) const;
+ Item *source_expr, Item *source_const) const
+ override;
bool subquery_type_allows_materialization(const Item *inner,
- const Item *outer) const;
- Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
- bool set_comparator_func(Arg_comparator *cmp) const;
+ const Item *outer) const override;
+ Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const
+ override;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
+ bool set_comparator_func(Arg_comparator *cmp) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- 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_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;
+ Item **items, uint nitems) const
+ override;
+ bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override;
+ bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override;
+ bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override;
+ bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override;
+ bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const
+ override;
+ bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const
+ override;
+ bool Item_val_bool(Item *item) const override;
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;
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const override;
+ longlong Item_val_int_signed_typecast(Item *item) const override;
+ longlong Item_val_int_unsigned_typecast(Item *item) const override;
+ String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const
+ override;
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
- String *) const;
+ String *) const override;
double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
- const;
+ const override;
longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
- const;
+ const override;
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
- my_decimal *) const;
+ my_decimal *) const override;
void Item_func_hybrid_field_type_get_date(THD *,
Item_func_hybrid_field_type *,
Temporal::Warn *,
MYSQL_TIME *,
- 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;
+ date_mode_t fuzzydate)
+ const override;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *) const
+ override;
+ double Item_func_min_max_val_real(Item_func_min_max *) const override;
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const override;
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
- my_decimal *) const;
+ my_decimal *) const override;
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;
- cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
- in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
- bool Item_func_in_fix_comparator_compatible_types(THD *thd,
- Item_func_in *) const;
- bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
- bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
- bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
- bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
- bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const;
- bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const;
- bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
- bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
- bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
+ MYSQL_TIME *, date_mode_t fuzzydate) const
+ override;
+ bool Item_func_between_fix_length_and_dec(Item_func_between *func) const
+ override;
+ longlong Item_func_between_val_int(Item_func_between *func) const override;
+ bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const
+ override;
+ cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
+ in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const
+ override;
+ bool Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *)
+ const override;
+ bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
+ bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const override;
+ bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override;
+ bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override;
+ bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override;
+ bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override;
+ bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override;
+ bool Item_func_div_fix_length_and_dec(Item_func_div *) const override;
+ bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override;
+ const Vers_type_handler *vers() const override { return &vers_type_timestamp; }
};
class Type_handler_general_purpose_string: public Type_handler_string_result
{
public:
- bool is_general_purpose_string_type() const { return true; }
- bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p) const;
+ bool is_general_purpose_string_type() const override { return true; }
};
@@ -4783,534 +5293,615 @@ public:
class Type_handler_tiny: public Type_handler_general_purpose_int
{
- static const Name m_name_tiny;
- static const Type_limits_int m_limits_sint8;
- static const Type_limits_int m_limits_uint8;
public:
virtual ~Type_handler_tiny() {}
- const Name name() const { return m_name_tiny; }
- enum_field_types field_type() const { return MYSQL_TYPE_TINY; }
- protocol_send_type_t protocol_send_type() const
+ enum_field_types field_type() const override { return MYSQL_TYPE_TINY; }
+ const Type_handler *type_handler_unsigned() const override;
+ const Type_handler *type_handler_signed() const override;
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_TINY;
}
- const Type_limits_int *type_limits_int_by_unsigned_flag(bool unsigned_fl) const
- {
- return unsigned_fl ? &m_limits_uint8 : &m_limits_sint8;
- }
- uint32 calc_pack_length(uint32 length) const { return 1; }
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ const Type_limits_int *type_limits_int() const override;
+ uint32 calc_pack_length(uint32 length) const override { return 1; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 4; }
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_tiny(item, protocol, buf);
}
- Field *make_conversion_table_field(TABLE *TABLE, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_TINY); }
- Field *make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
+};
+
+
+class Type_handler_utiny: public Type_handler_tiny
+{
+public:
+ uint flags() const override { return UNSIGNED_FLAG; }
+ const Type_limits_int *type_limits_int() const override;
};
class Type_handler_short: public Type_handler_general_purpose_int
{
- static const Name m_name_short;
- static const Type_limits_int m_limits_sint16;
- static const Type_limits_int m_limits_uint16;
public:
virtual ~Type_handler_short() {}
- const Name name() const { return m_name_short; }
- enum_field_types field_type() const { return MYSQL_TYPE_SHORT; }
- protocol_send_type_t protocol_send_type() const
+ enum_field_types field_type() const override { return MYSQL_TYPE_SHORT; }
+ const Type_handler *type_handler_unsigned() const override;
+ const Type_handler *type_handler_signed() const override;
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_SHORT;
}
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_short(item, protocol, buf);
}
- const Type_limits_int *type_limits_int_by_unsigned_flag(bool unsigned_fl) const
- {
- return unsigned_fl ? &m_limits_uint16 : &m_limits_sint16;
- }
- uint32 calc_pack_length(uint32 length) const { return 2; }
- Field *make_conversion_table_field(TABLE *TABLE, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ const Type_limits_int *type_limits_int() const override;
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 6; }
+ uint32 calc_pack_length(uint32 length) const override{ return 2; }
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_SHORT); }
- Field *make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
+};
+
+
+class Type_handler_ushort: public Type_handler_short
+{
+public:
+ uint flags() const override { return UNSIGNED_FLAG; }
+ const Type_limits_int *type_limits_int() const override;
};
class Type_handler_long: public Type_handler_general_purpose_int
{
- static const Name m_name_int;
- static const Type_limits_int m_limits_sint32;
- static const Type_limits_int m_limits_uint32;
public:
virtual ~Type_handler_long() {}
- const Name name() const { return m_name_int; }
- enum_field_types field_type() const { return MYSQL_TYPE_LONG; }
- protocol_send_type_t protocol_send_type() const
+ enum_field_types field_type() const override { return MYSQL_TYPE_LONG; }
+ const Type_handler *type_handler_unsigned() const override;
+ const Type_handler *type_handler_signed() const override;
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_LONG;
}
- const Type_limits_int *type_limits_int_by_unsigned_flag(bool unsigned_fl) const
- {
- return unsigned_fl ? &m_limits_uint32 : &m_limits_sint32;
- }
- uint32 calc_pack_length(uint32 length) const { return 4; }
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ const Type_limits_int *type_limits_int() const override;
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 11; }
+ uint32 calc_pack_length(uint32 length) const override { return 4; }
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_long(item, protocol, buf);
}
- Field *make_conversion_table_field(TABLE *TABLE, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_LONG); }
- Field *make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
+};
+
+
+class Type_handler_ulong: public Type_handler_long
+{
+public:
+ uint flags() const override { return UNSIGNED_FLAG; }
+ const Type_limits_int *type_limits_int() const override;
};
class Type_handler_bool: public Type_handler_long
{
- static const Name m_name_bool;
public:
- const Name name() const { return m_name_bool; }
- bool is_bool_type() const { return true; }
- void Item_update_null_value(Item *item) const;
- bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const;
+ bool is_bool_type() const override { return true; }
+ const Type_handler *type_handler_unsigned() const override;
+ const Type_handler *type_handler_signed() const override;
+ void Item_update_null_value(Item *item) const override;
+ bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const override;
};
class Type_handler_longlong: public Type_handler_general_purpose_int
{
- static const Name m_name_longlong;
- static const Type_limits_int m_limits_sint64;
- static const Type_limits_int m_limits_uint64;
public:
virtual ~Type_handler_longlong() {}
- const Name name() const { return m_name_longlong; }
- enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; }
- protocol_send_type_t protocol_send_type() const
+ enum_field_types field_type() const override{ return MYSQL_TYPE_LONGLONG; }
+ const Type_handler *type_handler_unsigned() const override;
+ const Type_handler *type_handler_signed() const override;
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_LONGLONG;
}
- const Type_limits_int *type_limits_int_by_unsigned_flag(bool unsigned_fl) const
- {
- return unsigned_fl ? &m_limits_uint64 : &m_limits_sint64;
- }
- uint32 calc_pack_length(uint32 length) const { return 8; }
+ const Type_limits_int *type_limits_int() const override;
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 20; }
+ uint32 calc_pack_length(uint32 length) const override { return 8; }
Item *create_typecast_item(THD *thd, Item *item,
- const Type_cast_attributes &attr) const;
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ const Type_cast_attributes &attr) const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_longlong(item, protocol, buf);
}
- Field *make_conversion_table_field(TABLE *TABLE, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{
return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_LONGLONG);
}
- Field *make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
};
-class Type_handler_vers_trx_id: public Type_handler_longlong
+class Type_handler_ulonglong: public Type_handler_longlong
+{
+public:
+ uint flags() const override { return UNSIGNED_FLAG; }
+ const Type_limits_int *type_limits_int() const override;
+};
+
+
+class Type_handler_vers_trx_id: public Type_handler_ulonglong
{
public:
virtual ~Type_handler_vers_trx_id() {}
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE_SHARE *share) const override;
};
class Type_handler_int24: public Type_handler_general_purpose_int
{
- static const Name m_name_mediumint;
- static const Type_limits_int m_limits_sint24;
- static const Type_limits_int m_limits_uint24;
public:
virtual ~Type_handler_int24() {}
- const Name name() const { return m_name_mediumint; }
- enum_field_types field_type() const { return MYSQL_TYPE_INT24; }
- protocol_send_type_t protocol_send_type() const
+ enum_field_types field_type() const override { return MYSQL_TYPE_INT24; }
+ const Type_handler *type_handler_unsigned() const override;
+ const Type_handler *type_handler_signed() const override;
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_LONG;
}
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_long(item, protocol, buf);
}
- const Type_limits_int *type_limits_int_by_unsigned_flag(bool unsigned_fl) const
- {
- return unsigned_fl ? &m_limits_uint24 : &m_limits_sint24;
- }
- uint32 calc_pack_length(uint32 length) const { return 3; }
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ const Type_limits_int *type_limits_int() const override;
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 9; }
+ uint32 calc_pack_length(uint32 length) const override { return 3; }
+ Field *make_conversion_table_field(MEM_ROOT *mem_root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_INT24); }
- Field *make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
+};
+
+
+class Type_handler_uint24: public Type_handler_int24
+{
+public:
+ uint flags() const override { return UNSIGNED_FLAG; }
+ const Type_limits_int *type_limits_int() const override;
};
class Type_handler_year: public Type_handler_int_result
{
- static const Name m_name_year;
public:
virtual ~Type_handler_year() {}
- const Name name() const { return m_name_year; }
- enum_field_types field_type() const { return MYSQL_TYPE_YEAR; }
- protocol_send_type_t protocol_send_type() const
+ enum_field_types field_type() const override { return MYSQL_TYPE_YEAR; }
+ uint flags() const override { return UNSIGNED_FLAG; }
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_SHORT;
}
- uint32 max_display_length(const Item *item) const;
- uint32 Item_decimal_notation_int_digits(const Item *item) const { return 4; };
- uint32 calc_pack_length(uint32 length) const { return 1; }
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ uint32 max_display_length(const Item *item) const override;
+ uint32 Item_decimal_notation_int_digits(const Item *item) const override
+ { return 4; };
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 4; }
+ uint32 calc_pack_length(uint32 length) const override { return 1; }
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_short(item, protocol, buf);
}
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
void Column_definition_reuse_fix_attributes(THD *thd,
Column_definition *c,
- const Field *field) const;
+ const Field *field)
+ const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_YEAR); }
- Field *make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
+ uint32 flags) const override;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn,
- MYSQL_TIME *ltime, date_mode_t fuzzydate) const;
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const override;
void Item_func_hybrid_field_type_get_date(THD *,
Item_func_hybrid_field_type *item,
Temporal::Warn *,
MYSQL_TIME *to,
- date_mode_t fuzzydate) const;
+ date_mode_t fuzzydate)
+ const override;
+ const Vers_type_handler *vers() const override { return NULL; }
};
class Type_handler_bit: public Type_handler_int_result
{
- static const Name m_name_bit;
public:
virtual ~Type_handler_bit() {}
- const Name name() const { return m_name_bit; }
- enum_field_types field_type() const { return MYSQL_TYPE_BIT; }
- protocol_send_type_t protocol_send_type() const
+ enum_field_types field_type() const override { return MYSQL_TYPE_BIT; }
+ uint flags() const override { return UNSIGNED_FLAG; }
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_STRING;
}
- uint32 max_display_length(const Item *item) const;
- uint32 Item_decimal_notation_int_digits(const Item *item) const;
+ uint32 max_display_length(const Item *item) const override;
+ uint32 Item_decimal_notation_int_digits(const Item *item) const override;
static uint32 Bit_decimal_notation_int_digits(const Item *item);
- uint32 calc_pack_length(uint32 length) const { return length / 8; }
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override { return length / 8; }
+ uint calc_key_length(const Column_definition &def) const override;
+ void
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+ uchar *buff) const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_str(item, protocol, buf);
}
- String *print_item_value(THD *thd, Item *item, String *str) const
+ String *print_item_value(THD *thd, Item *item, String *str) const override
{
return print_item_value_csstr(thd, item, str);
}
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ void show_binlog_type(const Conv_source &src, const Field &, String *str)
+ const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *c,
handler *file,
- ulonglong table_flags) const;
+ ulonglong table_flags) const override;
bool Column_definition_redefine_stage1(Column_definition *def,
const Column_definition *dup,
const handler *file,
const Schema_specification_st *schema)
- const;
+ const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ ulonglong table_flags) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE_SHARE *share) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
- bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p) const;
+ uint32 flags) const override;
};
class Type_handler_float: public Type_handler_real_result
{
- static const Name m_name_float;
public:
virtual ~Type_handler_float() {}
- const Name name() const { return m_name_float; }
- enum_field_types field_type() const { return MYSQL_TYPE_FLOAT; }
- protocol_send_type_t protocol_send_type() const
+ enum_field_types field_type() const override { return MYSQL_TYPE_FLOAT; }
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_FLOAT;
}
- bool type_can_have_auto_increment_attribute() const { return true; }
- uint32 max_display_length(const Item *item) const { return 25; }
- uint32 Item_decimal_notation_int_digits(const Item *item) const { return 39; }
- uint32 calc_pack_length(uint32 length) const { return sizeof(float); }
+ bool type_can_have_auto_increment_attribute() const override { return true; }
+ uint32 max_display_length(const Item *item) const override { return 25; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 12; }
+ uint32 Item_decimal_notation_int_digits(const Item *item) const override
+ { return 39; }
+ uint32 calc_pack_length(uint32 length) const override { return sizeof(float); }
Item *create_typecast_item(THD *thd, Item *item,
- const Type_cast_attributes &attr) const;
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ const Type_cast_attributes &attr) const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_float(item, protocol, buf);
}
- Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *)
+ const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_real(c, MYSQL_TYPE_FLOAT); }
- Field *make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
- String *) const;
- String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
+ String *) const override;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *)
+ const override;
};
class Type_handler_double: public Type_handler_real_result
{
- static const Name m_name_double;
public:
virtual ~Type_handler_double() {}
- const Name name() const { return m_name_double; }
- enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
- protocol_send_type_t protocol_send_type() const
+ enum_field_types field_type() const override { return MYSQL_TYPE_DOUBLE; }
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_DOUBLE;
}
- bool type_can_have_auto_increment_attribute() const { return true; }
- uint32 max_display_length(const Item *item) const { return 53; }
- uint32 Item_decimal_notation_int_digits(const Item *item) const { return 309; }
- uint32 calc_pack_length(uint32 length) const { return sizeof(double); }
+ bool type_can_have_auto_increment_attribute() const override { return true; }
+ uint32 max_display_length(const Item *item) const override { return 53; }
+ uint32 Item_decimal_notation_int_digits(const Item *item) const override
+ { return 309; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 22; }
+ uint32 calc_pack_length(uint32 length) const override
+ {
+ return sizeof(double);
+ }
Item *create_typecast_item(THD *thd, Item *item,
- const Type_cast_attributes &attr) const;
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ const Type_cast_attributes &attr) const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_double(item, protocol, buf);
}
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_real(c, MYSQL_TYPE_DOUBLE); }
- Field *make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
- String *) const;
- String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
+ String *) const override;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *)
+ const override;
};
class Type_handler_time_common: public Type_handler_temporal_result
{
- static const Name m_name_time;
public:
virtual ~Type_handler_time_common() { }
- const Name name() const { return m_name_time; }
- enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
- protocol_send_type_t protocol_send_type() const
+ const Name &default_value() const override;
+ enum_field_types field_type() const override { return MYSQL_TYPE_TIME; }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ return DYN_COL_TIME;
+ }
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_TIME;
}
- enum_mysql_timestamp_type mysql_timestamp_type() const
+ enum_mysql_timestamp_type mysql_timestamp_type() const override
{
return MYSQL_TIMESTAMP_TIME;
}
+ bool partition_field_check(const LEX_CSTRING &field_name,
+ Item *item_expr) const override
+ {
+ return partition_field_check_result_type(item_expr, STRING_RESULT);
+ }
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Item_literal *create_literal_item(THD *thd, const char *str, size_t length,
- CHARSET_INFO *cs, bool send_error) const;
+ CHARSET_INFO *cs, bool send_error)
+ const override;
Item *create_typecast_item(THD *thd, Item *item,
- const Type_cast_attributes &attr) const;
+ const Type_cast_attributes &attr)
+ const override;
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
- Item *a, Item *b) const;
- uint Item_decimal_scale(const Item *item) const
+ Item *a, Item *b) const override;
+ uint Item_decimal_scale(const Item *item) const override
{
return Item_decimal_scale_with_seconds(item);
}
- uint Item_decimal_precision(const Item *item) const;
- uint Item_divisor_precision_increment(const Item *item) const
+ uint Item_decimal_precision(const Item *item) const override;
+ uint Item_divisor_precision_increment(const Item *item) const override
{
return Item_divisor_precision_increment_with_seconds(item);
}
- const Type_handler *type_handler_for_comparison() const;
- 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(THD *thd, Item *item, st_value *value) const;
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ const Type_handler *type_handler_for_comparison() const override;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
+ const override;
+ void Column_definition_implicit_upgrade(Column_definition *c) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
+ bool
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const override;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_time(item, protocol, buf);
}
- void Item_update_null_value(Item *item) const;
- int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
- String *print_item_value(THD *thd, Item *item, String *str) const;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
- longlong Item_val_int_unsigned_typecast(Item *item) const;
+ void Item_update_null_value(Item *item) const override;
+ int Item_save_in_field(Item *item, Field *field, bool no_conversions)
+ const override;
+ String *print_item_value(THD *thd, Item *item, String *str) const override;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
+ longlong Item_val_int_unsigned_typecast(Item *item) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- Item **items, uint nitems) const;
+ Item **items, uint nitems)
+ const override;
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
- String *) const;
+ String *) const override;
double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
- const;
+ const override;
longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
- const;
+ const override;
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
- my_decimal *) const;
+ my_decimal *) const override;
void Item_func_hybrid_field_type_get_date(THD *,
Item_func_hybrid_field_type *,
Temporal::Warn *,
MYSQL_TIME *,
- 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;
+ date_mode_t fuzzydate)
+ const override;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override;
+ double Item_func_min_max_val_real(Item_func_min_max *) const override;
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const override;
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
- my_decimal *) const;
+ my_decimal *) const override;
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;
- bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
- Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
- bool set_comparator_func(Arg_comparator *cmp) const;
- cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
- in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
- void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ MYSQL_TIME *, date_mode_t fuzzydate)
+ const override;
+ longlong Item_func_between_val_int(Item_func_between *func) const override;
+ bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
+ Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp)
+ const override;
+ bool set_comparator_func(Arg_comparator *cmp) const override;
+ cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
+ in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs)
+ const override;
+ void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len)
+ const override;
};
@@ -5321,25 +5912,29 @@ class Type_handler_time: public Type_handler_time_common
public:
static uint hires_bytes(uint dec) { return m_hires_bytes[dec]; }
virtual ~Type_handler_time() {}
- const Name version() const { return m_version_mariadb53; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ const Name version() const override { return version_mariadb53(); }
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return MIN_TIME_WIDTH; }
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_TIME); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE_SHARE *share) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -5347,26 +5942,29 @@ class Type_handler_time2: public Type_handler_time_common
{
public:
virtual ~Type_handler_time2() {}
- const Name version() const { return m_version_mysql56; }
- enum_field_types real_field_type() const { return MYSQL_TYPE_TIME2; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ const Name version() const override { return version_mysql56(); }
+ enum_field_types real_field_type() const override { return MYSQL_TYPE_TIME2; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_TIME2); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE_SHARE *share) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -5375,89 +5973,122 @@ class Type_handler_temporal_with_date: public Type_handler_temporal_result
public:
virtual ~Type_handler_temporal_with_date() {}
Item_literal *create_literal_item(THD *thd, const char *str, size_t length,
- CHARSET_INFO *cs, bool send_error) const;
+ CHARSET_INFO *cs, bool send_error)
+ const override;
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(THD *thd, Item *item, st_value *value) const;
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ Item *a, Item *b) const override;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
+ const override;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value)
+ const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_date(item, protocol, buf);
}
- void Item_update_null_value(Item *item) const;
- int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
- Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
- bool set_comparator_func(Arg_comparator *cmp) const;
- cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
- in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
- longlong Item_func_between_val_int(Item_func_between *func) const;
+ void Item_update_null_value(Item *item) const override;
+ int Item_save_in_field(Item *item, Field *field, bool no_conversions)
+ const override;
+ Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp)
+ const override;
+ bool set_comparator_func(Arg_comparator *cmp) const override;
+ cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
+ in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs)
+ const override;
+ longlong Item_func_between_val_int(Item_func_between *func) const override;
};
class Type_handler_date_common: public Type_handler_temporal_with_date
{
- static const Name m_name_date;
public:
virtual ~Type_handler_date_common() {}
- const Name name() const { return m_name_date; }
- const Type_handler *type_handler_for_comparison() const;
- enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
- protocol_send_type_t protocol_send_type() const
+ const Name &default_value() const override;
+ const Type_handler *type_handler_for_comparison() const override;
+ enum_field_types field_type() const override { return MYSQL_TYPE_DATE; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 3; }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ return DYN_COL_DATE;
+ }
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_DATE;
}
- enum_mysql_timestamp_type mysql_timestamp_type() const
+ enum_mysql_timestamp_type mysql_timestamp_type() const override
{
return MYSQL_TIMESTAMP_DATE;
}
- bool cond_notnull_field_isnull_to_field_eq_zero() const
+ bool cond_notnull_field_isnull_to_field_eq_zero() const override
{
return true;
}
+ bool partition_field_check(const LEX_CSTRING &field_name,
+ Item *item_expr) const override
+ {
+ return partition_field_check_result_type(item_expr, STRING_RESULT);
+ }
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Item_literal *create_literal_item(THD *thd, const char *str, size_t length,
- CHARSET_INFO *cs, bool send_error) const;
+ CHARSET_INFO *cs, bool send_error)
+ const override;
Item *create_typecast_item(THD *thd, Item *item,
- const Type_cast_attributes &attr) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
- uint Item_decimal_precision(const Item *item) const;
- 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;
+ const Type_cast_attributes &attr)
+ const override;
+ bool validate_implicit_default_value(THD *thd,
+ const Column_definition &def)
+ const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
+ void
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+ uchar *buff) const override;
+ uint Item_decimal_precision(const Item *item) const override;
+ String *print_item_value(THD *thd, Item *item, String *str) const override;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override;
+ double Item_func_min_max_val_real(Item_func_min_max *) const override;
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const override;
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
- my_decimal *) const;
+ my_decimal *) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- Item **items, uint nitems) const;
+ Item **items, uint nitems)
+ const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
};
class Type_handler_date: public Type_handler_date_common
{
public:
virtual ~Type_handler_date() {}
- uint32 calc_pack_length(uint32 length) const { return 4; }
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ uint32 calc_pack_length(uint32 length) const override { return 4; }
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_DATE); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE_SHARE *share) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -5465,80 +6096,111 @@ class Type_handler_newdate: public Type_handler_date_common
{
public:
virtual ~Type_handler_newdate() {}
- enum_field_types real_field_type() const { return MYSQL_TYPE_NEWDATE; }
- uint32 calc_pack_length(uint32 length) const { return 3; }
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ enum_field_types real_field_type() const override
+ {
+ return MYSQL_TYPE_NEWDATE;
+ }
+ uint32 calc_pack_length(uint32 length) const override { return 3; }
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_NEWDATE); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE_SHARE *share) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
class Type_handler_datetime_common: public Type_handler_temporal_with_date
{
- static const Name m_name_datetime;
public:
virtual ~Type_handler_datetime_common() {}
- const Name name() const { return m_name_datetime; }
- const Type_handler *type_handler_for_comparison() const;
- enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
- protocol_send_type_t protocol_send_type() const
+ const Name &default_value() const override;
+ const Type_handler *type_handler_for_comparison() const override;
+ enum_field_types field_type() const override
+ {
+ return MYSQL_TYPE_DATETIME;
+ }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ return DYN_COL_DATETIME;
+ }
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_DATETIME;
}
- enum_mysql_timestamp_type mysql_timestamp_type() const
+ enum_mysql_timestamp_type mysql_timestamp_type() const override
{
return MYSQL_TIMESTAMP_DATETIME;
}
- bool cond_notnull_field_isnull_to_field_eq_zero() const
+ bool cond_notnull_field_isnull_to_field_eq_zero() const override
{
return true;
}
+ bool partition_field_check(const LEX_CSTRING &field_name,
+ Item *item_expr) const override
+ {
+ return partition_field_check_result_type(item_expr, STRING_RESULT);
+ }
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Item *create_typecast_item(THD *thd, Item *item,
- const Type_cast_attributes &attr) const;
- void Column_definition_implicit_upgrade(Column_definition *c) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
- uint Item_decimal_scale(const Item *item) const
+ const Type_cast_attributes &attr) const override;
+ bool validate_implicit_default_value(THD *thd, const Column_definition &def)
+ const override;
+ void Column_definition_implicit_upgrade(Column_definition *c) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
+ bool
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const override;
+ uint Item_decimal_scale(const Item *item) const override
{
return Item_decimal_scale_with_seconds(item);
}
- uint Item_decimal_precision(const Item *item) const;
- uint Item_divisor_precision_increment(const Item *item) const
+ uint Item_decimal_precision(const Item *item) const override;
+ uint Item_divisor_precision_increment(const Item *item) const override
{
return Item_divisor_precision_increment_with_seconds(item);
}
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_datetime(item, protocol, buf);
}
- 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_func_round_fix_length_and_dec(Item_func_round *) const;
+ String *print_item_value(THD *thd, Item *item, String *str) const override;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override;
+ double Item_func_min_max_val_real(Item_func_min_max *) const override;
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const override;
+ my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, my_decimal *)
+ const override;
+ bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- Item **items, uint nitems) const;
- void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ Item **items, uint nitems)
+ const override;
+ void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len)
+ const override;
};
@@ -5549,25 +6211,29 @@ class Type_handler_datetime: public Type_handler_datetime_common
public:
static uint hires_bytes(uint dec) { return m_hires_bytes[dec]; }
virtual ~Type_handler_datetime() {}
- const Name version() const { return m_version_mariadb53; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ const Name version() const override { return version_mariadb53(); }
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return MAX_DATETIME_WIDTH; }
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_DATETIME); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE_SHARE *share) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -5575,105 +6241,132 @@ class Type_handler_datetime2: public Type_handler_datetime_common
{
public:
virtual ~Type_handler_datetime2() {}
- const Name version() const { return m_version_mysql56; }
- enum_field_types real_field_type() const { return MYSQL_TYPE_DATETIME2; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ const Name version() const override { return version_mysql56(); }
+ enum_field_types real_field_type() const override
+ {
+ return MYSQL_TYPE_DATETIME2;
+ }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_DATETIME2); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE_SHARE *share) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
class Type_handler_timestamp_common: public Type_handler_temporal_with_date
{
- static const Name m_name_timestamp;
protected:
bool TIME_to_native(THD *, const MYSQL_TIME *from, Native *to, uint dec) const;
public:
virtual ~Type_handler_timestamp_common() {}
- const Name name() const { return m_name_timestamp; }
- const Type_handler *type_handler_for_comparison() const;
- const Type_handler *type_handler_for_native_format() const;
- enum_field_types field_type() const { return MYSQL_TYPE_TIMESTAMP; }
- protocol_send_type_t protocol_send_type() const
+ const Name &default_value() const override;
+ const Type_handler *type_handler_for_comparison() const override;
+ const Type_handler *type_handler_for_native_format() const override;
+ enum_field_types field_type() const override { return MYSQL_TYPE_TIMESTAMP; }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ return DYN_COL_DATETIME;
+ }
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_DATETIME;
}
- enum_mysql_timestamp_type mysql_timestamp_type() const
+ enum_mysql_timestamp_type mysql_timestamp_type() const override
{
return MYSQL_TIMESTAMP_DATETIME;
}
- bool is_val_native_ready() const
+ bool is_val_native_ready() const override
{
return true;
}
- bool is_timestamp_type() const
+ bool is_timestamp_type() const override
{
return true;
}
- void Column_definition_implicit_upgrade(Column_definition *c) const;
+ void Column_definition_implicit_upgrade(Column_definition *c) const override;
+ bool
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const override;
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
- Item *a, Item *b) const;
- bool Item_val_native_with_conversion(THD *thd, Item *, Native *to) const;
- bool Item_val_native_with_conversion_result(THD *thd, Item *, Native *to) const;
- bool Item_param_val_native(THD *thd, Item_param *item, Native *to) const;
- int cmp_native(const Native &a, const Native &b) const;
- longlong Item_func_between_val_int(Item_func_between *func) const;
- bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
- cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
- in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs) const;
- void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field,
- Sort_param *param) const;
- void sortlength(THD *thd,
- const Type_std_attributes *item,
- SORT_FIELD_ATTR *attr) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
- uint Item_decimal_scale(const Item *item) const
+ Item *a, Item *b) const override;
+ bool Item_val_native_with_conversion(THD *thd, Item *, Native *to)
+ const override;
+ bool Item_val_native_with_conversion_result(THD *thd, Item *, Native *to)
+ const override;
+ bool Item_param_val_native(THD *thd, Item_param *item, Native *to)
+ const override;
+ int cmp_native(const Native &a, const Native &b) const override;
+ longlong Item_func_between_val_int(Item_func_between *func) const override;
+ bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
+ cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
+ in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs)
+ const override;
+ void make_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const override;
+ uint make_packed_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const override;
+ void sort_length(THD *thd,
+ const Type_std_attributes *item,
+ SORT_FIELD_ATTR *attr) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
+ uint Item_decimal_scale(const Item *item) const override
{
return Item_decimal_scale_with_seconds(item);
}
- uint Item_decimal_precision(const Item *item) const;
- uint Item_divisor_precision_increment(const Item *item) const
+ uint Item_decimal_precision(const Item *item) const override;
+ uint Item_divisor_precision_increment(const Item *item) const override
{
return Item_divisor_precision_increment_with_seconds(item);
}
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_timestamp(item, protocol, buf);
}
- int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
- String *print_item_value(THD *thd, Item *item, String *str) const;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
- Item_copy *create_item_copy(THD *thd, 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;
+ int Item_save_in_field(Item *item, Field *field, bool no_conversions)
+ const override;
+ String *print_item_value(THD *thd, Item *item, String *str) const override;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
+ Item_copy *create_item_copy(THD *thd, Item *item) const override;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override;
+ double Item_func_min_max_val_real(Item_func_min_max *) const override;
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const override;
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
- my_decimal *) const;
- bool set_comparator_func(Arg_comparator *cmp) const;
+ my_decimal *) const override;
+ bool set_comparator_func(Arg_comparator *cmp) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- Item **items, uint nitems) const;
+ Item **items, uint nitems)
+ const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
- MYSQL_TIME *, date_mode_t fuzzydate) const;
+ MYSQL_TIME *, date_mode_t fuzzydate)
+ const override;
};
@@ -5684,25 +6377,29 @@ class Type_handler_timestamp: public Type_handler_timestamp_common
public:
static uint sec_part_bytes(uint dec) { return m_sec_part_bytes[dec]; }
virtual ~Type_handler_timestamp() {}
- const Name version() const { return m_version_mariadb53; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ const Name version() const override { return version_mariadb53(); }
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return MAX_DATETIME_WIDTH; }
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_TIMESTAMP); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE_SHARE *share) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -5710,151 +6407,176 @@ class Type_handler_timestamp2: public Type_handler_timestamp_common
{
public:
virtual ~Type_handler_timestamp2() {}
- const Name version() const { return m_version_mysql56; }
- enum_field_types real_field_type() const { return MYSQL_TYPE_TIMESTAMP2; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ const Name version() const override { return version_mysql56(); }
+ enum_field_types real_field_type() const override
+ {
+ return MYSQL_TYPE_TIMESTAMP2;
+ }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{
return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_TIMESTAMP2);
}
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE_SHARE *share) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
class Type_handler_olddecimal: public Type_handler_decimal_result
{
- static const Name m_name_decimal;
public:
virtual ~Type_handler_olddecimal() {}
- const Name name() const { return m_name_decimal; }
- enum_field_types field_type() const { return MYSQL_TYPE_DECIMAL; }
- uint32 calc_pack_length(uint32 length) const { return length; }
- const Type_handler *type_handler_for_tmp_table(const Item *item) const;
- const Type_handler *type_handler_for_union(const Item *item) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ enum_field_types field_type() const override { return MYSQL_TYPE_DECIMAL; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override { return length; }
+ const Type_handler *type_handler_for_tmp_table(const Item *item) const override;
+ const Type_handler *type_handler_for_union(const Item *item) const override;
+ void show_binlog_type(const Conv_source &src, const Field &, String *str)
+ const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_DECIMAL); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE_SHARE *share) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
class Type_handler_newdecimal: public Type_handler_decimal_result
{
- static const Name m_name_decimal;
public:
virtual ~Type_handler_newdecimal() {}
- const Name name() const { return m_name_decimal; }
- enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ enum_field_types field_type() const override { return MYSQL_TYPE_NEWDECIMAL; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
+ uint calc_key_length(const Column_definition &def) const override;
+ void show_binlog_type(const Conv_source &src, const Field &, String *str)
+ const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *c,
handler *file,
- ulonglong table_flags) const;
+ ulonglong table_flags) const override;
bool Column_definition_redefine_stage1(Column_definition *def,
const Column_definition *dup,
const handler *file,
const Schema_specification_st *schema)
- const;
+ const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ ulonglong table_flags) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE_SHARE *share) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
class Type_handler_null: public Type_handler_general_purpose_string
{
- static const Name m_name_null;
public:
virtual ~Type_handler_null() {}
- const Name name() const { return m_name_null; }
- enum_field_types field_type() const { return MYSQL_TYPE_NULL; }
- const Type_handler *type_handler_for_comparison() const;
- const Type_handler *type_handler_for_tmp_table(const Item *item) const;
- const Type_handler *type_handler_for_union(const Item *) const;
- uint32 max_display_length(const Item *item) const { return 0; }
- uint32 calc_pack_length(uint32 length) const { return 0; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_NULL; }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ return DYN_COL_NULL;
+ }
+ const Type_handler *type_handler_for_comparison() const override;
+ const Type_handler *type_handler_for_tmp_table(const Item *item) const override;
+ const Type_handler *type_handler_for_union(const Item *) const override;
+ uint32 max_display_length(const Item *item) const override { return 0; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ {
+ return 0;
+ }
+ uint32 calc_pack_length(uint32 length) const override { return 0; }
bool Item_const_eq(const Item_const *a, const Item_const *b,
- bool binary_cmp) 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;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ bool binary_cmp) const override;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *c,
handler *file,
- ulonglong table_flags) const;
+ ulonglong table_flags) const override;
bool Column_definition_redefine_stage1(Column_definition *def,
const Column_definition *dup,
const handler *file,
const Schema_specification_st *schema)
- const;
+ const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_NULL); }
- Field *make_table_field(const LEX_CSTRING *name,
+ void
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+ uchar *buff) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE_SHARE *share) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
class Type_handler_longstr: public Type_handler_general_purpose_string
{
public:
- bool type_can_have_key_part() const
+ bool type_can_have_key_part() const override
{
return true;
}
@@ -5863,61 +6585,82 @@ public:
class Type_handler_string: public Type_handler_longstr
{
- static const Name m_name_char;
public:
virtual ~Type_handler_string() {}
- const Name name() const { return m_name_char; }
- enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
- bool is_param_long_data_type() const { return true; }
- uint32 calc_pack_length(uint32 length) const { return length; }
- const Type_handler *type_handler_for_tmp_table(const Item *item) const
+ enum_field_types field_type() const override { return MYSQL_TYPE_STRING; }
+ ulong KEY_pack_flags(uint column_nr) const override
+ {
+ return HA_PACK_KEY;
+ }
+ bool is_param_long_data_type() const override { return true; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override { return length; }
+ const Type_handler *type_handler_for_tmp_table(const Item *item) const override
{
return varstring_type_handler(item);
}
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ bool partition_field_check(const LEX_CSTRING &field_name,
+ Item *item_expr) const override
+ {
+ return partition_field_check_result_type(item_expr, STRING_RESULT);
+ }
+ void show_binlog_type(const Conv_source &src, const Field &dst, String *str)
+ const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_set_attributes(THD *thd,
+ Column_definition *def,
+ const Lex_field_type_st &attr,
+ CHARSET_INFO *cs,
+ column_definition_type_t type)
+ const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ ulonglong table_flags) const override;
+ bool Key_part_spec_init_ft(Key_part_spec *part,
+ const Column_definition &def) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE_SHARE *share) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
/* Old varchar */
class Type_handler_var_string: public Type_handler_string
{
- static const Name m_name_var_string;
public:
virtual ~Type_handler_var_string() {}
- const Name name() const { return m_name_var_string; }
- enum_field_types field_type() const { return MYSQL_TYPE_VAR_STRING; }
- enum_field_types real_field_type() const { return MYSQL_TYPE_STRING; }
- enum_field_types traditional_merge_field_type() const
+ enum_field_types field_type() const override { return MYSQL_TYPE_VAR_STRING; }
+ enum_field_types real_field_type() const override { return MYSQL_TYPE_STRING; }
+ enum_field_types traditional_merge_field_type() const override
{
return MYSQL_TYPE_VARCHAR;
}
- const Type_handler *type_handler_for_tmp_table(const Item *item) const
+ const Type_handler *type_handler_for_tmp_table(const Item *item) const override
{
return varstring_type_handler(item);
}
- void Column_definition_implicit_upgrade(Column_definition *c) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ void show_binlog_type(const Conv_source &src, const Field &dst, String *str)
+ const override;
+ void Column_definition_implicit_upgrade(Column_definition *c) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_STRING); }
- const Type_handler *type_handler_for_union(const Item *item) const
+ const Type_handler *type_handler_for_union(const Item *item) const override
{
return varstring_type_handler(item);
}
@@ -5926,65 +6669,114 @@ public:
class Type_handler_varchar: public Type_handler_longstr
{
- static const Name m_name_varchar;
public:
virtual ~Type_handler_varchar() {}
- const Name name() const { return m_name_varchar; }
- enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
- enum_field_types type_code_for_protocol() const
+ enum_field_types field_type() const override { return MYSQL_TYPE_VARCHAR; }
+ ulong KEY_pack_flags(uint column_nr) const override
+ {
+ if (column_nr == 0)
+ return HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
+ return HA_PACK_KEY;
+ }
+ enum_field_types type_code_for_protocol() const override
{
return MYSQL_TYPE_VAR_STRING; // Keep things compatible for old clients
}
- uint32 calc_pack_length(uint32 length) const
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override
{
return (length + (length < 256 ? 1: 2));
}
- const Type_handler *type_handler_for_tmp_table(const Item *item) const
+ const Type_handler *type_handler_for_tmp_table(const Item *item) const override
{
return varstring_type_handler(item);
}
- const Type_handler *type_handler_for_union(const Item *item) const
+ const Type_handler *type_handler_for_union(const Item *item) const override
{
return varstring_type_handler(item);
}
- bool is_param_long_data_type() const { return true; }
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ bool is_param_long_data_type() const override { return true; }
+ bool partition_field_check(const LEX_CSTRING &field_name,
+ Item *item_expr) const override
+ {
+ return partition_field_check_result_type(item_expr, STRING_RESULT);
+ }
+ void show_binlog_type(const Conv_source &src, const Field &dst, String *str)
+ const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_set_attributes(THD *thd,
+ Column_definition *def,
+ const Lex_field_type_st &attr,
+ CHARSET_INFO *cs,
+ column_definition_type_t type)
+ const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ ulonglong table_flags) const override;
+ bool Key_part_spec_init_ft(Key_part_spec *part,
+ const Column_definition &def) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE_SHARE *share) const override;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
- bool adjust_spparam_type(Spvar_definition *def, Item *from) const;
+ uint32 flags) const override;
+ bool adjust_spparam_type(Spvar_definition *def, Item *from) const override;
};
class Type_handler_hex_hybrid: public Type_handler_varchar
{
- static const Name m_name_hex_hybrid;
public:
virtual ~Type_handler_hex_hybrid() {}
- const Name name() const { return m_name_hex_hybrid; }
- const Type_handler *cast_to_int_type_handler() const;
- const Type_handler *type_handler_for_system_time() const;
+ const Type_handler *cast_to_int_type_handler() const override;
};
class Type_handler_varchar_compressed: public Type_handler_varchar
{
public:
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ enum_field_types real_field_type() const override
+ {
+ return MYSQL_TYPE_VARCHAR_COMPRESSED;
+ }
+ ulong KEY_pack_flags(uint column_nr) const override
+ {
+ DBUG_ASSERT(0);
+ return 0;
+ }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ bool partition_field_check(const LEX_CSTRING &field_name,
+ Item *item_expr) const override
+ {
+ partition_field_type_not_allowed(field_name);
+ return true;
+ }
+ void show_binlog_type(const Conv_source &src, const Field &dst, String *str)
+ const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ DBUG_ASSERT(0);
+ return DYN_COL_STRING;
+ }
};
@@ -5992,311 +6784,288 @@ class Type_handler_blob_common: public Type_handler_longstr
{
public:
virtual ~Type_handler_blob_common() { }
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ virtual uint length_bytes() const= 0;
+ ulong KEY_pack_flags(uint column_nr) const override
+ {
+ if (column_nr == 0)
+ return HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
+ return HA_PACK_KEY;
+ }
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
const Type_handler *type_handler_for_tmp_table(const Item *item) const
+ override
{
return blob_type_handler(item);
}
- const Type_handler *type_handler_for_union(const Item *item) const
+ const Type_handler *type_handler_for_union(const Item *item) const override
{
return blob_type_handler(item);
}
bool subquery_type_allows_materialization(const Item *inner,
- const Item *outer) const
+ const Item *outer) const override
{
return false; // Materialization does not work with BLOB columns
}
- bool is_param_long_data_type() const { return true; }
- bool Column_definition_fix_attributes(Column_definition *c) const;
- void Column_definition_reuse_fix_attributes(THD *thd,
- Column_definition *c,
- const Field *field) const;
+ bool is_param_long_data_type() const override { return true; }
+ uint calc_key_length(const Column_definition &def) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const;
+ ulonglong table_flags) const override;
+ void
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+ uchar *buff) const override;
+ bool Key_part_spec_init_ft(Key_part_spec *part,
+ const Column_definition &def) const override;
+ bool Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
+ bool Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *has_key_needed) const override;
+ bool Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
+ bool Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- Item **items, uint nitems) const;
- void Item_param_setup_conversion(THD *thd, Item_param *) const;
-
+ Item **items, uint nitems) const
+ override;
+ void Item_param_setup_conversion(THD *thd, Item_param *) const override;
+
+ bool partition_field_check(const LEX_CSTRING &field_name,
+ Item *item_expr) const override;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
+ const Vers_type_handler *vers() const override { return &vers_type_timestamp; }
};
class Type_handler_tiny_blob: public Type_handler_blob_common
{
- static const Name m_name_tinyblob;
public:
virtual ~Type_handler_tiny_blob() {}
- const Name name() const { return m_name_tinyblob; }
- enum_field_types field_type() const { return MYSQL_TYPE_TINY_BLOB; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ uint length_bytes() const override { return 1; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_TINY_BLOB; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
- uint max_octet_length() const { return UINT_MAX8; }
+ TABLE_SHARE *share) const override;
+ uint max_octet_length() const override { return UINT_MAX8; }
};
class Type_handler_medium_blob: public Type_handler_blob_common
{
- static const Name m_name_mediumblob;
public:
virtual ~Type_handler_medium_blob() {}
- const Name name() const { return m_name_mediumblob; }
- enum_field_types field_type() const { return MYSQL_TYPE_MEDIUM_BLOB; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ uint length_bytes() const override { return 3; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_MEDIUM_BLOB; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
- uint max_octet_length() const { return UINT_MAX24; }
+ TABLE_SHARE *share) const override;
+ uint max_octet_length() const override { return UINT_MAX24; }
};
class Type_handler_long_blob: public Type_handler_blob_common
{
- static const Name m_name_longblob;
public:
virtual ~Type_handler_long_blob() {}
- const Name name() const { return m_name_longblob; }
- enum_field_types field_type() const { return MYSQL_TYPE_LONG_BLOB; }
- uint32 calc_pack_length(uint32 length) const;
+ uint length_bytes() const override { return 4; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_LONG_BLOB; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
Item *create_typecast_item(THD *thd, Item *item,
- const Type_cast_attributes &attr) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ const Type_cast_attributes &attr) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
- uint max_octet_length() const { return UINT_MAX32; }
+ TABLE_SHARE *share) const override;
+ uint max_octet_length() const override { return UINT_MAX32; }
};
class Type_handler_blob: public Type_handler_blob_common
{
- static const Name m_name_blob;
public:
virtual ~Type_handler_blob() {}
- const Name name() const { return m_name_blob; }
- enum_field_types field_type() const { return MYSQL_TYPE_BLOB; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ uint length_bytes() const override { return 2; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_BLOB; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
- uint max_octet_length() const { return UINT_MAX16; }
+ TABLE_SHARE *share) const override;
+ uint max_octet_length() const override { return UINT_MAX16; }
};
class Type_handler_blob_compressed: public Type_handler_blob
{
public:
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
-};
-
-
-#ifdef HAVE_SPATIAL
-class Type_handler_geometry: public Type_handler_string_result
-{
- static const Name m_name_geometry;
-public:
- virtual ~Type_handler_geometry() {}
- const Name name() const { return m_name_geometry; }
- enum_field_types field_type() const { return MYSQL_TYPE_GEOMETRY; }
- bool is_param_long_data_type() const { return true; }
- uint32 calc_pack_length(uint32 length) const;
- const Type_handler *type_handler_for_comparison() const;
- bool type_can_have_key_part() const
+ enum_field_types real_field_type() const override
{
- return true;
+ return MYSQL_TYPE_BLOB_COMPRESSED;
}
- bool subquery_type_allows_materialization(const Item *inner,
- const Item *outer) const
+ ulong KEY_pack_flags(uint column_nr) const override
{
- return false; // Materialization does not work with GEOMETRY columns
+ DBUG_ASSERT(0);
+ return 0;
}
- void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
- bool Item_param_set_from_value(THD *thd,
- Item_param *param,
- const Type_all_attributes *attr,
- const st_value *value) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- void
- Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
- uchar *buff) const;
- bool
- Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
- TABLE_SHARE *share,
- const uchar *buffer,
- LEX_CUSTRING *gis_options) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
- void Column_definition_reuse_fix_attributes(THD *thd,
- Column_definition *c,
- const Field *field) const;
- bool Column_definition_prepare_stage1(THD *thd,
- MEM_ROOT *mem_root,
- Column_definition *c,
- handler *file,
- ulonglong table_flags) const;
- bool Column_definition_prepare_stage2(Column_definition *c,
- handler *file,
- ulonglong table_flags) const;
- Field *make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const;
-
- Field *make_table_field_from_def(TABLE_SHARE *share,
- MEM_ROOT *mem_root,
- const LEX_CSTRING *name,
- const Record_addr &addr,
- const Bit_addr &bit,
- const Column_definition_attributes *attr,
- uint32 flags) const;
-
- bool can_return_int() const { return false; }
- bool can_return_decimal() const { return false; }
- bool can_return_real() const { return false; }
- bool can_return_text() const { return false; }
- bool can_return_date() const { return false; }
- bool can_return_time() const { return false; }
- bool is_traditional_type() const
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ void show_binlog_type(const Conv_source &src, const Field &, String *str)
+ const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
{
- return false;
+ DBUG_ASSERT(0);
+ return DYN_COL_STRING;
}
- bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
- bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
- bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
- bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
- bool Item_hybrid_func_fix_attributes(THD *thd,
- const char *name,
- Type_handler_hybrid_field_type *h,
- Type_all_attributes *attr,
- Item **items, uint nitems) 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_func_signed_fix_length_and_dec(Item_func_signed *) const;
- bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *) const;
- bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *) const;
- bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *) const;
- bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *) const;
- bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const;
- bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *) const;
- bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *) const;
- bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *) const;
-};
-
-extern MYSQL_PLUGIN_IMPORT Type_handler_geometry type_handler_geometry;
-#endif
+};
class Type_handler_typelib: public Type_handler_general_purpose_string
{
public:
virtual ~Type_handler_typelib() { }
- enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
- const Type_handler *type_handler_for_item_field() const;
- const Type_handler *cast_to_int_type_handler() const;
+ enum_field_types field_type() const override { return MYSQL_TYPE_STRING; }
+ const Type_handler *type_handler_for_item_field() const override;
+ const Type_handler *cast_to_int_type_handler() const override;
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- Item **items, uint nitems) const;
+ Item **items, uint nitems)
+ const override;
void Column_definition_reuse_fix_attributes(THD *thd,
Column_definition *c,
- const Field *field) const;
+ const Field *field)
+ const override;
bool Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *c,
handler *file,
- ulonglong table_flags) const;
+ ulonglong table_flags)
+ const override;
bool Column_definition_redefine_stage1(Column_definition *def,
const Column_definition *dup,
const handler *file,
const Schema_specification_st *schema)
- const;
+ const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
- bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p) const;
+ uchar **pos, ulong len) const override;
+ const Vers_type_handler *vers() const override { return NULL; }
};
class Type_handler_enum: public Type_handler_typelib
{
- static const Name m_name_enum;
public:
virtual ~Type_handler_enum() {}
- const Name name() const { return m_name_enum; }
- enum_field_types real_field_type() const { return MYSQL_TYPE_ENUM; }
- enum_field_types traditional_merge_field_type() const
+ enum_field_types real_field_type() const override { return MYSQL_TYPE_ENUM; }
+ enum_field_types traditional_merge_field_type() const override
{
return MYSQL_TYPE_ENUM;
}
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ uint32 calc_pack_length(uint32 length) const override;
+ uint calc_key_length(const Column_definition &def) const override;
+ void
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+ uchar *buff) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target)
+ const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ ulonglong table_flags) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE_SHARE *share) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
};
class Type_handler_set: public Type_handler_typelib
{
- static const Name m_name_set;
public:
virtual ~Type_handler_set() {}
- const Name name() const { return m_name_set; }
- enum_field_types real_field_type() const { return MYSQL_TYPE_SET; }
- enum_field_types traditional_merge_field_type() const
+ enum_field_types real_field_type() const override { return MYSQL_TYPE_SET; }
+ enum_field_types traditional_merge_field_type() const override
{
return MYSQL_TYPE_SET;
}
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ uint32 calc_pack_length(uint32 length) const override;
+ uint calc_key_length(const Column_definition &def) const override;
+ void
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+ uchar *buff) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target)
+ const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ ulonglong table_flags) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE_SHARE *share) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -6305,10 +7074,45 @@ class Type_handler_interval_DDhhmmssff: public Type_handler_long_blob
{
public:
Item *create_typecast_item(THD *thd, Item *item,
- const Type_cast_attributes &attr) const;
+ const Type_cast_attributes &attr) const override;
+};
+
+
+class Function_collection
+{
+public:
+ virtual ~Function_collection() {}
+ virtual bool init()= 0;
+ virtual void cleanup()= 0;
+ virtual Create_func *find_native_function_builder(THD *thd,
+ const LEX_CSTRING &name)
+ const= 0;
};
+class Type_collection
+{
+public:
+ virtual ~Type_collection() {}
+ virtual bool init(Type_handler_data *data)
+ {
+ return false;
+ }
+ virtual const Type_handler *handler_by_name(const LEX_CSTRING &name) const= 0;
+ virtual const Type_handler *aggregate_for_result(const Type_handler *h1,
+ const Type_handler *h2)
+ const= 0;
+ virtual const Type_handler *aggregate_for_comparison(const Type_handler *h1,
+ const Type_handler *h2)
+ const= 0;
+ virtual const Type_handler *aggregate_for_min_max(const Type_handler *h1,
+ const Type_handler *h2)
+ const= 0;
+ virtual const Type_handler *aggregate_for_num_op(const Type_handler *h1,
+ const Type_handler *h2)
+ const= 0;
+};
+
/**
A handler for hybrid type functions, e.g.
@@ -6354,19 +7158,6 @@ public:
{
m_type_handler= other;
}
- const Type_handler *set_handler_by_result_type(Item_result type)
- {
- return (m_type_handler= Type_handler::get_handler_by_result_type(type));
- }
- const Type_handler *set_handler_by_result_type(Item_result type,
- uint max_octet_length,
- CHARSET_INFO *cs)
- {
- m_type_handler= Type_handler::get_handler_by_result_type(type);
- return m_type_handler=
- m_type_handler->type_handler_adjusted_to_max_octet_length(max_octet_length,
- cs);
- }
const Type_handler *set_handler_by_field_type(enum_field_types type)
{
return (m_type_handler= Type_handler::get_handler_by_field_type(type));
@@ -6388,57 +7179,76 @@ public:
const Type_handler *h0, const Type_handler *h1);
};
+/*
+ Helper template to simplify creating builtin types with names.
+ Plugin types inherit from Type_handler_xxx types that do not set the name in
+ the constructor, as sql_plugin.cc sets the type name from the plugin name.
+*/
+template <typename TypeHandler>
+class Named_type_handler : public TypeHandler
+{
+ public:
+ Named_type_handler(const char *n) : TypeHandler()
+ { Type_handler::set_name(Name(n, static_cast<uint>(strlen(n)))); }
+};
-extern MYSQL_PLUGIN_IMPORT Type_handler_row type_handler_row;
-extern MYSQL_PLUGIN_IMPORT Type_handler_null type_handler_null;
-
-extern MYSQL_PLUGIN_IMPORT Type_handler_float type_handler_float;
-extern MYSQL_PLUGIN_IMPORT Type_handler_double type_handler_double;
-
-extern MYSQL_PLUGIN_IMPORT Type_handler_bit type_handler_bit;
-
-extern MYSQL_PLUGIN_IMPORT Type_handler_enum type_handler_enum;
-extern MYSQL_PLUGIN_IMPORT Type_handler_set type_handler_set;
-
-extern MYSQL_PLUGIN_IMPORT Type_handler_string type_handler_string;
-extern MYSQL_PLUGIN_IMPORT Type_handler_var_string type_handler_var_string;
-extern MYSQL_PLUGIN_IMPORT Type_handler_varchar type_handler_varchar;
-extern MYSQL_PLUGIN_IMPORT Type_handler_hex_hybrid type_handler_hex_hybrid;
-
-extern MYSQL_PLUGIN_IMPORT Type_handler_tiny_blob type_handler_tiny_blob;
-extern MYSQL_PLUGIN_IMPORT Type_handler_medium_blob type_handler_medium_blob;
-extern MYSQL_PLUGIN_IMPORT Type_handler_long_blob type_handler_long_blob;
-extern MYSQL_PLUGIN_IMPORT Type_handler_blob type_handler_blob;
-
-extern MYSQL_PLUGIN_IMPORT Type_handler_bool type_handler_bool;
-extern MYSQL_PLUGIN_IMPORT Type_handler_tiny type_handler_tiny;
-extern MYSQL_PLUGIN_IMPORT Type_handler_short type_handler_short;
-extern MYSQL_PLUGIN_IMPORT Type_handler_int24 type_handler_int24;
-extern MYSQL_PLUGIN_IMPORT Type_handler_long type_handler_long;
-extern MYSQL_PLUGIN_IMPORT Type_handler_longlong type_handler_longlong;
-extern MYSQL_PLUGIN_IMPORT Type_handler_longlong type_handler_ulonglong;
-extern MYSQL_PLUGIN_IMPORT Type_handler_vers_trx_id type_handler_vers_trx_id;
-
-extern MYSQL_PLUGIN_IMPORT Type_handler_newdecimal type_handler_newdecimal;
-extern MYSQL_PLUGIN_IMPORT Type_handler_olddecimal type_handler_olddecimal;
-
-extern MYSQL_PLUGIN_IMPORT Type_handler_year type_handler_year;
-extern MYSQL_PLUGIN_IMPORT Type_handler_year type_handler_year2;
-extern MYSQL_PLUGIN_IMPORT Type_handler_newdate type_handler_newdate;
-extern MYSQL_PLUGIN_IMPORT Type_handler_date type_handler_date;
-extern MYSQL_PLUGIN_IMPORT Type_handler_time type_handler_time;
-extern MYSQL_PLUGIN_IMPORT Type_handler_time2 type_handler_time2;
-extern MYSQL_PLUGIN_IMPORT Type_handler_datetime type_handler_datetime;
-extern MYSQL_PLUGIN_IMPORT Type_handler_datetime2 type_handler_datetime2;
-extern MYSQL_PLUGIN_IMPORT Type_handler_timestamp type_handler_timestamp;
-extern MYSQL_PLUGIN_IMPORT Type_handler_timestamp2 type_handler_timestamp2;
-
-extern MYSQL_PLUGIN_IMPORT Type_handler_interval_DDhhmmssff
- type_handler_interval_DDhhmmssff;
+extern Named_type_handler<Type_handler_row> type_handler_row;
+extern Named_type_handler<Type_handler_null> type_handler_null;
+
+extern Named_type_handler<Type_handler_float> type_handler_float;
+extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_double> type_handler_double;
+
+extern Named_type_handler<Type_handler_bit> type_handler_bit;
+
+extern Named_type_handler<Type_handler_enum> type_handler_enum;
+extern Named_type_handler<Type_handler_set> type_handler_set;
+
+extern Named_type_handler<Type_handler_string> type_handler_string;
+extern Named_type_handler<Type_handler_var_string> type_handler_var_string;
+extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_varchar> type_handler_varchar;
+extern Named_type_handler<Type_handler_varchar_compressed> type_handler_varchar_compressed;
+extern Named_type_handler<Type_handler_hex_hybrid> type_handler_hex_hybrid;
+
+extern Named_type_handler<Type_handler_tiny_blob> type_handler_tiny_blob;
+extern Named_type_handler<Type_handler_medium_blob> type_handler_medium_blob;
+extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_long_blob> type_handler_long_blob;
+extern Named_type_handler<Type_handler_blob> type_handler_blob;
+extern Named_type_handler<Type_handler_blob_compressed> type_handler_blob_compressed;
+
+extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_bool> type_handler_bool;
+extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_tiny> type_handler_stiny;
+extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_short> type_handler_sshort;
+extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_int24> type_handler_sint24;
+extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_long> type_handler_slong;
+extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_longlong> type_handler_slonglong;
+
+extern Named_type_handler<Type_handler_utiny> type_handler_utiny;
+extern Named_type_handler<Type_handler_ushort> type_handler_ushort;
+extern Named_type_handler<Type_handler_uint24> type_handler_uint24;
+extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_ulong> type_handler_ulong;
+extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_ulonglong> type_handler_ulonglong;
+extern Named_type_handler<Type_handler_vers_trx_id> type_handler_vers_trx_id;
+
+extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_newdecimal> type_handler_newdecimal;
+extern Named_type_handler<Type_handler_olddecimal> type_handler_olddecimal;
+
+extern Named_type_handler<Type_handler_year> type_handler_year;
+extern Named_type_handler<Type_handler_year> type_handler_year2;
+extern Named_type_handler<Type_handler_newdate> type_handler_newdate;
+extern Named_type_handler<Type_handler_date> type_handler_date;
+extern Named_type_handler<Type_handler_time> type_handler_time;
+extern Named_type_handler<Type_handler_time2> type_handler_time2;
+extern Named_type_handler<Type_handler_datetime> type_handler_datetime;
+extern Named_type_handler<Type_handler_datetime2> type_handler_datetime2;
+extern Named_type_handler<Type_handler_timestamp> type_handler_timestamp;
+extern Named_type_handler<Type_handler_timestamp2> type_handler_timestamp2;
+
+extern Type_handler_interval_DDhhmmssff type_handler_interval_DDhhmmssff;
class Type_aggregator
{
bool m_is_commutative;
+public:
class Pair
{
public:
@@ -6456,12 +7266,29 @@ class Type_aggregator
return m_handler1 == handler1 && m_handler2 == handler2;
}
};
+ static const Type_handler *
+ find_handler_in_array(const Type_aggregator::Pair *pairs,
+ const Type_handler *h1,
+ const Type_handler *h2,
+ bool commutative)
+ {
+ for (const Type_aggregator::Pair *p= pairs; p->m_result; p++)
+ {
+ if (p->eq(h1, h2))
+ return p->m_result;
+ if (commutative && p->eq(h2, h1))
+ return p->m_result;
+ }
+ return NULL;
+ }
+
+private:
Dynamic_array<Pair> m_array;
const Pair* find_pair(const Type_handler *handler1,
const Type_handler *handler2) const;
public:
Type_aggregator(bool is_commutative= false)
- :m_is_commutative(is_commutative)
+ :m_is_commutative(is_commutative), m_array(PSI_INSTRUMENT_MEM)
{ }
bool add(const Type_handler *handler1,
const Type_handler *handler2,
@@ -6507,7 +7334,6 @@ public:
bool init();
};
-
extern Type_handler_data *type_handler_data;
#endif /* SQL_TYPE_H_INCLUDED */
diff --git a/sql/sql_type_geom.cc b/sql/sql_type_geom.cc
new file mode 100644
index 00000000000..c177eae2408
--- /dev/null
+++ b/sql/sql_type_geom.cc
@@ -0,0 +1,965 @@
+/*
+ Copyright (c) 2015, 2020, 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 Street, Fifth Floor, Boston, MA 02111-1301 USA */
+
+#include "mariadb.h"
+
+#ifdef HAVE_SPATIAL
+
+#include "sql_class.h"
+#include "sql_type_geom.h"
+#include "item_geofunc.h"
+
+Named_type_handler<Type_handler_geometry> type_handler_geometry("geometry");
+Named_type_handler<Type_handler_point> type_handler_point("point");
+Named_type_handler<Type_handler_linestring> type_handler_linestring("linestring");
+Named_type_handler<Type_handler_polygon> type_handler_polygon("polygon");
+Named_type_handler<Type_handler_multipoint> type_handler_multipoint("multipoint");
+Named_type_handler<Type_handler_multilinestring> type_handler_multilinestring("multilinestring");
+Named_type_handler<Type_handler_multipolygon> type_handler_multipolygon("multipolygon");
+Named_type_handler<Type_handler_geometrycollection> type_handler_geometrycollection("geometrycollection");
+
+Type_collection_geometry type_collection_geometry;
+
+
+LEX_CSTRING Type_handler_geometry::extended_metadata_data_type_name() const
+{
+ return geometry_type() == GEOM_GEOMETRY ? null_clex_str :
+ name().lex_cstring();
+}
+
+
+const Type_handler_geometry *
+Type_handler_geometry::type_handler_geom_by_type(uint type)
+{
+ switch (type) {
+ case Type_handler_geometry::GEOM_POINT:
+ return &type_handler_point;
+ case Type_handler_geometry::GEOM_LINESTRING:
+ return &type_handler_linestring;
+ case Type_handler_geometry::GEOM_POLYGON:
+ return &type_handler_polygon;
+ case Type_handler_geometry::GEOM_MULTIPOINT:
+ return &type_handler_multipoint;
+ case Type_handler_geometry::GEOM_MULTILINESTRING:
+ return &type_handler_multilinestring;
+ case Type_handler_geometry::GEOM_MULTIPOLYGON:
+ return &type_handler_multipolygon;
+ case Type_handler_geometry::GEOM_GEOMETRYCOLLECTION:
+ return &type_handler_geometrycollection;
+ case Type_handler_geometry::GEOM_GEOMETRY:
+ break;
+ }
+ return &type_handler_geometry;
+}
+
+
+const Type_handler *
+Type_collection_geometry::handler_by_name(const LEX_CSTRING &name) const
+{
+ if (type_handler_point.name().eq(name))
+ return &type_handler_point;
+ if (type_handler_linestring.name().eq(name))
+ return &type_handler_linestring;
+ if (type_handler_polygon.name().eq(name))
+ return &type_handler_polygon;
+ if (type_handler_multipoint.name().eq(name))
+ return &type_handler_multipoint;
+ if (type_handler_multilinestring.name().eq(name))
+ return &type_handler_multilinestring;
+ if (type_handler_multipolygon.name().eq(name))
+ return &type_handler_multipolygon;
+ if (type_handler_geometry.name().eq(name))
+ return &type_handler_geometry;
+ if (type_handler_geometrycollection.name().eq(name))
+ return &type_handler_geometrycollection;
+ return NULL;
+}
+
+
+const Type_collection *Type_handler_geometry::type_collection() const
+{
+ return &type_collection_geometry;
+}
+
+
+const Type_handler *
+Type_handler_geometry::type_handler_frm_unpack(const uchar *buffer) const
+{
+ // charset and geometry_type share the same byte in frm
+ return type_handler_geom_by_type((uint) buffer[14]);
+}
+
+
+const Type_handler *
+Type_collection_geometry::aggregate_for_comparison(const Type_handler *a,
+ const Type_handler *b)
+ const
+{
+ const Type_handler *h;
+ if ((h= aggregate_common(a, b)) ||
+ (h= aggregate_if_null(a, b)) ||
+ (h= aggregate_if_long_blob(a, b)))
+ return h;
+ return NULL;
+}
+
+
+const Type_handler *
+Type_collection_geometry::aggregate_for_result(const Type_handler *a,
+ const Type_handler *b)
+ const
+{
+ const Type_handler *h;
+ if ((h= aggregate_common(a, b)) ||
+ (h= aggregate_if_null(a, b)) ||
+ (h= aggregate_if_long_blob(a, b)) ||
+ (h= aggregate_if_string(a, b)))
+ return h;
+ return NULL;
+}
+
+
+const Type_handler *
+Type_collection_geometry::aggregate_for_min_max(const Type_handler *a,
+ const Type_handler *b)
+ const
+{
+ const Type_handler *h;
+ if ((h= aggregate_common(a, b)) ||
+ (h= aggregate_if_null(a, b)) ||
+ (h= aggregate_if_long_blob(a, b)) ||
+ (h= aggregate_if_string(a, b)))
+ return h;
+ return NULL;
+}
+
+
+const Type_handler *
+Type_collection_geometry::aggregate_if_string(const Type_handler *a,
+ const Type_handler *b) const
+{
+ if (a->type_collection() == this)
+ {
+ DBUG_ASSERT(b->type_collection() != this);
+ swap_variables(const Type_handler *, a, b);
+ }
+ if (a == &type_handler_hex_hybrid ||
+ a == &type_handler_tiny_blob ||
+ a == &type_handler_blob ||
+ a == &type_handler_medium_blob ||
+ a == &type_handler_varchar ||
+ a == &type_handler_string)
+ return &type_handler_long_blob;
+ return NULL;
+}
+
+
+#ifndef DBUG_OFF
+bool Type_collection_geometry::init_aggregators(Type_handler_data *data,
+ const Type_handler *geom) const
+{
+ Type_aggregator *r= &data->m_type_aggregator_for_result;
+ return
+ r->add(geom, &type_handler_hex_hybrid, &type_handler_long_blob) ||
+ r->add(geom, &type_handler_tiny_blob, &type_handler_long_blob) ||
+ r->add(geom, &type_handler_blob, &type_handler_long_blob) ||
+ r->add(geom, &type_handler_medium_blob, &type_handler_long_blob) ||
+ r->add(geom, &type_handler_varchar, &type_handler_long_blob) ||
+ r->add(geom, &type_handler_string, &type_handler_long_blob);
+}
+#endif
+
+
+bool Type_collection_geometry::init(Type_handler_data *data)
+{
+#ifndef DBUG_OFF
+ Type_aggregator *nct= &data->m_type_aggregator_non_commutative_test;
+ if (nct->add(&type_handler_point,
+ &type_handler_varchar,
+ &type_handler_long_blob))
+ return true;
+ return
+ init_aggregators(data, &type_handler_geometry) ||
+ init_aggregators(data, &type_handler_geometrycollection) ||
+ init_aggregators(data, &type_handler_point) ||
+ init_aggregators(data, &type_handler_linestring) ||
+ init_aggregators(data, &type_handler_polygon) ||
+ init_aggregators(data, &type_handler_multipoint) ||
+ init_aggregators(data, &type_handler_multilinestring) ||
+ init_aggregators(data, &type_handler_multipolygon);
+#endif // DBUG_OFF
+ return false;
+}
+
+
+bool Type_handler_geometry::check_type_geom_or_binary(const char *opname,
+ const Item *item)
+{
+ const Type_handler *handler= item->type_handler();
+ if (handler->type_handler_for_comparison() == &type_handler_geometry ||
+ (handler->is_general_purpose_string_type() &&
+ item->collation.collation == &my_charset_bin))
+ return false;
+ my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
+ handler->name().ptr(), opname);
+ return true;
+}
+
+
+bool Type_handler_geometry::check_types_geom_or_binary(const char *opname,
+ Item* const *args,
+ uint start, uint end)
+{
+ for (uint i= start; i < end ; i++)
+ {
+ if (check_type_geom_or_binary(opname, args[i]))
+ return true;
+ }
+ return false;
+}
+
+
+const Type_handler *Type_handler_geometry::type_handler_for_comparison() const
+{
+ return &type_handler_geometry;
+}
+
+
+Field *Type_handler_geometry::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ DBUG_ASSERT(target->type() == MYSQL_TYPE_GEOMETRY);
+ /*
+ We do not do not update feature_gis statistics here:
+ status_var_increment(target->table->in_use->status_var.feature_gis);
+ as this is only a temporary field.
+ The statistics was already incremented when "target" was created.
+ */
+ const Field_geom *fg= static_cast<const Field_geom*>(target);
+ return new (root)
+ Field_geom(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str,
+ table->s, 4, fg->type_handler_geom(), fg->srid);
+}
+
+
+bool Type_handler_geometry::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ def->flags|= BLOB_FLAG;
+ return false;
+}
+
+void Type_handler_geometry::
+ Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *def,
+ const Field *field) const
+{
+ def->srid= ((Field_geom*) field)->srid;
+}
+
+
+bool Type_handler_geometry::
+ Column_definition_prepare_stage1(THD *thd,
+ MEM_ROOT *mem_root,
+ Column_definition *def,
+ handler *file,
+ ulonglong table_flags) const
+{
+ def->create_length_to_internal_length_string();
+ return def->prepare_blob_field(thd);
+}
+
+
+bool Type_handler_geometry::
+ Column_definition_prepare_stage2(Column_definition *def,
+ handler *file,
+ ulonglong table_flags) const
+{
+ if (!(table_flags & HA_CAN_GEOMETRY))
+ {
+ my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "GEOMETRY");
+ return true;
+ }
+ return def->prepare_stage2_blob(file, table_flags, FIELDFLAG_GEOM);
+}
+
+bool Type_handler_geometry::Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ return part->check_primary_key_for_blob(file);
+}
+
+
+bool Type_handler_geometry::Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *hash_field_needed) const
+{
+ if (!part->length)
+ *hash_field_needed= true;
+ return part->check_key_for_blob(file);
+}
+
+
+bool Type_handler_geometry::Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ return part->init_multiple_key_for_blob(file);
+}
+
+
+bool Type_handler_geometry::Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ return part->check_foreign_key_for_blob(file);
+}
+
+
+bool Type_handler_geometry::Key_part_spec_init_spatial(Key_part_spec *part,
+ const Column_definition &def)
+ const
+{
+ if (part->length)
+ {
+ my_error(ER_WRONG_SUB_KEY, MYF(0));
+ return true;
+ }
+ /*
+ 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
+ Lately we'll extend this code to support more dimensions
+ */
+ part->length= 4 * sizeof(double);
+ return false;
+}
+
+
+Item *
+Type_handler_geometry::create_typecast_item(THD *thd, Item *item,
+ const Type_cast_attributes &attr)
+ const
+{
+ DBUG_EXECUTE_IF("emulate_geometry_create_typecast_item",
+ return new (thd->mem_root) Item_func_geometry_from_text(thd, item);
+ );
+
+ return NULL;
+}
+
+bool Type_handler_point::Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ /*
+ QQ:
+ The below assignment (here and in all other Key_part_spec_init_xxx methods)
+ overrides the explicitly given key part length, so in this query:
+ CREATE OR REPLACE TABLE t1 (a POINT, KEY(a(10)));
+ the key becomes KEY(a(25)).
+ This might be a bug.
+ */
+ part->length= octet_length();
+ return part->check_key_for_blob(file);
+}
+
+
+bool Type_handler_point::Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *hash_field_needed) const
+{
+ part->length= octet_length();
+ return part->check_key_for_blob(file);
+}
+
+
+bool Type_handler_point::Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length= octet_length();
+ return part->check_key_for_blob(file);
+}
+
+
+bool Type_handler_point::Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length= octet_length();
+ return part->check_key_for_blob(file);
+}
+
+
+Item *
+Type_handler_point::make_constructor_item(THD *thd, List<Item> *args) const
+{
+ if (!args || args->elements != 2)
+ return NULL;
+ Item_args tmp(thd, *args);
+ return new (thd->mem_root) Item_func_point(thd,
+ tmp.arguments()[0],
+ tmp.arguments()[1]);
+}
+
+
+Item *
+Type_handler_linestring::make_constructor_item(THD *thd, List<Item> *args) const
+{
+ return args ? new (thd->mem_root) Item_func_linestring(thd, *args) : NULL;
+}
+
+
+Item *
+Type_handler_polygon::make_constructor_item(THD *thd, List<Item> *args) const
+{
+ return args ? new (thd->mem_root) Item_func_polygon(thd, *args) : NULL;
+}
+
+
+Item *
+Type_handler_multipoint::make_constructor_item(THD *thd, List<Item> *args) const
+{
+ return args ? new (thd->mem_root) Item_func_multipoint(thd, *args) : NULL;
+}
+
+
+Item *
+Type_handler_multilinestring::make_constructor_item(THD *thd,
+ List<Item> *args) const
+{
+ return args ? new (thd->mem_root) Item_func_multilinestring(thd, *args) :
+ NULL;
+}
+
+
+Item *
+Type_handler_multipolygon::make_constructor_item(THD *thd,
+ List<Item> *args) const
+{
+ return args ? new (thd->mem_root) Item_func_multipolygon(thd, *args) : NULL;
+}
+
+
+Item *
+Type_handler_geometrycollection::make_constructor_item(THD *thd,
+ List<Item> *args) const
+{
+ return args ? new (thd->mem_root) Item_func_geometrycollection(thd, *args) :
+ NULL;
+}
+
+
+uint32 Type_handler_geometry::calc_pack_length(uint32 length) const
+{
+ return 4 + portable_sizeof_char_ptr;
+}
+
+
+Field *Type_handler_geometry::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+{
+ return new (root)
+ Field_geom(addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name, share, 4, this, 0);
+}
+
+
+bool Type_handler_geometry::
+ Item_hybrid_func_fix_attributes(THD *thd,
+ const char *func_name,
+ Type_handler_hybrid_field_type *handler,
+ Type_all_attributes *func,
+ Item **items, uint nitems) const
+{
+ DBUG_ASSERT(nitems > 0);
+ func->collation.set(&my_charset_bin);
+ func->unsigned_flag= false;
+ func->decimals= 0;
+ func->max_length= (uint32) UINT_MAX32;
+ func->set_maybe_null(true);
+ return false;
+}
+
+
+bool Type_handler_geometry::
+ Item_sum_sum_fix_length_and_dec(Item_sum_sum *item) const
+{
+ return Item_func_or_sum_illegal_param("sum");
+}
+
+
+bool Type_handler_geometry::
+ Item_sum_avg_fix_length_and_dec(Item_sum_avg *item) const
+{
+ return Item_func_or_sum_illegal_param("avg");
+}
+
+
+bool Type_handler_geometry::
+ Item_sum_variance_fix_length_and_dec(Item_sum_variance *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+
+bool Type_handler_geometry::
+ Item_func_signed_fix_length_and_dec(Item_func_signed *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_double_typecast_fix_length_and_dec(Item_double_typecast *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_float_typecast_fix_length_and_dec(Item_float_typecast *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) const
+{
+ if (item->cast_charset() != &my_charset_bin)
+ return Item_func_or_sum_illegal_param(item); // CAST(geom AS CHAR)
+ item->fix_length_and_dec_str();
+ return false; // CAST(geom AS BINARY)
+}
+
+
+bool Type_handler_geometry::
+ Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+
+bool Type_handler_geometry::
+ Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item)
+ const
+{
+ return Item_func_or_sum_illegal_param(item);
+
+}
+
+
+bool Type_handler_geometry::
+ Item_param_set_from_value(THD *thd,
+ Item_param *param,
+ const Type_all_attributes *attr,
+ const st_value *val) const
+{
+ param->unsigned_flag= false;
+ param->setup_conversion_blob(thd);
+ return param->set_str(val->m_string.ptr(), val->m_string.length(),
+ &my_charset_bin, &my_charset_bin);
+}
+
+
+void Type_handler_geometry::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_null(); // Not possible type code in the client-server protocol
+}
+
+
+Field *Type_handler_geometry::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ status_var_increment(current_thd->status_var.feature_gis);
+ return new (root)
+ Field_geom(rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, share,
+ attr->pack_flag_to_pack_length(), this, attr->srid);
+}
+
+
+void Type_handler_geometry::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_GEOM) == 0);
+ def->frm_pack_basic(buff);
+ buff[11]= 0;
+ buff[14]= (uchar) geometry_type();
+}
+
+
+
+/* Values 1-40 reserved for 1-byte options,
+ 41-80 for 2-byte options,
+ 81-120 for 4-byte options,
+ 121-160 for 8-byte options,
+ other - varied length in next 1-3 bytes.
+*/
+enum extra2_gis_field_options {
+ FIELDGEOM_END=0,
+ FIELDGEOM_STORAGE_MODEL=1,
+ FIELDGEOM_PRECISION=2,
+ FIELDGEOM_SCALE=3,
+ FIELDGEOM_SRID=81,
+};
+
+
+uint
+Type_handler_geometry::
+ Column_definition_gis_options_image(uchar *cbuf,
+ const Column_definition &def) const
+{
+ if (cbuf)
+ {
+ cbuf[0]= FIELDGEOM_STORAGE_MODEL;
+ cbuf[1]= (uchar) Field_geom::GEOM_STORAGE_WKB;
+
+ cbuf[2]= FIELDGEOM_PRECISION;
+ cbuf[3]= (uchar) def.length;
+
+ cbuf[4]= FIELDGEOM_SCALE;
+ cbuf[5]= (uchar) def.decimals;
+
+ cbuf[6]= FIELDGEOM_SRID;
+ int4store(cbuf + 7, ((uint32) def.srid));
+
+ cbuf[11]= FIELDGEOM_END;
+ }
+ return 12;
+}
+
+
+static uint gis_field_options_read(const uchar *buf, size_t buf_len,
+ Field_geom::storage_type *st_type,
+ uint *precision, uint *scale, uint *srid)
+{
+ const uchar *buf_end= buf + buf_len;
+ const uchar *cbuf= buf;
+ int option_id;
+
+ *precision= *scale= *srid= 0;
+ *st_type= Field_geom::GEOM_STORAGE_WKB;
+
+ if (!buf) /* can only happen with the old FRM file */
+ goto end_of_record;
+
+ while (cbuf < buf_end)
+ {
+ switch ((option_id= *(cbuf++)))
+ {
+ case FIELDGEOM_STORAGE_MODEL:
+ *st_type= (Field_geom::storage_type) cbuf[0];
+ break;
+ case FIELDGEOM_PRECISION:
+ *precision= cbuf[0];
+ break;
+ case FIELDGEOM_SCALE:
+ *scale= cbuf[0];
+ break;
+ case FIELDGEOM_SRID:
+ *srid= uint4korr(cbuf);
+ break;
+ case FIELDGEOM_END:
+ goto end_of_record;
+ }
+ if (option_id > 0 && option_id <= 40)
+ cbuf+= 1;
+ else if (option_id > 40 && option_id <= 80)
+ cbuf+= 2;
+ else if (option_id > 80 && option_id <= 120)
+ cbuf+= 4;
+ else if (option_id > 120 && option_id <= 160)
+ cbuf+= 8;
+ else /* > 160 and <=255 */
+ cbuf+= cbuf[0] ? 1 + cbuf[0] : 3 + uint2korr(cbuf+1);
+ }
+
+end_of_record:
+ return (uint)(cbuf - buf);
+}
+
+
+bool Type_handler_geometry::
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const
+{
+ uint gis_opt_read, gis_length, gis_decimals;
+ Field_geom::storage_type st_type;
+ attr->frm_unpack_basic(buffer);
+ gis_opt_read= gis_field_options_read(gis_options->str,
+ gis_options->length,
+ &st_type, &gis_length,
+ &gis_decimals, &attr->srid);
+ gis_options->str+= gis_opt_read;
+ gis_options->length-= gis_opt_read;
+ return false;
+}
+
+
+uint32
+Type_handler_geometry::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return (uint32) my_set_bits(4 * 8);
+}
+
+
+enum_conv_type
+Field_geom::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ return binlog_type() == source.real_field_type() ?
+ rpl_conv_type_from_same_data_type(source.metadata(), rli, param) :
+ CONV_TYPE_IMPOSSIBLE;
+}
+
+
+/*****************************************************************/
+void Field_geom::sql_type(String &res) const
+{
+ CHARSET_INFO *cs= &my_charset_latin1;
+ const Name tmp= m_type_handler->name();
+ res.set(tmp.ptr(), tmp.length(), cs);
+}
+
+
+int Field_geom::store(double nr)
+{
+ my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
+ ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
+ return -1;
+}
+
+
+int Field_geom::store(longlong nr, bool unsigned_val)
+{
+ my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
+ ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
+ return -1;
+}
+
+
+int Field_geom::store_decimal(const my_decimal *)
+{
+ my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
+ ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
+ return -1;
+}
+
+
+int Field_geom::store(const char *from, size_t length, CHARSET_INFO *cs)
+{
+ if (!length)
+ bzero(ptr, Field_blob::pack_length());
+ else
+ {
+ if (from == Geometry::bad_geometry_data.ptr())
+ goto err;
+ // Check given WKB
+ uint32 wkb_type;
+ if (length < SRID_SIZE + WKB_HEADER_SIZE + 4)
+ goto err;
+ wkb_type= uint4korr(from + SRID_SIZE + 1);
+ if (wkb_type < (uint32) Geometry::wkb_point ||
+ wkb_type > (uint32) Geometry::wkb_last)
+ goto err;
+
+ if (m_type_handler->geometry_type() != Type_handler_geometry::GEOM_GEOMETRY &&
+ m_type_handler->geometry_type() != Type_handler_geometry::GEOM_GEOMETRYCOLLECTION &&
+ (uint32) m_type_handler->geometry_type() != wkb_type)
+ {
+ const char *db= table->s->db.str;
+ const char *tab_name= table->s->table_name.str;
+
+ if (!db)
+ db= "";
+ if (!tab_name)
+ tab_name= "";
+
+ Geometry_buffer buffer;
+ Geometry *geom= NULL;
+ String wkt;
+ const char *dummy;
+ wkt.set_charset(&my_charset_latin1);
+ if (!(geom= Geometry::construct(&buffer, from, uint32(length))) ||
+ geom->as_wkt(&wkt, &dummy))
+ goto err;
+
+ my_error(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, MYF(0),
+ Geometry::ci_collection[m_type_handler->geometry_type()]->m_name.str,
+ wkt.c_ptr(),
+ db, tab_name, field_name.str,
+ (ulong) table->in_use->get_stmt_da()->
+ current_row_for_warning());
+ goto err_exit;
+ }
+
+ Field_blob::store_length(length);
+ if ((table->copy_blobs || length <= MAX_FIELD_WIDTH) &&
+ from != value.ptr())
+ { // Must make a copy
+ value.copy(from, length, cs);
+ from= value.ptr();
+ }
+ bmove(ptr + packlength, &from, sizeof(char*));
+ }
+ return 0;
+
+err:
+ my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
+ ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
+err_exit:
+ bzero(ptr, Field_blob::pack_length());
+ return -1;
+}
+
+
+bool Field_geom::is_equal(const Column_definition &new_field) const
+{
+ /*
+ - Allow ALTER..INPLACE to supertype (GEOMETRY),
+ e.g. POINT to GEOMETRY or POLYGON to GEOMETRY.
+ - Allow ALTER..INPLACE to the same geometry type: POINT -> POINT
+ */
+ if (new_field.type_handler() == m_type_handler)
+ return true;
+ const Type_handler_geometry *gth=
+ dynamic_cast<const Type_handler_geometry*>(new_field.type_handler());
+ return gth && gth->is_binary_compatible_geom_super_type_for(m_type_handler);
+}
+
+
+bool Field_geom::can_optimize_range(const Item_bool_func *cond,
+ const Item *item,
+ bool is_eq_func) const
+{
+ return item->cmp_type() == STRING_RESULT;
+}
+
+
+bool Field_geom::load_data_set_no_data(THD *thd, bool fixed_format)
+{
+ return Field_geom::load_data_set_null(thd);
+}
+
+
+bool Field_geom::load_data_set_null(THD *thd)
+{
+ Field_blob::reset();
+ if (!maybe_null())
+ {
+ my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field_name.str,
+ thd->get_stmt_da()->current_row_for_warning());
+ return true;
+ }
+ set_null();
+ set_has_explicit_value(); // Do not auto-update this field
+ return false;
+}
+
+
+uint Field_geom::get_key_image(uchar *buff,uint length, imagetype type_arg)
+{
+ if (type_arg == itMBR)
+ {
+ LEX_CSTRING tmp;
+ tmp.str= (const char *) get_ptr();
+ tmp.length= get_length(ptr);
+ return Geometry::get_key_image_itMBR(tmp, buff, length);
+ }
+ return Field_blob::get_key_image_itRAW(buff, length);
+}
+
+Binlog_type_info Field_geom::binlog_type_info() const
+{
+ DBUG_ASSERT(Field_geom::type() == binlog_type());
+ return Binlog_type_info(Field_geom::type(), pack_length_no_ptr(), 1,
+ field_charset(), type_handler_geom()->geometry_type());
+}
+
+#endif // HAVE_SPATIAL
diff --git a/sql/sql_type_geom.h b/sql/sql_type_geom.h
new file mode 100644
index 00000000000..b1aa8063902
--- /dev/null
+++ b/sql/sql_type_geom.h
@@ -0,0 +1,435 @@
+#ifndef SQL_TYPE_GEOM_H_INCLUDED
+#define SQL_TYPE_GEOM_H_INCLUDED
+/*
+ Copyright (c) 2015 MariaDB Foundation
+ Copyright (c) 2019 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 Street, Fifth Floor, Boston, MA 02111-1301 USA */
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mariadb.h"
+#include "sql_type.h"
+
+#ifdef HAVE_SPATIAL
+class Type_handler_geometry: public Type_handler_string_result
+{
+public:
+ enum geometry_types
+ {
+ GEOM_GEOMETRY = 0, GEOM_POINT = 1, GEOM_LINESTRING = 2, GEOM_POLYGON = 3,
+ GEOM_MULTIPOINT = 4, GEOM_MULTILINESTRING = 5, GEOM_MULTIPOLYGON = 6,
+ GEOM_GEOMETRYCOLLECTION = 7
+ };
+ static bool check_type_geom_or_binary(const char *opname, const Item *item);
+ static bool check_types_geom_or_binary(const char *opname,
+ Item * const *args,
+ uint start, uint end);
+ static const Type_handler_geometry *type_handler_geom_by_type(uint type);
+ LEX_CSTRING extended_metadata_data_type_name() const;
+public:
+ virtual ~Type_handler_geometry() {}
+ enum_field_types field_type() const override { return MYSQL_TYPE_GEOMETRY; }
+ bool Item_append_extended_type_info(Send_field_extended_metadata *to,
+ const Item *item) const override
+ {
+ LEX_CSTRING tmp= extended_metadata_data_type_name();
+ return tmp.length ? to->set_data_type_name(tmp) : false;
+ }
+ bool is_param_long_data_type() const override { return true; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
+ const Type_collection *type_collection() const override;
+ const Type_handler *type_handler_for_comparison() const override;
+ virtual geometry_types geometry_type() const { return GEOM_GEOMETRY; }
+ virtual Item *create_typecast_item(THD *thd, Item *item,
+ const Type_cast_attributes &attr)
+ const override;
+ const Type_handler *type_handler_frm_unpack(const uchar *buffer)
+ const override;
+ bool is_binary_compatible_geom_super_type_for(const Type_handler_geometry *th)
+ const
+ {
+ return geometry_type() == GEOM_GEOMETRY ||
+ geometry_type() == th->geometry_type();
+ }
+ bool type_can_have_key_part() const override { return true; }
+ bool subquery_type_allows_materialization(const Item *inner,
+ const Item *outer) const override
+ {
+ return false; // Materialization does not work with GEOMETRY columns
+ }
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const override;
+ bool Item_param_set_from_value(THD *thd,
+ Item_param *param,
+ const Type_all_attributes *attr,
+ const st_value *value) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ uint Column_definition_gis_options_image(uchar *buff,
+ const Column_definition &def)
+ const override;
+ bool Column_definition_data_type_info_image(Binary_string *to,
+ const Column_definition &def)
+ const override
+ {
+ return false;
+ }
+ void
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+ uchar *buff) const override;
+ bool
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options) const
+ override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
+ void Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *c,
+ const Field *field) const
+ override;
+ bool Column_definition_prepare_stage1(THD *thd,
+ MEM_ROOT *mem_root,
+ Column_definition *c,
+ handler *file,
+ ulonglong table_flags) const override;
+ bool Column_definition_prepare_stage2(Column_definition *c,
+ handler *file,
+ ulonglong table_flags) const override;
+ bool Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
+ bool Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *has_key_needed) const override;
+ bool Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
+ bool Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
+ bool Key_part_spec_init_spatial(Key_part_spec *part,
+ const Column_definition &def) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const override;
+
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const override;
+
+ bool can_return_int() const override { return false; }
+ bool can_return_decimal() const override { return false; }
+ bool can_return_real() const override { return false; }
+ bool can_return_text() const override { return false; }
+ bool can_return_date() const override { return false; }
+ bool can_return_time() const override { return false; }
+ bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
+ bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const override;
+ bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override;
+ bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override;
+ bool Item_hybrid_func_fix_attributes(THD *thd,
+ const char *name,
+ Type_handler_hybrid_field_type *h,
+ Type_all_attributes *attr,
+ Item **items, uint nitems) const
+ override;
+ bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override;
+ bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override;
+ bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override;
+
+ bool Item_func_signed_fix_length_and_dec(Item_func_signed *) const override;
+ bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *) const
+ override;
+ bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *) const
+ override;
+ bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *) const
+ override;
+ bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *) const
+ override;
+ bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const
+ override;
+ bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *) const
+ override;
+ bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *) const
+ override;
+ bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *) const
+ override;
+};
+
+
+class Type_handler_point: public Type_handler_geometry
+{
+ // Binary length of a POINT value: 4 byte SRID + 21 byte WKB POINT
+ static uint octet_length() { return 25; }
+public:
+ geometry_types geometry_type() const override { return GEOM_POINT; }
+ Item *make_constructor_item(THD *thd, List<Item> *args) const override;
+ bool Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
+ bool Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *has_key_needed) const override;
+ bool Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
+ bool Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
+};
+
+
+class Type_handler_linestring: public Type_handler_geometry
+{
+public:
+ geometry_types geometry_type() const override { return GEOM_LINESTRING; }
+ Item *make_constructor_item(THD *thd, List<Item> *args) const override;
+};
+
+
+class Type_handler_polygon: public Type_handler_geometry
+{
+public:
+ geometry_types geometry_type() const override { return GEOM_POLYGON; }
+ Item *make_constructor_item(THD *thd, List<Item> *args) const override;
+};
+
+
+class Type_handler_multipoint: public Type_handler_geometry
+{
+public:
+ geometry_types geometry_type() const override { return GEOM_MULTIPOINT; }
+ Item *make_constructor_item(THD *thd, List<Item> *args) const override;
+};
+
+
+class Type_handler_multilinestring: public Type_handler_geometry
+{
+public:
+ geometry_types geometry_type() const override { return GEOM_MULTILINESTRING; }
+ Item *make_constructor_item(THD *thd, List<Item> *args) const override;
+};
+
+
+class Type_handler_multipolygon: public Type_handler_geometry
+{
+public:
+ geometry_types geometry_type() const override { return GEOM_MULTIPOLYGON; }
+ Item *make_constructor_item(THD *thd, List<Item> *args) const override;
+};
+
+
+class Type_handler_geometrycollection: public Type_handler_geometry
+{
+public:
+ geometry_types geometry_type() const override { return GEOM_GEOMETRYCOLLECTION; }
+ Item *make_constructor_item(THD *thd, List<Item> *args) const override;
+};
+
+extern Named_type_handler<Type_handler_geometry> type_handler_geometry;
+extern Named_type_handler<Type_handler_point> type_handler_point;
+extern Named_type_handler<Type_handler_linestring> type_handler_linestring;
+extern Named_type_handler<Type_handler_polygon> type_handler_polygon;
+extern Named_type_handler<Type_handler_multipoint> type_handler_multipoint;
+extern Named_type_handler<Type_handler_multilinestring> type_handler_multilinestring;
+extern Named_type_handler<Type_handler_multipolygon> type_handler_multipolygon;
+extern Named_type_handler<Type_handler_geometrycollection> type_handler_geometrycollection;
+
+class Type_collection_geometry: public Type_collection
+{
+ const Type_handler *aggregate_common(const Type_handler *a,
+ const Type_handler *b) const
+ {
+ if (a == b)
+ return a;
+ if (dynamic_cast<const Type_handler_geometry*>(a) &&
+ dynamic_cast<const Type_handler_geometry*>(b))
+ return &type_handler_geometry;
+ return NULL;
+ }
+ const Type_handler *aggregate_if_null(const Type_handler *a,
+ const Type_handler *b) const
+ {
+ return a == &type_handler_null ? b :
+ b == &type_handler_null ? a :
+ NULL;
+ }
+ const Type_handler *aggregate_if_long_blob(const Type_handler *a,
+ const Type_handler *b) const
+ {
+ return a == &type_handler_long_blob ? &type_handler_long_blob :
+ b == &type_handler_long_blob ? &type_handler_long_blob :
+ NULL;
+ }
+ const Type_handler *aggregate_if_string(const Type_handler *a,
+ const Type_handler *b) const;
+#ifndef DBUG_OFF
+ bool init_aggregators(Type_handler_data *data, const Type_handler *geom) const;
+#endif
+public:
+ bool init(Type_handler_data *data) override;
+ const Type_handler *handler_by_name(const LEX_CSTRING &name) const override;
+ const Type_handler *aggregate_for_result(const Type_handler *a,
+ const Type_handler *b)
+ const override;
+ const Type_handler *aggregate_for_comparison(const Type_handler *a,
+ const Type_handler *b)
+ const override;
+ const Type_handler *aggregate_for_min_max(const Type_handler *a,
+ const Type_handler *b)
+ const override;
+ const Type_handler *aggregate_for_num_op(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return NULL;
+ }
+};
+
+extern Type_collection_geometry type_collection_geometry;
+
+#include "field.h"
+
+class Field_geom :public Field_blob
+{
+ const Type_handler_geometry *m_type_handler;
+public:
+ uint srid;
+ uint precision;
+ enum storage_type { GEOM_STORAGE_WKB= 0, GEOM_STORAGE_BINARY= 1};
+ enum storage_type storage;
+
+ Field_geom(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
+ enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
+ TABLE_SHARE *share, uint blob_pack_length,
+ const Type_handler_geometry *gth,
+ uint field_srid)
+ :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
+ field_name_arg, share, blob_pack_length, &my_charset_bin),
+ m_type_handler(gth)
+ { srid= field_srid; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
+ enum ha_base_keytype key_type() const override
+ {
+ return HA_KEYTYPE_VARBINARY2;
+ }
+ const Type_handler *type_handler() const override
+ {
+ return m_type_handler;
+ }
+ const Type_handler_geometry *type_handler_geom() const
+ {
+ return m_type_handler;
+ }
+ void set_type_handler(const Type_handler_geometry *th)
+ {
+ m_type_handler= th;
+ }
+ enum_field_types type() const override
+ {
+ return MYSQL_TYPE_GEOMETRY;
+ }
+ enum_field_types real_type() const override
+ {
+ return MYSQL_TYPE_GEOMETRY;
+ }
+ Information_schema_character_attributes
+ information_schema_character_attributes() const override
+ {
+ return Information_schema_character_attributes();
+ }
+ void make_send_field(Send_field *to) override
+ {
+ Field_longstr::make_send_field(to);
+ LEX_CSTRING tmp= m_type_handler->extended_metadata_data_type_name();
+ if (tmp.length)
+ to->set_data_type_name(tmp);
+ }
+ bool can_optimize_range(const Item_bool_func *cond,
+ const Item *item,
+ bool is_eq_func) const override;
+ void sql_type(String &str) const override;
+ Copy_func *get_copy_func(const Field *from) const override
+ {
+ const Type_handler_geometry *fth=
+ dynamic_cast<const Type_handler_geometry*>(from->type_handler());
+ if (fth && m_type_handler->is_binary_compatible_geom_super_type_for(fth))
+ return get_identical_copy_func();
+ return do_conv_blob;
+ }
+ bool memcpy_field_possible(const Field *from) const override
+ {
+ const Type_handler_geometry *fth=
+ dynamic_cast<const Type_handler_geometry*>(from->type_handler());
+ return fth &&
+ m_type_handler->is_binary_compatible_geom_super_type_for(fth) &&
+ !table->copy_blobs;
+ }
+ bool is_equal(const Column_definition &new_field) const override;
+ bool can_be_converted_by_engine(const Column_definition &new_type)
+ const override
+ {
+ return false; // Override the Field_blob behavior
+ }
+
+ int store(const char *to, size_t length, CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ int store_decimal(const my_decimal *) override;
+ uint size_of() const override{ return sizeof(*this); }
+ /**
+ Key length is provided only to support hash joins. (compared byte for byte)
+ Ex: SELECT .. FROM t1,t2 WHERE t1.field_geom1=t2.field_geom2.
+
+ The comparison is not very relevant, as identical geometry might be
+ represented differently, but we need to support it either way.
+ */
+ uint32 key_length() const override{ return packlength; }
+ uint get_key_image(uchar *buff,uint length, imagetype type_arg) override;
+
+ /**
+ Non-nullable GEOMETRY types cannot have defaults,
+ but the underlying blob must still be reset.
+ */
+ int reset(void) override{ return Field_blob::reset() || !maybe_null(); }
+ bool load_data_set_null(THD *thd) override;
+ bool load_data_set_no_data(THD *thd, bool fixed_format) override;
+
+ uint get_srid() const { return srid; }
+ void print_key_value(String *out, uint32 length) override
+ {
+ out->append(STRING_WITH_LEN("unprintable_geometry_value"));
+ }
+ Binlog_type_info binlog_type_info() const override;
+};
+
+#endif // HAVE_SPATIAL
+
+#endif // SQL_TYPE_GEOM_H_INCLUDED
diff --git a/sql/sql_type_json.cc b/sql/sql_type_json.cc
index f53a247d816..a804366ec03 100644
--- a/sql/sql_type_json.cc
+++ b/sql/sql_type_json.cc
@@ -35,8 +35,10 @@ Type_handler_json_longtext::make_json_valid_expr(THD *thd,
Lex_ident_sys_st str;
Item *field, *expr;
str.set_valid_utf8(field_name);
- if (unlikely(!(field= thd->lex->create_item_ident_field(thd, NullS, NullS,
- &str))))
+ if (unlikely(!(field= thd->lex->create_item_ident_field(thd,
+ Lex_ident_sys(),
+ Lex_ident_sys(),
+ str))))
return 0;
if (unlikely(!(expr= new (thd->mem_root) Item_func_json_valid(thd, field))))
return 0;
diff --git a/sql/sql_type_string.cc b/sql/sql_type_string.cc
new file mode 100644
index 00000000000..df46ef744f0
--- /dev/null
+++ b/sql/sql_type_string.cc
@@ -0,0 +1,104 @@
+/*
+ Copyright (c) 2019, 2020 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 Street, Fifth Floor, Boston, MA 02111-1301 USA */
+
+#include "mariadb.h"
+
+#include "sql_class.h"
+#include "sql_type_string.h"
+
+
+uchar *
+StringPack::pack(uchar *to, const uchar *from, uint max_length) const
+{
+ size_t length= MY_MIN(m_octet_length, max_length);
+ size_t local_char_length= char_length();
+ DBUG_PRINT("debug", ("length: %zu ", length));
+
+ if (length > local_char_length)
+ local_char_length= charset()->charpos(from, from + length,
+ local_char_length);
+ set_if_smaller(length, local_char_length);
+
+ /*
+ TODO: change charset interface to add a new function that does
+ the following or add a flag to lengthsp to do it itself
+ (this is for not packing padding adding bytes in BINARY
+ fields).
+ */
+ if (mbmaxlen() == 1)
+ {
+ while (length && from[length-1] == charset()->pad_char)
+ length --;
+ }
+ else
+ length= charset()->lengthsp((const char*) from, length);
+
+ // Length always stored little-endian
+ *to++= (uchar) length;
+ if (m_octet_length > 255)
+ *to++= (uchar) (length >> 8);
+
+ // Store the actual bytes of the string
+ memcpy(to, from, length);
+ return to+length;
+}
+
+
+const uchar *
+StringPack::unpack(uchar *to, const uchar *from, const uchar *from_end,
+ uint param_data) const
+{
+ uint from_length, length;
+
+ /*
+ Compute the declared length of the field on the master. This is
+ used to decide if one or two bytes should be read as length.
+ */
+ if (param_data)
+ from_length= (((param_data >> 4) & 0x300) ^ 0x300) + (param_data & 0x00ff);
+ else
+ from_length= m_octet_length;
+
+ DBUG_PRINT("debug",
+ ("param_data: 0x%x, field_length: %u, from_length: %u",
+ param_data, m_octet_length, from_length));
+ /*
+ Compute the actual length of the data by reading one or two bits
+ (depending on the declared field length on the master).
+ */
+ if (from_length > 255)
+ {
+ if (from + 2 > from_end)
+ return 0;
+ length= uint2korr(from);
+ from+= 2;
+ }
+ else
+ {
+ if (from + 1 > from_end)
+ return 0;
+ length= (uint) *from++;
+ }
+ if (from + length > from_end || length > m_octet_length)
+ return 0;
+
+ memcpy(to, from, length);
+ // Pad the string with the pad character of the fields charset
+ charset()->fill((char*) to + length,
+ m_octet_length - length,
+ charset()->pad_char);
+ return from+length;
+}
diff --git a/sql/sql_type_string.h b/sql/sql_type_string.h
new file mode 100644
index 00000000000..fca46e91394
--- /dev/null
+++ b/sql/sql_type_string.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2019 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_STRING_INCLUDED
+#define SQL_TYPE_STRING_INCLUDED
+
+class StringPack
+{
+ CHARSET_INFO *m_cs;
+ uint32 m_octet_length;
+ CHARSET_INFO *charset() const { return m_cs; }
+ uint mbmaxlen() const { return m_cs->mbmaxlen; };
+ uint32 char_length() const { return m_octet_length / mbmaxlen(); }
+public:
+ StringPack(CHARSET_INFO *cs, uint32 octet_length)
+ :m_cs(cs),
+ m_octet_length(octet_length)
+ { }
+ uchar *pack(uchar *to, const uchar *from, uint max_length) const;
+ const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end,
+ uint param_data) const;
+public:
+ static uint max_packed_col_length(uint max_length)
+ {
+ return (max_length > 255 ? 2 : 1) + max_length;
+ }
+ static uint packed_col_length(const uchar *data_ptr, uint length)
+ {
+ if (length > 255)
+ return uint2korr(data_ptr)+2;
+ return (uint) *data_ptr + 1;
+ }
+};
+
+
+#endif // SQL_TYPE_STRING_INCLUDED
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index 35c799d4a86..4da85de7852 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -110,6 +110,8 @@ extern "C" uchar* get_hash_key(const uchar *buff, size_t *length,
return (uchar*) udf->name.str;
}
+static PSI_memory_key key_memory_udf_mem;
+
#ifdef HAVE_PSI_INTERFACE
static PSI_rwlock_key key_rwlock_THR_LOCK_udf;
@@ -118,6 +120,11 @@ static PSI_rwlock_info all_udf_rwlocks[]=
{ &key_rwlock_THR_LOCK_udf, "THR_LOCK_udf", PSI_FLAG_GLOBAL}
};
+static PSI_memory_info all_udf_memory[]=
+{
+ { &key_memory_udf_mem, "udf_mem", PSI_FLAG_GLOBAL}
+};
+
static void init_udf_psi_keys(void)
{
const char* category= "sql";
@@ -128,6 +135,9 @@ static void init_udf_psi_keys(void)
count= array_elements(all_udf_rwlocks);
PSI_server->register_rwlock(category, all_udf_rwlocks, count);
+
+ count= array_elements(all_udf_memory);
+ mysql_memory_register(category, all_udf_memory, count);
}
#endif
@@ -154,10 +164,11 @@ void udf_init()
mysql_rwlock_init(key_rwlock_THR_LOCK_udf, &THR_LOCK_udf);
- init_sql_alloc(&mem, "udf", UDF_ALLOC_BLOCK_SIZE, 0, MYF(0));
+ init_sql_alloc(key_memory_udf_mem, &mem, UDF_ALLOC_BLOCK_SIZE, 0, MYF(0));
THD *new_thd = new THD(0);
if (!new_thd ||
- my_hash_init(&udf_hash,system_charset_info,32,0,0,get_hash_key, NULL, 0))
+ my_hash_init(key_memory_udf_mem,
+ &udf_hash,system_charset_info,32,0,0,get_hash_key, NULL, 0))
{
sql_print_error("Can't allocate memory for udf structures");
my_hash_free(&udf_hash);
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 5ff88e02f5d..f8025cdf701 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -72,7 +72,7 @@ void select_unit::change_select()
switch (step)
{
case INTERSECT_TYPE:
- intersect_mark->value= prev_step= curr_step;
+ prev_step= curr_step;
curr_step= current_select_number;
break;
case EXCEPT_TYPE:
@@ -83,6 +83,7 @@ void select_unit::change_select()
}
DBUG_VOID_RETURN;
}
+
/**
Fill temporary tables for UNION/EXCEPT/INTERSECT
@@ -93,7 +94,7 @@ UNION:
EXCEPT:
looks for the record in the table (with 'counter' field first if
INTERSECT present in the sequence) and delete it if found
-INTESECT:
+INTERSECT:
looks for the same record with 'counter' field of previous operation,
put as a 'counter' number of the current SELECT.
We scan the table and remove all records which marked with not last
@@ -108,28 +109,29 @@ INTESECT:
*/
int select_unit::send_data(List<Item> &values)
{
- int rc;
+ int rc= 0;
int not_reported_error= 0;
- if (unit->offset_limit_cnt)
- { // using limit offset,count
- unit->offset_limit_cnt--;
- return 0;
- }
- if (thd->killed == ABORT_QUERY)
- return 0;
+
if (table->no_rows_with_nulls)
table->null_catch_flags= CHECK_ROW_FOR_NULLS_TO_REJECT;
- if (intersect_mark)
+
+ fill_record(thd, table, table->field + addon_cnt, values, true, false);
+ /* set up initial values for records to be written */
+ if (addon_cnt && step == UNION_TYPE)
{
- fill_record(thd, table, table->field + 1, values, TRUE, FALSE);
- table->field[0]->store((ulonglong) curr_step, 1);
+ DBUG_ASSERT(addon_cnt == 1);
+ table->field[0]->store((longlong) curr_step, 1);
}
- else
- fill_record(thd, table, table->field, values, TRUE, FALSE);
+
if (unlikely(thd->is_error()))
{
rc= 1;
- goto end;
+ if (unlikely(not_reported_error))
+ {
+ DBUG_ASSERT(rc);
+ table->file->print_error(not_reported_error, MYF(0));
+ }
+ return rc;
}
if (table->no_rows_with_nulls)
{
@@ -137,105 +139,58 @@ int select_unit::send_data(List<Item> &values)
if (table->null_catch_flags)
{
rc= 0;
- goto end;
+ if (unlikely(not_reported_error))
+ {
+ DBUG_ASSERT(rc);
+ table->file->print_error(not_reported_error, MYF(0));
+ }
+ return rc;
}
}
- // select_unit::change_select() change step & Co correctly for each SELECT
+ /* select_unit::change_select() change step & Co correctly for each SELECT */
+ int find_res;
switch (step)
{
- case UNION_TYPE:
- {
- if (unlikely((write_err=
- table->file->ha_write_tmp_row(table->record[0]))))
- {
- if (write_err == HA_ERR_FOUND_DUPP_KEY)
- {
- /*
- Inform upper level that we found a duplicate key, that should not
- be counted as part of limit
- */
- rc= -1;
- goto end;
- }
- bool is_duplicate= FALSE;
- /* create_internal_tmp_table_from_heap will generate error if needed */
- if (table->file->is_fatal_error(write_err, HA_CHECK_DUP) &&
- create_internal_tmp_table_from_heap(thd, table,
- tmp_table_param.start_recinfo,
- &tmp_table_param.recinfo,
- write_err, 1, &is_duplicate))
- {
- rc= 1;
- goto end;
- }
+ case UNION_TYPE:
+ rc= write_record();
+ /* no reaction with conversion */
+ if (rc == -2)
+ rc= 0;
+ break;
- if (is_duplicate)
- {
- rc= -1;
- goto end;
- }
- }
- break;
- }
- case EXCEPT_TYPE:
- {
- int find_res;
- /*
- The temporary table uses very first index or constrain for
- checking unique constrain.
- */
- if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
- {
- DBUG_ASSERT(!table->triggers);
- table->status|= STATUS_DELETED;
- not_reported_error= table->file->ha_delete_tmp_row(table->record[0]);
- rc= MY_TEST(not_reported_error);
- goto end;
- }
- else
- {
- if ((rc= not_reported_error= (find_res != 1)))
- goto end;
- }
- break;
- }
- case INTERSECT_TYPE:
+ case EXCEPT_TYPE:
+ /*
+ The temporary table uses very first index or constrain for
+ checking unique constrain.
+ */
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ rc= delete_record();
+ else
+ rc= not_reported_error= (find_res != 1);
+ break;
+ case INTERSECT_TYPE:
+ /*
+ The temporary table uses very first index or constrain for
+ checking unique constrain.
+ */
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
{
- int find_res;
- /*
- The temporary table uses very first index or constrain for
- checking unique constrain.
- */
- if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ DBUG_ASSERT(!table->triggers);
+ if (table->field[0]->val_int() == prev_step)
{
- DBUG_ASSERT(!table->triggers);
- if (table->field[0]->val_int() != prev_step)
- {
- rc= 0;
- goto end;
- }
- store_record(table, record[1]);
- table->field[0]->store(curr_step, 0);
- not_reported_error= table->file->ha_update_tmp_row(table->record[1],
- table->record[0]);
+ not_reported_error= update_counter(table->field[0], curr_step);
rc= MY_TEST(not_reported_error);
DBUG_ASSERT(rc != HA_ERR_RECORD_IS_THE_SAME);
- goto end;
}
- else
- {
- if ((rc= not_reported_error= (find_res != 1)))
- goto end;
- }
- break;
}
- default:
- DBUG_ASSERT(0);
+ else
+ rc= not_reported_error= (find_res != 1);
+ break;
+ default:
+ DBUG_ASSERT(0);
}
- rc= 0;
-end:
if (unlikely(not_reported_error))
{
DBUG_ASSERT(rc);
@@ -251,7 +206,7 @@ bool select_unit::send_eof()
thd->lex->current_select->next_select()->get_linkage() == INTERSECT_TYPE))
{
/*
- it is not INTESECT or next SELECT in the sequence is INTERSECT so no
+ it is not INTERSECT or next SELECT in the sequence is INTERSECT so no
need filtering (the last INTERSECT in this sequence of intersects will
filter).
*/
@@ -265,15 +220,14 @@ bool select_unit::send_eof()
TODO: as optimization for simple case this could be moved to
'fake_select' WHERE condition
*/
- handler *file= table->file;
int error;
- if (unlikely(file->ha_rnd_init_with_error(1)))
+ if (table->file->ha_rnd_init_with_error(1))
return 1;
-
do
{
- if (unlikely(error= file->ha_rnd_next(table->record[0])))
+ error= table->file->ha_rnd_next(table->record[0]);
+ if (unlikely(error))
{
if (error == HA_ERR_END_OF_FILE)
{
@@ -283,9 +237,9 @@ bool select_unit::send_eof()
break;
}
if (table->field[0]->val_int() != curr_step)
- error= file->ha_delete_tmp_row(table->record[0]);
- } while (likely(!error));
- file->ha_rnd_end();
+ error= delete_record();
+ } while (!error);
+ table->file->ha_rnd_end();
if (unlikely(error))
table->file->print_error(error, MYF(0));
@@ -303,6 +257,8 @@ int select_union_recursive::send_data(List<Item> &values)
write_err != HA_ERR_FOUND_DUPP_UNIQUE)
{
int err;
+ DBUG_ASSERT(incr_table->s->reclength == table->s->reclength ||
+ incr_table->s->reclength == table->s->reclength - MARIA_UNIQUE_HASH_LENGTH);
if ((err= incr_table->file->ha_write_tmp_row(table->record[0])))
{
bool is_duplicate;
@@ -345,6 +301,7 @@ bool select_unit::flush()
create_table whether to physically create result table
keep_row_order keep rows in order as they were inserted
hidden number of hidden fields (for INTERSECT)
+ plus one for `ALL`
DESCRIPTION
Create a temporary table that is used to store the result of a UNION,
@@ -433,6 +390,143 @@ select_union_recursive::create_result_table(THD *thd_arg,
}
+/*
+ @brief
+ Write a record
+
+ @retval
+ -2 conversion happened
+ -1 found a duplicate key
+ 0 no error
+ 1 if an error is reported
+*/
+
+int select_unit::write_record()
+{
+ if (unlikely((write_err= table->file->ha_write_tmp_row(table->record[0]))))
+ {
+ if (write_err == HA_ERR_FOUND_DUPP_KEY)
+ {
+ /*
+ Inform upper level that we found a duplicate key, that should not
+ be counted as part of limit
+ */
+ return -1;
+ }
+ bool is_duplicate= false;
+ /* create_internal_tmp_table_from_heap will generate error if needed */
+ if (table->file->is_fatal_error(write_err, HA_CHECK_DUP))
+ {
+ if (!create_internal_tmp_table_from_heap(thd, table,
+ tmp_table_param.start_recinfo,
+ &tmp_table_param.recinfo,
+ write_err, 1, &is_duplicate))
+ {
+ return -2;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ if (is_duplicate)
+ {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ @brief
+ Update counter for a record
+
+ @retval
+ 0 no error
+ -1 error occurred
+*/
+
+int select_unit::update_counter(Field* counter, longlong value)
+{
+ store_record(table, record[1]);
+ counter->store(value, 0);
+ int error= table->file->ha_update_tmp_row(table->record[1],
+ table->record[0]);
+ return error;
+}
+
+
+/*
+ @brief
+ Try to disable index
+
+ @retval
+ true index is disabled this time
+ false this time did not disable the index
+*/
+
+bool select_unit_ext::disable_index_if_needed(SELECT_LEX *curr_sl)
+{
+ if (is_index_enabled &&
+ (curr_sl == curr_sl->master_unit()->union_distinct ||
+ !curr_sl->next_select()) )
+ {
+ is_index_enabled= false;
+ if (table->file->ha_disable_indexes(HA_KEY_SWITCH_ALL))
+ return false;
+ table->no_keyread=1;
+ return true;
+ }
+ return false;
+}
+
+/*
+ @brief
+ Unfold a record
+
+ @retval
+ 0 no error
+ -1 conversion happened
+*/
+
+int select_unit_ext::unfold_record(ha_rows cnt)
+{
+
+ DBUG_ASSERT(cnt > 0);
+ int error= 0;
+ bool is_convertion_happened= false;
+ while (--cnt)
+ {
+ error= write_record();
+ if (error == -2)
+ {
+ is_convertion_happened= true;
+ error= -1;
+ }
+ }
+ if (is_convertion_happened)
+ return -1;
+ return error;
+}
+
+/*
+ @brief
+ Delete a record
+
+ @retval
+ 0 no error
+ 1 if an error is reported
+*/
+
+int select_unit::delete_record()
+{
+ DBUG_ASSERT(!table->triggers);
+ table->status|= STATUS_DELETED;
+ int not_reported_error= table->file->ha_delete_tmp_row(table->record[0]);
+ return MY_TEST(not_reported_error);
+}
+
/**
Reset and empty the temporary table that stores the materialized query
result.
@@ -448,6 +542,350 @@ void select_unit::cleanup()
}
+/*
+ @brief
+ Set up value needed by send_data() and send_eof()
+
+ @detail
+ - For EXCEPT we will decrease the counter by one
+ and INTERSECT / UNION we increase the counter.
+
+ - For INTERSECT we will modify the second extra field (intersect counter)
+ and for EXCEPT / UNION we modify the first (duplicate counter)
+*/
+
+void select_unit_ext::change_select()
+{
+ select_unit::change_select();
+ switch(step){
+ case UNION_TYPE:
+ increment= 1;
+ curr_op_type= UNION_DISTINCT;
+ break;
+ case EXCEPT_TYPE:
+ increment= -1;
+ curr_op_type= EXCEPT_DISTINCT;
+ break;
+ case INTERSECT_TYPE:
+ increment= 1;
+ curr_op_type= INTERSECT_DISTINCT;
+ break;
+ default: DBUG_ASSERT(0);
+ }
+ if (!thd->lex->current_select->distinct)
+ /* change type from DISTINCT to ALL */
+ curr_op_type= (set_op_type)(curr_op_type + 1);
+
+ duplicate_cnt= table->field[addon_cnt - 1];
+ if (addon_cnt == 2)
+ additional_cnt= table->field[addon_cnt - 2];
+ else
+ additional_cnt= NULL;
+}
+
+
+/*
+ @brief
+ Fill temporary tables for operations need extra fields
+
+ @detail
+ - If this operation is not distinct, we try to find it and increase the
+ counter by "increment" setted in select_unit_ext::change_select().
+
+ - If it is distinct, for UNION we write this record; for INTERSECT we
+ try to find it and increase the intersect counter if found; for EXCEPT
+ we try to find it and delete that record if found.
+
+*/
+
+int select_unit_ext::send_data(List<Item> &values)
+{
+ int rc= 0;
+ int not_reported_error= 0;
+ int find_res;
+
+ if (table->no_rows_with_nulls)
+ table->null_catch_flags= CHECK_ROW_FOR_NULLS_TO_REJECT;
+
+ fill_record(thd, table, table->field + addon_cnt, values, true, false);
+ /* set up initial values for records to be written */
+ if ( step == UNION_TYPE )
+ {
+ /* set duplicate counter to 1 */
+ duplicate_cnt->store((longlong) 1, 1);
+ /* set the other counter to 0 */
+ if (curr_op_type == INTERSECT_ALL)
+ additional_cnt->store((longlong) 0, 1);
+ }
+
+ if (unlikely(thd->is_error()))
+ {
+ rc= 1;
+ if (unlikely(not_reported_error))
+ {
+ DBUG_ASSERT(rc);
+ table->file->print_error(not_reported_error, MYF(0));
+ }
+ return rc;
+ }
+ if (table->no_rows_with_nulls)
+ {
+ table->null_catch_flags&= ~CHECK_ROW_FOR_NULLS_TO_REJECT;
+ if (table->null_catch_flags)
+ {
+ if (unlikely(not_reported_error))
+ {
+ DBUG_ASSERT(rc);
+ table->file->print_error(not_reported_error, MYF(0));
+ }
+ return rc;
+ }
+ }
+
+ switch(curr_op_type)
+ {
+ case UNION_ALL:
+ if (!is_index_enabled ||
+ (find_res= table->file->find_unique_row(table->record[0], 0)))
+ {
+ rc= write_record();
+ /* no reaction with conversion */
+ if (rc == -2)
+ rc= 0;
+ }
+ else
+ {
+ longlong cnt= duplicate_cnt->val_int() + increment;
+ not_reported_error= update_counter(duplicate_cnt, cnt);
+ DBUG_ASSERT(!table->triggers);
+ rc= MY_TEST(not_reported_error);
+ }
+ break;
+
+ case EXCEPT_ALL:
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ {
+ longlong cnt= duplicate_cnt->val_int() + increment;
+ if (cnt == 0)
+ rc= delete_record();
+ else
+ {
+ not_reported_error= update_counter(duplicate_cnt, cnt);
+ DBUG_ASSERT(!table->triggers);
+ rc= MY_TEST(not_reported_error);
+ }
+ }
+ break;
+
+ case INTERSECT_ALL:
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ {
+ longlong cnt= duplicate_cnt->val_int() + increment;
+ if (cnt <= additional_cnt->val_int())
+ {
+ not_reported_error= update_counter(duplicate_cnt, cnt);
+ DBUG_ASSERT(!table->triggers);
+ rc= MY_TEST(not_reported_error);
+ }
+ }
+ break;
+
+ case UNION_DISTINCT:
+ rc= write_record();
+ /* no reaction with conversion */
+ if (rc == -2)
+ rc= 0;
+ break;
+
+ case EXCEPT_DISTINCT:
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ rc= delete_record();
+ else
+ rc= not_reported_error= (find_res != 1);
+ break;
+
+ case INTERSECT_DISTINCT:
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ {
+ if (additional_cnt->val_int() == prev_step)
+ {
+ not_reported_error= update_counter(additional_cnt, curr_step);
+ rc= MY_TEST(not_reported_error);
+ DBUG_ASSERT(rc != HA_ERR_RECORD_IS_THE_SAME);
+ }
+ else if (additional_cnt->val_int() != curr_step)
+ rc= delete_record();
+ }
+ else
+ rc= not_reported_error= (find_res != 1);
+ break;
+
+ default:
+ DBUG_ASSERT(0);
+ }
+
+ if (unlikely(not_reported_error))
+ {
+ DBUG_ASSERT(rc);
+ table->file->print_error(not_reported_error, MYF(0));
+ }
+ return rc;
+}
+
+
+/*
+ @brief
+ Do post-operation after a operator
+
+ @detail
+ We need to scan in these cases:
+ - If this operation is DISTINCT and next is ALL,
+ duplicate counter needs to be set to 1.
+ - If this operation is INTERSECT ALL and counter needs to be updated.
+ - If next operation is INTERSECT ALL,
+ set up the second extra field (called "intersect_counter") to 0.
+ this extra field counts records in the second operand.
+
+ If this operation is equal to "union_distinct" or is the last operation,
+ we'll disable index. Then if this operation is ALL we'll unfold records.
+*/
+
+bool select_unit_ext::send_eof()
+{
+ int error= 0;
+ SELECT_LEX *curr_sl= thd->lex->current_select;
+ SELECT_LEX *next_sl= curr_sl->next_select();
+ bool is_next_distinct= next_sl && next_sl->distinct;
+ bool is_next_intersect_all=
+ next_sl &&
+ next_sl->get_linkage() == INTERSECT_TYPE &&
+ !next_sl->distinct;
+ bool need_unfold= (disable_index_if_needed(curr_sl) &&
+ !curr_sl->distinct);
+
+ if (((curr_sl->distinct && !is_next_distinct) ||
+ curr_op_type == INTERSECT_ALL ||
+ is_next_intersect_all) &&
+ !need_unfold)
+ {
+ if (!next_sl)
+ DBUG_ASSERT(curr_op_type != INTERSECT_ALL);
+ bool need_update_row;
+ if (unlikely(table->file->ha_rnd_init_with_error(1)))
+ return 1;
+ do
+ {
+ need_update_row= false;
+ if (unlikely(error= table->file->ha_rnd_next(table->record[0])))
+ {
+ if (error == HA_ERR_END_OF_FILE)
+ {
+ error= 0;
+ break;
+ }
+ break;
+ }
+ store_record(table, record[1]);
+
+ if (curr_sl->distinct && !is_next_distinct)
+ {
+ /* set duplicate counter to 1 if next operation is ALL */
+ duplicate_cnt->store(1, 0);
+ need_update_row= true;
+ }
+
+ if (is_next_intersect_all)
+ {
+ longlong d_cnt_val= duplicate_cnt->val_int();
+ if (d_cnt_val == 0)
+ error= delete_record();
+ else
+ {
+ if (curr_op_type == INTERSECT_ALL)
+ {
+ longlong a_cnt_val= additional_cnt->val_int();
+ if (a_cnt_val < d_cnt_val)
+ d_cnt_val= a_cnt_val;
+ }
+ additional_cnt->store(d_cnt_val, 0);
+ duplicate_cnt->store((longlong)0, 0);
+ need_update_row= true;
+ }
+ }
+
+ if (need_update_row)
+ error= table->file->ha_update_tmp_row(table->record[1],
+ table->record[0]);
+ } while (likely(!error));
+ table->file->ha_rnd_end();
+ }
+
+ /* unfold */
+ else if (need_unfold)
+ {
+ /* unfold if is ALL operation */
+ ha_rows dup_cnt;
+ if (unlikely(table->file->ha_rnd_init_with_error(1)))
+ return 1;
+ do
+ {
+ if (unlikely(error= table->file->ha_rnd_next(table->record[0])))
+ {
+ if (error == HA_ERR_END_OF_FILE)
+ {
+ error= 0;
+ break;
+ }
+ break;
+ }
+ dup_cnt= (ha_rows)duplicate_cnt->val_int();
+ /* delete record if not exist in the second operand */
+ if (dup_cnt == 0)
+ {
+ error= delete_record();
+ continue;
+ }
+ if (curr_op_type == INTERSECT_ALL)
+ {
+ ha_rows add_cnt= (ha_rows)additional_cnt->val_int();
+ if (dup_cnt > add_cnt && add_cnt > 0)
+ dup_cnt= (ha_rows)add_cnt;
+ }
+
+ if (dup_cnt == 1)
+ continue;
+
+ duplicate_cnt->store((longlong)1, 0);
+ if (additional_cnt)
+ additional_cnt->store((longlong)0, 0);
+ error= table->file->ha_update_tmp_row(table->record[1],
+ table->record[0]);
+ if (unlikely(error))
+ break;
+
+ if (unfold_record(dup_cnt) == -1)
+ {
+ /* restart the scan */
+ if (unlikely(table->file->ha_rnd_init_with_error(1)))
+ return 1;
+
+ duplicate_cnt= table->field[addon_cnt - 1];
+ if (addon_cnt == 2)
+ additional_cnt= table->field[addon_cnt - 2];
+ else
+ additional_cnt= NULL;
+ continue;
+ }
+ } while (likely(!error));
+ table->file->ha_rnd_end();
+ }
+
+ if (unlikely(error))
+ table->file->print_error(error, MYF(0));
+
+ return (MY_TEST(error));
+}
+
void select_union_recursive::cleanup()
{
if (table)
@@ -653,7 +1091,6 @@ bool st_select_lex_unit::prepare_join(THD *thd_arg, SELECT_LEX *sl,
can_skip_order_by= is_union_select && !(sl->braces && sl->explicit_limit);
saved_error= join->prepare(sl->table_list.first,
- sl->with_wild,
(derived && derived->merged ? NULL : sl->where),
(can_skip_order_by ? 0 :
sl->order_list.elements) +
@@ -667,8 +1104,6 @@ bool st_select_lex_unit::prepare_join(THD *thd_arg, SELECT_LEX *sl,
thd_arg->lex->proc_list.first),
sl, this);
- /* There are no * in the statement anymore (for PS) */
- sl->with_wild= 0;
last_procedure= join->procedure;
if (unlikely(saved_error || (saved_error= thd_arg->is_fatal_error)))
@@ -818,6 +1253,29 @@ bool st_select_lex_unit::join_union_item_types(THD *thd_arg,
}
+bool init_item_int(THD* thd, Item_int* &item)
+{
+ if (!item)
+ {
+ Query_arena *arena, backup_arena;
+ arena= thd->activate_stmt_arena_if_needed(&backup_arena);
+
+ item= new (thd->mem_root) Item_int(thd, 0);
+
+ if (arena)
+ thd->restore_active_arena(arena, &backup_arena);
+
+ if (!item)
+ return false;
+ }
+ else
+ {
+ item->value= 0;
+ }
+ return true;
+}
+
+
bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
select_result *sel_result,
ulong additional_options)
@@ -829,7 +1287,8 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
uint union_part_count= 0;
select_result *tmp_result;
bool is_union_select;
- bool have_except= FALSE, have_intersect= FALSE;
+ bool have_except= false, have_intersect= false,
+ have_except_all_or_intersect_all= false;
bool instantiate_tmp_table= false;
bool single_tvc= !first_sl->next_select() && first_sl->tvc;
bool single_tvc_wo_order= single_tvc && !first_sl->order_list.elements;
@@ -867,7 +1326,7 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
max/min subquery (ALL/ANY optimization)
*/
result= sel_result;
-
+
if (prepared)
{
if (describe)
@@ -885,8 +1344,7 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
else
{
sl->join->result= result;
- select_limit_cnt= HA_POS_ERROR;
- offset_limit_cnt= 0;
+ lim.set_unlimited();
if (!sl->join->procedure &&
result->prepare(sl->join->fields_list, this))
{
@@ -906,15 +1364,27 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
found_rows_for_union= first_sl->options & OPTION_FOUND_ROWS;
is_union_select= is_unit_op() || fake_select_lex || single_tvc;
+ /* will only optimize once */
+ if (!bag_set_op_optimized && !is_recursive)
+ {
+ optimize_bag_operation(false);
+ }
+
for (SELECT_LEX *s= first_sl; s; s= s->next_select())
{
switch (s->linkage)
{
case INTERSECT_TYPE:
have_intersect= TRUE;
+ if (!s->distinct){
+ have_except_all_or_intersect_all= true;
+ }
break;
case EXCEPT_TYPE:
have_except= TRUE;
+ if (!s->distinct){
+ have_except_all_or_intersect_all= TRUE;
+ }
break;
default:
break;
@@ -941,7 +1411,21 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
else
{
if (!is_recursive)
- union_result= new (thd->mem_root) select_unit(thd);
+ {
+ /*
+ class "select_unit_ext" handles query contains EXCEPT ALL and / or
+ INTERSECT ALL. Others are handled by class "select_unit"
+ If have EXCEPT ALL or INTERSECT ALL in the query. First operand
+ should be UNION ALL
+ */
+ if (have_except_all_or_intersect_all)
+ {
+ union_result= new (thd->mem_root) select_unit_ext(thd);
+ first_sl->distinct= false;
+ }
+ else
+ union_result= new (thd->mem_root) select_unit(thd);
+ }
else
{
with_element->rec_result=
@@ -1079,7 +1563,7 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
{
if (with_element)
{
- if (with_element->rename_columns_of_derived_unit(thd, this))
+ if (with_element->process_columns_of_derived_unit(thd, this))
goto err;
if (check_duplicate_names(thd, sl->item_list, 0))
goto err;
@@ -1116,6 +1600,10 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
instantiate_tmp_table, false,
0))
goto err;
+ if (have_except_all_or_intersect_all)
+ {
+ union_result->init();
+ }
if (!derived_arg->table)
{
derived_arg->table= with_element->rec_result->rec_tables.head();
@@ -1127,6 +1615,7 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
}
}
}
+
// In case of a non-recursive UNION, join data types for all UNION parts.
if (!is_recursive && join_union_item_types(thd, types, union_part_count))
goto err;
@@ -1202,48 +1691,42 @@ cont:
if (global_parameters()->ftfunc_list->elements)
create_options= create_options | TMP_TABLE_FORCE_MYISAM;
+ /* extra field counter */
+ uint hidden= 0;
+ Item_int *addon_fields[2]= {0};
if (!is_recursive)
{
- uint hidden= 0;
- if (have_intersect)
+ if (have_except_all_or_intersect_all)
{
- hidden= 1;
- if (!intersect_mark)
- {
- /*
- For intersect we add a hidden column first that contains
- the current select number of the time when the row was
- added to the temporary table
- */
-
- Query_arena *arena, backup_arena;
- arena= thd->activate_stmt_arena_if_needed(&backup_arena);
-
- intersect_mark= new (thd->mem_root) Item_int(thd, 0);
-
- if (arena)
- thd->restore_active_arena(arena, &backup_arena);
+ /* add duplicate_count */
+ ++hidden;
+ }
+ /* add intersect_count */
+ if (have_intersect)
+ ++hidden;
- if (!intersect_mark)
- goto err;
- }
- else
- intersect_mark->value= 0; //reset
- types.push_front(union_result->intersect_mark= intersect_mark);
- union_result->intersect_mark->name.str= "___";
- union_result->intersect_mark->name.length= 3;
+ for(uint i= 0; i< hidden; i++)
+ {
+ init_item_int(thd, addon_fields[i]);
+ types.push_front(addon_fields[i]);
+ addon_fields[i]->name.str= i ? "__CNT_1" : "__CNT_2";
+ addon_fields[i]->name.length= 7;
}
bool error=
union_result->create_result_table(thd, &types,
- MY_TEST(union_distinct),
+ MY_TEST(union_distinct) ||
+ have_except_all_or_intersect_all ||
+ have_intersect,
create_options, &empty_clex_str, false,
instantiate_tmp_table, false,
hidden);
- if (intersect_mark)
+ union_result->addon_cnt= hidden;
+ for (uint i= 0; i < hidden; i++)
types.pop();
if (unlikely(error))
goto err;
}
+
if (fake_select_lex && !fake_select_lex->first_cond_optimization)
{
save_tablenr= result_table_list.tablenr_exec;
@@ -1271,9 +1754,8 @@ cont:
arena= thd->activate_stmt_arena_if_needed(&backup_arena);
saved_error= table->fill_item_list(&item_list);
- // Item_list is inherited from 'types', so there could be the counter
- if (intersect_mark)
- item_list.pop(); // remove intersect counter
+ for (uint i= 0; i < hidden; i++)
+ item_list.pop();
if (arena)
thd->restore_active_arena(arena, &backup_arena);
@@ -1318,7 +1800,7 @@ cont:
We're in execution of a prepared statement or stored procedure:
reset field items to point at fields from the created temporary table.
*/
- table->reset_item_list(&item_list, intersect_mark ? 1 : 0);
+ table->reset_item_list(&item_list, hidden);
}
if (fake_select_lex != NULL &&
(thd->stmt_arena->is_stmt_prepare() ||
@@ -1332,7 +1814,7 @@ cont:
DBUG_RETURN(TRUE);
}
saved_error= fake_select_lex->join->
- prepare(fake_select_lex->table_list.first, 0, 0,
+ prepare(fake_select_lex->table_list.first, 0,
global_parameters()->order_list.elements, // og_num
global_parameters()->order_list.first, // order
false, NULL, NULL, NULL, fake_select_lex, this);
@@ -1352,9 +1834,170 @@ err:
/**
+ @brief
+ Optimize a sequence of set operations
+
+ @param first_sl first select of the level now under processing
+
+ @details
+ The method optimizes with the following rules:
+ - (1)If a subsequence of INTERSECT contains at least one INTERSECT DISTINCT
+ or this subsequence is followed by UNION/EXCEPT DISTINCT then all
+ elements in the subsequence can changed for INTERSECT DISTINCT
+ - (2)If previous set operation is DISTINCT then EXCEPT ALL can be replaced
+ for EXCEPT DISTINCT
+ - (3)If UNION DISTINCT / EXCEPT DISTINCT follows a subsequence of UNION ALL
+ then all set operations of this subsequence can be replaced for
+ UNION DISTINCT
+
+ For derived table it will look up outer select, and do optimize based on
+ outer select.
+
+ Variable "union_distinct" will be updated in the end.
+ Not compatible with Oracle Mode.
+*/
+
+void st_select_lex_unit::optimize_bag_operation(bool is_outer_distinct)
+{
+ /*
+ skip run optimize for:
+ ORACLE MODE
+ CREATE VIEW
+ PREPARE ... FROM
+ recursive
+ */
+ if ((thd->variables.sql_mode & MODE_ORACLE) ||
+ (thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW) ||
+ (fake_select_lex != NULL && thd->stmt_arena->is_stmt_prepare()) ||
+ (with_element && with_element->is_recursive ))
+ return;
+ DBUG_ASSERT(!bag_set_op_optimized);
+
+ SELECT_LEX *sl;
+ /* INTERSECT subsequence can occur only at the very beginning */
+ /* The first select with linkage == INTERSECT_TYPE */
+ SELECT_LEX *intersect_start= NULL;
+ /* The first select after the INTERSECT subsequence */
+ SELECT_LEX *intersect_end= NULL;
+ /*
+ Will point to the last node before UNION ALL subsequence.
+ Index can be disable there.
+ */
+ SELECT_LEX *disable_index= NULL;
+ /*
+ True if there is a select with:
+ linkage == INTERSECT_TYPE && distinct==true
+ */
+ bool any_intersect_distinct= false;
+ SELECT_LEX *prev_sl= first_select();
+
+ /* process INTERSECT subsequence in the begining */
+ for (sl= prev_sl->next_select(); sl; prev_sl= sl, sl= sl->next_select())
+ {
+ if (sl->linkage != INTERSECT_TYPE)
+ {
+ intersect_end= sl;
+ break;
+ }
+ else
+ {
+ if (!intersect_start)
+ intersect_start= sl;
+ if (sl->distinct)
+ {
+ any_intersect_distinct= true;
+ disable_index= sl;
+ }
+ }
+ }
+
+ /* if subquery only contains INTERSECT and outer is UNION DISTINCT*/
+ if (!sl && is_outer_distinct)
+ any_intersect_distinct= true;
+
+ /* The first select of the current UNION ALL subsequence */
+ SELECT_LEX *union_all_start= NULL;
+ for ( ; sl; prev_sl= sl, sl= sl->next_select())
+ {
+ DBUG_ASSERT (sl->linkage != INTERSECT_TYPE);
+ if (!sl->distinct)
+ {
+ if (sl->linkage == UNION_TYPE)
+ {
+ if (!union_all_start)
+ {
+ union_all_start= sl;
+ }
+ }
+ else
+ {
+ DBUG_ASSERT (sl->linkage == EXCEPT_TYPE);
+ union_all_start= NULL;
+ if (prev_sl->distinct && prev_sl->is_set_op())
+ {
+ sl->distinct= true;
+ disable_index= sl;
+ }
+ }
+ }
+ else
+ { /* sl->distinct == true */
+ for (SELECT_LEX *si= union_all_start; si && si != sl; si= si->next_select())
+ {
+ si->distinct= true;
+ }
+ union_all_start= NULL;
+ disable_index= sl;
+ }
+ }
+
+ if (is_outer_distinct)
+ {
+ for (SELECT_LEX *si= union_all_start; si && si != sl; si= si->next_select())
+ {
+ si->distinct= true;
+ }
+ union_all_start= NULL;
+ }
+
+ if (any_intersect_distinct ||
+ (intersect_end != NULL && intersect_end->distinct))
+ {
+ for (sl= intersect_start; sl && sl != intersect_end; sl= sl->next_select())
+ {
+ sl->distinct= true;
+ if (disable_index && disable_index->linkage == INTERSECT_TYPE)
+ disable_index= sl;
+ }
+ }
+ /*
+ if disable_index points to a INTERSECT, based on rule 1 we can set it
+ to the last INTERSECT node.
+ */
+ if (disable_index && disable_index->linkage == INTERSECT_TYPE &&
+ intersect_end && intersect_end->distinct)
+ disable_index= intersect_end;
+ /* union_distinct controls when to disable index */
+ union_distinct= disable_index;
+
+ /* recursive call this function for whole lex tree */
+ for(sl= first_select(); sl; sl= sl->next_select())
+ {
+ if (sl->is_unit_nest() &&
+ sl->first_inner_unit() &&
+ !sl->first_inner_unit()->bag_set_op_optimized)
+ sl->first_inner_unit()->optimize_bag_operation(sl->distinct);
+ }
+
+ /* mark as optimized */
+ bag_set_op_optimized= true;
+}
+
+
+/**
Run optimization phase.
- @return FALSE unit successfully passed optimization phase.
+ @return false unit successfully passed optimization phase.
@return TRUE an error occur.
*/
bool st_select_lex_unit::optimize()
@@ -1364,10 +2007,10 @@ bool st_select_lex_unit::optimize()
DBUG_ENTER("st_select_lex_unit::optimize");
if (optimized && !uncacheable && !describe)
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(false);
if (with_element && with_element->is_recursive && optimize_started)
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(false);
optimize_started= true;
if (uncacheable || !item || !item->assigned() || describe)
@@ -1387,9 +2030,12 @@ bool st_select_lex_unit::optimize()
table->file->info(HA_STATUS_VARIABLE);
}
/* re-enabling indexes for next subselect iteration */
- if (union_distinct && table->file->ha_enable_indexes(HA_KEY_SWITCH_ALL))
+ if ((union_result->force_enable_index_if_needed() || union_distinct))
{
- DBUG_ASSERT(0);
+ if(table->file->ha_enable_indexes(HA_KEY_SWITCH_ALL))
+ DBUG_ASSERT(0);
+ else
+ table->no_keyread= 0;
}
}
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
@@ -1397,7 +2043,7 @@ bool st_select_lex_unit::optimize()
if (sl->tvc)
{
sl->tvc->select_options=
- (select_limit_cnt == HA_POS_ERROR || sl->braces) ?
+ (lim.is_unlimited() || sl->braces) ?
sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union;
if (sl->tvc->optimize(thd))
{
@@ -1417,13 +2063,13 @@ bool st_select_lex_unit::optimize()
set_limit(sl);
if (sl == global_parameters() || describe)
{
- offset_limit_cnt= 0;
+ lim.remove_offset();
/*
We can't use LIMIT at this stage if we are using ORDER BY for the
whole query
*/
if (sl->order_list.first || describe)
- select_limit_cnt= HA_POS_ERROR;
+ lim.set_unlimited();
}
/*
@@ -1432,7 +2078,7 @@ bool st_select_lex_unit::optimize()
Otherwise, SQL_CALC_FOUND_ROWS should be done on all sub parts.
*/
sl->join->select_options=
- (select_limit_cnt == HA_POS_ERROR || sl->braces) ?
+ (lim.is_unlimited() || sl->braces) ?
sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union;
saved_error= sl->join->optimize();
@@ -1512,13 +2158,13 @@ bool st_select_lex_unit::exec()
set_limit(sl);
if (sl == global_parameters() || describe)
{
- offset_limit_cnt= 0;
+ lim.remove_offset();
/*
We can't use LIMIT at this stage if we are using ORDER BY for the
whole query
*/
if (sl->order_list.first || describe)
- select_limit_cnt= HA_POS_ERROR;
+ lim.set_unlimited();
}
/*
@@ -1529,14 +2175,14 @@ bool st_select_lex_unit::exec()
if (sl->tvc)
{
sl->tvc->select_options=
- (select_limit_cnt == HA_POS_ERROR || sl->braces) ?
+ (lim.is_unlimited() || sl->braces) ?
sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union;
saved_error= sl->tvc->optimize(thd);
}
else
{
- sl->join->select_options=
- (select_limit_cnt == HA_POS_ERROR || sl->braces) ?
+ sl->join->select_options=
+ (lim.is_unlimited() || sl->braces) ?
sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union;
saved_error= sl->join->optimize();
}
@@ -1548,7 +2194,8 @@ bool st_select_lex_unit::exec()
sl->tvc->exec(sl);
else
sl->join->exec();
- if (sl == union_distinct && !(with_element && with_element->is_recursive))
+ if (sl == union_distinct && !have_except_all_or_intersect_all &&
+ !(with_element && with_element->is_recursive))
{
// This is UNION DISTINCT, so there should be a fake_select_lex
DBUG_ASSERT(fake_select_lex != NULL);
@@ -1558,9 +2205,6 @@ bool st_select_lex_unit::exec()
}
if (!sl->tvc)
saved_error= sl->join->error;
- offset_limit_cnt= (ha_rows)(sl->offset_limit ?
- sl->offset_limit->val_uint() :
- 0);
if (likely(!saved_error))
{
examined_rows+= thd->get_examined_row_count();
@@ -1587,8 +2231,8 @@ bool st_select_lex_unit::exec()
DBUG_RETURN(1);
}
}
- if (found_rows_for_union && !sl->braces &&
- select_limit_cnt != HA_POS_ERROR)
+ if (found_rows_for_union && !sl->braces &&
+ !lim.is_unlimited())
{
/*
This is a union without braces. Remember the number of rows that
@@ -1674,14 +2318,13 @@ bool st_select_lex_unit::exec()
if (!was_executed)
save_union_explain_part2(thd->lex->explain);
- saved_error= mysql_select(thd,
- &result_table_list,
- 0, item_list, NULL,
+ saved_error= mysql_select(thd, &result_table_list,
+ item_list, NULL,
global_parameters()->order_list.elements,
global_parameters()->order_list.first,
- NULL, NULL, NULL,
- fake_select_lex->options | SELECT_NO_UNLOCK,
- result, this, fake_select_lex);
+ NULL, NULL, NULL,
+ fake_select_lex->options | SELECT_NO_UNLOCK,
+ result, this, fake_select_lex);
}
else
{
@@ -1697,14 +2340,12 @@ bool st_select_lex_unit::exec()
to reset them back, we re-do all of the actions (yes it is ugly):
*/ // psergey-todo: is the above really necessary anymore??
join->init(thd, item_list, fake_select_lex->options, result);
- saved_error= mysql_select(thd,
- &result_table_list,
- 0, item_list, NULL,
+ saved_error= mysql_select(thd, &result_table_list, item_list, NULL,
global_parameters()->order_list.elements,
global_parameters()->order_list.first,
- NULL, NULL, NULL,
- fake_select_lex->options | SELECT_NO_UNLOCK,
- result, this, fake_select_lex);
+ NULL, NULL, NULL,
+ fake_select_lex->options | SELECT_NO_UNLOCK,
+ result, this, fake_select_lex);
}
else
{
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index af09675d917..d0a920fd473 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -35,7 +35,6 @@
#include "probes_mysql.h"
#include "debug_sync.h"
#include "key.h" // is_key_used
-#include "sql_acl.h" // *_ACL, check_grant
#include "records.h" // init_read_record,
// end_read_record
#include "filesort.h" // filesort
@@ -373,7 +372,7 @@ int mysql_update(THD *thd,
bool need_sort= TRUE;
bool reverse= FALSE;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- uint want_privilege;
+ privilege_t want_privilege(NO_ACL);
#endif
uint table_count= 0;
ha_rows updated, found;
@@ -441,7 +440,6 @@ int mysql_update(THD *thd,
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "UPDATE");
DBUG_RETURN(1);
}
- query_plan.updating_a_view= MY_TEST(table_list->view);
/* Calculate "table->covering_keys" based on the WHERE */
table->covering_keys= table->s->keys_in_use;
@@ -670,7 +668,7 @@ int mysql_update(THD *thd,
if (!(explain= query_plan.save_explain_update_data(query_plan.mem_root, thd)))
goto err;
- ANALYZE_START_TRACKING(&explain->command_tracker);
+ ANALYZE_START_TRACKING(thd, &explain->command_tracker);
DBUG_EXECUTE_IF("show_explain_probe_update_exec_start",
dbug_serve_apcs(thd, 1););
@@ -1177,7 +1175,7 @@ update_begin:
break;
}
}
- ANALYZE_STOP_TRACKING(&explain->command_tracker);
+ ANALYZE_STOP_TRACKING(thd, &explain->command_tracker);
table->auto_increment_field_not_null= FALSE;
dup_key_found= 0;
/*
@@ -1875,8 +1873,8 @@ int mysql_multi_update_prepare(THD *thd)
(SELECT_ACL & ~tlist->grant.privilege);
table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege);
}
- DBUG_PRINT("info", ("table: %s want_privilege: %u", tl->alias.str,
- (uint) table->grant.want_privilege));
+ DBUG_PRINT("info", ("table: %s want_privilege: %llx", tl->alias.str,
+ (longlong) table->grant.want_privilege));
}
/*
Set exclude_from_table_unique_test value back to FALSE. It is needed for
@@ -1918,7 +1916,7 @@ bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, List<Item> *fields,
DBUG_RETURN(1);
res= mysql_select(thd,
- table_list, select_lex->with_wild, total_list, conds,
+ table_list, total_list, conds,
select_lex->order_list.elements,
select_lex->order_list.first, NULL, NULL, NULL,
options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
@@ -2352,7 +2350,7 @@ loop_end:
tmp_param->field_count= temp_fields.elements;
tmp_param->func_count= temp_fields.elements - 1;
calc_group_buffer(tmp_param, &group);
- /* small table, ignore SQL_BIG_TABLES */
+ /* small table, ignore @@big_tables */
my_bool save_big_tables= thd->variables.big_tables;
thd->variables.big_tables= FALSE;
tmp_tables[cnt]=create_tmp_table(thd, tmp_param, temp_fields,
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index cfaa5141a3b..b2e977151fd 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -27,7 +27,6 @@
#include "sql_show.h" // append_identifier
#include "sql_table.h" // build_table_filename
#include "sql_db.h" // mysql_opt_change_db, mysql_change_db
-#include "sql_acl.h" // *_ACL, check_grant
#include "sql_select.h"
#include "parse_file.h"
#include "sp_head.h"
@@ -37,6 +36,7 @@
#include "sql_derived.h"
#include "sql_cte.h" // check_dependencies_in_with_clauses()
#include "opt_trace.h"
+#include "wsrep_mysqld.h"
#define MD5_BUFF_LENGTH 33
@@ -137,7 +137,7 @@ bool check_duplicate_names(THD *thd, List<Item> &item_list, bool gen_unique_view
Item *check;
/* treat underlying fields like set by user names */
if (item->real_item()->type() == Item::FIELD_ITEM)
- item->is_autogenerated_name= FALSE;
+ item->common_flags&= ~IS_AUTO_GENERATED_NAME;
itc.rewind();
while ((check= itc++) && check != item)
{
@@ -145,9 +145,9 @@ bool check_duplicate_names(THD *thd, List<Item> &item_list, bool gen_unique_view
{
if (!gen_unique_view_name)
goto err;
- if (item->is_autogenerated_name)
+ if (item->is_autogenerated_name())
make_unique_view_field_name(thd, item, item_list, item);
- else if (check->is_autogenerated_name)
+ else if (check->is_autogenerated_name())
make_unique_view_field_name(thd, check, item_list, item);
else
goto err;
@@ -179,7 +179,7 @@ void make_valid_column_names(THD *thd, List<Item> &item_list)
for (uint column_no= 1; (item= it++); column_no++)
{
- if (!item->is_autogenerated_name || !check_column_name(item->name.str))
+ if (!item->is_autogenerated_name() || !check_column_name(item->name.str))
continue;
name_len= my_snprintf(buff, NAME_LEN, "Name_exp_%u", column_no);
item->orig_name= item->name.str;
@@ -454,6 +454,14 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
goto err;
}
+#ifdef WITH_WSREP
+ if(!wsrep_should_replicate_ddl_iterate(thd, static_cast<const TABLE_LIST *>(tables)))
+ {
+ res= TRUE;
+ goto err;
+ }
+#endif
+
view= lex->unlink_first_table(&link_to_local);
if (check_db_dir_existence(view->db.str))
@@ -556,8 +564,8 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
}
while ((item= it++, name= nm++))
{
- item->set_name(thd, name->str, (uint) name->length, system_charset_info);
- item->is_autogenerated_name= FALSE;
+ item->set_name(thd, *name);
+ item->common_flags&= ~IS_AUTO_GENERATED_NAME;
}
}
@@ -592,7 +600,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
This will hold the intersection of the priviliges on all columns in the
view.
*/
- uint final_priv= VIEW_ANY_ACL;
+ privilege_t final_priv(VIEW_ANY_ACL);
for (sl= select_lex; sl; sl= sl->next_select())
{
@@ -602,8 +610,9 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
while ((item= it++))
{
Item_field *fld= item->field_for_view_update();
- uint priv= (get_column_grant(thd, &view->grant, view->db.str,
- view->table_name.str, item->name.str) &
+ privilege_t priv(get_column_grant(thd, &view->grant, view->db.str,
+ view->table_name.str,
+ item->name.str) &
VIEW_ANY_ACL);
if (!fld)
@@ -646,7 +655,8 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
*/
if (!res)
- tdc_remove_table(thd, TDC_RT_REMOVE_ALL, view->db.str, view->table_name.str, false);
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, view->db.str,
+ view->table_name.str);
if (!res && mysql_bin_log.is_open())
{
@@ -926,16 +936,13 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
view_query.length(0);
is_query.length(0);
{
- sql_mode_t sql_mode= thd->variables.sql_mode & MODE_ANSI_QUOTES;
- thd->variables.sql_mode&= ~MODE_ANSI_QUOTES;
+ Sql_mode_instant_remove sms(thd, MODE_ANSI_QUOTES);
lex->unit.print(&view_query, enum_query_type(QT_VIEW_INTERNAL |
QT_ITEM_ORIGINAL_FUNC_NULLIF));
lex->unit.print(&is_query, enum_query_type(QT_TO_SYSTEM_CHARSET |
QT_WITHOUT_INTRODUCERS |
QT_ITEM_ORIGINAL_FUNC_NULLIF));
-
- thd->variables.sql_mode|= sql_mode;
}
DBUG_PRINT("info", ("View: %.*s", view_query.length(), view_query.ptr()));
@@ -1869,8 +1876,8 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
For a view, there is a TABLE_SHARE object.
Remove it from the table definition cache, in case the view was cached.
*/
- tdc_remove_table(thd, TDC_RT_REMOVE_ALL, view->db.str, view->table_name.str,
- FALSE);
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, view->db.str,
+ view->table_name.str);
query_cache_invalidate3(thd, view, 0);
sp_cache_invalidate();
}
diff --git a/sql/sql_window.cc b/sql/sql_window.cc
index 7e319c96000..a9a1dccf9f6 100644
--- a/sql/sql_window.cc
+++ b/sql/sql_window.cc
@@ -778,10 +778,10 @@ public:
{
//DBUG_ASSERT(info->read_record == rr_from_tempfile);
rownum= 0;
- io_cache= (IO_CACHE*)my_malloc(sizeof(IO_CACHE), MYF(0));
+ io_cache= (IO_CACHE*)my_malloc(PSI_INSTRUMENT_ME, sizeof(IO_CACHE), MYF(0));
init_slave_io_cache(info->io_cache, io_cache);
- ref_buffer= (uchar*)my_malloc(ref_length, MYF(0));
+ ref_buffer= (uchar*)my_malloc(PSI_INSTRUMENT_ME, ref_length, MYF(0));
ref_buffer_valid= false;
}
}
@@ -2816,7 +2816,7 @@ bool compute_window_func(THD *thd,
List_iterator_fast<Group_bound_tracker> iter_part_trackers(partition_trackers);
ha_rows rownum= 0;
- uchar *rowid_buf= (uchar*) my_malloc(tbl->file->ref_length, MYF(0));
+ uchar *rowid_buf= (uchar*) my_malloc(PSI_INSTRUMENT_ME, tbl->file->ref_length, MYF(0));
while (true)
{
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 7d4715dbbb8..cf9d11efe08 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2010, 2019, MariaDB Corporation.
+ Copyright (c) 2010, 2020, 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
@@ -38,7 +38,6 @@
#include "sql_parse.h" /* comp_*_creator */
#include "sql_table.h" /* primary_key_name */
#include "sql_partition.h" /* partition_info, HASH_PARTITION */
-#include "sql_acl.h" /* *_ACL */
#include "sql_class.h" /* Key_part_spec, enum_filetype, Diag_condition_item_name */
#include "slave.h"
#include "lex_symbol.h"
@@ -136,7 +135,7 @@ int yylex(void *yylval, void *yythd);
to abort from the parser.
*/
-void MYSQLerror(THD *thd, const char *s)
+static void yyerror(THD *thd, const char *s)
{
/*
Restore the original LEX if it was replaced when parsing
@@ -153,7 +152,9 @@ void MYSQLerror(THD *thd, const char *s)
#ifndef DBUG_OFF
-void turn_parser_debug_on()
+#define __CONCAT_UNDERSCORED(x,y) x ## _ ## y
+#define _CONCAT_UNDERSCORED(x,y) __CONCAT_UNDERSCORED(x,y)
+void _CONCAT_UNDERSCORED(turn_parser_debug_on,yyparse)()
{
/*
MYSQLdebug is in sql/sql_yacc.cc, in bison generated code.
@@ -175,493 +176,6 @@ void turn_parser_debug_on()
#endif
-/**
- Helper action for a case expression statement (the expr in 'CASE expr').
- This helper is used for 'searched' cases only.
- @param lex the parser lex context
- @param expr the parsed expression
- @return 0 on success
-*/
-
-int LEX::case_stmt_action_expr(Item* expr)
-{
- int case_expr_id= spcont->register_case_expr();
- sp_instr_set_case_expr *i;
-
- if (spcont->push_case_expr_id(case_expr_id))
- return 1;
-
- i= new (thd->mem_root)
- sp_instr_set_case_expr(sphead->instructions(), spcont, case_expr_id, expr,
- this);
-
- sphead->add_cont_backpatch(i);
- return sphead->add_instr(i);
-}
-
-/**
- Helper action for a case when condition.
- This helper is used for both 'simple' and 'searched' cases.
- @param lex the parser lex context
- @param when the parsed expression for the WHEN clause
- @param simple true for simple cases, false for searched cases
-*/
-
-int LEX::case_stmt_action_when(Item *when, bool simple)
-{
- uint ip= sphead->instructions();
- sp_instr_jump_if_not *i;
- Item_case_expr *var;
- Item *expr;
-
- if (simple)
- {
- var= new (thd->mem_root)
- Item_case_expr(thd, spcont->get_current_case_expr_id());
-
-#ifdef DBUG_ASSERT_EXISTS
- if (var)
- {
- var->m_sp= sphead;
- }
-#endif
-
- expr= new (thd->mem_root) Item_func_eq(thd, var, when);
- i= new (thd->mem_root) sp_instr_jump_if_not(ip, spcont, expr, this);
- }
- else
- i= new (thd->mem_root) sp_instr_jump_if_not(ip, spcont, when, this);
-
- /*
- BACKPATCH: Registering forward jump from
- "case_stmt_action_when" to "case_stmt_action_then"
- (jump_if_not from instruction 2 to 5, 5 to 8 ... in the example)
- */
-
- return
- !MY_TEST(i) ||
- sphead->push_backpatch(thd, i, spcont->push_label(thd, &empty_clex_str, 0)) ||
- sphead->add_cont_backpatch(i) ||
- sphead->add_instr(i);
-}
-
-/**
- Helper action for a case then statements.
- This helper is used for both 'simple' and 'searched' cases.
- @param lex the parser lex context
-*/
-
-int LEX::case_stmt_action_then()
-{
- uint ip= sphead->instructions();
- sp_instr_jump *i= new (thd->mem_root) sp_instr_jump(ip, spcont);
- if (!MY_TEST(i) || sphead->add_instr(i))
- return 1;
-
- /*
- BACKPATCH: Resolving forward jump from
- "case_stmt_action_when" to "case_stmt_action_then"
- (jump_if_not from instruction 2 to 5, 5 to 8 ... in the example)
- */
-
- sphead->backpatch(spcont->pop_label());
-
- /*
- BACKPATCH: Registering forward jump from
- "case_stmt_action_then" to after END CASE
- (jump from instruction 4 to 12, 7 to 12 ... in the example)
- */
-
- return sphead->push_backpatch(thd, i, spcont->last_label());
-}
-
-
-/**
- Helper action for a SET statement.
- Used to push a system variable into the assignment list.
-
- @param tmp the system variable with base name
- @param var_type the scope of the variable
- @param val the value being assigned to the variable
-
- @return TRUE if error, FALSE otherwise.
-*/
-
-bool
-LEX::set_system_variable(enum enum_var_type var_type,
- sys_var *sysvar, const LEX_CSTRING *base_name,
- Item *val)
-{
- set_var *setvar;
-
- /* No AUTOCOMMIT from a stored function or trigger. */
- if (spcont && sysvar == Sys_autocommit_ptr)
- sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
-
- if (val && val->type() == Item::FIELD_ITEM &&
- ((Item_field*)val)->table_name)
- {
- my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), sysvar->name.str);
- return TRUE;
- }
-
- if (!(setvar= new (thd->mem_root) set_var(thd, var_type, sysvar,
- base_name, val)))
- return TRUE;
-
- return var_list.push_back(setvar, thd->mem_root);
-}
-
-
-/**
- Helper action for a SET statement.
- Used to SET a field of NEW row.
-
- @param name the field name
- @param val the value being assigned to the row
-
- @return TRUE if error, FALSE otherwise.
-*/
-
-bool LEX::set_trigger_new_row(const LEX_CSTRING *name, Item *val)
-{
- Item_trigger_field *trg_fld;
- sp_instr_set_trigger_field *sp_fld;
-
- /* QQ: Shouldn't this be field's default value ? */
- if (! val)
- val= new (thd->mem_root) Item_null(thd);
-
- DBUG_ASSERT(trg_chistics.action_time == TRG_ACTION_BEFORE &&
- (trg_chistics.event == TRG_EVENT_INSERT ||
- trg_chistics.event == TRG_EVENT_UPDATE));
-
- trg_fld= new (thd->mem_root)
- Item_trigger_field(thd, current_context(),
- Item_trigger_field::NEW_ROW,
- name, UPDATE_ACL, FALSE);
-
- if (unlikely(trg_fld == NULL))
- return TRUE;
-
- sp_fld= new (thd->mem_root)
- sp_instr_set_trigger_field(sphead->instructions(),
- spcont, trg_fld, val, this);
-
- if (unlikely(sp_fld == NULL))
- return TRUE;
-
- /*
- Let us add this item to list of all Item_trigger_field
- objects in trigger.
- */
- trg_table_fields.link_in_list(trg_fld, &trg_fld->next_trg_field);
-
- return sphead->add_instr(sp_fld);
-}
-
-
-/**
- Create an object to represent a SP variable in the Item-hierarchy.
-
- @param name The SP variable name.
- @param spvar The SP variable (optional).
- @param start_in_q Start position of the SP variable name in the query.
- @param end_in_q End position of the SP variable name in the query.
-
- @remark If spvar is not specified, the name is used to search for the
- variable in the parse-time context. If the variable does not
- exist, a error is set and NULL is returned to the caller.
-
- @return An Item_splocal object representing the SP variable, or NULL on error.
-*/
-Item_splocal*
-LEX::create_item_for_sp_var(const Lex_ident_cli_st *cname, sp_variable *spvar)
-{
- const Sp_rcontext_handler *rh;
- Item_splocal *item;
- const char *start_in_q= cname->pos();
- const char *end_in_q= cname->end();
- uint pos_in_q, len_in_q;
- Lex_ident_sys name(thd, cname);
-
- if (name.is_null())
- return NULL; // EOM
-
- /* If necessary, look for the variable. */
- if (spcont && !spvar)
- spvar= find_variable(&name, &rh);
-
- if (!spvar)
- {
- my_error(ER_SP_UNDECLARED_VAR, MYF(0), name.str);
- return NULL;
- }
-
- DBUG_ASSERT(spcont && spvar);
-
- /* Position and length of the SP variable name in the query. */
- pos_in_q= (uint)(start_in_q - sphead->m_tmp_query);
- len_in_q= (uint)(end_in_q - start_in_q);
-
- item= new (thd->mem_root)
- Item_splocal(thd, rh, &name, spvar->offset, spvar->type_handler(),
- pos_in_q, len_in_q);
-
-#ifdef DBUG_ASSERT_EXISTS
- if (item)
- item->m_sp= sphead;
-#endif
-
- return item;
-}
-
-/**
- Helper to resolve the SQL:2003 Syntax exception 1) in <in predicate>.
- See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383.
- This function returns the proper item for the SQL expression
- <code>left [NOT] IN ( expr )</code>
- @param thd the current thread
- @param left the in predicand
- @param equal true for IN predicates, false for NOT IN predicates
- @param expr first and only expression of the in value list
- @return an expression representing the IN predicate.
-*/
-Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
- Item *expr)
-{
- /*
- Relevant references for this issue:
- - SQL:2003, Part 2, section 8.4 <in predicate>, page 383,
- - SQL:2003, Part 2, section 7.2 <row value expression>, page 296,
- - SQL:2003, Part 2, section 6.3 <value expression primary>, page 174,
- - SQL:2003, Part 2, section 7.15 <subquery>, page 370,
- - SQL:2003 Feature F561, "Full value expressions".
-
- The exception in SQL:2003 Note 184 means:
- Item_singlerow_subselect, which corresponds to a <scalar subquery>,
- should be re-interpreted as an Item_in_subselect, which corresponds
- to a <table subquery> when used inside an <in predicate>.
-
- Our reading of Note 184 is reccursive, so that all:
- - IN (( <subquery> ))
- - IN ((( <subquery> )))
- - IN '('^N <subquery> ')'^N
- - etc
- should be interpreted as a <table subquery>, no matter how deep in the
- expression the <subquery> is.
- */
-
- Item *result;
-
- DBUG_ENTER("handle_sql2003_note184_exception");
-
- if (expr->type() == Item::SUBSELECT_ITEM)
- {
- Item_subselect *expr2 = (Item_subselect*) expr;
-
- if (expr2->substype() == Item_subselect::SINGLEROW_SUBS)
- {
- Item_singlerow_subselect *expr3 = (Item_singlerow_subselect*) expr2;
- st_select_lex *subselect;
-
- /*
- Implement the mandated change, by altering the semantic tree:
- left IN Item_singlerow_subselect(subselect)
- is modified to
- left IN (subselect)
- which is represented as
- Item_in_subselect(left, subselect)
- */
- subselect= expr3->invalidate_and_restore_select_lex();
- result= new (thd->mem_root) Item_in_subselect(thd, left, subselect);
-
- if (! equal)
- result = negate_expression(thd, result);
-
- DBUG_RETURN(result);
- }
- }
-
- if (equal)
- result= new (thd->mem_root) Item_func_eq(thd, left, expr);
- else
- result= new (thd->mem_root) Item_func_ne(thd, left, expr);
-
- DBUG_RETURN(result);
-}
-
-/**
- Create a separate LEX for each assignment if in SP.
-
- If we are in SP we want have own LEX for each assignment.
- This is mostly because it is hard for several sp_instr_set
- and sp_instr_set_trigger instructions share one LEX.
- (Well, it is theoretically possible but adds some extra
- overhead on preparation for execution stage and IMO less
- robust).
-
- QQ: May be we should simply prohibit group assignments in SP?
-
- @see sp_create_assignment_instr
-
- @param thd Thread context
- @param no_lookahead True if the parser has no lookahead
-*/
-
-void sp_create_assignment_lex(THD *thd, bool no_lookahead)
-{
- LEX *lex= thd->lex;
-
- if (lex->sphead)
- {
- Lex_input_stream *lip= &thd->m_parser_state->m_lip;
- LEX *old_lex= lex;
- lex->sphead->reset_lex(thd);
- lex= thd->lex;
-
- /* Set new LEX as if we at start of set rule. */
- lex->sql_command= SQLCOM_SET_OPTION;
- mysql_init_select(lex);
- lex->var_list.empty();
- lex->autocommit= 0;
- /* get_ptr() is only correct with no lookahead. */
- if (no_lookahead)
- lex->sphead->m_tmp_query= lip->get_ptr();
- else
- lex->sphead->m_tmp_query= lip->get_tok_end();
- /* Inherit from outer lex. */
- lex->option_type= old_lex->option_type;
- lex->main_select_push();
- }
-}
-
-
-/**
- Create a SP instruction for a SET assignment.
-
- @see sp_create_assignment_lex
-
- @param thd Thread context
- @param no_lookahead True if the parser has no lookahead
-
- @return false if success, true otherwise.
-*/
-
-bool sp_create_assignment_instr(THD *thd, bool no_lookahead)
-{
- LEX *lex= thd->lex;
-
- if (lex->sphead)
- {
- if (!lex->var_list.is_empty())
- {
- /*
- We have assignment to user or system variable or
- option setting, so we should construct sp_instr_stmt
- for it.
- */
- Lex_input_stream *lip= &thd->m_parser_state->m_lip;
-
- /*
- Extract the query statement from the tokenizer. The
- end is either lip->ptr, if there was no lookahead,
- lip->tok_end otherwise.
- */
- static const LEX_CSTRING setsp= { STRING_WITH_LEN("SET ") };
- const char *qend= no_lookahead ? lip->get_ptr() : lip->get_tok_end();
- Lex_cstring qbuf(lex->sphead->m_tmp_query, qend);
- if (lex->new_sp_instr_stmt(thd, setsp, qbuf))
- return true;
- }
- lex->pop_select();
- if (lex->check_main_unit_semantics())
- {
- /*
- "lex" can be referrenced by:
- - sp_instr_set SET a= expr;
- - sp_instr_set_row_field SET r.a= expr;
- - sp_instr_stmt (just generated above) SET @a= expr;
- In this case, "lex" is fully owned by sp_instr_xxx and it will
- be deleted by the destructor ~sp_instr_xxx().
- So we should remove "lex" from the stack sp_head::m_lex,
- to avoid double free.
- Note, in case "lex" is not owned by any sp_instr_xxx,
- it's also safe to remove it from the stack right now.
- So we can remove it unconditionally, without testing lex->sp_lex_in_use.
- */
- lex->sphead->restore_lex(thd);
- return true;
- }
- enum_var_type inner_option_type= lex->option_type;
- if (lex->sphead->restore_lex(thd))
- return true;
- /* Copy option_type to outer lex in case it has changed. */
- thd->lex->option_type= inner_option_type;
- }
- return false;
-}
-
-void LEX::add_key_to_list(LEX_CSTRING *field_name,
- enum Key::Keytype type, bool check_exists)
-{
- Key *key;
- MEM_ROOT *mem_root= thd->mem_root;
- key= new (mem_root)
- Key(type, &null_clex_str, HA_KEY_ALG_UNDEF, false,
- DDL_options(check_exists ?
- DDL_options::OPT_IF_NOT_EXISTS :
- DDL_options::OPT_NONE));
- key->columns.push_back(new (mem_root) Key_part_spec(field_name, 0),
- mem_root);
- alter_info.key_list.push_back(key, mem_root);
-}
-
-bool LEX::add_alter_list(const char *name, Virtual_column_info *expr,
- bool exists)
-{
- MEM_ROOT *mem_root= thd->mem_root;
- Alter_column *ac= new (mem_root) Alter_column(name, expr, exists);
- if (unlikely(ac == NULL))
- return true;
- alter_info.alter_list.push_back(ac, mem_root);
- alter_info.flags|= ALTER_CHANGE_COLUMN_DEFAULT;
- return false;
-}
-
-void LEX::init_last_field(Column_definition *field,
- const LEX_CSTRING *field_name,
- const CHARSET_INFO *cs)
-{
- last_field= field;
-
- field->field_name= *field_name;
-
- /* reset LEX fields that are used in Create_field::set_and_check() */
- charset= cs;
-}
-
-
-bool LEX::set_bincmp(CHARSET_INFO *cs, bool bin)
-{
- /*
- if charset is NULL - we're parsing a field declaration.
- we cannot call find_bin_collation for a field here, because actual
- field charset is determined in get_sql_field_charset() much later.
- so we only set a flag.
- */
- if (!charset)
- {
- charset= cs;
- last_field->flags|= bin ? BINCMP_FLAG : 0;
- return false;
- }
-
- charset= bin ? find_bin_collation(cs ? cs : charset)
- : cs ? cs : charset;
- return charset == NULL;
-}
-
#define bincmp_collation(X,Y) \
do \
{ \
@@ -669,18 +183,6 @@ bool LEX::set_bincmp(CHARSET_INFO *cs, bool bin)
MYSQL_YYABORT; \
} while(0)
-
-Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
-{
- Virtual_column_info *v= new (thd->mem_root) Virtual_column_info();
- if (unlikely(!v))
- return 0;
- v->expr= expr;
- v->utf8= 0; /* connection charset */
- return v;
-}
-
-
%}
%union {
int num;
@@ -694,6 +196,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
Lex_ident_cli_st kwd;
Lex_ident_cli_st ident_cli;
Lex_ident_sys_st ident_sys;
+ Lex_column_list_privilege_st column_list_privilege;
Lex_string_with_metadata_st lex_string_with_metadata;
Lex_spblock_st spblock;
Lex_spblock_handlers_st spblock_handlers;
@@ -721,10 +224,12 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
Lex_order_limit_lock *order_limit_lock;
/* pointers */
+ Lex_ident_sys *ident_sys_ptr;
Create_field *create_field;
Spvar_definition *spvar_definition;
Row_definition_list *spvar_definition_list;
const Type_handler *type_handler;
+ const class Sp_handler *sp_handler;
CHARSET_INFO *charset;
Condition_information_item *cond_info_item;
DYNCALL_CREATE_DEF *dyncol_def;
@@ -735,6 +240,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
Item_basic_constant *item_basic_constant;
Key_part_spec *key_part;
LEX *lex;
+ sp_expr_lex *expr_lex;
sp_assignment_lex *assignment_lex;
class sp_lex_cursor *sp_cursor_stmt;
LEX_CSTRING *lex_str_ptr;
@@ -746,7 +252,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
List<sp_assignment_lex> *sp_assignment_lex_list;
List<Statement_information_item> *stmt_info_list;
List<String> *string_list;
- List<LEX_CSTRING> *lex_str_list;
+ List<Lex_ident_sys> *ident_sys_list;
Statement_information_item *stmt_info_item;
String *string;
TABLE_LIST *table_list;
@@ -755,6 +261,8 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
char *simple_string;
const char *const_simple_string;
chooser_compare_func_creator boolfunc2creator;
+ class Lex_grant_privilege *lex_grant;
+ class Lex_grant_object_name *lex_grant_ident;
class my_var *myvar;
class sp_condition_value *spcondvalue;
class sp_head *sphead;
@@ -779,7 +287,6 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
enum Condition_information_item::Name cond_info_item_name;
enum enum_diag_condition_item_name diag_condition_item_name;
enum Diagnostics_information::Which_area diag_area;
- enum Field::geometry_type geom_type;
enum enum_fk_option m_fk_option;
enum Item_udftype udf_type;
enum Key::Keytype key_type;
@@ -802,9 +309,10 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
enum Window_frame::Frame_exclusion frame_exclusion;
enum trigger_order_type trigger_action_order_type;
DDL_options_st object_ddl_options;
- enum vers_sys_type_t vers_range_unit;
+ enum vers_kind_t vers_range_unit;
enum Column_definition::enum_column_versioning vers_column_versioning;
enum plsql_cursor_attr_t plsql_cursor_attr;
+ privilege_t privilege;
}
%{
@@ -817,10 +325,18 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%parse-param { THD *thd }
%lex-param { THD *thd }
/*
- Currently there are 38 shift/reduce conflicts.
We should not introduce new conflicts any more.
*/
-%expect 38
+
+/* Start SQL_MODE_DEFAULT_SPECIFIC */
+%expect 37
+/* End SQL_MODE_DEFAULT_SPECIFIC */
+
+
+/* Start SQL_MODE_ORACLE_SPECIFIC
+%expect 40
+End SQL_MODE_ORACLE_SPECIFIC */
+
/*
Comments for TOKENS.
@@ -842,316 +358,340 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
*/
+%token <lex_str> '@'
+
/*
- Reserved keywords and operators
+ Special purpose tokens
+*/
+%token <NONE> ABORT_SYM /* INTERNAL (used in lex) */
+%token <NONE> IMPOSSIBLE_ACTION /* To avoid warning for yyerrlab1 */
+%token <NONE> END_OF_INPUT /* INTERNAL */
+%token <kwd> COLON_ORACLE_SYM /* INTERNAL */
+%token <kwd> PARAM_MARKER /* INTERNAL */
+%token <NONE> FOR_SYSTEM_TIME_SYM /* INTERNAL */
+%token <NONE> LEFT_PAREN_ALT /* INTERNAL */
+%token <NONE> LEFT_PAREN_WITH /* INTERNAL */
+%token <NONE> LEFT_PAREN_LIKE /* INTERNAL */
+%token <NONE> ORACLE_CONCAT_SYM /* INTERNAL */
+%token <NONE> PERCENT_ORACLE_SYM /* INTERNAL */
+%token <NONE> WITH_CUBE_SYM /* INTERNAL */
+%token <NONE> WITH_ROLLUP_SYM /* INTERNAL */
+%token <NONE> WITH_SYSTEM_SYM /* INTERNAL */
+
+
+/*
+ Identifiers
*/
-%token ABORT_SYM /* INTERNAL (used in lex) */
-%token ACCESSIBLE_SYM
-%token ADD /* SQL-2003-R */
-%token ALL /* SQL-2003-R */
-%token ALTER /* SQL-2003-R */
-%token ANALYZE_SYM
-%token AND_AND_SYM /* OPERATOR */
-%token AND_SYM /* SQL-2003-R */
-%token AS /* SQL-2003-R */
-%token ASC /* SQL-2003-N */
-%token ASENSITIVE_SYM /* FUTURE-USE */
-%token BEFORE_SYM /* SQL-2003-N */
-%token BETWEEN_SYM /* SQL-2003-R */
-%token BIGINT /* SQL-2003-R */
-%token BINARY /* SQL-2003-R */
-%token BIN_NUM
-%token BIT_AND /* MYSQL-FUNC */
-%token BIT_OR /* MYSQL-FUNC */
-%token BIT_XOR /* MYSQL-FUNC */
-%token BLOB_MARIADB_SYM /* SQL-2003-R */
-%token BLOB_ORACLE_SYM /* Oracle-R */
-%token BODY_ORACLE_SYM /* Oracle-R */
-%token BOTH /* SQL-2003-R */
-%token BY /* SQL-2003-R */
-%token CALL_SYM /* SQL-2003-R */
-%token CASCADE /* SQL-2003-N */
-%token CASE_SYM /* SQL-2003-R */
-%token CAST_SYM /* SQL-2003-R */
-%token CHANGE
-%token CHAR_SYM /* SQL-2003-R */
-%token CHECK_SYM /* SQL-2003-R */
-%token COLLATE_SYM /* SQL-2003-R */
-%token CONDITION_SYM /* SQL-2003-R, SQL-2008-R */
-%token CONSTRAINT /* SQL-2003-R */
-%token CONTINUE_MARIADB_SYM /* SQL-2003-R, Oracle-R */
-%token CONTINUE_ORACLE_SYM /* SQL-2003-R, Oracle-R */
-%token CONVERT_SYM /* SQL-2003-N */
-%token COUNT_SYM /* SQL-2003-N */
-%token CREATE /* SQL-2003-R */
-%token CROSS /* SQL-2003-R */
-%token CUME_DIST_SYM
-%token CURDATE /* MYSQL-FUNC */
-%token CURRENT_USER /* SQL-2003-R */
-%token CURRENT_ROLE /* SQL-2003-R */
-%token CURSOR_SYM /* SQL-2003-R */
-%token CURTIME /* MYSQL-FUNC */
-%token DATABASE
-%token DATABASES
-%token DATE_ADD_INTERVAL /* MYSQL-FUNC */
-%token DATE_SUB_INTERVAL /* MYSQL-FUNC */
-%token DAY_HOUR_SYM
-%token DAY_MICROSECOND_SYM
-%token DAY_MINUTE_SYM
-%token DAY_SECOND_SYM
-%token DECIMAL_NUM
-%token DECIMAL_SYM /* SQL-2003-R */
-%token DECLARE_MARIADB_SYM /* SQL-2003-R */
-%token DECLARE_ORACLE_SYM /* Oracle-R */
-%token DEFAULT /* SQL-2003-R */
-%token DELETE_DOMAIN_ID_SYM
-%token DELETE_SYM /* SQL-2003-R */
-%token DENSE_RANK_SYM
-%token DESC /* SQL-2003-N */
-%token DESCRIBE /* SQL-2003-R */
-%token DETERMINISTIC_SYM /* SQL-2003-R */
-%token DISTINCT /* SQL-2003-R */
-%token DIV_SYM
-%token DOUBLE_SYM /* SQL-2003-R */
-%token DO_DOMAIN_IDS_SYM
-%token DOT_DOT_SYM
-%token DROP /* SQL-2003-R */
-%token DUAL_SYM
-%token EACH_SYM /* SQL-2003-R */
-%token ELSE /* SQL-2003-R */
-%token ELSEIF_MARIADB_SYM
-%token ELSIF_ORACLE_SYM /* PLSQL-R */
-%token ENCLOSED
-%token END_OF_INPUT /* INTERNAL */
-%token EQUAL_SYM /* OPERATOR */
-%token ESCAPED
-%token EXCEPT_SYM /* SQL-2003-R */
-%token EXISTS /* SQL-2003-R */
-%token EXTRACT_SYM /* SQL-2003-N */
-%token FALSE_SYM /* SQL-2003-R */
-%token FETCH_SYM /* SQL-2003-R */
-%token FIRST_VALUE_SYM /* SQL-2011 */
-%token FLOAT_NUM
-%token FLOAT_SYM /* SQL-2003-R */
-%token FOREIGN /* SQL-2003-R */
-%token FOR_SYM /* SQL-2003-R */
-%token FOR_SYSTEM_TIME_SYM /* INTERNAL */
-%token FROM
-%token FULLTEXT_SYM
-%token GE
-%token GOTO_ORACLE_SYM /* Oracle-R */
-%token GRANT /* SQL-2003-R */
-%token GROUP_SYM /* SQL-2003-R */
-%token GROUP_CONCAT_SYM
-%token LAG_SYM /* SQL-2011 */
-%token LEAD_SYM /* SQL-2011 */
-%token HAVING /* SQL-2003-R */
-%token HEX_NUM
-%token HEX_STRING
-%token HOUR_MICROSECOND_SYM
-%token HOUR_MINUTE_SYM
-%token HOUR_SECOND_SYM
%token IDENT
%token IDENT_QUOTED
-%token IF_SYM
-%token IGNORE_DOMAIN_IDS_SYM
-%token IGNORE_SYM
-%token INDEX_SYM
-%token INFILE
-%token INNER_SYM /* SQL-2003-R */
-%token INOUT_SYM /* SQL-2003-R */
-%token INSENSITIVE_SYM /* SQL-2003-R */
-%token INSERT /* SQL-2003-R */
-%token INTERSECT_SYM /* SQL-2003-R */
-%token INTERVAL_SYM /* SQL-2003-R */
-%token INTO /* SQL-2003-R */
-%token INT_SYM /* SQL-2003-R */
-%token IN_SYM /* SQL-2003-R */
-%token IS /* SQL-2003-R */
-%token ITERATE_SYM
-%token JOIN_SYM /* SQL-2003-R */
-%token KEYS
-%token KEY_SYM /* SQL-2003-N */
-%token KILL_SYM
-%token LE /* OPERATOR */
-%token LEADING /* SQL-2003-R */
-%token LEAVE_SYM
-%token LEFT /* SQL-2003-R */
-%token LEFT_PAREN_ALT /* INTERNAL */
-%token LEFT_PAREN_WITH /* INTERNAL */
-%token LEFT_PAREN_LIKE /* INTERNAL */
%token LEX_HOSTNAME
-%token LIKE /* SQL-2003-R */
-%token LIMIT
-%token LINEAR_SYM
-%token LINES
-%token LOAD
-%token LOCATOR_SYM /* SQL-2003-N */
-%token LOCK_SYM
-%token LONGBLOB
-%token LONGTEXT
-%token LONG_NUM
-%token LONG_SYM
-%token LOOP_SYM
-%token LOW_PRIORITY
-%token MASTER_SSL_VERIFY_SERVER_CERT_SYM
-%token MATCH /* SQL-2003-R */
-%token MAX_SYM /* SQL-2003-N */
-%token MAXVALUE_SYM /* SQL-2003-N */
-%token MEDIAN_SYM
-%token MEDIUMBLOB
-%token MEDIUMINT
-%token MEDIUMTEXT
-%token MINUTE_MICROSECOND_SYM
-%token MINUTE_SECOND_SYM
-%token MIN_SYM /* SQL-2003-N */
-%token MODIFIES_SYM /* SQL-2003-R */
-%token MOD_SYM /* SQL-2003-N */
-%token MYSQL_CONCAT_SYM /* OPERATOR */
-%token NATURAL /* SQL-2003-R */
-%token NCHAR_STRING
-%token NE /* OPERATOR */
-%token NEG
-%token NOT2_SYM
-%token NOT_SYM /* SQL-2003-R */
-%token NOW_SYM
-%token NO_WRITE_TO_BINLOG
-%token NTILE_SYM
-%token NULL_SYM /* SQL-2003-R */
-%token NUM
-%token NUMERIC_SYM /* SQL-2003-R */
-%token NTH_VALUE_SYM /* SQL-2011 */
-%token ON /* SQL-2003-R */
-%token OPTIMIZE
-%token OPTIONALLY
-%token ORACLE_CONCAT_SYM /* INTERNAL */
-%token OR2_SYM
-%token ORDER_SYM /* SQL-2003-R */
-%token OR_SYM /* SQL-2003-R */
-%token OTHERS_ORACLE_SYM /* SQL-2011-N, PLSQL-R */
-%token OUTER
-%token OUTFILE
-%token OUT_SYM /* SQL-2003-R */
-%token OVER_SYM
-%token PACKAGE_ORACLE_SYM /* Oracle-R */
-%token PAGE_CHECKSUM_SYM
-%token PARAM_MARKER
-%token PARSE_VCOL_EXPR_SYM
-%token PARTITION_SYM /* SQL-2003-R */
-%token PERCENT_ORACLE_SYM /* INTERNAL */
-%token PERCENT_RANK_SYM
-%token PERCENTILE_CONT_SYM
-%token PERCENTILE_DISC_SYM
-%token PORTION_SYM /* SQL-2016-R */
-%token POSITION_SYM /* SQL-2003-N */
-%token PRECISION /* SQL-2003-R */
-%token PRIMARY_SYM /* SQL-2003-R */
-%token PROCEDURE_SYM /* SQL-2003-R */
-%token PURGE
-%token RAISE_ORACLE_SYM /* PLSQL-R */
-%token RANGE_SYM /* SQL-2003-R */
-%token RANK_SYM
-%token READS_SYM /* SQL-2003-R */
-%token READ_SYM /* SQL-2003-N */
-%token READ_WRITE_SYM
-%token REAL /* SQL-2003-R */
-%token RECURSIVE_SYM
-%token REF_SYSTEM_ID_SYM
-%token REFERENCES /* SQL-2003-R */
-%token REGEXP
-%token RELEASE_SYM /* SQL-2003-R */
-%token RENAME
-%token REPEAT_SYM /* MYSQL-FUNC */
-%token REPLACE /* MYSQL-FUNC */
-%token REQUIRE_SYM
-%token RESIGNAL_SYM /* SQL-2003-R */
-%token RESTRICT
-%token RETURNING_SYM
-%token RETURN_MARIADB_SYM /* SQL-2003-R, PLSQL-R */
-%token RETURN_ORACLE_SYM /* SQL-2003-R, PLSQL-R */
-%token REVOKE /* SQL-2003-R */
-%token RIGHT /* SQL-2003-R */
-%token ROWS_SYM /* SQL-2003-R */
-%token ROWTYPE_ORACLE_SYM /* PLSQL-R */
-%token ROW_NUMBER_SYM
-%token SECOND_MICROSECOND_SYM
-%token SELECT_SYM /* SQL-2003-R */
-%token SENSITIVE_SYM /* FUTURE-USE */
-%token SEPARATOR_SYM
-%token SERVER_OPTIONS
-%token SET /* SQL-2003-R */
-%token SET_VAR
-%token SHIFT_LEFT /* OPERATOR */
-%token SHIFT_RIGHT /* OPERATOR */
-%token SHOW
-%token SIGNAL_SYM /* SQL-2003-R */
-%token SMALLINT /* SQL-2003-R */
-%token SPATIAL_SYM
-%token SPECIFIC_SYM /* SQL-2003-R */
-%token SQLEXCEPTION_SYM /* SQL-2003-R */
-%token SQLSTATE_SYM /* SQL-2003-R */
-%token SQLWARNING_SYM /* SQL-2003-R */
-%token SQL_BIG_RESULT
-%token SQL_SMALL_RESULT
-%token SQL_SYM /* SQL-2003-R */
-%token SSL_SYM
-%token STARTING
-%token STATS_AUTO_RECALC_SYM
-%token STATS_PERSISTENT_SYM
-%token STATS_SAMPLE_PAGES_SYM
-%token STDDEV_SAMP_SYM /* SQL-2003-N */
-%token STD_SYM
-%token STRAIGHT_JOIN
-%token SUBSTRING /* SQL-2003-N */
-%token SUM_SYM /* SQL-2003-N */
-%token SYSDATE
-%token TABLE_REF_PRIORITY
-%token TABLE_SYM /* SQL-2003-R */
-%token TERMINATED
-%token TEXT_STRING
-%token THEN_SYM /* SQL-2003-R */
-%token TINYBLOB
-%token TINYINT
-%token TINYTEXT
-%token TO_SYM /* SQL-2003-R */
-%token TRAILING /* SQL-2003-R */
-%token TRIGGER_SYM /* SQL-2003-R */
-%token TRIM /* SQL-2003-N */
-%token TRUE_SYM /* SQL-2003-R */
-%token ULONGLONG_NUM
-%token UNDERSCORE_CHARSET
-%token UNDO_SYM /* FUTURE-USE */
-%token UNION_SYM /* SQL-2003-R */
-%token UNIQUE_SYM
-%token UNLOCK_SYM
-%token UNSIGNED
-%token UPDATE_SYM /* SQL-2003-R */
-%token USAGE /* SQL-2003-N */
-%token USE_SYM
-%token USING /* SQL-2003-R */
-%token UTC_DATE_SYM
-%token UTC_TIMESTAMP_SYM
-%token UTC_TIME_SYM
-%token VALUES /* SQL-2003-R */
-%token VALUES_IN_SYM
-%token VALUES_LESS_SYM
-%token VARBINARY
-%token VARCHAR /* SQL-2003-R */
-%token VARIANCE_SYM
-%token VARYING /* SQL-2003-R */
-%token VAR_SAMP_SYM
-%token WHEN_SYM /* SQL-2003-R */
-%token WHERE /* SQL-2003-R */
-%token WHILE_SYM
-%token WITH /* SQL-2003-R */
-%token WITH_CUBE_SYM /* INTERNAL */
-%token WITH_ROLLUP_SYM /* INTERNAL */
-%token WITH_SYSTEM_SYM /* INTERNAL */
-%token XOR
-%token YEAR_MONTH_SYM
-%token ZEROFILL
-
-%token IMPOSSIBLE_ACTION /* To avoid warning for yyerrlab1 */
+%token UNDERSCORE_CHARSET /* _latin1 */
+
+
+/*
+ Literals
+*/
+%token BIN_NUM /* LITERAL */
+%token DECIMAL_NUM /* LITERAL */
+%token FLOAT_NUM /* LITERAL */
+%token HEX_NUM /* LITERAL */
+%token HEX_STRING /* LITERAL */
+%token LONG_NUM /* LITERAL */
+%token NCHAR_STRING /* LITERAL */
+%token NUM /* LITERAL */
+%token TEXT_STRING /* LITERAL */
+%token ULONGLONG_NUM /* LITERAL */
+
+
+/*
+ Operators
+*/
+%token <NONE> AND_AND_SYM /* OPERATOR */
+%token <NONE> DOT_DOT_SYM /* OPERATOR */
+%token <NONE> EQUAL_SYM /* OPERATOR */
+%token <NONE> GE /* OPERATOR */
+%token <NONE> LE /* OPERATOR */
+%token <NONE> MYSQL_CONCAT_SYM /* OPERATOR */
+%token <NONE> NE /* OPERATOR */
+%token <NONE> NOT2_SYM /* OPERATOR */
+%token <NONE> OR2_SYM /* OPERATOR */
+%token <NONE> SET_VAR /* OPERATOR */
+%token <NONE> SHIFT_LEFT /* OPERATOR */
+%token <NONE> SHIFT_RIGHT /* OPERATOR */
+
+
+/*
+ Reserved keywords
+*/
+%token <kwd> ACCESSIBLE_SYM
+%token <kwd> ADD /* SQL-2003-R */
+%token <kwd> ALL /* SQL-2003-R */
+%token <kwd> ALTER /* SQL-2003-R */
+%token <kwd> ANALYZE_SYM
+%token <kwd> AND_SYM /* SQL-2003-R */
+%token <kwd> ASC /* SQL-2003-N */
+%token <kwd> ASENSITIVE_SYM /* FUTURE-USE */
+%token <kwd> AS /* SQL-2003-R */
+%token <kwd> BEFORE_SYM /* SQL-2003-N */
+%token <kwd> BETWEEN_SYM /* SQL-2003-R */
+%token <kwd> BIGINT /* SQL-2003-R */
+%token <kwd> BINARY /* SQL-2003-R */
+%token <kwd> BIT_AND /* MYSQL-FUNC */
+%token <kwd> BIT_OR /* MYSQL-FUNC */
+%token <kwd> BIT_XOR /* MYSQL-FUNC */
+%token <kwd> BLOB_MARIADB_SYM /* SQL-2003-R */
+%token <kwd> BLOB_ORACLE_SYM /* Oracle-R */
+%token <kwd> BODY_ORACLE_SYM /* Oracle-R */
+%token <kwd> BOTH /* SQL-2003-R */
+%token <kwd> BY /* SQL-2003-R */
+%token <kwd> CALL_SYM /* SQL-2003-R */
+%token <kwd> CASCADE /* SQL-2003-N */
+%token <kwd> CASE_SYM /* SQL-2003-R */
+%token <kwd> CAST_SYM /* SQL-2003-R */
+%token <kwd> CHANGE
+%token <kwd> CHAR_SYM /* SQL-2003-R */
+%token <kwd> CHECK_SYM /* SQL-2003-R */
+%token <kwd> COLLATE_SYM /* SQL-2003-R */
+%token <kwd> CONDITION_SYM /* SQL-2003-R, SQL-2008-R */
+%token <kwd> CONSTRAINT /* SQL-2003-R */
+%token <kwd> CONTINUE_MARIADB_SYM /* SQL-2003-R, Oracle-R */
+%token <kwd> CONTINUE_ORACLE_SYM /* SQL-2003-R, Oracle-R */
+%token <kwd> CONVERT_SYM /* SQL-2003-N */
+%token <kwd> COUNT_SYM /* SQL-2003-N */
+%token <kwd> CREATE /* SQL-2003-R */
+%token <kwd> CROSS /* SQL-2003-R */
+%token <kwd> CUME_DIST_SYM
+%token <kwd> CURDATE /* MYSQL-FUNC */
+%token <kwd> CURRENT_ROLE /* SQL-2003-R */
+%token <kwd> CURRENT_USER /* SQL-2003-R */
+%token <kwd> CURSOR_SYM /* SQL-2003-R */
+%token <kwd> CURTIME /* MYSQL-FUNC */
+%token <kwd> DATABASE
+%token <kwd> DATABASES
+%token <kwd> DATE_ADD_INTERVAL /* MYSQL-FUNC */
+%token <kwd> DATE_SUB_INTERVAL /* MYSQL-FUNC */
+%token <kwd> DAY_HOUR_SYM
+%token <kwd> DAY_MICROSECOND_SYM
+%token <kwd> DAY_MINUTE_SYM
+%token <kwd> DAY_SECOND_SYM
+%token <kwd> DECIMAL_SYM /* SQL-2003-R */
+%token <kwd> DECLARE_MARIADB_SYM /* SQL-2003-R */
+%token <kwd> DECLARE_ORACLE_SYM /* Oracle-R */
+%token <kwd> DEFAULT /* SQL-2003-R */
+%token <kwd> DELETE_DOMAIN_ID_SYM
+%token <kwd> DELETE_SYM /* SQL-2003-R */
+%token <kwd> DENSE_RANK_SYM
+%token <kwd> DESCRIBE /* SQL-2003-R */
+%token <kwd> DESC /* SQL-2003-N */
+%token <kwd> DETERMINISTIC_SYM /* SQL-2003-R */
+%token <kwd> DISTINCT /* SQL-2003-R */
+%token <kwd> DIV_SYM
+%token <kwd> DO_DOMAIN_IDS_SYM
+%token <kwd> DOUBLE_SYM /* SQL-2003-R */
+%token <kwd> DROP /* SQL-2003-R */
+%token <kwd> DUAL_SYM
+%token <kwd> EACH_SYM /* SQL-2003-R */
+%token <kwd> ELSEIF_MARIADB_SYM
+%token <kwd> ELSE /* SQL-2003-R */
+%token <kwd> ELSIF_ORACLE_SYM /* PLSQL-R */
+%token <kwd> ENCLOSED
+%token <kwd> ESCAPED
+%token <kwd> EXCEPT_SYM /* SQL-2003-R */
+%token <kwd> EXISTS /* SQL-2003-R */
+%token <kwd> EXTRACT_SYM /* SQL-2003-N */
+%token <kwd> FALSE_SYM /* SQL-2003-R */
+%token <kwd> FETCH_SYM /* SQL-2003-R */
+%token <kwd> FIRST_VALUE_SYM /* SQL-2011 */
+%token <kwd> FLOAT_SYM /* SQL-2003-R */
+%token <kwd> FOREIGN /* SQL-2003-R */
+%token <kwd> FOR_SYM /* SQL-2003-R */
+%token <kwd> FROM
+%token <kwd> FULLTEXT_SYM
+%token <kwd> GOTO_ORACLE_SYM /* Oracle-R */
+%token <kwd> GRANT /* SQL-2003-R */
+%token <kwd> GROUP_CONCAT_SYM
+%token <rwd> JSON_ARRAYAGG_SYM
+%token <rwd> JSON_OBJECTAGG_SYM
+%token <kwd> GROUP_SYM /* SQL-2003-R */
+%token <kwd> HAVING /* SQL-2003-R */
+%token <kwd> HOUR_MICROSECOND_SYM
+%token <kwd> HOUR_MINUTE_SYM
+%token <kwd> HOUR_SECOND_SYM
+%token <kwd> IF_SYM
+%token <kwd> IGNORE_DOMAIN_IDS_SYM
+%token <kwd> IGNORE_SYM
+%token <kwd> INDEX_SYM
+%token <kwd> INFILE
+%token <kwd> INNER_SYM /* SQL-2003-R */
+%token <kwd> INOUT_SYM /* SQL-2003-R */
+%token <kwd> INSENSITIVE_SYM /* SQL-2003-R */
+%token <kwd> INSERT /* SQL-2003-R */
+%token <kwd> IN_SYM /* SQL-2003-R */
+%token <kwd> INTERSECT_SYM /* SQL-2003-R */
+%token <kwd> INTERVAL_SYM /* SQL-2003-R */
+%token <kwd> INTO /* SQL-2003-R */
+%token <kwd> INT_SYM /* SQL-2003-R */
+%token <kwd> IS /* SQL-2003-R */
+%token <kwd> ITERATE_SYM
+%token <kwd> JOIN_SYM /* SQL-2003-R */
+%token <kwd> KEYS
+%token <kwd> KEY_SYM /* SQL-2003-N */
+%token <kwd> KILL_SYM
+%token <kwd> LAG_SYM /* SQL-2011 */
+%token <kwd> LEADING /* SQL-2003-R */
+%token <kwd> LEAD_SYM /* SQL-2011 */
+%token <kwd> LEAVE_SYM
+%token <kwd> LEFT /* SQL-2003-R */
+%token <kwd> LIKE /* SQL-2003-R */
+%token <kwd> LIMIT
+%token <kwd> LINEAR_SYM
+%token <kwd> LINES
+%token <kwd> LOAD
+%token <kwd> LOCATOR_SYM /* SQL-2003-N */
+%token <kwd> LOCK_SYM
+%token <kwd> LONGBLOB
+%token <kwd> LONG_SYM
+%token <kwd> LONGTEXT
+%token <kwd> LOOP_SYM
+%token <kwd> LOW_PRIORITY
+%token <kwd> MASTER_SSL_VERIFY_SERVER_CERT_SYM
+%token <kwd> MATCH /* SQL-2003-R */
+%token <kwd> MAX_SYM /* SQL-2003-N */
+%token <kwd> MAXVALUE_SYM /* SQL-2003-N */
+%token <kwd> MEDIAN_SYM
+%token <kwd> MEDIUMBLOB
+%token <kwd> MEDIUMINT
+%token <kwd> MEDIUMTEXT
+%token <kwd> MIN_SYM /* SQL-2003-N */
+%token <kwd> MINUTE_MICROSECOND_SYM
+%token <kwd> MINUTE_SECOND_SYM
+%token <kwd> MODIFIES_SYM /* SQL-2003-R */
+%token <kwd> MOD_SYM /* SQL-2003-N */
+%token <kwd> NATURAL /* SQL-2003-R */
+%token <kwd> NEG
+%token <kwd> NOT_SYM /* SQL-2003-R */
+%token <kwd> NO_WRITE_TO_BINLOG
+%token <kwd> NOW_SYM
+%token <kwd> NTH_VALUE_SYM /* SQL-2011 */
+%token <kwd> NTILE_SYM
+%token <kwd> NULL_SYM /* SQL-2003-R */
+%token <kwd> NUMERIC_SYM /* SQL-2003-R */
+%token <kwd> ON /* SQL-2003-R */
+%token <kwd> OPTIMIZE
+%token <kwd> OPTIONALLY
+%token <kwd> ORDER_SYM /* SQL-2003-R */
+%token <kwd> OR_SYM /* SQL-2003-R */
+%token <kwd> OTHERS_ORACLE_SYM /* SQL-2011-N, PLSQL-R */
+%token <kwd> OUTER
+%token <kwd> OUTFILE
+%token <kwd> OUT_SYM /* SQL-2003-R */
+%token <kwd> OVER_SYM
+%token <kwd> PACKAGE_ORACLE_SYM /* Oracle-R */
+%token <kwd> PAGE_CHECKSUM_SYM
+%token <kwd> PARSE_VCOL_EXPR_SYM
+%token <kwd> PARTITION_SYM /* SQL-2003-R */
+%token <kwd> PERCENTILE_CONT_SYM
+%token <kwd> PERCENTILE_DISC_SYM
+%token <kwd> PERCENT_RANK_SYM
+%token <kwd> PORTION_SYM /* SQL-2016-R */
+%token <kwd> POSITION_SYM /* SQL-2003-N */
+%token <kwd> PRECISION /* SQL-2003-R */
+%token <kwd> PRIMARY_SYM /* SQL-2003-R */
+%token <kwd> PROCEDURE_SYM /* SQL-2003-R */
+%token <kwd> PURGE
+%token <kwd> RAISE_ORACLE_SYM /* PLSQL-R */
+%token <kwd> RANGE_SYM /* SQL-2003-R */
+%token <kwd> RANK_SYM
+%token <kwd> READS_SYM /* SQL-2003-R */
+%token <kwd> READ_SYM /* SQL-2003-N */
+%token <kwd> READ_WRITE_SYM
+%token <kwd> REAL /* SQL-2003-R */
+%token <kwd> RECURSIVE_SYM
+%token <kwd> REFERENCES /* SQL-2003-R */
+%token <kwd> REF_SYSTEM_ID_SYM
+%token <kwd> REGEXP
+%token <kwd> RELEASE_SYM /* SQL-2003-R */
+%token <kwd> RENAME
+%token <kwd> REPEAT_SYM /* MYSQL-FUNC */
+%token <kwd> REPLACE /* MYSQL-FUNC */
+%token <kwd> REQUIRE_SYM
+%token <kwd> RESIGNAL_SYM /* SQL-2003-R */
+%token <kwd> RESTRICT
+%token <kwd> RETURNING_SYM
+%token <kwd> RETURN_MARIADB_SYM /* SQL-2003-R, PLSQL-R */
+%token <kwd> RETURN_ORACLE_SYM /* SQL-2003-R, PLSQL-R */
+%token <kwd> REVOKE /* SQL-2003-R */
+%token <kwd> RIGHT /* SQL-2003-R */
+%token <kwd> ROW_NUMBER_SYM
+%token <kwd> ROWS_SYM /* SQL-2003-R */
+%token <kwd> ROWTYPE_ORACLE_SYM /* PLSQL-R */
+%token <kwd> SECOND_MICROSECOND_SYM
+%token <kwd> SELECT_SYM /* SQL-2003-R */
+%token <kwd> SENSITIVE_SYM /* FUTURE-USE */
+%token <kwd> SEPARATOR_SYM
+%token <kwd> SERVER_OPTIONS
+%token <kwd> SET /* SQL-2003-R */
+%token <kwd> SHOW
+%token <kwd> SIGNAL_SYM /* SQL-2003-R */
+%token <kwd> SMALLINT /* SQL-2003-R */
+%token <kwd> SPATIAL_SYM
+%token <kwd> SPECIFIC_SYM /* SQL-2003-R */
+%token <kwd> SQL_BIG_RESULT
+%token <kwd> SQLEXCEPTION_SYM /* SQL-2003-R */
+%token <kwd> SQL_SMALL_RESULT
+%token <kwd> SQLSTATE_SYM /* SQL-2003-R */
+%token <kwd> SQL_SYM /* SQL-2003-R */
+%token <kwd> SQLWARNING_SYM /* SQL-2003-R */
+%token <kwd> SSL_SYM
+%token <kwd> STARTING
+%token <kwd> STATS_AUTO_RECALC_SYM
+%token <kwd> STATS_PERSISTENT_SYM
+%token <kwd> STATS_SAMPLE_PAGES_SYM
+%token <kwd> STDDEV_SAMP_SYM /* SQL-2003-N */
+%token <kwd> STD_SYM
+%token <kwd> STRAIGHT_JOIN
+%token <kwd> SUBSTRING /* SQL-2003-N */
+%token <kwd> SUM_SYM /* SQL-2003-N */
+%token <kwd> SYSDATE
+%token <kwd> TABLE_REF_PRIORITY
+%token <kwd> TABLE_SYM /* SQL-2003-R */
+%token <kwd> TERMINATED
+%token <kwd> THEN_SYM /* SQL-2003-R */
+%token <kwd> TINYBLOB
+%token <kwd> TINYINT
+%token <kwd> TINYTEXT
+%token <kwd> TO_SYM /* SQL-2003-R */
+%token <kwd> TRAILING /* SQL-2003-R */
+%token <kwd> TRIGGER_SYM /* SQL-2003-R */
+%token <kwd> TRIM /* SQL-2003-N */
+%token <kwd> TRUE_SYM /* SQL-2003-R */
+%token <kwd> UNDO_SYM /* FUTURE-USE */
+%token <kwd> UNION_SYM /* SQL-2003-R */
+%token <kwd> UNIQUE_SYM
+%token <kwd> UNLOCK_SYM
+%token <kwd> UNSIGNED
+%token <kwd> UPDATE_SYM /* SQL-2003-R */
+%token <kwd> USAGE /* SQL-2003-N */
+%token <kwd> USE_SYM
+%token <kwd> USING /* SQL-2003-R */
+%token <kwd> UTC_DATE_SYM
+%token <kwd> UTC_TIMESTAMP_SYM
+%token <kwd> UTC_TIME_SYM
+%token <kwd> VALUES_IN_SYM
+%token <kwd> VALUES_LESS_SYM
+%token <kwd> VALUES /* SQL-2003-R */
+%token <kwd> VARBINARY
+%token <kwd> VARCHAR /* SQL-2003-R */
+%token <kwd> VARIANCE_SYM
+%token <kwd> VAR_SAMP_SYM
+%token <kwd> VARYING /* SQL-2003-R */
+%token <kwd> WHEN_SYM /* SQL-2003-R */
+%token <kwd> WHERE /* SQL-2003-R */
+%token <kwd> WHILE_SYM
+%token <kwd> WITH /* SQL-2003-R */
+%token <kwd> XOR
+%token <kwd> YEAR_MONTH_SYM
+%token <kwd> ZEROFILL
/*
@@ -1217,7 +757,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> COALESCE /* SQL-2003-N */
%token <kwd> CODE_SYM
%token <kwd> COLLATION_SYM /* SQL-2003-N */
-%token <kwd> COLON_ORACLE_SYM /* INTERNAL */
%token <kwd> COLUMNS
%token <kwd> COLUMN_ADD_SYM
%token <kwd> COLUMN_CHECK_SYM
@@ -1295,6 +834,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> EXTENT_SIZE_SYM
%token <kwd> FAST_SYM
%token <kwd> FAULTS_SYM
+%token <kwd> FEDERATED_SYM /* MariaDB privilege */
%token <kwd> FILE_SYM
%token <kwd> FIRST_SYM /* SQL-2003-N */
%token <kwd> FIXED_SYM
@@ -1308,8 +848,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> FUNCTION_SYM /* SQL-2003-R, Oracle-R */
%token <kwd> GENERAL
%token <kwd> GENERATED_SYM
-%token <kwd> GEOMETRYCOLLECTION
-%token <kwd> GEOMETRY_SYM
%token <kwd> GET_FORMAT /* MYSQL-FUNC */
%token <kwd> GET_SYM /* SQL-2003-R */
%token <kwd> GLOBAL_SYM /* SQL-2003-R */
@@ -1349,7 +887,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> LEAVES
%token <kwd> LESS_SYM
%token <kwd> LEVEL_SYM
-%token <kwd> LINESTRING
%token <kwd> LIST_SYM
%token <kwd> LOCAL_SYM /* SQL-2003-R */
%token <kwd> LOCKS_SYM
@@ -1394,10 +931,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> MIN_ROWS
%token <kwd> MODE_SYM
%token <kwd> MODIFY_SYM
+%token <kwd> MONITOR_SYM /* MariaDB privilege */
%token <kwd> MONTH_SYM /* SQL-2003-R */
-%token <kwd> MULTILINESTRING
-%token <kwd> MULTIPOINT
-%token <kwd> MULTIPOLYGON
%token <kwd> MUTEX_SYM
%token <kwd> MYSQL_SYM
%token <kwd> MYSQL_ERRNO_SYM
@@ -1444,8 +979,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> PHASE_SYM
%token <kwd> PLUGINS_SYM
%token <kwd> PLUGIN_SYM
-%token <kwd> POINT_SYM
-%token <kwd> POLYGON
%token <kwd> PORT_SYM
%token <kwd> PRECEDES_SYM /* MYSQL */
%token <kwd> PRECEDING_SYM /* SQL-2011-N */
@@ -1480,6 +1013,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> REORGANIZE_SYM
%token <kwd> REPAIR
%token <kwd> REPEATABLE_SYM /* SQL-2003-N */
+%token <kwd> REPLAY_SYM /* MariaDB privilege */
%token <kwd> REPLICATION
%token <kwd> RESET_SYM
%token <kwd> RESTART_SYM
@@ -1703,7 +1237,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 USER
+%left TRANSACTION_SYM TIMESTAMP PERIOD_SYM SYSTEM USER COMMENT_SYM
/*
@@ -1741,20 +1275,17 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
key_cache_name
sp_opt_label BIN_NUM TEXT_STRING_filesystem
opt_constraint constraint opt_ident
- sp_block_label opt_place opt_db
-
-%type <lex_str>
- sp_label
+ sp_block_label sp_control_label opt_place opt_db
%type <ident_sys>
IDENT_sys
ident
label_ident
sp_decl_ident
- ident_set_usual_case
ident_or_empty
ident_table_alias
ident_sysvar_name
+ ident_for_loop_index
%type <lex_string_with_metadata>
TEXT_STRING
@@ -1769,9 +1300,14 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
IDENT_QUOTED
IDENT_cli
ident_cli
+ ident_cli_set_usual_case
+
+%type <ident_sys_ptr>
+ ident_sys_alloc
%type <kwd>
keyword_data_type
+ keyword_cast_type
keyword_ident
keyword_label
keyword_set_special_case
@@ -1785,6 +1321,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
keyword_sysvar_type
keyword_table_alias
keyword_verb_clause
+ charset
+ reserved_keyword_udt
+ reserved_keyword_udt_not_param_type
+ non_reserved_keyword_udt
%type <table>
table_ident table_ident_nodb references xid
@@ -1799,7 +1339,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
wild_and_where
%type <const_simple_string>
- field_length opt_field_length opt_field_length_default_1
+ field_length opt_field_length
opt_compression_method
%type <string>
@@ -1807,6 +1347,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <type_handler> int_type real_type
+%type <sp_handler> sp_handler
+
%type <Lex_field_type> type_with_opt_collate field_type
field_type_numeric
field_type_string
@@ -1817,9 +1359,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <Lex_dyncol_type> opt_dyncol_type dyncol_type
numeric_dyncol_type temporal_dyncol_type string_dyncol_type
-%type <create_field> field_spec column_def
+%type <column_list_privilege>
+ column_list_privilege
-%type <geom_type> spatial_type
+%type <create_field> field_spec column_def
%type <num>
order_dir lock_option
@@ -1856,12 +1399,28 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <m_fk_option>
delete_option
+%type <privilege>
+ column_privilege
+ object_privilege
+ opt_grant_options
+ opt_grant_option
+ grant_option_list
+ grant_option
+
+%type <lex_grant>
+ object_privilege_list
+ grant_privileges
+
+%type <lex_grant_ident>
+ grant_ident
+
%type <ulong_num>
ulong_num real_ulong_num merge_insert_types
- ws_nweights opt_versioning_interval_start
+ ws_nweights
ws_level_flag_desc ws_level_flag_reverse ws_level_flags
opt_ws_levels ws_level_list ws_level_list_item ws_level_number
ws_level_range ws_level_list_or_range bool
+ field_options last_field_options
%type <ulonglong_number>
ulonglong_num real_ulonglong_num size_number
@@ -1873,6 +1432,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <lock_type>
replace_lock_option opt_low_priority insert_lock_option load_data_lock
+ insert_replace_option
%type <item>
literal insert_ident order_ident temporal_literal
@@ -1883,7 +1443,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
primary_expr string_factor_expr mysql_concatenation_expr
select_sublist_qualified_asterisk
expr_or_default set_expr_or_default
- geometry_function signed_literal expr_or_literal
+ signed_literal expr_or_literal
opt_escape
sp_opt_default
simple_ident_nospvar
@@ -1904,7 +1464,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
signal_allowed_expr
simple_target_specification
condition_number
- reset_lex_expr
+ opt_versioning_interval_start
%type <item_param> param_marker
@@ -1924,6 +1484,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
sp_cursor_stmt_lex
sp_cursor_stmt
+%type <expr_lex>
+ expr_lex
+
%type <assignment_lex>
assignment_source_lex
assignment_source_expr
@@ -2038,9 +1601,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <select_order> opt_order_clause order_clause order_list
%type <NONE>
+ directly_executable_statement
analyze_stmt_command backup backup_statements
- query verb_clause create change select select_into
- do drop insert replace insert2
+ query verb_clause create create_routine change select select_into
+ do drop drop_routine insert replace insert_start stmt_end
insert_values update delete truncate rename compound_statement
show describe load alter optimize keycache preload flush
reset purge begin_stmt_mariadb commit rollback savepoint release
@@ -2050,7 +1614,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
opt_persistent_stat_clause persistent_stat_spec
persistent_column_stat_spec persistent_index_stat_spec
table_column_list table_index_list table_index_name
- check start checksum
+ check start checksum opt_returning
field_list field_list_item kill key_def constraint_def
keycache_list keycache_list_or_parts assign_to_keycache
assign_to_keycache_parts
@@ -2061,7 +1625,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
procedure_list procedure_list2 procedure_item
field_def handler opt_generated_always
opt_ignore opt_column opt_restrict
- grant revoke set lock unlock string_list field_options
+ grant revoke set lock unlock string_list
opt_binary table_lock_list table_lock
ref_list opt_match_clause opt_on_update_delete use
opt_delete_options opt_delete_option varchar nchar nvarchar
@@ -2069,9 +1633,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
attribute attribute_list
compressed_deprecated_data_type_attribute
compressed_deprecated_column_attribute
- column_list column_list_id
- opt_column_list grant_privileges grant_ident grant_list grant_option
- object_privilege object_privilege_list user_list user_and_role_list
+ grant_list
+ user_list user_and_role_list
rename_list table_or_tables
clear_privileges flush_options flush_option
opt_flush_lock flush_lock flush_options_list
@@ -2080,7 +1643,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
table_to_table_list table_to_table opt_table_list opt_as
handler_rkey_function handler_read_or_scan
single_multi table_wild_list table_wild_one opt_wild
- opt_and charset
+ opt_and
select_var_list select_var_list_init help
opt_extended_describe shutdown
opt_format_json
@@ -2089,7 +1652,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
view_list_opt view_list view_select
- trigger_tail sp_tail event_tail
+ trigger_tail event_tail
install uninstall partition_entry binlog_base64_event
normal_key_options normal_key_opts all_key_opt
spatial_key_options fulltext_key_options normal_key_opt
@@ -2109,23 +1672,24 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
opt_delete_gtid_domain
asrow_attribute
opt_constraint_no_id
-END_OF_INPUT
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
+%type <NONE> sp_if_then_statements sp_case_then_statements
%type <NONE> sp_proc_stmt_statement sp_proc_stmt_return
- sp_proc_stmt_in_returns_clause
%type <NONE> sp_proc_stmt_compound_ok
%type <NONE> sp_proc_stmt_if
%type <NONE> sp_labeled_control sp_unlabeled_control
-%type <NONE> sp_labeled_block sp_unlabeled_block sp_unlabeled_block_not_atomic
+%type <NONE> sp_labeled_block sp_unlabeled_block
%type <NONE> sp_proc_stmt_continue_oracle
%type <NONE> sp_proc_stmt_exit_oracle
%type <NONE> sp_proc_stmt_leave
%type <NONE> sp_proc_stmt_iterate
%type <NONE> sp_proc_stmt_goto_oracle
+%type <NONE> sp_proc_stmt_with_cursor
%type <NONE> sp_proc_stmt_open sp_proc_stmt_fetch sp_proc_stmt_close
%type <NONE> case_stmt_specification
%type <NONE> loop_body while_body repeat_body
+%type <NONE> for_loop_statements
%type <num> view_algorithm view_check_option
%type <view_suid> view_suid opt_view_suid
@@ -2137,15 +1701,14 @@ END_OF_INPUT
%type <num> sp_decl_idents sp_decl_idents_init_vars
%type <num> sp_handler_type sp_hcond_list
%type <spcondvalue> sp_cond sp_hcond sqlstate signal_value opt_signal_value
-%type <spblock> sp_decl_handler
-%type <spblock> sp_decls sp_decl sp_decl_body sp_decl_variable_list
%type <spname> sp_name
%type <spvar> sp_param_name sp_param_name_and_type
+%type <spvar> sp_param_name_and_type_anchored
%type <for_loop> sp_for_loop_index_and_bounds
%type <for_loop_bounds> sp_for_loop_bounds
%type <trim> trim_operands
%type <num> opt_sp_for_loop_direction
-%type <spvar_mode> sp_opt_inout
+%type <spvar_mode> sp_parameter_type
%type <index_hint> index_hint_type
%type <num> index_hint_clause normal_join inner_join
%type <filetype> data_or_xml
@@ -2180,20 +1743,72 @@ END_OF_INPUT
'-' '+' '*' '/' '%' '(' ')'
',' '!' '{' '}' '&' '|'
-%type <NONE>
- AND_SYM OR_SYM BETWEEN_SYM CASE_SYM
- THEN_SYM WHEN_SYM DIV_SYM MOD_SYM OR2_SYM AND_AND_SYM DELETE_SYM
- MYSQL_CONCAT_SYM ORACLE_CONCAT_SYM
-
%type <with_clause> with_clause
%type <lex_str_ptr> query_name
-%type <lex_str_list> opt_with_column_list
+%type <ident_sys_list>
+ comma_separated_ident_list
+ opt_with_column_list
+ with_column_list
+ opt_cycle
%type <vers_range_unit> opt_history_unit
%type <vers_history_point> history_point
%type <vers_column_versioning> with_or_without_system
+
+/* Start SQL_MODE_DEFAULT_SPECIFIC */
+%type <NONE> sp_tail_standalone
+%type <NONE> sp_unlabeled_block_not_atomic
+%type <NONE> sp_proc_stmt_in_returns_clause
+%type <lex_str> sp_label
+%type <spblock> sp_decl_handler
+%type <spblock> sp_decls
+%type <spblock> sp_decl
+%type <spblock> sp_decl_body
+%type <spblock> sp_decl_variable_list
+%type <spblock> sp_decl_variable_list_anchored
+%type <kwd> reserved_keyword_udt_param_type
+/* End SQL_MODE_DEFAULT_SPECIFIC */
+
+
+/* Start SQL_MODE_ORACLE_SPECIFIC
+%type <NONE> set_assign
+%type <spvar_mode> sp_opt_inout
+%type <NONE> sp_tail_standalone
+%type <NONE> sp_labelable_stmt
+%type <simple_string> remember_end_opt
+%type <lex_str> opt_package_routine_end_name
+%type <lex_str> label_declaration_oracle
+%type <lex_str> labels_declaration_oracle
+%type <kwd> keyword_directly_assignable
+%type <ident_sys> ident_directly_assignable
+%type <ident_cli> ident_cli_directly_assignable
+%type <spname> opt_sp_name
+%type <spblock> sp_decl_body_list
+%type <spblock> opt_sp_decl_body_list
+%type <spblock> sp_decl_variable_list
+%type <spblock> sp_decl_variable_list_anchored
+%type <spblock> sp_decl_non_handler
+%type <spblock> sp_decl_non_handler_list
+%type <spblock> sp_decl_handler
+%type <spblock> sp_decl_handler_list
+%type <spblock> opt_sp_decl_handler_list
+%type <spblock> package_implementation_routine_definition
+%type <spblock> package_implementation_item_declaration
+%type <spblock> package_implementation_declare_section
+%type <spblock> package_implementation_declare_section_list1
+%type <spblock> package_implementation_declare_section_list2
+%type <spblock_handlers> sp_block_statements_and_exceptions
+%type <spblock_handlers> package_implementation_executable_section
+%type <sp_instr_addr> sp_instr_addr
+%type <num> opt_exception_clause exception_handlers
+%type <lex> remember_lex
+%type <lex> package_routine_lex
+%type <lex> package_specification_function
+%type <lex> package_specification_procedure
+End SQL_MODE_ORACLE_SPECIFIC */
+
%%
@@ -2228,7 +1843,7 @@ query:
thd->lex->sql_command= SQLCOM_EMPTY_QUERY;
YYLIP->found_semicolon= NULL;
}
- | verb_clause
+ | directly_executable_statement
{
Lex_input_stream *lip = YYLIP;
@@ -2253,7 +1868,7 @@ query:
}
';'
opt_end_of_input
- | verb_clause END_OF_INPUT
+ | directly_executable_statement END_OF_INPUT
{
/* Single query, not terminated. */
YYLIP->found_semicolon= NULL;
@@ -2265,14 +1880,14 @@ opt_end_of_input:
| END_OF_INPUT
;
-verb_clause:
+directly_executable_statement:
statement
| begin_stmt_mariadb
| compound_statement
;
/* Verb clauses, except begin and compound_statement */
-statement:
+verb_clause:
alter
| analyze
| analyze_stmt_command
@@ -2805,6 +2420,7 @@ create:
| create_or_replace DATABASE opt_if_not_exists ident
{
Lex->create_info.default_table_charset= NULL;
+ Lex->create_info.schema_comment= NULL;
Lex->create_info.used_fields= 0;
if (Lex->main_select_push())
MYSQL_YYABORT;
@@ -2853,15 +2469,6 @@ create:
{
Lex->pop_select(); //main select
}
- | create_or_replace definer_opt PROCEDURE_SYM opt_if_not_exists
- {
- if (Lex->stmt_create_procedure_start($1 | $4))
- MYSQL_YYABORT;
- }
- sp_tail
- {
- Lex->stmt_create_routine_finalize();
- }
| create_or_replace definer_opt EVENT_SYM
{
if (Lex->main_select_push())
@@ -2872,37 +2479,6 @@ create:
{
Lex->pop_select(); //main select
}
- | create_or_replace definer opt_aggregate FUNCTION_SYM opt_if_not_exists
- sp_name '('
- {
- if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6))
- MYSQL_YYABORT;
- }
- sp_fdparam_list ')'
- sf_return_type
- sf_c_chistics_and_body
- {
- Lex->stmt_create_routine_finalize();
- }
- | create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists
- sp_name '('
- {
- if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6))
- MYSQL_YYABORT;
- }
- sp_fdparam_list ')'
- sf_return_type
- sf_c_chistics_and_body
- {
- Lex->stmt_create_routine_finalize();
- }
- | create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists
- ident RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
- {
- if (Lex->stmt_create_udf_function($1 | $5, $3, $6,
- (Item_result) $8, $10))
- MYSQL_YYABORT;
- }
| create_or_replace USER_SYM opt_if_not_exists clear_privileges
grant_list opt_require_clause opt_resource_options opt_account_locking opt_password_expiration
{
@@ -2928,6 +2504,7 @@ create:
| create_or_replace { Lex->set_command(SQLCOM_CREATE_SERVER, $1); }
server_def
{ }
+ | create_routine
;
opt_sequence:
@@ -3267,9 +2844,6 @@ clear_privileges:
{
LEX *lex=Lex;
lex->users_list.empty();
- lex->columns.empty();
- lex->grant= lex->grant_tot_col= 0;
- lex->all_privileges= 0;
lex->first_select_lex()->db= null_clex_str;
lex->account_options.reset();
}
@@ -3280,6 +2854,15 @@ opt_aggregate:
| AGGREGATE_SYM { $$= GROUP_AGGREGATE; }
;
+
+sp_handler:
+ FUNCTION_SYM { $$= &sp_handler_function; }
+ | PROCEDURE_SYM { $$= &sp_handler_procedure; }
+ | PACKAGE_ORACLE_SYM { $$= &sp_handler_package_spec; }
+ | PACKAGE_ORACLE_SYM BODY_ORACLE_SYM { $$= &sp_handler_package_body; }
+ ;
+
+
sp_name:
ident '.' ident
{
@@ -3396,30 +2979,7 @@ sp_param_name:
sp_param_name_and_type:
sp_param_name type_with_opt_collate
{
- if (unlikely(Lex->sp_param_fill_definition($$= $1)))
- MYSQL_YYABORT;
- }
- | sp_param_name TYPE_SYM OF_SYM ident '.' ident
- {
- if (unlikely(Lex->sphead->spvar_fill_type_reference(thd,
- $$= $1, $4,
- $6)))
- MYSQL_YYABORT;
- }
- | sp_param_name TYPE_SYM OF_SYM ident '.' ident '.' ident
- {
- if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $$= $1,
- $4, $6, $8)))
- MYSQL_YYABORT;
- }
- | sp_param_name ROW_SYM TYPE_SYM OF_SYM ident
- {
- if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $5)))
- MYSQL_YYABORT;
- }
- | sp_param_name ROW_SYM TYPE_SYM OF_SYM ident '.' ident
- {
- if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $5, $7)))
+ if (unlikely(Lex->sp_param_fill_definition($$= $1, $2)))
MYSQL_YYABORT;
}
| sp_param_name ROW_SYM row_type_body
@@ -3427,6 +2987,7 @@ sp_param_name_and_type:
if (unlikely(Lex->sphead->spvar_fill_row(thd, $$= $1, $3)))
MYSQL_YYABORT;
}
+ | sp_param_name_and_type_anchored
;
/* Stored PROCEDURE parameter declaration list */
@@ -3440,13 +3001,8 @@ sp_pdparams:
| sp_pdparam
;
-sp_pdparam:
- sp_opt_inout sp_param_name_and_type { $2->mode=$1; }
- ;
-
-sp_opt_inout:
- /* Empty */ { $$= sp_variable::MODE_IN; }
- | IN_SYM { $$= sp_variable::MODE_IN; }
+sp_parameter_type:
+ IN_SYM { $$= sp_variable::MODE_IN; }
| OUT_SYM { $$= sp_variable::MODE_OUT; }
| INOUT_SYM { $$= sp_variable::MODE_INOUT; }
;
@@ -3463,6 +3019,10 @@ sp_parenthesized_pdparam_list:
}
;
+sp_parenthesized_fdparam_list:
+ '(' sp_fdparam_list ')'
+ ;
+
sp_proc_stmts:
/* Empty */ {}
| sp_proc_stmts sp_proc_stmt ';'
@@ -3473,26 +3033,6 @@ sp_proc_stmts1:
| sp_proc_stmts1 sp_proc_stmt ';'
;
-sp_decls:
- /* Empty */
- {
- $$.init();
- }
- | sp_decls sp_decl ';'
- {
- /* We check for declarations out of (standard) order this way
- because letting the grammar rules reflect it caused tricky
- shift/reduce conflicts with the wrong result. (And we get
- better error handling this way.) */
- if (unlikely(Lex->sp_declarations_join(&$$, $1, $2)))
- MYSQL_YYABORT;
- }
- ;
-
-sp_decl:
- DECLARE_MARIADB_SYM sp_decl_body { $$= $2; }
- ;
-
optionally_qualified_column_ident:
sp_decl_ident
@@ -3515,16 +3055,13 @@ optionally_qualified_column_ident:
}
;
-row_field_name:
- ident
- {
- if (!($$= Lex->row_field_name(thd, $1)))
- MYSQL_YYABORT;
- }
- ;
row_field_definition:
row_field_name type_with_opt_collate
+ {
+ Lex->last_field->set_attributes(thd, $2, Lex->charset,
+ COLUMN_DEFINITION_ROUTINE_LOCAL);
+ }
;
row_field_definition_list:
@@ -3554,27 +3091,15 @@ sp_decl_idents_init_vars:
sp_decl_variable_list:
sp_decl_idents_init_vars
type_with_opt_collate
- sp_opt_default
{
- if (unlikely(Lex->sp_variable_declarations_finalize(thd, $1,
- &Lex->last_field[0],
- $3)))
- MYSQL_YYABORT;
- $$.init_using_vars($1);
+ Lex->last_field->set_attributes(thd, $2, Lex->charset,
+ COLUMN_DEFINITION_ROUTINE_LOCAL);
}
- | sp_decl_idents_init_vars
- TYPE_SYM OF_SYM optionally_qualified_column_ident
sp_opt_default
{
- if (unlikely(Lex->sp_variable_declarations_with_ref_finalize(thd, $1, $4, $5)))
- MYSQL_YYABORT;
- $$.init_using_vars($1);
- }
- | sp_decl_idents_init_vars
- ROW_SYM TYPE_SYM OF_SYM optionally_qualified_column_ident
- sp_opt_default
- {
- if (unlikely(Lex->sp_variable_declarations_rowtype_finalize(thd, $1, $5, $6)))
+ if (unlikely(Lex->sp_variable_declarations_finalize(thd, $1,
+ &Lex->last_field[0],
+ $4)))
MYSQL_YYABORT;
$$.init_using_vars($1);
}
@@ -3586,33 +3111,7 @@ sp_decl_variable_list:
MYSQL_YYABORT;
$$.init_using_vars($1);
}
- ;
-
-sp_decl_body:
- sp_decl_variable_list
- | sp_decl_ident CONDITION_SYM FOR_SYM sp_cond
- {
- if (unlikely(Lex->spcont->declare_condition(thd, &$1, $4)))
- MYSQL_YYABORT;
- $$.vars= $$.hndlrs= $$.curs= 0;
- $$.conds= 1;
- }
- | sp_decl_handler
- | sp_decl_ident CURSOR_SYM
- {
- Lex->sp_block_init(thd);
- }
- opt_parenthesized_cursor_formal_parameters
- FOR_SYM sp_cursor_stmt
- {
- sp_pcontext *param_ctx= Lex->spcont;
- if (unlikely(Lex->sp_block_finalize(thd)))
- MYSQL_YYABORT;
- if (unlikely(Lex->sp_declare_cursor(thd, &$1, $6, param_ctx, true)))
- MYSQL_YYABORT;
- $$.vars= $$.conds= $$.hndlrs= 0;
- $$.curs= 1;
- }
+ | sp_decl_variable_list_anchored
;
sp_decl_handler:
@@ -3790,18 +3289,8 @@ signal_stmt:
signal_value:
ident
{
- LEX *lex= Lex;
- sp_condition_value *cond;
-
- /* SIGNAL foo cannot be used outside of stored programs */
- if (unlikely(lex->spcont == NULL))
- my_yyabort_error((ER_SP_COND_MISMATCH, MYF(0), $1.str));
- cond= lex->spcont->find_declared_or_predefined_condition(thd, &$1);
- if (unlikely(cond == NULL))
- my_yyabort_error((ER_SP_COND_MISMATCH, MYF(0), $1.str));
- if (unlikely(cond->type != sp_condition_value::SQLSTATE))
- my_yyabort_error((ER_SIGNAL_BAD_CONDITION_TYPE, MYF(0)));
- $$= cond;
+ if (!($$= Lex->stmt_signal_value($1)))
+ MYSQL_YYABORT;
}
| sqlstate
{ $$= $1; }
@@ -4092,48 +3581,6 @@ sp_decl_idents:
}
;
-sp_opt_default:
- /* Empty */ { $$ = NULL; }
- | DEFAULT expr { $$ = $2; }
- ;
-
-/*
- ps_proc_stmt_in_returns_clause is a statement that is allowed
- in the RETURNS clause of a stored function definition directly,
- without the BEGIN..END block.
- It should not include any syntax structures starting with '(', to avoid
- shift/reduce conflicts with the rule "field_type" and its sub-rules
- that scan an optional length, like CHAR(1) or YEAR(4).
- See MDEV-9166.
-*/
-sp_proc_stmt_in_returns_clause:
- sp_proc_stmt_return
- | sp_labeled_block
- | sp_unlabeled_block
- | sp_labeled_control
- | sp_proc_stmt_compound_ok
- ;
-
-sp_proc_stmt:
- sp_proc_stmt_in_returns_clause
- | sp_proc_stmt_statement
- | sp_proc_stmt_continue_oracle
- | sp_proc_stmt_exit_oracle
- | sp_proc_stmt_leave
- | sp_proc_stmt_iterate
- | sp_proc_stmt_goto_oracle
- | sp_proc_stmt_open
- | sp_proc_stmt_fetch
- | sp_proc_stmt_close
- ;
-
-sp_proc_stmt_compound_ok:
- sp_proc_stmt_if
- | case_stmt_specification
- | sp_unlabeled_block_not_atomic
- | sp_unlabeled_control
- ;
-
sp_proc_stmt_if:
IF_SYM
{
@@ -4144,7 +3591,7 @@ sp_proc_stmt_if:
sp_if END IF_SYM
{ Lex->sphead->do_cont_backpatch(); }
;
-
+
sp_proc_stmt_statement:
{
LEX *lex= thd->lex;
@@ -4153,7 +3600,7 @@ sp_proc_stmt_statement:
lex->sphead->reset_lex(thd);
lex->sphead->m_tmp_query= lip->get_tok_start();
}
- statement
+ sp_statement
{
if (Lex->sp_proc_stmt_statement_finalize(thd, yychar == YYEMPTY) ||
Lex->sphead->restore_lex(thd))
@@ -4168,15 +3615,11 @@ RETURN_ALLMODES_SYM:
;
sp_proc_stmt_return:
- RETURN_ALLMODES_SYM
- { Lex->sphead->reset_lex(thd); }
- expr
+ RETURN_ALLMODES_SYM expr_lex
{
- LEX *lex= Lex;
- sp_head *sp= lex->sphead;
- if (unlikely(sp->m_handler->add_instr_freturn(thd, sp, lex->spcont,
- $3, lex)) ||
- unlikely(sp->restore_lex(thd)))
+ sp_head *sp= $2->sphead;
+ if (unlikely(sp->m_handler->add_instr_freturn(thd, sp, $2->spcont,
+ $2->get_item(), $2)))
MYSQL_YYABORT;
}
| RETURN_ORACLE_SYM
@@ -4189,10 +3632,6 @@ sp_proc_stmt_return:
}
;
-reset_lex_expr:
- { Lex->sphead->reset_lex(thd); } expr { $$= $2; }
- ;
-
sp_proc_stmt_exit_oracle:
EXIT_ORACLE_SYM
{
@@ -4204,16 +3643,14 @@ sp_proc_stmt_exit_oracle:
if (unlikely(Lex->sp_exit_statement(thd, &$2, NULL)))
MYSQL_YYABORT;
}
- | EXIT_ORACLE_SYM WHEN_SYM reset_lex_expr
+ | EXIT_ORACLE_SYM WHEN_SYM expr_lex
{
- if (unlikely(Lex->sp_exit_statement(thd, $3)) ||
- unlikely(Lex->sphead->restore_lex(thd)))
+ if (unlikely($3->sp_exit_statement(thd, $3->get_item())))
MYSQL_YYABORT;
}
- | EXIT_ORACLE_SYM label_ident WHEN_SYM reset_lex_expr
+ | EXIT_ORACLE_SYM label_ident WHEN_SYM expr_lex
{
- if (unlikely(Lex->sp_exit_statement(thd, &$2, $4)) ||
- unlikely(Lex->sphead->restore_lex(thd)))
+ if (unlikely($4->sp_exit_statement(thd, &$2, $4->get_item())))
MYSQL_YYABORT;
}
;
@@ -4221,24 +3658,22 @@ sp_proc_stmt_exit_oracle:
sp_proc_stmt_continue_oracle:
CONTINUE_ORACLE_SYM
{
- if (unlikely(Lex->sp_continue_statement(thd, NULL)))
+ if (unlikely(Lex->sp_continue_statement(thd)))
MYSQL_YYABORT;
}
| CONTINUE_ORACLE_SYM label_ident
{
- if (unlikely(Lex->sp_continue_statement(thd, &$2, NULL)))
+ if (unlikely(Lex->sp_continue_statement(thd, &$2)))
MYSQL_YYABORT;
}
- | CONTINUE_ORACLE_SYM WHEN_SYM reset_lex_expr
+ | CONTINUE_ORACLE_SYM WHEN_SYM expr_lex
{
- if (unlikely(Lex->sp_continue_statement(thd, $3)) ||
- unlikely(Lex->sphead->restore_lex(thd)))
+ if (unlikely($3->sp_continue_when_statement(thd)))
MYSQL_YYABORT;
}
- | CONTINUE_ORACLE_SYM label_ident WHEN_SYM reset_lex_expr
+ | CONTINUE_ORACLE_SYM label_ident WHEN_SYM expr_lex
{
- if (unlikely(Lex->sp_continue_statement(thd, &$2, $4)) ||
- unlikely(Lex->sphead->restore_lex(thd)))
+ if (unlikely($4->sp_continue_when_statement(thd, &$2)))
MYSQL_YYABORT;
}
;
@@ -4268,6 +3703,26 @@ sp_proc_stmt_goto_oracle:
}
;
+
+expr_lex:
+ {
+ DBUG_ASSERT(Lex->sphead);
+ if (unlikely(!($<expr_lex>$= new (thd->mem_root)
+ sp_expr_lex(thd, thd->lex))))
+ MYSQL_YYABORT;
+ Lex->sphead->reset_lex(thd, $<expr_lex>$);
+ }
+ expr
+ {
+ $$= $<expr_lex>1;
+ $$->sp_lex_in_use= true;
+ $$->set_item($2);
+ if ($$->sphead->restore_lex(thd))
+ MYSQL_YYABORT;
+ }
+ ;
+
+
assignment_source_lex:
{
DBUG_ASSERT(Lex->sphead);
@@ -4332,6 +3787,12 @@ opt_parenthesized_cursor_actual_parameters:
| '(' cursor_actual_parameters ')' { $$= $2; }
;
+sp_proc_stmt_with_cursor:
+ sp_proc_stmt_open
+ | sp_proc_stmt_fetch
+ | sp_proc_stmt_close
+ ;
+
sp_proc_stmt_open:
OPEN_SYM ident opt_parenthesized_cursor_actual_parameters
{
@@ -4417,34 +3878,15 @@ sp_fetch_list:
;
sp_if:
- { Lex->sphead->reset_lex(thd); }
- expr THEN_SYM
+ expr_lex THEN_SYM
{
- LEX *lex= Lex;
- sp_head *sp= lex->sphead;
- sp_pcontext *ctx= lex->spcont;
- uint ip= sp->instructions();
- sp_instr_jump_if_not *i= new (thd->mem_root)
- sp_instr_jump_if_not(ip, ctx, $2, lex);
- if (unlikely(i == NULL) ||
- unlikely(sp->push_backpatch(thd, i, ctx->push_label(thd, &empty_clex_str, 0))) ||
- unlikely(sp->add_cont_backpatch(i)) ||
- unlikely(sp->add_instr(i)))
- MYSQL_YYABORT;
- if (unlikely(sp->restore_lex(thd)))
+ if (unlikely($1->sp_if_expr(thd)))
MYSQL_YYABORT;
}
- sp_proc_stmts1
+ sp_if_then_statements
{
- sp_head *sp= Lex->sphead;
- sp_pcontext *ctx= Lex->spcont;
- uint ip= sp->instructions();
- sp_instr_jump *i= new (thd->mem_root) sp_instr_jump(ip, ctx);
- if (unlikely(i == NULL) ||
- unlikely(sp->add_instr(i)))
+ if (unlikely($1->sp_if_after_statements(thd)))
MYSQL_YYABORT;
- sp->backpatch(ctx->pop_label());
- sp->push_backpatch(thd, i, ctx->push_label(thd, &empty_clex_str, 0));
}
sp_elseifs
{
@@ -4457,7 +3899,8 @@ sp_if:
sp_elseifs:
/* Empty */
| ELSEIF_MARIADB_SYM sp_if
- | ELSE sp_proc_stmts1
+ | ELSIF_ORACLE_SYM sp_if
+ | ELSE sp_if_then_statements
;
case_stmt_specification:
@@ -4531,13 +3974,9 @@ case_stmt_specification:
;
case_stmt_body:
- { Lex->sphead->reset_lex(thd); /* For expr $2 */ }
- expr
+ expr_lex
{
- if (unlikely(Lex->case_stmt_action_expr($2)))
- MYSQL_YYABORT;
-
- if (Lex->sphead->restore_lex(thd))
+ if (unlikely($1->case_stmt_action_expr()))
MYSQL_YYABORT;
}
simple_when_clause_list
@@ -4557,23 +3996,14 @@ searched_when_clause_list:
;
simple_when_clause:
- WHEN_SYM
- {
- Lex->sphead->reset_lex(thd); /* For expr $3 */
- }
- expr
+ WHEN_SYM expr_lex
{
/* Simple case: <caseval> = <whenval> */
-
- LEX *lex= Lex;
- if (unlikely(lex->case_stmt_action_when($3, true)))
- MYSQL_YYABORT;
- /* For expr $3 */
- if (unlikely(lex->sphead->restore_lex(thd)))
+ if (unlikely($2->case_stmt_action_when(true)))
MYSQL_YYABORT;
}
THEN_SYM
- sp_proc_stmts1
+ sp_case_then_statements
{
if (unlikely(Lex->case_stmt_action_then()))
MYSQL_YYABORT;
@@ -4581,21 +4011,13 @@ simple_when_clause:
;
searched_when_clause:
- WHEN_SYM
+ WHEN_SYM expr_lex
{
- Lex->sphead->reset_lex(thd); /* For expr $3 */
- }
- expr
- {
- LEX *lex= Lex;
- if (unlikely(lex->case_stmt_action_when($3, false)))
- MYSQL_YYABORT;
- /* For expr $3 */
- if (unlikely(lex->sphead->restore_lex(thd)))
+ if (unlikely($2->case_stmt_action_when(false)))
MYSQL_YYABORT;
}
THEN_SYM
- sp_proc_stmts1
+ sp_case_then_statements
{
if (unlikely(Lex->case_stmt_action_then()))
MYSQL_YYABORT;
@@ -4614,11 +4036,7 @@ else_clause_opt:
unlikely(sp->add_instr(i)))
MYSQL_YYABORT;
}
- | ELSE sp_proc_stmts1
- ;
-
-sp_label:
- label_ident ':' { $$= $1; }
+ | ELSE sp_case_then_statements
;
sp_opt_label:
@@ -4626,61 +4044,6 @@ sp_opt_label:
| label_ident { $$= $1; }
;
-sp_block_label:
- sp_label
- {
- if (unlikely(Lex->spcont->block_label_declare(&$1)))
- MYSQL_YYABORT;
- $$= $1;
- }
- ;
-
-sp_labeled_block:
- sp_block_label
- BEGIN_MARIADB_SYM
- {
- Lex->sp_block_init(thd, &$1);
- }
- sp_decls
- sp_proc_stmts
- END
- sp_opt_label
- {
- if (unlikely(Lex->sp_block_finalize(thd, $4, &$7)))
- MYSQL_YYABORT;
- }
- ;
-
-sp_unlabeled_block:
- BEGIN_MARIADB_SYM
- {
- Lex->sp_block_init(thd);
- }
- sp_decls
- sp_proc_stmts
- END
- {
- if (unlikely(Lex->sp_block_finalize(thd, $3)))
- MYSQL_YYABORT;
- }
- ;
-
-sp_unlabeled_block_not_atomic:
- BEGIN_MARIADB_SYM not ATOMIC_SYM /* TODO: BEGIN ATOMIC (not -> opt_not) */
- {
- if (unlikely(Lex->maybe_start_compound_statement(thd)))
- MYSQL_YYABORT;
- Lex->sp_block_init(thd);
- }
- sp_decls
- sp_proc_stmts
- END
- {
- if (unlikely(Lex->sp_block_finalize(thd, $5)))
- MYSQL_YYABORT;
- }
- ;
-
/* This adds one shift/reduce conflict */
opt_sp_for_loop_direction:
/* Empty */ { $$= 1; }
@@ -4688,7 +4051,7 @@ opt_sp_for_loop_direction:
;
sp_for_loop_index_and_bounds:
- ident sp_for_loop_bounds
+ ident_for_loop_index sp_for_loop_bounds
{
if (unlikely(Lex->sp_for_loop_declarations(thd, &$$, &$1, $2)))
MYSQL_YYABORT;
@@ -4730,39 +4093,11 @@ loop_body:
}
;
-while_body:
- expr DO_SYM
- {
- LEX *lex= Lex;
- if (unlikely(lex->sp_while_loop_expression(thd, $1)))
- MYSQL_YYABORT;
- if (lex->sphead->restore_lex(thd))
- MYSQL_YYABORT;
- }
- sp_proc_stmts1 END WHILE_SYM
- {
- if (unlikely(Lex->sp_while_loop_finalize(thd)))
- MYSQL_YYABORT;
- }
- ;
-
repeat_body:
- sp_proc_stmts1 UNTIL_SYM
- { Lex->sphead->reset_lex(thd); }
- expr END REPEAT_SYM
+ sp_proc_stmts1 UNTIL_SYM expr_lex END REPEAT_SYM
{
- LEX *lex= Lex;
- uint ip= lex->sphead->instructions();
- sp_label *lab= lex->spcont->last_label(); /* Jumping back */
- sp_instr_jump_if_not *i= new (thd->mem_root)
- sp_instr_jump_if_not(ip, lex->spcont, $4, lab->ip, lex);
- if (unlikely(i == NULL) ||
- unlikely(lex->sphead->add_instr(i)))
- MYSQL_YYABORT;
- if (lex->sphead->restore_lex(thd))
+ if ($3->sp_repeat_loop_finalize(thd))
MYSQL_YYABORT;
- /* We can shortcut the cont_backpatch here */
- i->m_cont_dest= ip+1;
}
;
@@ -4775,22 +4110,21 @@ pop_sp_loop_label:
;
sp_labeled_control:
- sp_label LOOP_SYM
+ sp_control_label LOOP_SYM
{
if (unlikely(Lex->sp_push_loop_label(thd, &$1)))
MYSQL_YYABORT;
}
loop_body pop_sp_loop_label
{ }
- | sp_label WHILE_SYM
+ | sp_control_label WHILE_SYM
{
if (unlikely(Lex->sp_push_loop_label(thd, &$1)))
MYSQL_YYABORT;
- Lex->sphead->reset_lex(thd);
}
while_body pop_sp_loop_label
{ }
- | sp_label FOR_SYM
+ | sp_control_label FOR_SYM
{
// See "The FOR LOOP statement" comments in sql_lex.cc
Lex->sp_block_init(thd); // The outer DECLARE..BEGIN..END block
@@ -4802,9 +4136,7 @@ sp_labeled_control:
if (unlikely(Lex->sp_for_loop_condition_test(thd, $4)))
MYSQL_YYABORT;
}
- DO_SYM
- sp_proc_stmts1
- END FOR_SYM
+ for_loop_statements
{
if (unlikely(Lex->sp_for_loop_finalize(thd, $4)))
MYSQL_YYABORT;
@@ -4814,7 +4146,7 @@ sp_labeled_control:
if (unlikely(Lex->sp_for_loop_outer_block_finalize(thd, $4)))
MYSQL_YYABORT;
}
- | sp_label REPEAT_SYM
+ | sp_control_label REPEAT_SYM
{
if (unlikely(Lex->sp_push_loop_label(thd, &$1)))
MYSQL_YYABORT;
@@ -4837,7 +4169,6 @@ sp_unlabeled_control:
{
if (unlikely(Lex->sp_push_loop_empty_label(thd)))
MYSQL_YYABORT;
- Lex->sphead->reset_lex(thd);
}
while_body
{
@@ -4857,9 +4188,7 @@ sp_unlabeled_control:
if (unlikely(Lex->sp_for_loop_condition_test(thd, $3)))
MYSQL_YYABORT;
}
- DO_SYM
- sp_proc_stmts1
- END FOR_SYM
+ for_loop_statements
{
if (unlikely(Lex->sp_for_loop_finalize(thd, $3)))
MYSQL_YYABORT;
@@ -5298,7 +4627,7 @@ opt_create_partitioning:
/*
This part of the parser is about handling of the partition information.
- It's first version was written by Mikael Ronstrm with lots of answers to
+ Its first version was written by Mikael Ronström with lots of answers to
questions provided by Antony Curtis.
The partition grammar can be called from three places.
@@ -5983,7 +5312,8 @@ 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(thd, $2, $3, $4)))
+ const char *table_name= Lex->create_last_non_select_table->table_name.str;
+ if (unlikely(part_info->vers_set_interval(thd, $2, $3, $4, table_name)))
MYSQL_YYABORT;
}
| LIMIT ulonglong_num
@@ -6003,17 +5333,11 @@ opt_versioning_rotation:
opt_versioning_interval_start:
/* empty */
{
- $$= thd->query_start();
+ $$= NULL;
}
- | STARTS_SYM ulong_num
+ | STARTS_SYM literal
{
- /* only allowed from mysql_unpack_partition() */
- if (unlikely(!Lex->part_info->table))
- {
- thd->parse_error(ER_SYNTAX_ERROR, $1.pos());
- MYSQL_YYABORT;
- }
- $$= (ulong)$2;
+ $$= $2;
}
;
@@ -6039,6 +5363,11 @@ create_database_options:
create_database_option:
default_collation {}
| default_charset {}
+ | COMMENT_SYM opt_equal TEXT_STRING_sys
+ {
+ Lex->create_info.schema_comment= thd->make_clex_string($3);
+ Lex->create_info.used_fields|= HA_CREATE_USED_COMMENT;
+ }
;
opt_if_not_exists_table_element:
@@ -6471,8 +5800,13 @@ field_list_item:
column_def:
field_spec
{ $$= $1; }
- | field_spec references
- { $$= $1; }
+ | field_spec opt_constraint references
+ {
+ if (unlikely(Lex->add_column_foreign_key(&($1->field_name), &$2,
+ $3, DDL_options())))
+ MYSQL_YYABORT;
+ $$= $1;
+ }
;
key_def:
@@ -6533,29 +5867,9 @@ key_def:
}
'(' key_list ')' references
{
- LEX *lex=Lex;
- Key *key= (new (thd->mem_root)
- Foreign_key($5.str ? &$5 : &$1,
- &lex->last_key->columns,
- &$10->db,
- &$10->table,
- &lex->ref_list,
- lex->fk_delete_opt,
- lex->fk_update_opt,
- lex->fk_match_option,
- $4));
- if (unlikely(key == NULL))
- MYSQL_YYABORT;
- /*
- handle_if_exists_options() expectes the two keys in this order:
- the Foreign_key, followed by its auto-generated Key.
- */
- lex->alter_info.key_list.push_back(key, thd->mem_root);
- lex->alter_info.key_list.push_back(Lex->last_key, thd->mem_root);
- lex->option_list= NULL;
-
- /* Only used for ALTER TABLE. Ignored otherwise. */
- lex->alter_info.flags|= ALTER_ADD_FOREIGN_KEY;
+ if (unlikely(Lex->add_table_foreign_key($5.str ? &$5 : &$1,
+ $1.str ? &$1 : &$5, $10, $4)))
+ MYSQL_YYABORT;
}
;
@@ -6649,11 +5963,15 @@ field_spec:
;
field_type_or_serial:
- field_type { Lex->last_field->set_attributes($1, Lex->charset); }
+ field_type
+ {
+ Lex->last_field->set_attributes(thd, $1, Lex->charset,
+ COLUMN_DEFINITION_TABLE_FIELD);
+ }
field_def
| SERIAL_SYM
{
- Lex->last_field->set_handler(&type_handler_longlong);
+ Lex->last_field->set_handler(&type_handler_ulonglong);
Lex->last_field->flags|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG
| UNSIGNED_FLAG | UNIQUE_KEY_FLAG;
}
@@ -6828,12 +6146,30 @@ field_type:
| field_type_string
| field_type_lob
| field_type_misc
+ | IDENT_sys float_options srid_option
+ {
+ if (Lex->set_field_type_udt(&$$, $1, $2))
+ MYSQL_YYABORT;
+ }
+ | reserved_keyword_udt float_options srid_option
+ {
+ if (Lex->set_field_type_udt(&$$, $1, $2))
+ MYSQL_YYABORT;
+ }
+ | non_reserved_keyword_udt float_options srid_option
+ {
+ if (Lex->set_field_type_udt(&$$, $1, $2))
+ MYSQL_YYABORT;
+ }
;
field_type_numeric:
- int_type opt_field_length field_options { $$.set($1, $2); }
- | real_type opt_precision field_options { $$.set($1, $2); }
- | FLOAT_SYM float_options field_options
+ int_type opt_field_length last_field_options
+ {
+ $$.set_handler_length_flags($1, $2, (uint32) $3);
+ }
+ | real_type opt_precision last_field_options { $$.set($1, $2); }
+ | FLOAT_SYM float_options last_field_options
{
$$.set(&type_handler_float, $2);
if ($2.length() && !$2.dec())
@@ -6849,30 +6185,30 @@ field_type_numeric:
$$.set(&type_handler_float);
}
}
- | BIT_SYM opt_field_length_default_1
+ | BIT_SYM opt_field_length
{
$$.set(&type_handler_bit, $2);
}
| BOOL_SYM
{
- $$.set(&type_handler_tiny, "1");
+ $$.set(&type_handler_stiny, "1");
}
| BOOLEAN_SYM
{
- $$.set(&type_handler_tiny, "1");
+ $$.set(&type_handler_stiny, "1");
}
- | DECIMAL_SYM float_options field_options
+ | DECIMAL_SYM float_options last_field_options
{ $$.set(&type_handler_newdecimal, $2);}
- | NUMBER_ORACLE_SYM float_options field_options
+ | NUMBER_ORACLE_SYM float_options last_field_options
{
if ($2.length() != 0)
$$.set(&type_handler_newdecimal, $2);
else
$$.set(&type_handler_double);
}
- | NUMERIC_SYM float_options field_options
+ | NUMERIC_SYM float_options last_field_options
{ $$.set(&type_handler_newdecimal, $2);}
- | FIXED_SYM float_options field_options
+ | FIXED_SYM float_options last_field_options
{ $$.set(&type_handler_newdecimal, $2);}
;
@@ -6885,39 +6221,39 @@ opt_binary_and_compression:
;
field_type_string:
- char opt_field_length_default_1 opt_binary
+ char opt_field_length opt_binary
{
$$.set(&type_handler_string, $2);
}
- | nchar opt_field_length_default_1 opt_bin_mod
+ | nchar opt_field_length opt_bin_mod
{
$$.set(&type_handler_string, $2);
bincmp_collation(national_charset_info, $3);
}
- | BINARY opt_field_length_default_1
+ | BINARY opt_field_length
{
Lex->charset=&my_charset_bin;
$$.set(&type_handler_string, $2);
}
- | varchar field_length opt_binary_and_compression
+ | varchar opt_field_length opt_binary_and_compression
{
$$.set(&type_handler_varchar, $2);
}
- | VARCHAR2_ORACLE_SYM field_length opt_binary_and_compression
+ | VARCHAR2_ORACLE_SYM opt_field_length opt_binary_and_compression
{
$$.set(&type_handler_varchar, $2);
}
- | nvarchar field_length opt_compressed opt_bin_mod
+ | nvarchar opt_field_length opt_compressed opt_bin_mod
{
$$.set(&type_handler_varchar, $2);
bincmp_collation(national_charset_info, $4);
}
- | VARBINARY field_length opt_compressed
+ | VARBINARY opt_field_length opt_compressed
{
Lex->charset=&my_charset_bin;
$$.set(&type_handler_varchar, $2);
}
- | RAW_ORACLE_SYM field_length opt_compressed
+ | RAW_ORACLE_SYM opt_field_length opt_compressed
{
Lex->charset= &my_charset_bin;
$$.set(&type_handler_varchar, $2);
@@ -6925,7 +6261,7 @@ field_type_string:
;
field_type_temporal:
- YEAR_SYM opt_field_length field_options
+ YEAR_SYM opt_field_length last_field_options
{
if ($2)
{
@@ -7003,17 +6339,6 @@ field_type_lob:
Lex->charset=&my_charset_bin;
$$.set(&type_handler_long_blob);
}
- | spatial_type float_options srid_option
- {
-#ifdef HAVE_SPATIAL
- Lex->charset=&my_charset_bin;
- Lex->last_field->geom_type= $1;
- $$.set(&type_handler_geometry, $2);
-#else
- my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name,
- sym_group_geom.needed_define));
-#endif
- }
| MEDIUMBLOB opt_compressed
{
Lex->charset=&my_charset_bin;
@@ -7057,17 +6382,6 @@ field_type_misc:
{ $$.set(&type_handler_set); }
;
-spatial_type:
- GEOMETRY_SYM { $$= Field::GEOM_GEOMETRY; }
- | GEOMETRYCOLLECTION { $$= Field::GEOM_GEOMETRYCOLLECTION; }
- | POINT_SYM { $$= Field::GEOM_POINT; }
- | MULTIPOINT { $$= Field::GEOM_MULTIPOINT; }
- | LINESTRING { $$= Field::GEOM_LINESTRING; }
- | MULTILINESTRING { $$= Field::GEOM_MULTILINESTRING; }
- | POLYGON { $$= Field::GEOM_POLYGON; }
- | MULTIPOLYGON { $$= Field::GEOM_MULTIPOLYGON; }
- ;
-
char:
CHAR_SYM {}
;
@@ -7091,11 +6405,11 @@ nvarchar:
;
int_type:
- INT_SYM { $$= &type_handler_long; }
- | TINYINT { $$= &type_handler_tiny; }
- | SMALLINT { $$= &type_handler_short; }
- | MEDIUMINT { $$= &type_handler_int24; }
- | BIGINT { $$= &type_handler_longlong; }
+ INT_SYM { $$= &type_handler_slong; }
+ | TINYINT { $$= &type_handler_stiny; }
+ | SMALLINT { $$= &type_handler_sshort; }
+ | MEDIUMINT { $$= &type_handler_sint24; }
+ | BIGINT { $$= &type_handler_slonglong; }
;
real_type:
@@ -7130,12 +6444,16 @@ precision:
;
field_options:
- /* empty */ {}
- | SIGNED_SYM {}
- | UNSIGNED { Lex->last_field->flags|= UNSIGNED_FLAG;}
- | ZEROFILL { Lex->last_field->flags|= UNSIGNED_FLAG | ZEROFILL_FLAG; }
- | UNSIGNED ZEROFILL { Lex->last_field->flags|= UNSIGNED_FLAG | ZEROFILL_FLAG; }
- | ZEROFILL UNSIGNED { Lex->last_field->flags|= UNSIGNED_FLAG | ZEROFILL_FLAG; }
+ /* empty */ { $$= 0; }
+ | SIGNED_SYM { $$= 0; }
+ | UNSIGNED { $$= UNSIGNED_FLAG; }
+ | ZEROFILL { $$= UNSIGNED_FLAG | ZEROFILL_FLAG; }
+ | UNSIGNED ZEROFILL { $$= UNSIGNED_FLAG | ZEROFILL_FLAG; }
+ | ZEROFILL UNSIGNED { $$= UNSIGNED_FLAG | ZEROFILL_FLAG; }
+ ;
+
+last_field_options:
+ field_options { Lex->last_field->flags|= ($$= $1); }
;
field_length:
@@ -7150,11 +6468,6 @@ opt_field_length:
| field_length { $$= $1; }
;
-opt_field_length_default_1:
- /* empty */ { $$= (char*) "1"; }
- | field_length { $$= $1; }
- ;
-
opt_precision:
/* empty */ { $$.set(0, 0); }
| precision { $$= $1; }
@@ -7312,13 +6625,12 @@ type_with_opt_collate:
if (unlikely(!(Lex->charset= merge_charset_and_collation(Lex->charset, $2))))
MYSQL_YYABORT;
}
- Lex->last_field->set_attributes($1, Lex->charset);
}
;
charset:
- CHAR_SYM SET {}
- | CHARSET {}
+ CHAR_SYM SET { $$= $1; }
+ | CHARSET { $$= $1; }
;
charset_name:
@@ -7811,6 +7123,7 @@ alter:
| ALTER DATABASE ident_or_empty
{
Lex->create_info.default_table_charset= NULL;
+ Lex->create_info.schema_comment= NULL;
Lex->create_info.used_fields= 0;
if (Lex->main_select_push())
MYSQL_YYABORT;
@@ -7825,6 +7138,22 @@ alter:
MYSQL_YYABORT;
Lex->pop_select(); //main select
}
+ | ALTER DATABASE COMMENT_SYM opt_equal TEXT_STRING_sys
+ {
+ Lex->create_info.default_table_charset= NULL;
+ Lex->create_info.used_fields= 0;
+ Lex->create_info.schema_comment= thd->make_clex_string($5);
+ Lex->create_info.used_fields|= HA_CREATE_USED_COMMENT;
+ }
+ opt_create_database_options
+ {
+ LEX *lex=Lex;
+ lex->sql_command=SQLCOM_ALTER_DB;
+ lex->name= Lex_ident_sys();
+ if (lex->name.str == NULL &&
+ unlikely(lex->copy_db_to(&lex->name)))
+ MYSQL_YYABORT;
+ }
| ALTER DATABASE ident UPGRADE_SYM DATA_SYM DIRECTORY_SYM NAME_SYM
{
LEX *lex= Lex;
@@ -7835,44 +7164,18 @@ alter:
}
| ALTER PROCEDURE_SYM sp_name
{
- LEX *lex= Lex;
-
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE"));
- if (Lex->main_select_push())
+ if (Lex->stmt_alter_procedure_start($3))
MYSQL_YYABORT;
- lex->sp_chistics.init();
}
sp_a_chistics
- {
- LEX *lex=Lex;
-
- lex->sql_command= SQLCOM_ALTER_PROCEDURE;
- lex->spname= $3;
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
+ stmt_end {}
| ALTER FUNCTION_SYM sp_name
{
- LEX *lex= Lex;
-
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"));
- if (Lex->main_select_push())
+ if (Lex->stmt_alter_function_start($3))
MYSQL_YYABORT;
- lex->sp_chistics.init();
}
sp_a_chistics
- {
- LEX *lex=Lex;
-
- lex->sql_command= SQLCOM_ALTER_FUNCTION;
- lex->spname= $3;
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
+ stmt_end {}
| ALTER view_algorithm definer_opt opt_view_suid VIEW_SYM table_ident
{
if (Lex->main_select_push())
@@ -7880,12 +7183,7 @@ alter:
if (Lex->add_alter_view(thd, $2, $4, $6))
MYSQL_YYABORT;
}
- view_list_opt AS view_select
- {
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
+ view_list_opt AS view_select stmt_end {}
| ALTER definer_opt opt_view_suid VIEW_SYM table_ident
/*
We have two separate rules for ALTER VIEW rather that
@@ -7898,12 +7196,7 @@ alter:
if (Lex->add_alter_view(thd, VIEW_ALGORITHM_INHERIT, $3, $5))
MYSQL_YYABORT;
}
- view_list_opt AS view_select
- {
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
+ view_list_opt AS view_select stmt_end {}
| ALTER definer_opt remember_name EVENT_SYM sp_name
{
if (Lex->main_select_push())
@@ -8004,10 +7297,7 @@ alter:
Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_sequence($3);
if (unlikely(Lex->m_sql_cmd == NULL))
MYSQL_YYABORT;
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
+ } stmt_end {}
;
opt_account_locking:
@@ -8069,7 +7359,8 @@ opt_ev_sql_stmt:
;
ident_or_empty:
- /* empty */ { $$= Lex_ident_sys(); }
+ /* empty */
+ %prec PREC_BELOW_IDENTIFIER_OPT_SPECIAL_CASE { $$= Lex_ident_sys(); }
| ident
;
@@ -8417,13 +7708,12 @@ alter_list_item:
}
| ALTER opt_column opt_if_exists_table_element field_ident SET DEFAULT column_default_expr
{
- if (unlikely(Lex->add_alter_list($4.str, $7, $3)))
+ if (unlikely(Lex->add_alter_list($4, $7, $3)))
MYSQL_YYABORT;
}
| ALTER opt_column opt_if_exists_table_element field_ident DROP DEFAULT
{
- if (unlikely(Lex->add_alter_list($4.str, (Virtual_column_info*) 0,
- $3)))
+ if (unlikely(Lex->add_alter_list($4, (Virtual_column_info*) 0, $3)))
MYSQL_YYABORT;
}
| RENAME opt_to table_ident
@@ -8440,6 +7730,21 @@ alter_list_item:
lex->name= $3->table;
lex->alter_info.flags|= ALTER_RENAME;
}
+ | RENAME COLUMN_SYM ident TO_SYM ident
+ {
+ if (unlikely(Lex->add_alter_list($3, $5)))
+ MYSQL_YYABORT;
+ }
+ | RENAME key_or_index field_ident TO_SYM field_ident
+ {
+ LEX *lex=Lex;
+ Alter_rename_key *ak= new (thd->mem_root)
+ Alter_rename_key($3, $5);
+ if (ak == NULL)
+ MYSQL_YYABORT;
+ lex->alter_info.alter_rename_key_list.push_back(ak);
+ lex->alter_info.flags|= ALTER_RENAME_INDEX;
+ }
| CONVERT_SYM TO_SYM charset charset_name_or_default opt_collate
{
if (!$4)
@@ -9265,8 +8570,7 @@ query_specification_start:
{
SELECT_LEX *sel;
LEX *lex= Lex;
- if (!(sel= lex->alloc_select(TRUE)) ||
- lex->push_select(sel))
+ if (!(sel= lex->alloc_select(TRUE)) || lex->push_select(sel))
MYSQL_YYABORT;
sel->init_select();
sel->braces= FALSE;
@@ -9456,8 +8760,7 @@ query_expression_body:
{
if (!($$= Lex->add_primary_to_query_expression_body($1, $4,
$2.unit_type,
- $2.distinct,
- FALSE)))
+ $2.distinct)))
MYSQL_YYABORT;
}
| query_expression_body_ext_parens
@@ -9507,7 +8810,7 @@ subselect:
Consider the production rule of the SQL Standard
subquery:
- '(' query_expression')'
+ '(' query_expression ')'
This rule is equivalent to the rule
subquery:
@@ -9521,7 +8824,7 @@ subselect:
The latter can be re-written into
subquery:
- query_expression_body_ext_parens ')'
+ query_expression_body_ext_parens
| '(' with_clause query_expression_no_with_clause ')'
The last rule allows us to resolve properly the shift/reduce conflict
@@ -9589,7 +8892,7 @@ select_options:
opt_history_unit:
/* empty*/ %prec PREC_BELOW_IDENTIFIER_OPT_SPECIAL_CASE
{
- $$= VERS_UNDEFINED;
+ $$= VERS_TIMESTAMP;
}
| TRANSACTION_SYM
{
@@ -9758,7 +9061,7 @@ select_item_list:
{
Item *item= new (thd->mem_root)
Item_field(thd, &thd->lex->current_select->context,
- NULL, NULL, &star_clex_str);
+ star_clex_str);
if (unlikely(item == NULL))
MYSQL_YYABORT;
if (unlikely(add_item_to_list(thd, item)))
@@ -9784,8 +9087,8 @@ select_item:
if (unlikely(Lex->sql_command == SQLCOM_CREATE_VIEW &&
check_column_name($4.str)))
my_yyabort_error((ER_WRONG_COLUMN_NAME, MYF(0), $4.str));
- $2->is_autogenerated_name= FALSE;
- $2->set_name(thd, $4.str, $4.length, system_charset_info);
+ $2->common_flags&= ~IS_AUTO_GENERATED_NAME;
+ $2->set_name(thd, $4);
}
else if (!$2->name.str || $2->name.str == item_empty_name)
{
@@ -10463,7 +9766,8 @@ column_default_non_parenthesized_expr:
}
| CAST_SYM '(' expr AS cast_type ')'
{
- if (unlikely(!($$= $5.create_typecast_item(thd, $3, Lex->charset))))
+ if (unlikely(!($$= $5.create_typecast_item_or_error(thd, $3,
+ Lex->charset))))
MYSQL_YYABORT;
}
| CASE_SYM when_list_opt_else END
@@ -10479,7 +9783,8 @@ column_default_non_parenthesized_expr:
}
| CONVERT_SYM '(' expr ',' cast_type ')'
{
- if (unlikely(!($$= $5.create_typecast_item(thd, $3, Lex->charset))))
+ if (unlikely(!($$= $5.create_typecast_item_or_error(thd, $3,
+ Lex->charset))))
MYSQL_YYABORT;
}
| CONVERT_SYM '(' expr USING charset_name ')'
@@ -11192,78 +10497,6 @@ function_call_conflict:
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | geometry_function
- {
-#ifdef HAVE_SPATIAL
- $$= $1;
- /* $1 may be NULL, GEOM_NEW not tested for out of memory */
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
-#else
- my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name,
- sym_group_geom.needed_define));
-#endif
- }
- ;
-
-geometry_function:
- CONTAINS_SYM '(' expr ',' expr ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_precise_rel(thd, $3, $5,
- Item_func::SP_CONTAINS_FUNC));
- }
- | GEOMETRYCOLLECTION '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_geometrycollection,
- Geometry::wkb_point));
- }
- | LINESTRING '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_linestring,
- Geometry::wkb_point));
- }
- | MULTILINESTRING '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_multilinestring,
- Geometry::wkb_linestring));
- }
- | MULTIPOINT '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_multipoint,
- Geometry::wkb_point));
- }
- | MULTIPOLYGON '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_multipolygon,
- Geometry::wkb_polygon));
- }
- | POINT_SYM '(' expr ',' expr ')'
- {
- $$= GEOM_NEW(thd, Item_func_point(thd, $3, $5));
- }
- | POLYGON '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_polygon,
- Geometry::wkb_linestring));
- }
- | WITHIN '(' expr ',' expr ')'
- {
- $$= GEOM_NEW(thd, Item_func_spatial_precise_rel(thd, $3, $5,
- Item_func::SP_WITHIN_FUNC));
- }
;
/*
@@ -11297,6 +10530,7 @@ function_call_generic:
}
opt_udf_expr_list ')'
{
+ const Type_handler *h;
Create_func *builder;
Item *item= NULL;
@@ -11312,8 +10546,12 @@ function_call_generic:
This will be revised with WL#2128 (SQL PATH)
*/
- builder= find_native_function_builder(thd, &$1);
- if (builder)
+ if ((h= Type_handler::handler_by_name(thd, $1)) &&
+ (item= h->make_constructor_item(thd, $4)))
+ {
+ // Found a constructor with a proper argument count
+ }
+ else if ((builder= find_native_function_builder(thd, &$1)))
{
item= builder->create_func(thd, &$1, $4);
}
@@ -11344,6 +10582,18 @@ function_call_generic:
if (unlikely(! ($$= item)))
MYSQL_YYABORT;
}
+ | CONTAINS_SYM '(' opt_expr_list ')'
+ {
+ if (!($$= Lex->make_item_func_call_native_or_parse_error(thd,
+ $1, $3)))
+ MYSQL_YYABORT;
+ }
+ | WITHIN '(' opt_expr_list ')'
+ {
+ if (!($$= Lex->make_item_func_call_native_or_parse_error(thd,
+ $1, $3)))
+ MYSQL_YYABORT;
+ }
| ident_cli '.' ident_cli '(' opt_expr_list ')'
{
if (unlikely(!($$= Lex->make_item_func_call_generic(thd, &$1, &$3, $5))))
@@ -11399,8 +10649,8 @@ udf_expr:
*/
if ($4.str)
{
- $2->is_autogenerated_name= FALSE;
- $2->set_name(thd, $4.str, $4.length, system_charset_info);
+ $2->common_flags&= ~IS_AUTO_GENERATED_NAME;
+ $2->set_name(thd, $4);
}
/*
A field has to have its proper name in order for name
@@ -11558,6 +10808,49 @@ sum_expr:
$5->empty();
sel->gorder_list.empty();
}
+ | JSON_ARRAYAGG_SYM '(' opt_distinct
+ { Select->in_sum_expr++; }
+ expr_list opt_gorder_clause opt_glimit_clause
+ ')'
+ {
+ SELECT_LEX *sel= Select;
+ List<Item> *args= $5;
+ sel->in_sum_expr--;
+ if (args && args->elements > 1)
+ {
+ /* JSON_ARRAYAGG supports only one parameter */
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), "JSON_ARRAYAGG");
+ MYSQL_YYABORT;
+ }
+ String* s= new (thd->mem_root) String(",", 1, &my_charset_latin1);
+ if (unlikely(s == NULL))
+ MYSQL_YYABORT;
+
+ $$= new (thd->mem_root)
+ Item_func_json_arrayagg(thd, Lex->current_context(),
+ $3, args,
+ sel->gorder_list, s, $7,
+ sel->select_limit,
+ sel->offset_limit);
+ if (unlikely($$ == NULL))
+ MYSQL_YYABORT;
+ sel->select_limit= NULL;
+ sel->offset_limit= NULL;
+ sel->explicit_limit= 0;
+ $5->empty();
+ sel->gorder_list.empty();
+ }
+ | JSON_OBJECTAGG_SYM '('
+ { Select->in_sum_expr++; }
+ expr ',' expr ')'
+ {
+ SELECT_LEX *sel= Select;
+ sel->in_sum_expr--;
+
+ $$= new (thd->mem_root) Item_func_json_objectagg(thd, $4, $6);
+ if (unlikely($$ == NULL))
+ MYSQL_YYABORT;
+ }
;
window_func_expr:
@@ -11946,12 +11239,27 @@ cast_type:
}
| cast_type_numeric { $$= $1; Lex->charset= NULL; }
| cast_type_temporal { $$= $1; Lex->charset= NULL; }
+ | IDENT_sys
+ {
+ if (Lex->set_cast_type_udt(&$$, $1))
+ MYSQL_YYABORT;
+ }
+ | reserved_keyword_udt
+ {
+ if (Lex->set_cast_type_udt(&$$, $1))
+ MYSQL_YYABORT;
+ }
+ | non_reserved_keyword_udt
+ {
+ if (Lex->set_cast_type_udt(&$$, $1))
+ MYSQL_YYABORT;
+ }
;
cast_type_numeric:
- INT_SYM { $$.set(&type_handler_longlong); }
- | SIGNED_SYM { $$.set(&type_handler_longlong); }
- | SIGNED_SYM INT_SYM { $$.set(&type_handler_longlong); }
+ INT_SYM { $$.set(&type_handler_slonglong); }
+ | SIGNED_SYM { $$.set(&type_handler_slonglong); }
+ | SIGNED_SYM INT_SYM { $$.set(&type_handler_slonglong); }
| UNSIGNED { $$.set(&type_handler_ulonglong); }
| UNSIGNED INT_SYM { $$.set(&type_handler_ulonglong); }
| DECIMAL_SYM float_options { $$.set(&type_handler_newdecimal, $2); }
@@ -12624,7 +11932,7 @@ opt_window_clause:
{}
| WINDOW_SYM
window_def_list
- {}
+ {}
;
window_def_list:
@@ -13047,7 +12355,7 @@ int_num:
ulong_num:
opt_plus NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); }
- | HEX_NUM { $$= (ulong) strtol($1.str, (char**) 0, 16); }
+ | HEX_NUM { $$= strtoul($1.str, (char**) 0, 16); }
| opt_plus LONG_NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); }
| opt_plus ULONGLONG_NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); }
| opt_plus DECIMAL_NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); }
@@ -13116,7 +12424,7 @@ procedure_clause:
lex->proc_list.next= &lex->proc_list.first;
Item_field *item= new (thd->mem_root)
Item_field(thd, &lex->current_select->context,
- NULL, NULL, &$2);
+ $2);
if (unlikely(item == NULL))
MYSQL_YYABORT;
if (unlikely(add_proc_to_list(thd, item)))
@@ -13315,43 +12623,6 @@ drop:
lex->set_command(SQLCOM_DROP_DB, $3);
lex->name= $4;
}
- | DROP FUNCTION_SYM opt_if_exists ident '.' ident
- {
- LEX *lex= thd->lex;
- sp_name *spname;
- if (unlikely($4.str && check_db_name((LEX_STRING*) &$4)))
- my_yyabort_error((ER_WRONG_DB_NAME, MYF(0), $4.str));
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"));
- lex->set_command(SQLCOM_DROP_FUNCTION, $3);
- spname= new (thd->mem_root) sp_name(&$4, &$6, true);
- if (unlikely(spname == NULL))
- MYSQL_YYABORT;
- lex->spname= spname;
- }
- | DROP FUNCTION_SYM opt_if_exists ident
- {
- LEX *lex= thd->lex;
- LEX_CSTRING db= {0, 0};
- sp_name *spname;
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"));
- if (thd->db.str && unlikely(lex->copy_db_to(&db)))
- MYSQL_YYABORT;
- lex->set_command(SQLCOM_DROP_FUNCTION, $3);
- spname= new (thd->mem_root) sp_name(&db, &$4, false);
- if (unlikely(spname == NULL))
- MYSQL_YYABORT;
- lex->spname= spname;
- }
- | DROP PROCEDURE_SYM opt_if_exists sp_name
- {
- LEX *lex=Lex;
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE"));
- lex->set_command(SQLCOM_DROP_PROCEDURE, $3);
- lex->spname= $4;
- }
| DROP USER_SYM opt_if_exists clear_privileges user_list
{
Lex->set_command(SQLCOM_DROP_USER, $3);
@@ -13406,6 +12677,7 @@ drop:
}
table_list
{}
+ | drop_routine
;
table_list:
@@ -13491,53 +12763,51 @@ opt_temporary:
insert:
INSERT
{
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_INSERT;
- lex->duplicates= DUP_ERROR;
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- mysql_init_select(lex);
- lex->current_select->parsing_place= BEFORE_OPT_LIST;
+ Lex->sql_command= SQLCOM_INSERT;
+ Lex->duplicates= DUP_ERROR;
}
- insert_lock_option
- opt_ignore insert2
+ insert_start insert_lock_option opt_ignore opt_into insert_table
{
- Select->set_lock_for_tables($3, true);
- Lex->current_select= Lex->first_select_lex();
+ Select->set_lock_for_tables($4, true);
}
- insert_field_spec opt_insert_update
+ insert_field_spec opt_insert_update opt_returning
+ stmt_end
{
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
Lex->mark_first_table_as_inserting();
}
- ;
+ ;
replace:
REPLACE
{
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_REPLACE;
- lex->duplicates= DUP_REPLACE;
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- mysql_init_select(lex);
- lex->current_select->parsing_place= BEFORE_OPT_LIST;
+ Lex->sql_command = SQLCOM_REPLACE;
+ Lex->duplicates= DUP_REPLACE;
}
- replace_lock_option insert2
+ insert_start replace_lock_option opt_into insert_table
{
- Select->set_lock_for_tables($3, true);
- Lex->current_select= Lex->first_select_lex();
+ Select->set_lock_for_tables($4, true);
}
- insert_field_spec
+ insert_field_spec opt_returning
+ stmt_end
{
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
Lex->mark_first_table_as_inserting();
}
- ;
+ ;
+
+insert_start: {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ mysql_init_select(Lex);
+ Lex->current_select->parsing_place= BEFORE_OPT_LIST;
+ }
+ ;
+
+stmt_end: {
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
+ ;
insert_lock_option:
/* empty */
@@ -13549,19 +12819,17 @@ insert_lock_option:
*/
$$= (Lex->sphead ? TL_WRITE_DEFAULT : TL_WRITE_CONCURRENT_INSERT);
}
- | LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; }
- | DELAYED_SYM
- {
- // QQ: why was +1?
- Lex->keyword_delayed_begin_offset= (uint)($1.pos() - thd->query());
- Lex->keyword_delayed_end_offset= (uint)($1.end() - thd->query());
- $$= TL_WRITE_DELAYED;
- }
+ | insert_replace_option
| HIGH_PRIORITY { $$= TL_WRITE; }
;
replace_lock_option:
- opt_low_priority { $$= $1; }
+ /* empty */ { $$= TL_WRITE_DEFAULT; }
+ | insert_replace_option
+ ;
+
+insert_replace_option:
+ LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; }
| DELAYED_SYM
{
Lex->keyword_delayed_begin_offset= (uint)($1.pos() - thd->query());
@@ -13570,10 +12838,7 @@ replace_lock_option:
}
;
-insert2:
- INTO insert_table {}
- | insert_table {}
- ;
+opt_into: /* nothing */ | INTO ;
insert_table:
{
@@ -13822,10 +13087,7 @@ update:
{
if ($10)
Select->order_list= *($10);
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
+ } stmt_end {}
;
update_list:
@@ -13878,6 +13140,7 @@ delete:
lex->first_select_lex()->order_list.empty();
}
delete_part2
+ { }
;
opt_delete_system_time:
@@ -13916,19 +13179,19 @@ delete_single_table:
;
delete_single_table_for_period:
- delete_single_table opt_for_portion_of_time_clause
- {
- if ($2)
- Lex->last_table()->period_conditions= Lex->period_conditions;
- }
- ;
+ delete_single_table opt_for_portion_of_time_clause
+ {
+ if ($2)
+ Lex->last_table()->period_conditions= Lex->period_conditions;
+ }
+ ;
single_multi:
delete_single_table_for_period
opt_where_clause
opt_order_clause
delete_limit_clause
- opt_select_expressions
+ opt_returning
{
if ($3)
Select->order_list= *($3);
@@ -13944,10 +13207,7 @@ single_multi:
{
if (unlikely(multi_delete_set_locks_and_link_aux_tables(Lex)))
MYSQL_YYABORT;
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
+ } stmt_end {}
| FROM table_alias_ref_list
{
mysql_init_multi_delete(Lex);
@@ -13958,15 +13218,31 @@ single_multi:
{
if (unlikely(multi_delete_set_locks_and_link_aux_tables(Lex)))
MYSQL_YYABORT;
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
+ } stmt_end {}
;
-opt_select_expressions:
- /* empty */
- | RETURNING_SYM select_item_list
+opt_returning:
+ /* empty */
+ {
+ DBUG_ASSERT(!Lex->has_returning());
+ }
+ | RETURNING_SYM
+ {
+ DBUG_ASSERT(!Lex->has_returning());
+ if (($<num>$= (Select != Lex->returning())))
+ {
+ SELECT_LEX *sl= Lex->returning();
+ sl->set_master_unit(0);
+ Select->add_slave(Lex->create_unit(sl));
+ sl->include_global((st_select_lex_node**)&Lex->all_selects_list);
+ Lex->push_select(sl);
+ }
+ }
+ select_item_list
+ {
+ if ($<num>2)
+ Lex->pop_select();
+ }
;
table_wild_list:
@@ -14043,6 +13319,7 @@ truncate:
if (unlikely(lex->m_sql_cmd == NULL))
MYSQL_YYABORT;
}
+ opt_truncate_table_storage_clause { }
;
opt_table_sym:
@@ -14359,26 +13636,36 @@ show_param:
MYSQL_YYABORT;
lex->table_type= TABLE_TYPE_SEQUENCE;
}
+ | BINLOG_SYM STATUS_SYM
+ {
+ Lex->sql_command = SQLCOM_SHOW_BINLOG_STAT;
+ }
| MASTER_SYM STATUS_SYM
{
- Lex->sql_command = SQLCOM_SHOW_MASTER_STAT;
+ Lex->sql_command = SQLCOM_SHOW_BINLOG_STAT;
}
| ALL SLAVES STATUS_SYM
{
+ if (!(Lex->m_sql_cmd= new (thd->mem_root)
+ Sql_cmd_show_slave_status(true)))
+ MYSQL_YYABORT;
Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
- Lex->verbose= 1;
}
| SLAVE STATUS_SYM
{
LEX *lex= thd->lex;
lex->mi.connection_name= null_clex_str;
+ if (!(lex->m_sql_cmd= new (thd->mem_root)
+ Sql_cmd_show_slave_status()))
+ MYSQL_YYABORT;
lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
- lex->verbose= 0;
}
| SLAVE connection_name STATUS_SYM
{
+ if (!(Lex->m_sql_cmd= new (thd->mem_root)
+ Sql_cmd_show_slave_status()))
+ MYSQL_YYABORT;
Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
- Lex->verbose= 0;
}
| CREATE PROCEDURE_SYM sp_name
{
@@ -14400,12 +13687,24 @@ show_param:
lex->sql_command = SQLCOM_SHOW_CREATE_PACKAGE;
lex->spname= $3;
}
+ | CREATE PACKAGE_ORACLE_SYM sp_name
+ {
+ LEX *lex= Lex;
+ lex->sql_command = SQLCOM_SHOW_CREATE_PACKAGE;
+ lex->spname= $3;
+ }
| CREATE PACKAGE_MARIADB_SYM BODY_MARIADB_SYM sp_name
{
LEX *lex= Lex;
lex->sql_command = SQLCOM_SHOW_CREATE_PACKAGE_BODY;
lex->spname= $4;
}
+ | CREATE PACKAGE_ORACLE_SYM BODY_ORACLE_SYM sp_name
+ {
+ LEX *lex= Lex;
+ lex->sql_command = SQLCOM_SHOW_CREATE_PACKAGE_BODY;
+ lex->spname= $4;
+ }
| CREATE TRIGGER_SYM sp_name
{
LEX *lex= Lex;
@@ -14446,6 +13745,13 @@ show_param:
if (unlikely(prepare_schema_table(thd, lex, 0, SCH_PROCEDURES)))
MYSQL_YYABORT;
}
+ | PACKAGE_ORACLE_SYM STATUS_SYM wild_and_where
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_SHOW_STATUS_PACKAGE;
+ if (unlikely(prepare_schema_table(thd, lex, 0, SCH_PROCEDURES)))
+ MYSQL_YYABORT;
+ }
| PACKAGE_MARIADB_SYM BODY_MARIADB_SYM STATUS_SYM wild_and_where
{
LEX *lex= Lex;
@@ -14453,6 +13759,13 @@ show_param:
if (unlikely(prepare_schema_table(thd, lex, 0, SCH_PROCEDURES)))
MYSQL_YYABORT;
}
+ | PACKAGE_ORACLE_SYM BODY_ORACLE_SYM STATUS_SYM wild_and_where
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_SHOW_STATUS_PACKAGE_BODY;
+ if (unlikely(prepare_schema_table(thd, lex, 0, SCH_PROCEDURES)))
+ MYSQL_YYABORT;
+ }
| PROCEDURE_SYM CODE_SYM sp_name
{
Lex->sql_command= SQLCOM_SHOW_PROC_CODE;
@@ -14468,6 +13781,11 @@ show_param:
Lex->sql_command= SQLCOM_SHOW_PACKAGE_BODY_CODE;
Lex->spname= $4;
}
+ | PACKAGE_ORACLE_SYM BODY_ORACLE_SYM CODE_SYM sp_name
+ {
+ Lex->sql_command= SQLCOM_SHOW_PACKAGE_BODY_CODE;
+ Lex->spname= $4;
+ }
| CREATE EVENT_SYM sp_name
{
Lex->spname= $3;
@@ -15029,10 +14347,8 @@ load:
opt_xml_rows_identified_by
opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec
opt_load_data_set_spec
+ stmt_end
{
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
Lex->mark_first_table_as_inserting();
}
;
@@ -15345,8 +14661,8 @@ literal:
will include the introducer and the original hex/bin notation.
*/
item_str= new (thd->mem_root)
- Item_string_with_introducer(thd, NULL, $2->ptr(), $2->length(),
- $1);
+ Item_string_with_introducer(thd, null_clex_str,
+ $2->lex_cstring(), $1);
if (unlikely(!item_str ||
!item_str->check_well_formed_result(true)))
MYSQL_YYABORT;
@@ -15460,46 +14776,78 @@ with_list:
with_list_element:
query_name
opt_with_column_list
- {
- $2= new List<LEX_CSTRING> (Lex->with_column_list);
- if (unlikely($2 == NULL))
- MYSQL_YYABORT;
- Lex->with_column_list.empty();
- }
- AS '(' query_expression ')'
+ AS '(' query_expression ')' opt_cycle
{
LEX *lex= thd->lex;
const char *query_start= lex->sphead ? lex->sphead->m_tmp_query
: thd->query();
- const char *spec_start= $5.pos() + 1;
- With_element *elem= new With_element($1, *$2, $6);
+ const char *spec_start= $4.pos() + 1;
+ With_element *elem= new With_element($1, *$2, $5);
if (elem == NULL || Lex->curr_with_clause->add_with_element(elem))
MYSQL_YYABORT;
- if (elem->set_unparsed_spec(thd, spec_start, $7.pos(),
+ if (elem->set_unparsed_spec(thd, spec_start, $6.pos(),
spec_start - query_start))
MYSQL_YYABORT;
+ if ($7)
+ {
+ elem->set_cycle_list($7);
+ }
}
;
+opt_cycle:
+ /* empty */
+ { $$= NULL; }
+ |
+ CYCLE_SYM
+ {
+ if (!Lex->curr_with_clause->with_recursive)
+ {
+ thd->parse_error(ER_SYNTAX_ERROR, $1.pos());
+ }
+ }
+ comma_separated_ident_list RESTRICT
+ {
+ $$= $3;
+ }
+ ;
+
opt_with_column_list:
/* empty */
- { $$= NULL; }
+ {
+ if (($$= new (thd->mem_root) List<Lex_ident_sys>) == NULL)
+ MYSQL_YYABORT;
+ }
| '(' with_column_list ')'
- { $$= NULL; }
+ { $$= $2; }
;
-
with_column_list:
- ident
+ comma_separated_ident_list
+ ;
+
+ident_sys_alloc:
+ ident_cli
{
- Lex->with_column_list.push_back((LEX_CSTRING*)
- thd->memdup(&$1, sizeof(LEX_CSTRING)));
+ void *buf= thd->alloc(sizeof(Lex_ident_sys));
+ if (!buf)
+ MYSQL_YYABORT;
+ $$= new (buf) Lex_ident_sys(thd, &$1);
+ }
+ ;
+
+comma_separated_ident_list:
+ ident_sys_alloc
+ {
+ $$= new (thd->mem_root) List<Lex_ident_sys>;
+ if (unlikely($$ == NULL || $$->push_back($1)))
+ MYSQL_YYABORT;
}
- | with_column_list ',' ident
+ | comma_separated_ident_list ',' ident_sys_alloc
{
- Lex->with_column_list.push_back((LEX_CSTRING*)
- thd->memdup(&$3, sizeof(LEX_CSTRING)));
+ if (($$= $1)->push_back($3))
+ MYSQL_YYABORT;
}
;
@@ -15736,13 +15084,9 @@ ident_table_alias:
}
;
-ident_set_usual_case:
- IDENT_sys
- | keyword_set_usual_case
- {
- if (unlikely($$.copy_keyword(thd, &$1)))
- MYSQL_YYABORT;
- }
+ident_cli_set_usual_case:
+ IDENT_cli { $$= $1; }
+ | keyword_set_usual_case { $$= $1; }
;
ident_sysvar_name:
@@ -15847,6 +15191,7 @@ user: user_maybe_role
/* Keywords which we allow as table aliases. */
keyword_table_alias:
keyword_data_type
+ | keyword_cast_type
| keyword_set_special_case
| keyword_sp_block_section
| keyword_sp_head
@@ -15854,11 +15199,14 @@ keyword_table_alias:
| keyword_sp_var_not_label
| keyword_sysvar_type
| keyword_verb_clause
+ | FUNCTION_SYM
+ | EXCEPTION_ORACLE_SYM
;
/* Keyword that we allow for identifiers (except SP labels) */
keyword_ident:
keyword_data_type
+ | keyword_cast_type
| keyword_set_special_case
| keyword_sp_block_section
| keyword_sp_head
@@ -15866,52 +15214,47 @@ keyword_ident:
| keyword_sp_var_not_label
| keyword_sysvar_type
| keyword_verb_clause
+ | FUNCTION_SYM
| WINDOW_SYM
- ;
-
-/*
- Keywords that we allow for labels in SPs.
- Should not include keywords that start a statement or SP characteristics.
-*/
-keyword_label:
- keyword_data_type
- | keyword_set_special_case
- | keyword_sp_var_and_label
- | keyword_sysvar_type
+ | EXCEPTION_ORACLE_SYM
;
keyword_sysvar_name:
keyword_data_type
+ | keyword_cast_type
| keyword_set_special_case
| keyword_sp_block_section
| keyword_sp_head
| keyword_sp_var_and_label
| keyword_sp_var_not_label
| keyword_verb_clause
+ | FUNCTION_SYM
| WINDOW_SYM
+ | EXCEPTION_ORACLE_SYM
;
-keyword_sp_decl:
+keyword_set_usual_case:
keyword_data_type
- | keyword_set_special_case
+ | keyword_cast_type
| keyword_sp_block_section
| keyword_sp_head
| keyword_sp_var_and_label
| keyword_sp_var_not_label
| keyword_sysvar_type
| keyword_verb_clause
+ | FUNCTION_SYM
| WINDOW_SYM
+ | EXCEPTION_ORACLE_SYM
;
-keyword_set_usual_case:
- keyword_data_type
- | keyword_sp_block_section
+non_reserved_keyword_udt:
+ keyword_sp_var_not_label
| keyword_sp_head
- | keyword_sp_var_and_label
- | keyword_sp_var_not_label
- | keyword_sysvar_type
| keyword_verb_clause
- | WINDOW_SYM
+ | keyword_set_special_case
+ | keyword_sp_block_section
+ | keyword_sysvar_type
+ | keyword_sp_var_and_label
;
/*
@@ -15963,7 +15306,6 @@ keyword_sp_var_not_label:
| RESTORE_SYM
| SECURITY_SYM
| SERVER_SYM
- | SIGNED_SYM
| SOCKET_SYM
| SLAVE
| SLAVES
@@ -16053,15 +15395,6 @@ keyword_set_special_case:
| PASSWORD_SYM
;
-/*
- Keywords that start an SP block section.
-*/
-keyword_sp_block_section:
- BEGIN_MARIADB_SYM
- | EXCEPTION_ORACLE_SYM
- | END
- ;
-
keyword_sysvar_type:
GLOBAL_SYM
| LOCAL_SYM
@@ -16083,21 +15416,13 @@ keyword_data_type:
| DATETIME
| ENUM
| FIXED_SYM
- | GEOMETRYCOLLECTION
- | GEOMETRY_SYM
| JSON_SYM
- | LINESTRING
| MEDIUM_SYM
- | MULTILINESTRING
- | MULTIPOINT
- | MULTIPOLYGON
| NATIONAL_SYM
| NCHAR_SYM
| NUMBER_MARIADB_SYM
| NUMBER_ORACLE_SYM
| NVARCHAR_SYM
- | POINT_SYM
- | POLYGON
| RAW_MARIADB_SYM
| RAW_ORACLE_SYM
| ROW_SYM
@@ -16111,6 +15436,11 @@ keyword_data_type:
;
+keyword_cast_type:
+ SIGNED_SYM
+ ;
+
+
/*
These keywords are fine for both SP variable names and SP labels.
*/
@@ -16208,6 +15538,7 @@ keyword_sp_var_and_label:
| FAST_SYM
| FOUND_SYM
| ENABLE_SYM
+ | FEDERATED_SYM
| FULL
| FILE_SYM
| FIRST_SYM
@@ -16286,6 +15617,7 @@ keyword_sp_var_and_label:
| MIN_ROWS
| MODIFY_SYM
| MODE_SYM
+ | MONITOR_SYM
| MONTH_SYM
| MUTEX_SYM
| MYSQL_SYM
@@ -16347,6 +15679,7 @@ keyword_sp_var_and_label:
| RELOAD
| REORGANIZE_SYM
| REPEATABLE_SYM
+ | REPLAY_SYM
| REPLICATION
| RESOURCES
| RESTART_SYM
@@ -16413,7 +15746,6 @@ keyword_sp_var_and_label:
| TYPES_SYM
| TYPE_SYM
| UDF_RETURNS_SYM
- | FUNCTION_SYM
| UNCOMMITTED_SYM
| UNDEFINED_SYM
| UNDO_BUFFER_SIZE_SYM
@@ -16438,6 +15770,246 @@ keyword_sp_var_and_label:
| VIA_SYM
;
+
+reserved_keyword_udt_not_param_type:
+ ACCESSIBLE_SYM
+ | ADD
+ | ALL
+ | ALTER
+ | ANALYZE_SYM
+ | AND_SYM
+ | AS
+ | ASC
+ | ASENSITIVE_SYM
+ | BEFORE_SYM
+ | BETWEEN_SYM
+ | BIT_AND
+ | BIT_OR
+ | BIT_XOR
+ | BODY_ORACLE_SYM
+ | BOTH
+ | BY
+ | CALL_SYM
+ | CASCADE
+ | CASE_SYM
+ | CAST_SYM
+ | CHANGE
+ | CHECK_SYM
+ | COLLATE_SYM
+ | CONSTRAINT
+ | CONTINUE_MARIADB_SYM
+ | CONTINUE_ORACLE_SYM
+ | CONVERT_SYM
+ | COUNT_SYM
+ | CREATE
+ | CROSS
+ | CUME_DIST_SYM
+ | CURDATE
+ | CURRENT_USER
+ | CURRENT_ROLE
+ | CURTIME
+ | DATABASE
+ | DATABASES
+ | DATE_ADD_INTERVAL
+ | DATE_SUB_INTERVAL
+ | DAY_HOUR_SYM
+ | DAY_MICROSECOND_SYM
+ | DAY_MINUTE_SYM
+ | DAY_SECOND_SYM
+ | DECLARE_MARIADB_SYM
+ | DECLARE_ORACLE_SYM
+ | DEFAULT
+ | DELETE_DOMAIN_ID_SYM
+ | DELETE_SYM
+ | DENSE_RANK_SYM
+ | DESC
+ | DESCRIBE
+ | DETERMINISTIC_SYM
+ | DISTINCT
+ | DIV_SYM
+ | DO_DOMAIN_IDS_SYM
+ | DROP
+ | DUAL_SYM
+ | EACH_SYM
+ | ELSE
+ | ELSEIF_MARIADB_SYM
+ | ELSIF_ORACLE_SYM
+ | ENCLOSED
+ | ESCAPED
+ | EXCEPT_SYM
+ | EXISTS
+ | EXTRACT_SYM
+ | FALSE_SYM
+ | FETCH_SYM
+ | FIRST_VALUE_SYM
+ | FOREIGN
+ | FROM
+ | FULLTEXT_SYM
+ | GOTO_ORACLE_SYM
+ | GRANT
+ | GROUP_SYM
+ | GROUP_CONCAT_SYM
+ | LAG_SYM
+ | LEAD_SYM
+ | HAVING
+ | HOUR_MICROSECOND_SYM
+ | HOUR_MINUTE_SYM
+ | HOUR_SECOND_SYM
+ | IF_SYM
+ | IGNORE_DOMAIN_IDS_SYM
+ | IGNORE_SYM
+ | INDEX_SYM
+ | INFILE
+ | INNER_SYM
+ | INSENSITIVE_SYM
+ | INSERT
+ | INTERSECT_SYM
+ | INTERVAL_SYM
+ | INTO
+ | IS
+ | ITERATE_SYM
+ | JOIN_SYM
+ | KEYS
+ | KEY_SYM
+ | KILL_SYM
+ | LEADING
+ | LEAVE_SYM
+ | LEFT
+ | LIKE
+ | LIMIT
+ | LINEAR_SYM
+ | LINES
+ | LOAD
+ | LOCATOR_SYM
+ | LOCK_SYM
+ | LOOP_SYM
+ | LOW_PRIORITY
+ | MASTER_SSL_VERIFY_SERVER_CERT_SYM
+ | MATCH
+ | MAX_SYM
+ | MAXVALUE_SYM
+ | MEDIAN_SYM
+ | MINUTE_MICROSECOND_SYM
+ | MINUTE_SECOND_SYM
+ | MIN_SYM
+ | MODIFIES_SYM
+ | MOD_SYM
+ | NATURAL
+ | NEG
+ | NOT_SYM
+ | NOW_SYM
+ | NO_WRITE_TO_BINLOG
+ | NTILE_SYM
+ | NULL_SYM
+ | NTH_VALUE_SYM
+ | ON
+ | OPTIMIZE
+ | OPTIONALLY
+ | ORDER_SYM
+ | OR_SYM
+ | OTHERS_ORACLE_SYM
+ | OUTER
+ | OUTFILE
+ | OVER_SYM
+ | PACKAGE_ORACLE_SYM
+ | PAGE_CHECKSUM_SYM
+ | PARSE_VCOL_EXPR_SYM
+ | PARTITION_SYM
+ | PERCENT_RANK_SYM
+ | PERCENTILE_CONT_SYM
+ | PERCENTILE_DISC_SYM
+ | PORTION_SYM
+ | POSITION_SYM
+ | PRECISION
+ | PRIMARY_SYM
+ | PROCEDURE_SYM
+ | PURGE
+ | RAISE_ORACLE_SYM
+ | RANGE_SYM
+ | RANK_SYM
+ | READS_SYM
+ | READ_SYM
+ | READ_WRITE_SYM
+ | RECURSIVE_SYM
+ | REF_SYSTEM_ID_SYM
+ | REFERENCES
+ | REGEXP
+ | RELEASE_SYM
+ | RENAME
+ | REPEAT_SYM
+ | REPLACE
+ | REQUIRE_SYM
+ | RESIGNAL_SYM
+ | RESTRICT
+ | RETURNING_SYM
+ | RETURN_MARIADB_SYM
+ | RETURN_ORACLE_SYM
+ | REVOKE
+ | RIGHT
+ | ROWS_SYM
+ | ROWTYPE_ORACLE_SYM
+ | ROW_NUMBER_SYM
+ | SECOND_MICROSECOND_SYM
+ | SELECT_SYM
+ | SENSITIVE_SYM
+ | SEPARATOR_SYM
+ | SERVER_OPTIONS
+ | SHOW
+ | SIGNAL_SYM
+ | SPATIAL_SYM
+ | SPECIFIC_SYM
+ | SQLEXCEPTION_SYM
+ | SQLSTATE_SYM
+ | SQLWARNING_SYM
+ | SQL_BIG_RESULT
+ | SQL_SMALL_RESULT
+ | SQL_SYM
+ | SSL_SYM
+ | STARTING
+ | STATS_AUTO_RECALC_SYM
+ | STATS_PERSISTENT_SYM
+ | STATS_SAMPLE_PAGES_SYM
+ | STDDEV_SAMP_SYM
+ | STD_SYM
+ | STRAIGHT_JOIN
+ | SUBSTRING
+ | SUM_SYM
+ | SYSDATE
+ | TABLE_REF_PRIORITY
+ | TABLE_SYM
+ | TERMINATED
+ | THEN_SYM
+ | TO_SYM
+ | TRAILING
+ | TRIGGER_SYM
+ | TRIM
+ | TRUE_SYM
+ | UNDO_SYM
+ | UNION_SYM
+ | UNIQUE_SYM
+ | UNLOCK_SYM
+ | UPDATE_SYM
+ | USAGE
+ | USE_SYM
+ | USING
+ | UTC_DATE_SYM
+ | UTC_TIMESTAMP_SYM
+ | UTC_TIME_SYM
+ | VALUES
+ | VALUES_IN_SYM
+ | VALUES_LESS_SYM
+ | VARIANCE_SYM
+ | VARYING
+ | VAR_SAMP_SYM
+ | WHEN_SYM
+ | WHERE
+ | WHILE_SYM
+ | WITH
+ | XOR
+ | YEAR_MONTH_SYM
+ | ZEROFILL
+ ;
+
/*
SQLCOM_SET_OPTION statement.
@@ -16452,111 +16024,74 @@ set:
if (lex->main_select_push())
MYSQL_YYABORT;
lex->set_stmt_init();
- lex->var_list.empty();
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
}
- start_option_value_list
+ set_param
+ stmt_end {}
+ ;
+
+set_param:
+ option_value_no_option_type
+ | option_value_no_option_type ',' option_value_list
+ | TRANSACTION_SYM
{
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
+ Lex->option_type= OPT_DEFAULT;
+ if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
- | SET STATEMENT_SYM
+ transaction_characteristics
{
- if (Lex->main_select_push())
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
- Lex->set_stmt_init();
}
- set_stmt_option_value_following_option_type_list
+ | option_type
+ {
+ Lex->option_type= $1;
+ }
+ start_option_value_list_following_option_type
+ | STATEMENT_SYM
+ set_stmt_option_list
{
LEX *lex= Lex;
if (unlikely(lex->table_or_sp_used()))
my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "SET STATEMENT"));
lex->stmt_var_list= lex->var_list;
lex->var_list.empty();
- Lex->pop_select(); //main select
if (Lex->check_main_unit_semantics())
MYSQL_YYABORT;
}
- FOR_SYM verb_clause
- {}
+ FOR_SYM directly_executable_statement
;
-set_stmt_option_value_following_option_type_list:
+set_stmt_option_list:
/*
Only system variables can be used here. If this condition is changed
please check careful code under lex->option_type == OPT_STATEMENT
condition on wrong type casts.
*/
- option_value_following_option_type
- | set_stmt_option_value_following_option_type_list ',' option_value_following_option_type
+ set_stmt_option
+ | set_stmt_option_list ',' set_stmt_option
;
-/* Start of option value list */
-start_option_value_list:
- option_value_no_option_type
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
- option_value_list_continued
- | TRANSACTION_SYM
- {
- Lex->option_type= OPT_DEFAULT;
- }
- transaction_characteristics
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
- | option_type
- {
- Lex->option_type= $1;
- }
- start_option_value_list_following_option_type
- ;
-
-
/* Start of option value list, option_type was given */
start_option_value_list_following_option_type:
option_value_following_option_type
+ | option_value_following_option_type ',' option_value_list
+ | TRANSACTION_SYM
{
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
- option_value_list_continued
- | TRANSACTION_SYM transaction_characteristics
+ transaction_characteristics
{
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
;
-/* Remainder of the option value list after first option value. */
-option_value_list_continued:
- /* empty */
- | ',' option_value_list
- ;
-
/* Repeating list of option values after first option value. */
option_value_list:
- {
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
- }
- option_value
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
- | option_value_list ','
- {
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
- }
option_value
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
+ | option_value_list ',' option_value
;
/* Wrapper around option values following the first option value in the stmt. */
@@ -16589,16 +16124,21 @@ opt_var_ident_type:
| SESSION_SYM '.' { $$=OPT_SESSION; }
;
-/* Option values with preceding option_type. */
-option_value_following_option_type:
- ident equal set_expr_or_default
+/*
+ SET STATEMENT options do not need their own LEX or Query_arena.
+ Let's put them to the main ones.
+*/
+set_stmt_option:
+ ident_cli equal set_expr_or_default
{
- if (unlikely(Lex->set_system_variable(Lex->option_type, &$1, $3)))
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_system_variable(Lex->option_type, &tmp, $3)))
MYSQL_YYABORT;
}
- | ident '.' ident equal set_expr_or_default
+ | ident_cli '.' ident equal set_expr_or_default
{
- if (unlikely(Lex->set_system_variable(thd, Lex->option_type, &$1, &$3, $5)))
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_system_variable(thd, Lex->option_type, &tmp, &$3, $5)))
MYSQL_YYABORT;
}
| DEFAULT '.' ident equal set_expr_or_default
@@ -16608,45 +16148,132 @@ option_value_following_option_type:
}
;
+
+/* Option values with preceding option_type. */
+option_value_following_option_type:
+ ident_cli equal
+ {
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_system_variable(Lex->option_type, &tmp, $4)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ | ident_cli '.' ident equal
+ {
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_system_variable(thd, Lex->option_type, &tmp, &$3, $6)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ | DEFAULT '.' ident equal
+ {
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $6)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ ;
+
/* Option values without preceding option_type. */
option_value_no_option_type:
- ident_set_usual_case equal set_expr_or_default
+ ident_cli_set_usual_case equal
{
- if (unlikely(Lex->set_variable(&$1, $3)))
+ if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
- | ident '.' ident equal set_expr_or_default
+ set_expr_or_default
{
- if (unlikely(Lex->set_variable(&$1, &$3, $5)))
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_variable(&tmp, $4)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
- | DEFAULT '.' ident equal set_expr_or_default
+ | ident_cli_set_usual_case '.' ident equal
{
- if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $5)))
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_variable(&tmp, &$3, $6)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ | DEFAULT '.' ident equal
+ {
+ if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
- | '@' ident_or_text equal expr
+ set_expr_or_default
{
- if (unlikely(Lex->set_user_variable(thd, &$2, $4)))
+ if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $6)))
+ MYSQL_YYABORT;
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
- | '@' '@' opt_var_ident_type ident_sysvar_name equal set_expr_or_default
+ | '@' ident_or_text equal
{
- if (unlikely(Lex->set_system_variable($3, &$4, $6)))
+ if (sp_create_assignment_lex(thd, $1.str))
MYSQL_YYABORT;
}
- | '@' '@' opt_var_ident_type ident_sysvar_name '.' ident equal set_expr_or_default
+ expr
{
- if (unlikely(Lex->set_system_variable(thd, $3, &$4, &$6, $8)))
+ if (unlikely(Lex->set_user_variable(thd, &$2, $5)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
- | '@' '@' opt_var_ident_type DEFAULT '.' ident equal set_expr_or_default
+ | '@' '@' opt_var_ident_type ident_sysvar_name equal
{
- if (unlikely(Lex->set_default_system_variable($3, &$6, $8)))
+ if (sp_create_assignment_lex(thd, $1.str))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ if (unlikely(Lex->set_system_variable($3, &$4, $7)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ | '@' '@' opt_var_ident_type ident_sysvar_name '.' ident equal
+ {
+ if (sp_create_assignment_lex(thd, $1.str))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ if (unlikely(Lex->set_system_variable(thd, $3, &$4, &$6, $9)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ | '@' '@' opt_var_ident_type DEFAULT '.' ident equal
+ {
+ if (sp_create_assignment_lex(thd, $1.str))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ if (unlikely(Lex->set_default_system_variable($3, &$6, $9)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| charset old_or_new_charset_name_or_default
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex= thd->lex;
CHARSET_INFO *cs2;
cs2= $2 ? $2: global_system_variables.character_set_client;
@@ -16658,6 +16285,8 @@ option_value_no_option_type:
if (unlikely(var == NULL))
MYSQL_YYABORT;
lex->var_list.push_back(var, thd->mem_root);
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
}
| NAMES_SYM equal expr
{
@@ -16672,6 +16301,8 @@ option_value_no_option_type:
}
| NAMES_SYM charset_name_or_default opt_collate
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex= Lex;
CHARSET_INFO *cs2;
CHARSET_INFO *cs3;
@@ -16686,11 +16317,14 @@ option_value_no_option_type:
set_var_collation_client *var;
var= new (thd->mem_root) set_var_collation_client(cs3, cs3, cs3);
if (unlikely(var == NULL) ||
- unlikely(lex->var_list.push_back(var, thd->mem_root)))
+ unlikely(lex->var_list.push_back(var, thd->mem_root)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| DEFAULT ROLE_SYM grant_role
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex = Lex;
LEX_USER *user;
if (unlikely(!(user=(LEX_USER *) thd->calloc(sizeof(LEX_USER)))))
@@ -16706,9 +16340,13 @@ option_value_no_option_type:
thd->lex->autocommit= TRUE;
if (lex->sphead)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
}
| DEFAULT ROLE_SYM grant_role FOR_SYM user
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex = Lex;
set_var_default_role *var= (new (thd->mem_root)
set_var_default_role($5, $3->user));
@@ -16718,22 +16356,36 @@ option_value_no_option_type:
thd->lex->autocommit= TRUE;
if (lex->sphead)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
}
| ROLE_SYM ident_or_text
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex = Lex;
set_var_role *var= new (thd->mem_root) set_var_role($2);
if (unlikely(var == NULL) ||
- unlikely(lex->var_list.push_back(var, thd->mem_root)))
+ unlikely(lex->var_list.push_back(var, thd->mem_root)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
- | ROLE_SYM equal set_expr_or_default
+ | ROLE_SYM equal
{
- if (unlikely(Lex->set_variable(&$1, $3)))
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_variable(&tmp, $4)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| PASSWORD_SYM opt_for_user text_or_password
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex = Lex;
set_var_password *var= (new (thd->mem_root)
set_var_password(lex->definer));
@@ -16743,6 +16395,8 @@ option_value_no_option_type:
lex->autocommit= TRUE;
if (lex->sphead)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
}
;
@@ -17071,34 +16725,12 @@ revoke:
revoke_command:
grant_privileges ON opt_table grant_ident FROM user_and_role_list
{
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_REVOKE;
- lex->type= 0;
- }
- | grant_privileges ON FUNCTION_SYM grant_ident FROM user_and_role_list
- {
- if (unlikely(Lex->add_grant_command(thd, SQLCOM_REVOKE,
- TYPE_ENUM_FUNCTION)))
+ if (Lex->stmt_revoke_table(thd, $1, *$4))
MYSQL_YYABORT;
}
- | grant_privileges ON PROCEDURE_SYM grant_ident FROM user_and_role_list
+ | grant_privileges ON sp_handler grant_ident FROM user_and_role_list
{
- if (unlikely(Lex->add_grant_command(thd, SQLCOM_REVOKE,
- TYPE_ENUM_PROCEDURE)))
- MYSQL_YYABORT;
- }
- | grant_privileges ON PACKAGE_ORACLE_SYM grant_ident
- FROM user_and_role_list
- {
- if (unlikely(Lex->add_grant_command(thd, SQLCOM_REVOKE,
- TYPE_ENUM_PACKAGE)))
- MYSQL_YYABORT;
- }
- | grant_privileges ON PACKAGE_ORACLE_SYM BODY_ORACLE_SYM grant_ident
- FROM user_and_role_list
- {
- if (unlikely(Lex->add_grant_command(thd, SQLCOM_REVOKE,
- TYPE_ENUM_PACKAGE_BODY)))
+ if (Lex->stmt_revoke_sp(thd, $1, *$4, *$3))
MYSQL_YYABORT;
}
| ALL opt_privileges ',' GRANT OPTION FROM user_and_role_list
@@ -17107,10 +16739,8 @@ revoke_command:
}
| PROXY_SYM ON user FROM user_list
{
- LEX *lex= Lex;
- lex->users_list.push_front ($3);
- lex->sql_command= SQLCOM_REVOKE;
- lex->type= TYPE_ENUM_PROXY;
+ if (Lex->stmt_revoke_proxy(thd, $3))
+ MYSQL_YYABORT;
}
| admin_option_for_role FROM user_and_role_list
{
@@ -17136,44 +16766,19 @@ grant_command:
grant_privileges ON opt_table grant_ident TO_SYM grant_list
opt_require_clause opt_grant_options
{
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_GRANT;
- lex->type= 0;
- }
- | grant_privileges ON FUNCTION_SYM grant_ident TO_SYM grant_list
- opt_require_clause opt_grant_options
- {
- if (unlikely(Lex->add_grant_command(thd, SQLCOM_GRANT,
- TYPE_ENUM_FUNCTION)))
- MYSQL_YYABORT;
- }
- | grant_privileges ON PROCEDURE_SYM grant_ident TO_SYM grant_list
- opt_require_clause opt_grant_options
- {
- if (unlikely(Lex->add_grant_command(thd, SQLCOM_GRANT,
- TYPE_ENUM_PROCEDURE)))
+ if (Lex->stmt_grant_table(thd, $1, *$4, $8))
MYSQL_YYABORT;
}
- | grant_privileges ON PACKAGE_ORACLE_SYM grant_ident TO_SYM grant_list
+ | grant_privileges ON sp_handler grant_ident TO_SYM grant_list
opt_require_clause opt_grant_options
{
- if (unlikely(Lex->add_grant_command(thd, SQLCOM_GRANT,
- TYPE_ENUM_PACKAGE)))
- MYSQL_YYABORT;
- }
- | grant_privileges ON PACKAGE_ORACLE_SYM BODY_ORACLE_SYM grant_ident TO_SYM grant_list
- opt_require_clause opt_grant_options
- {
- if (unlikely(Lex->add_grant_command(thd, SQLCOM_GRANT,
- TYPE_ENUM_PACKAGE_BODY)))
+ if (Lex->stmt_grant_sp(thd, $1, *$4, *$3, $8))
MYSQL_YYABORT;
}
| PROXY_SYM ON user TO_SYM grant_list opt_grant_option
{
- LEX *lex= Lex;
- lex->users_list.push_front ($3);
- lex->sql_command= SQLCOM_GRANT;
- lex->type= TYPE_ENUM_PROXY;
+ if (Lex->stmt_grant_proxy(thd, $3, $6))
+ MYSQL_YYABORT;
}
| grant_role TO_SYM grant_list opt_with_admin_option
{
@@ -17224,7 +16829,7 @@ grant_role:
{
CHARSET_INFO *cs= system_charset_info;
/* trim end spaces (as they'll be lost in mysql.user anyway) */
- $1.length= cs->cset->lengthsp(cs, $1.str, $1.length);
+ $1.length= cs->lengthsp($1.str, $1.length);
((char*) $1.str)[$1.length] = '\0';
if (unlikely($1.length == 0))
my_yyabort_error((ER_INVALID_ROLE, MYF(0), ""));
@@ -17248,11 +16853,11 @@ opt_table:
;
grant_privileges:
- object_privilege_list {}
+ object_privilege_list
| ALL opt_privileges
{
- Lex->all_privileges= 1;
- Lex->grant= GLOBAL_ACLS;
+ if (!($$= new (thd->mem_root) Lex_grant_privilege(GLOBAL_ACLS, true)))
+ MYSQL_YYABORT;
}
;
@@ -17263,49 +16868,85 @@ opt_privileges:
object_privilege_list:
object_privilege
+ {
+ if (!($$= new (thd->mem_root) Lex_grant_privilege($1)))
+ MYSQL_YYABORT;
+ }
+ | column_list_privilege
+ {
+ if (!($$= new (thd->mem_root) Lex_grant_privilege()) ||
+ $$->add_column_list_privilege(thd, $1.m_columns[0],
+ $1.m_privilege))
+ MYSQL_YYABORT;
+ }
| object_privilege_list ',' object_privilege
+ {
+ ($$= $1)->add_object_privilege($3);
+ }
+ | object_privilege_list ',' column_list_privilege
+ {
+ if (($$= $1)->add_column_list_privilege(thd, $3.m_columns[0],
+ $3.m_privilege))
+ MYSQL_YYABORT;
+ }
+ ;
+
+column_list_privilege:
+ column_privilege '(' comma_separated_ident_list ')'
+ {
+ $$= Lex_column_list_privilege($3, $1);
+ }
+ ;
+
+column_privilege:
+ SELECT_SYM { $$= SELECT_ACL; }
+ | INSERT { $$= INSERT_ACL; }
+ | UPDATE_SYM { $$= UPDATE_ACL; }
+ | REFERENCES { $$= REFERENCES_ACL; }
;
object_privilege:
- SELECT_SYM
- { Lex->which_columns = SELECT_ACL;}
- opt_column_list {}
- | INSERT
- { Lex->which_columns = INSERT_ACL;}
- opt_column_list {}
- | UPDATE_SYM
- { Lex->which_columns = UPDATE_ACL; }
- opt_column_list {}
- | REFERENCES
- { Lex->which_columns = REFERENCES_ACL;}
- opt_column_list {}
- | DELETE_SYM { Lex->grant |= DELETE_ACL;}
- | USAGE {}
- | INDEX_SYM { Lex->grant |= INDEX_ACL;}
- | ALTER { Lex->grant |= ALTER_ACL;}
- | CREATE { Lex->grant |= CREATE_ACL;}
- | DROP { Lex->grant |= DROP_ACL;}
- | EXECUTE_SYM { Lex->grant |= EXECUTE_ACL;}
- | RELOAD { Lex->grant |= RELOAD_ACL;}
- | SHUTDOWN { Lex->grant |= SHUTDOWN_ACL;}
- | PROCESS { Lex->grant |= PROCESS_ACL;}
- | FILE_SYM { Lex->grant |= FILE_ACL;}
- | GRANT OPTION { Lex->grant |= GRANT_ACL;}
- | SHOW DATABASES { Lex->grant |= SHOW_DB_ACL;}
- | SUPER_SYM { Lex->grant |= SUPER_ACL;}
- | CREATE TEMPORARY TABLES { Lex->grant |= CREATE_TMP_ACL;}
- | LOCK_SYM TABLES { Lex->grant |= LOCK_TABLES_ACL; }
- | REPLICATION SLAVE { Lex->grant |= REPL_SLAVE_ACL; }
- | REPLICATION CLIENT_SYM { Lex->grant |= REPL_CLIENT_ACL; }
- | CREATE VIEW_SYM { Lex->grant |= CREATE_VIEW_ACL; }
- | SHOW VIEW_SYM { Lex->grant |= SHOW_VIEW_ACL; }
- | CREATE ROUTINE_SYM { Lex->grant |= CREATE_PROC_ACL; }
- | ALTER ROUTINE_SYM { Lex->grant |= ALTER_PROC_ACL; }
- | CREATE USER_SYM { Lex->grant |= CREATE_USER_ACL; }
- | EVENT_SYM { Lex->grant |= EVENT_ACL;}
- | TRIGGER_SYM { Lex->grant |= TRIGGER_ACL; }
- | CREATE TABLESPACE { Lex->grant |= CREATE_TABLESPACE_ACL; }
- | DELETE_SYM HISTORY_SYM { Lex->grant |= DELETE_HISTORY_ACL; }
+ SELECT_SYM { $$= SELECT_ACL; }
+ | INSERT { $$= INSERT_ACL; }
+ | UPDATE_SYM { $$= UPDATE_ACL; }
+ | REFERENCES { $$= REFERENCES_ACL; }
+ | DELETE_SYM { $$= DELETE_ACL;}
+ | USAGE { $$= NO_ACL; }
+ | INDEX_SYM { $$= INDEX_ACL;}
+ | ALTER { $$= ALTER_ACL;}
+ | CREATE { $$= CREATE_ACL;}
+ | DROP { $$= DROP_ACL;}
+ | EXECUTE_SYM { $$= EXECUTE_ACL;}
+ | RELOAD { $$= RELOAD_ACL;}
+ | SHUTDOWN { $$= SHUTDOWN_ACL;}
+ | PROCESS { $$= PROCESS_ACL;}
+ | FILE_SYM { $$= FILE_ACL;}
+ | GRANT OPTION { $$= GRANT_ACL;}
+ | SHOW DATABASES { $$= SHOW_DB_ACL;}
+ | SUPER_SYM { $$= SUPER_ACL;}
+ | CREATE TEMPORARY TABLES { $$= CREATE_TMP_ACL;}
+ | LOCK_SYM TABLES { $$= LOCK_TABLES_ACL; }
+ | REPLICATION SLAVE { $$= REPL_SLAVE_ACL; }
+ | REPLICATION CLIENT_SYM { $$= BINLOG_MONITOR_ACL; /*Compatibility*/ }
+ | CREATE VIEW_SYM { $$= CREATE_VIEW_ACL; }
+ | SHOW VIEW_SYM { $$= SHOW_VIEW_ACL; }
+ | CREATE ROUTINE_SYM { $$= CREATE_PROC_ACL; }
+ | ALTER ROUTINE_SYM { $$= ALTER_PROC_ACL; }
+ | CREATE USER_SYM { $$= CREATE_USER_ACL; }
+ | EVENT_SYM { $$= EVENT_ACL;}
+ | TRIGGER_SYM { $$= TRIGGER_ACL; }
+ | CREATE TABLESPACE { $$= CREATE_TABLESPACE_ACL; }
+ | DELETE_SYM HISTORY_SYM { $$= DELETE_HISTORY_ACL; }
+ | SET USER_SYM { $$= SET_USER_ACL; }
+ | FEDERATED_SYM ADMIN_SYM { $$= FEDERATED_ADMIN_ACL; }
+ | CONNECTION_SYM ADMIN_SYM { $$= CONNECTION_ADMIN_ACL; }
+ | READ_SYM ONLY_SYM ADMIN_SYM { $$= READ_ONLY_ADMIN_ACL; }
+ | READ_ONLY_SYM ADMIN_SYM { $$= READ_ONLY_ADMIN_ACL; }
+ | BINLOG_SYM MONITOR_SYM { $$= BINLOG_MONITOR_ACL; }
+ | BINLOG_SYM ADMIN_SYM { $$= BINLOG_ADMIN_ACL; }
+ | BINLOG_SYM REPLAY_SYM { $$= BINLOG_REPLAY_ACL; }
+ | REPLICATION MASTER_SYM ADMIN_SYM { $$= REPL_MASTER_ADMIN_ACL; }
+ | REPLICATION SLAVE ADMIN_SYM { $$= REPL_SLAVE_ADMIN_ACL; }
;
opt_and:
@@ -17345,41 +16986,30 @@ require_list_element:
grant_ident:
'*'
{
- LEX *lex= Lex;
- if (unlikely(lex->copy_db_to(&lex->current_select->db)))
+ LEX_CSTRING db;
+ if (unlikely(Lex->copy_db_to(&db)))
+ MYSQL_YYABORT;
+ if (!($$= new (thd->mem_root) Lex_grant_object_name(db,
+ Lex_grant_object_name::STAR)))
MYSQL_YYABORT;
- if (lex->grant == GLOBAL_ACLS)
- lex->grant = DB_ACLS & ~GRANT_ACL;
- else if (unlikely(lex->columns.elements))
- my_yyabort_error((ER_ILLEGAL_GRANT_FOR_TABLE, MYF(0)));
}
| ident '.' '*'
{
- LEX *lex= Lex;
- lex->current_select->db= $1;
- if (lex->grant == GLOBAL_ACLS)
- lex->grant = DB_ACLS & ~GRANT_ACL;
- else if (unlikely(lex->columns.elements))
- my_yyabort_error((ER_ILLEGAL_GRANT_FOR_TABLE, MYF(0)));
+ if (!($$= new (thd->mem_root) Lex_grant_object_name($1,
+ Lex_grant_object_name::IDENT_STAR)))
+ MYSQL_YYABORT;
}
| '*' '.' '*'
{
- LEX *lex= Lex;
- lex->current_select->db= null_clex_str;
- if (lex->grant == GLOBAL_ACLS)
- lex->grant= GLOBAL_ACLS & ~GRANT_ACL;
- else if (unlikely(lex->columns.elements))
- my_yyabort_error((ER_ILLEGAL_GRANT_FOR_TABLE, MYF(0)));
+ if (!($$= new (thd->mem_root) Lex_grant_object_name(
+ null_clex_str,
+ Lex_grant_object_name::STAR_STAR)))
+ MYSQL_YYABORT;
}
| table_ident
{
- LEX *lex=Lex;
- if (unlikely(!lex->current_select->
- add_table_to_list(thd, $1,NULL,
- TL_OPTION_UPDATING)))
+ if (!($$= new (thd->mem_root) Lex_grant_object_name($1)))
MYSQL_YYABORT;
- if (lex->grant == GLOBAL_ACLS)
- lex->grant = TABLE_ACLS & ~GRANT_ACL;
}
;
@@ -17490,49 +17120,6 @@ opt_auth_str:
}
;
-opt_column_list:
- /* empty */
- {
- LEX *lex=Lex;
- lex->grant |= lex->which_columns;
- }
- | '(' column_list ')' { }
- ;
-
-column_list:
- column_list ',' column_list_id
- | column_list_id
- ;
-
-column_list_id:
- ident
- {
- String *new_str= new (thd->mem_root) String((const char*) $1.str,$1.length,system_charset_info);
- if (unlikely(new_str == NULL))
- MYSQL_YYABORT;
- List_iterator <LEX_COLUMN> iter(Lex->columns);
- class LEX_COLUMN *point;
- LEX *lex=Lex;
- while ((point=iter++))
- {
- if (!my_strcasecmp(system_charset_info,
- point->column.c_ptr(), new_str->c_ptr()))
- break;
- }
- lex->grant_tot_col|= lex->which_columns;
- if (point)
- point->rights |= lex->which_columns;
- else
- {
- LEX_COLUMN *col= (new (thd->mem_root)
- LEX_COLUMN(*new_str,lex->which_columns));
- if (unlikely(col == NULL))
- MYSQL_YYABORT;
- lex->columns.push_back(col, thd->mem_root);
- }
- }
- ;
-
opt_require_clause:
/* empty */
| REQUIRE_SYM require_list
@@ -17593,23 +17180,23 @@ opt_resource_options:
opt_grant_options:
- /* empty */ {}
- | WITH grant_option_list {}
+ /* empty */ { $$= NO_ACL; }
+ | WITH grant_option_list { $$= $2; }
;
opt_grant_option:
- /* empty */ {}
- | WITH GRANT OPTION { Lex->grant |= GRANT_ACL;}
+ /* empty */ { $$= NO_ACL; }
+ | WITH GRANT OPTION { $$= GRANT_ACL; }
;
grant_option_list:
- grant_option_list grant_option {}
- | grant_option {}
+ grant_option_list grant_option { $$= $1 | $2; }
+ | grant_option
;
grant_option:
- GRANT OPTION { Lex->grant |= GRANT_ACL;}
- | resource_option {}
+ GRANT OPTION { $$= GRANT_ACL;}
+ | resource_option { $$= NO_ACL; }
;
begin_stmt_mariadb:
@@ -17716,10 +17303,10 @@ release:
unit_type_decl:
UNION_SYM union_option
{ $$.unit_type= UNION_TYPE; $$.distinct= $2; }
- | INTERSECT_SYM
- { $$.unit_type= INTERSECT_TYPE; $$.distinct= 1; }
- | EXCEPT_SYM
- { $$.unit_type= EXCEPT_TYPE; $$.distinct= 1; }
+ | INTERSECT_SYM union_option
+ { $$.unit_type= INTERSECT_TYPE; $$.distinct= $2; }
+ | EXCEPT_SYM union_option
+ { $$.unit_type= EXCEPT_TYPE; $$.distinct= $2; }
;
/*
@@ -17740,6 +17327,7 @@ query_expression_option:
Select->options|= SELECT_HIGH_PRIORITY;
}
| DISTINCT { Select->options|= SELECT_DISTINCT; }
+ | UNIQUE_SYM { Select->options|= SELECT_DISTINCT; }
| SQL_SMALL_RESULT { Select->options|= SELECT_SMALL_RESULT; }
| SQL_BIG_RESULT { Select->options|= SELECT_BIG_RESULT; }
| SQL_BUFFER_RESULT { Select->options|= OPTION_BUFFER_RESULT; }
@@ -17948,7 +17536,6 @@ trigger_tail:
sf_return_type:
- RETURNS_SYM
{
LEX *lex= Lex;
lex->init_last_field(&lex->sphead->m_return_field_def,
@@ -17957,47 +17544,11 @@ sf_return_type:
}
type_with_opt_collate
{
- if (unlikely(Lex->sphead->fill_field_definition(thd,
- Lex->last_field)))
+ if (unlikely(Lex->sf_return_fill_definition($2)))
MYSQL_YYABORT;
}
;
-sf_c_chistics_and_body:
- sp_c_chistics
- {
- LEX *lex= thd->lex;
- lex->sphead->set_c_chistics(lex->sp_chistics);
- lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start());
- }
- sp_proc_stmt_in_returns_clause
- {
- if (unlikely(Lex->sp_body_finalize_function(thd)))
- MYSQL_YYABORT;
- }
- ;
-
-
-sp_tail:
- sp_name
- {
- if (unlikely(!Lex->make_sp_head_no_recursive(thd, $1,
- &sp_handler_procedure,
- DEFAULT_AGGREGATE)))
- MYSQL_YYABORT;
- }
- sp_parenthesized_pdparam_list
- sp_c_chistics
- {
- Lex->sphead->set_c_chistics(Lex->sp_chistics);
- Lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start());
- }
- sp_proc_stmt
- {
- if (unlikely(Lex->sp_body_finalize_procedure(thd)))
- MYSQL_YYABORT;
- }
- ;
/*************************************************************************/
@@ -18063,7 +17614,10 @@ xid:
}
| text_string ',' text_string ',' ulong_num
{
- MYSQL_YYABORT_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
+ MYSQL_YYABORT_UNLESS($1->length() <= MAXGTRIDSIZE &&
+ $3->length() <= MAXBQUALSIZE &&
+ $5 <= static_cast<ulong>(
+ std::numeric_limits<int32_t>::max()));
if (unlikely(!(Lex->xid=(XID *)thd->alloc(sizeof(XID)))))
MYSQL_YYABORT;
Lex->xid->set($5, $1->ptr(), $1->length(), $3->ptr(), $3->length());
@@ -18133,6 +17687,1419 @@ keep_gcc_happy:
}
;
+_empty:
+ /* Empty */
+ ;
+
+/* Start SQL_MODE_DEFAULT_SPECIFIC */
+
+
+statement:
+ verb_clause
+ ;
+
+sp_statement:
+ statement
+ ;
+
+sp_if_then_statements:
+ sp_proc_stmts1
+ ;
+
+sp_case_then_statements:
+ sp_proc_stmts1
+ ;
+
+reserved_keyword_udt_param_type:
+ INOUT_SYM
+ | IN_SYM
+ | OUT_SYM
+ ;
+
+reserved_keyword_udt:
+ reserved_keyword_udt_not_param_type
+ | reserved_keyword_udt_param_type
+ ;
+
+// Keywords that start an SP block section
+keyword_sp_block_section:
+ BEGIN_MARIADB_SYM
+ | END
+ ;
+
+// Keywords that we allow for labels in SPs.
+// Should not include keywords that start a statement or SP characteristics.
+keyword_label:
+ keyword_data_type
+ | keyword_set_special_case
+ | keyword_sp_var_and_label
+ | keyword_sysvar_type
+ | FUNCTION_SYM
+ | EXCEPTION_ORACLE_SYM
+ ;
+
+keyword_sp_decl:
+ keyword_data_type
+ | keyword_cast_type
+ | keyword_set_special_case
+ | keyword_sp_block_section
+ | keyword_sp_head
+ | keyword_sp_var_and_label
+ | keyword_sp_var_not_label
+ | keyword_sysvar_type
+ | keyword_verb_clause
+ | FUNCTION_SYM
+ | WINDOW_SYM
+ ;
+
+opt_truncate_table_storage_clause:
+ _empty
+ ;
+
+
+ident_for_loop_index:
+ ident
+ ;
+
+row_field_name:
+ ident
+ {
+ if (!($$= Lex->row_field_name(thd, $1)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+while_body:
+ expr_lex DO_SYM
+ {
+ if (unlikely($1->sp_while_loop_expression(thd)))
+ MYSQL_YYABORT;
+ }
+ sp_proc_stmts1 END WHILE_SYM
+ {
+ if (unlikely(Lex->sp_while_loop_finalize(thd)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+for_loop_statements:
+ DO_SYM sp_proc_stmts1 END FOR_SYM
+ { }
+ ;
+
+sp_label:
+ label_ident ':' { $$= $1; }
+ ;
+
+sp_control_label:
+ sp_label
+ ;
+
+sp_block_label:
+ sp_label
+ {
+ if (unlikely(Lex->spcont->block_label_declare(&$1)))
+ MYSQL_YYABORT;
+ $$= $1;
+ }
+ ;
+
+sp_opt_default:
+ _empty { $$ = NULL; }
+ | DEFAULT expr { $$ = $2; }
+ ;
+
+sp_pdparam:
+ sp_parameter_type sp_param_name_and_type { $2->mode=$1; }
+ | sp_param_name_and_type { $1->mode= sp_variable::MODE_IN; }
+ ;
+
+sp_decl_variable_list_anchored:
+ sp_decl_idents_init_vars
+ TYPE_SYM OF_SYM optionally_qualified_column_ident
+ sp_opt_default
+ {
+ if (unlikely(Lex->sp_variable_declarations_with_ref_finalize(thd, $1, $4, $5)))
+ MYSQL_YYABORT;
+ $$.init_using_vars($1);
+ }
+ | sp_decl_idents_init_vars
+ ROW_SYM TYPE_SYM OF_SYM optionally_qualified_column_ident
+ sp_opt_default
+ {
+ if (unlikely(Lex->sp_variable_declarations_rowtype_finalize(thd, $1, $5, $6)))
+ MYSQL_YYABORT;
+ $$.init_using_vars($1);
+ }
+ ;
+
+sp_param_name_and_type_anchored:
+ sp_param_name TYPE_SYM OF_SYM ident '.' ident
+ {
+ if (unlikely(Lex->sphead->spvar_fill_type_reference(thd,
+ $$= $1, $4,
+ $6)))
+ MYSQL_YYABORT;
+ }
+ | sp_param_name TYPE_SYM OF_SYM ident '.' ident '.' ident
+ {
+ if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $$= $1,
+ $4, $6, $8)))
+ MYSQL_YYABORT;
+ }
+ | sp_param_name ROW_SYM TYPE_SYM OF_SYM ident
+ {
+ if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $5)))
+ MYSQL_YYABORT;
+ }
+ | sp_param_name ROW_SYM TYPE_SYM OF_SYM ident '.' ident
+ {
+ if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $5, $7)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+
+sf_c_chistics_and_body_standalone:
+ sp_c_chistics
+ {
+ LEX *lex= thd->lex;
+ lex->sphead->set_c_chistics(lex->sp_chistics);
+ lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start());
+ }
+ sp_proc_stmt_in_returns_clause
+ {
+ if (unlikely(Lex->sp_body_finalize_function(thd)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+sp_tail_standalone:
+ sp_name
+ {
+ if (unlikely(!Lex->make_sp_head_no_recursive(thd, $1,
+ &sp_handler_procedure,
+ DEFAULT_AGGREGATE)))
+ MYSQL_YYABORT;
+ }
+ sp_parenthesized_pdparam_list
+ sp_c_chistics
+ {
+ Lex->sphead->set_c_chistics(Lex->sp_chistics);
+ Lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start());
+ }
+ sp_proc_stmt
+ {
+ if (unlikely(Lex->sp_body_finalize_procedure(thd)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+drop_routine:
+ DROP FUNCTION_SYM opt_if_exists ident '.' ident
+ {
+ if (Lex->stmt_drop_function($3, $4, $6))
+ MYSQL_YYABORT;
+ }
+ | DROP FUNCTION_SYM opt_if_exists ident
+ {
+ if (Lex->stmt_drop_function($3, $4))
+ MYSQL_YYABORT;
+ }
+ | DROP PROCEDURE_SYM opt_if_exists sp_name
+ {
+ if (Lex->stmt_drop_procedure($3, $4))
+ MYSQL_YYABORT;
+ }
+ ;
+
+
+create_routine:
+ create_or_replace definer_opt PROCEDURE_SYM opt_if_not_exists
+ {
+ if (Lex->stmt_create_procedure_start($1 | $4))
+ MYSQL_YYABORT;
+ }
+ sp_tail_standalone
+ {
+ Lex->stmt_create_routine_finalize();
+ }
+ | create_or_replace definer opt_aggregate FUNCTION_SYM opt_if_not_exists
+ sp_name
+ {
+ if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6))
+ MYSQL_YYABORT;
+ }
+ sp_parenthesized_fdparam_list
+ RETURNS_SYM sf_return_type
+ sf_c_chistics_and_body_standalone
+ {
+ Lex->stmt_create_routine_finalize();
+ }
+ | create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists
+ sp_name
+ {
+ if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6))
+ MYSQL_YYABORT;
+ }
+ sp_parenthesized_fdparam_list
+ RETURNS_SYM sf_return_type
+ sf_c_chistics_and_body_standalone
+ {
+ Lex->stmt_create_routine_finalize();
+ }
+ | create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists
+ ident RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
+ {
+ if (Lex->stmt_create_udf_function($1 | $5, $3, $6,
+ (Item_result) $8, $10))
+ MYSQL_YYABORT;
+ }
+ ;
+
+
+sp_decls:
+ _empty
+ {
+ $$.init();
+ }
+ | sp_decls sp_decl ';'
+ {
+ // We check for declarations out of (standard) order this way
+ // because letting the grammar rules reflect it caused tricky
+ // shift/reduce conflicts with the wrong result. (And we get
+ // better error handling this way.)
+ if (unlikely(Lex->sp_declarations_join(&$$, $1, $2)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+sp_decl:
+ DECLARE_MARIADB_SYM sp_decl_body { $$= $2; }
+ ;
+
+
+sp_decl_body:
+ sp_decl_variable_list
+ | sp_decl_ident CONDITION_SYM FOR_SYM sp_cond
+ {
+ if (unlikely(Lex->spcont->declare_condition(thd, &$1, $4)))
+ MYSQL_YYABORT;
+ $$.vars= $$.hndlrs= $$.curs= 0;
+ $$.conds= 1;
+ }
+ | sp_decl_handler
+ | sp_decl_ident CURSOR_SYM
+ {
+ Lex->sp_block_init(thd);
+ }
+ opt_parenthesized_cursor_formal_parameters
+ FOR_SYM sp_cursor_stmt
+ {
+ sp_pcontext *param_ctx= Lex->spcont;
+ if (unlikely(Lex->sp_block_finalize(thd)))
+ MYSQL_YYABORT;
+ if (unlikely(Lex->sp_declare_cursor(thd, &$1, $6, param_ctx, true)))
+ MYSQL_YYABORT;
+ $$.vars= $$.conds= $$.hndlrs= 0;
+ $$.curs= 1;
+ }
+ ;
+
+
+
+// ps_proc_stmt_in_returns_clause is a statement that is allowed
+// in the RETURNS clause of a stored function definition directly,
+// without the BEGIN..END block.
+// It should not include any syntax structures starting with '(', to avoid
+// shift/reduce conflicts with the rule "field_type" and its sub-rules
+// that scan an optional length, like CHAR(1) or YEAR(4).
+// See MDEV-9166.
+
+sp_proc_stmt_in_returns_clause:
+ sp_proc_stmt_return
+ | sp_labeled_block
+ | sp_unlabeled_block
+ | sp_labeled_control
+ | sp_proc_stmt_compound_ok
+ ;
+
+sp_proc_stmt:
+ sp_proc_stmt_in_returns_clause
+ | sp_proc_stmt_statement
+ | sp_proc_stmt_continue_oracle
+ | sp_proc_stmt_exit_oracle
+ | sp_proc_stmt_leave
+ | sp_proc_stmt_iterate
+ | sp_proc_stmt_goto_oracle
+ | sp_proc_stmt_with_cursor
+ ;
+
+sp_proc_stmt_compound_ok:
+ sp_proc_stmt_if
+ | case_stmt_specification
+ | sp_unlabeled_block_not_atomic
+ | sp_unlabeled_control
+ ;
+
+
+sp_labeled_block:
+ sp_block_label
+ BEGIN_MARIADB_SYM
+ {
+ Lex->sp_block_init(thd, &$1);
+ }
+ sp_decls
+ sp_proc_stmts
+ END
+ sp_opt_label
+ {
+ if (unlikely(Lex->sp_block_finalize(thd, $4, &$7)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+sp_unlabeled_block:
+ BEGIN_MARIADB_SYM
+ {
+ Lex->sp_block_init(thd);
+ }
+ sp_decls
+ sp_proc_stmts
+ END
+ {
+ if (unlikely(Lex->sp_block_finalize(thd, $3)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+sp_unlabeled_block_not_atomic:
+ BEGIN_MARIADB_SYM not ATOMIC_SYM // TODO: BEGIN ATOMIC (not -> opt_not)
+ {
+ if (unlikely(Lex->maybe_start_compound_statement(thd)))
+ MYSQL_YYABORT;
+ Lex->sp_block_init(thd);
+ }
+ sp_decls
+ sp_proc_stmts
+ END
+ {
+ if (unlikely(Lex->sp_block_finalize(thd, $5)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+
+/* End SQL_MODE_DEFAULT_SPECIFIC */
+
+
+/* Start SQL_MODE_ORACLE_SPECIFIC
+
+statement:
+ verb_clause
+ | set_assign
+ ;
+
+sp_statement:
+ statement
+ | ident_cli_directly_assignable
+ {
+ // Direct procedure call (without the CALL keyword)
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->call_statement_start(thd, &tmp)))
+ MYSQL_YYABORT;
+ }
+ opt_sp_cparam_list
+ | ident_cli_directly_assignable '.' ident
+ {
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->call_statement_start(thd, &tmp, &$3)))
+ MYSQL_YYABORT;
+ }
+ opt_sp_cparam_list
+ ;
+
+sp_if_then_statements:
+ sp_proc_stmts1_implicit_block { }
+ ;
+
+sp_case_then_statements:
+ sp_proc_stmts1_implicit_block { }
+ ;
+
+reserved_keyword_udt:
+ reserved_keyword_udt_not_param_type
+ ;
+
+// Keywords that start an SP block section.
+keyword_sp_block_section:
+ BEGIN_ORACLE_SYM
+ | END
+ ;
+
+// Keywords that we allow for labels in SPs.
+// Should not include keywords that start a statement or SP characteristics.
+keyword_label:
+ keyword_data_type
+ | keyword_set_special_case
+ | keyword_sp_var_and_label
+ | keyword_sysvar_type
+ | FUNCTION_SYM
+ | COMPRESSED_SYM
+ | EXCEPTION_ORACLE_SYM
+ ;
+
+keyword_sp_decl:
+ keyword_sp_head
+ | keyword_set_special_case
+ | keyword_sp_var_and_label
+ | keyword_sp_var_not_label
+ | keyword_sysvar_type
+ | keyword_verb_clause
+ | WINDOW_SYM
+ ;
+
+opt_truncate_table_storage_clause:
+ _empty
+ | DROP STORAGE_SYM
+ | REUSE_SYM STORAGE_SYM
+ ;
+
+
+ident_for_loop_index:
+ ident_directly_assignable
+ ;
+
+row_field_name:
+ ident_directly_assignable
+ {
+ if (!($$= Lex->row_field_name(thd, $1)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+while_body:
+ expr_lex LOOP_SYM
+ {
+ if (unlikely($1->sp_while_loop_expression(thd)))
+ MYSQL_YYABORT;
+ }
+ sp_proc_stmts1 END LOOP_SYM
+ {
+ if (unlikely(Lex->sp_while_loop_finalize(thd)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+for_loop_statements:
+ LOOP_SYM sp_proc_stmts1 END LOOP_SYM
+ { }
+ ;
+
+
+sp_control_label:
+ labels_declaration_oracle
+ ;
+
+sp_block_label:
+ labels_declaration_oracle
+ {
+ if (unlikely(Lex->spcont->block_label_declare(&$1)))
+ MYSQL_YYABORT;
+ $$= $1;
+ }
+ ;
+
+
+remember_end_opt:
+ {
+ if (yychar == YYEMPTY)
+ $$= (char*) YYLIP->get_cpp_ptr_rtrim();
+ else
+ $$= (char*) YYLIP->get_cpp_tok_end_rtrim();
+ }
+ ;
+
+sp_opt_default:
+ _empty { $$ = NULL; }
+ | DEFAULT expr { $$ = $2; }
+ | SET_VAR expr { $$ = $2; }
+ ;
+
+sp_opt_inout:
+ _empty { $$= sp_variable::MODE_IN; }
+ | sp_parameter_type
+ | IN_SYM OUT_SYM { $$= sp_variable::MODE_INOUT; }
+ ;
+
+sp_pdparam:
+ sp_param_name sp_opt_inout type_with_opt_collate
+ {
+ $1->mode= $2;
+ if (unlikely(Lex->sp_param_fill_definition($1, $3)))
+ MYSQL_YYABORT;
+ }
+ | sp_param_name sp_opt_inout sp_decl_ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM
+ {
+ $1->mode= $2;
+ if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $1, $3, $5)))
+ MYSQL_YYABORT;
+ }
+ | sp_param_name sp_opt_inout sp_decl_ident '.' ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM
+ {
+ $1->mode= $2;
+ if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $1, $3, $5, $7)))
+ MYSQL_YYABORT;
+ }
+ | sp_param_name sp_opt_inout sp_decl_ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM
+ {
+ $1->mode= $2;
+ if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $1, $3)))
+ MYSQL_YYABORT;
+ }
+ | sp_param_name sp_opt_inout sp_decl_ident '.' ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM
+ {
+ $1->mode= $2;
+ if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $1, $3, $5)))
+ MYSQL_YYABORT;
+ }
+ | sp_param_name sp_opt_inout ROW_SYM row_type_body
+ {
+ $1->mode= $2;
+ if (unlikely(Lex->sphead->spvar_fill_row(thd, $1, $4)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+
+sp_proc_stmts1_implicit_block:
+ {
+ Lex->sp_block_init(thd);
+ }
+ sp_proc_stmts1
+ {
+ if (unlikely(Lex->sp_block_finalize(thd)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+
+remember_lex:
+ {
+ $$= thd->lex;
+ }
+ ;
+
+keyword_directly_assignable:
+ keyword_data_type
+ | keyword_cast_type
+ | keyword_set_special_case
+ | keyword_sp_var_and_label
+ | keyword_sp_var_not_label
+ | keyword_sysvar_type
+ | FUNCTION_SYM
+ | WINDOW_SYM
+ ;
+
+ident_directly_assignable:
+ IDENT_sys
+ | keyword_directly_assignable
+ {
+ if (unlikely($$.copy_keyword(thd, &$1)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+ident_cli_directly_assignable:
+ IDENT_cli
+ | keyword_directly_assignable { $$= $1; }
+ ;
+
+
+set_assign:
+ ident_cli_directly_assignable SET_VAR
+ {
+ LEX *lex=Lex;
+ lex->set_stmt_init();
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_variable(&tmp, $4)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY,
+ false)))
+ MYSQL_YYABORT;
+ }
+ | ident_cli_directly_assignable '.' ident SET_VAR
+ {
+ LEX *lex=Lex;
+ lex->set_stmt_init();
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ LEX *lex= Lex;
+ DBUG_ASSERT(lex->var_list.is_empty());
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(lex->set_variable(&tmp, &$3, $6)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY,
+ false)))
+ MYSQL_YYABORT;
+ }
+ | COLON_ORACLE_SYM ident '.' ident SET_VAR
+ {
+ LEX *lex= Lex;
+ if (unlikely(!lex->is_trigger_new_or_old_reference(&$2)))
+ {
+ thd->parse_error(ER_SYNTAX_ERROR, $1.pos());
+ MYSQL_YYABORT;
+ }
+ lex->set_stmt_init();
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ LEX_CSTRING tmp= { $2.str, $2.length };
+ if (unlikely(Lex->set_trigger_field(&tmp, &$4, $7)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY,
+ false)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+
+labels_declaration_oracle:
+ label_declaration_oracle { $$= $1; }
+ | labels_declaration_oracle label_declaration_oracle { $$= $2; }
+ ;
+
+label_declaration_oracle:
+ SHIFT_LEFT label_ident SHIFT_RIGHT
+ {
+ if (unlikely(Lex->sp_push_goto_label(thd, &$2)))
+ MYSQL_YYABORT;
+ $$= $2;
+ }
+ ;
+
+opt_exception_clause:
+ _empty { $$= 0; }
+ | EXCEPTION_ORACLE_SYM exception_handlers { $$= $2; }
+ ;
+
+exception_handlers:
+ exception_handler { $$= 1; }
+ | exception_handlers exception_handler { $$= $1 + 1; }
+ ;
+
+exception_handler:
+ WHEN_SYM
+ {
+ if (unlikely(Lex->sp_handler_declaration_init(thd, sp_handler::EXIT)))
+ MYSQL_YYABORT;
+ }
+ sp_hcond_list
+ THEN_SYM
+ sp_proc_stmts1_implicit_block
+ {
+ if (unlikely(Lex->sp_handler_declaration_finalize(thd, sp_handler::EXIT)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+sp_no_param:
+ _empty
+ {
+ Lex->sphead->m_param_begin= Lex->sphead->m_param_end=
+ YYLIP->get_cpp_tok_start() + 1;
+ }
+ ;
+
+opt_sp_parenthesized_fdparam_list:
+ sp_no_param
+ | sp_parenthesized_fdparam_list
+ ;
+
+opt_sp_parenthesized_pdparam_list:
+ sp_no_param
+ | sp_parenthesized_pdparam_list
+ ;
+
+
+opt_sp_name:
+ _empty { $$= NULL; }
+ | sp_name { $$= $1; }
+ ;
+
+
+opt_package_routine_end_name:
+ _empty { $$= null_clex_str; }
+ | ident { $$= $1; }
+ ;
+
+sp_tail_is:
+ IS
+ | AS
+ ;
+
+sp_instr_addr:
+ { $$= Lex->sphead->instructions(); }
+ ;
+
+sp_body:
+ {
+ Lex->sp_block_init(thd);
+ }
+ opt_sp_decl_body_list
+ {
+ if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd)))
+ MYSQL_YYABORT;
+ }
+ BEGIN_ORACLE_SYM
+ sp_block_statements_and_exceptions
+ {
+ $2.hndlrs+= $5.hndlrs;
+ if (unlikely(Lex->sp_block_finalize(thd, $2)))
+ MYSQL_YYABORT;
+ }
+ END
+ ;
+
+create_package_chistic:
+ COMMENT_SYM TEXT_STRING_sys
+ { Lex->sp_chistics.comment= $2; }
+ | sp_suid
+ { Lex->sp_chistics.suid= $1; }
+ ;
+
+create_package_chistics:
+ create_package_chistic {}
+ | create_package_chistics create_package_chistic { }
+ ;
+
+opt_create_package_chistics:
+ _empty
+ | create_package_chistics { }
+ ;
+
+opt_create_package_chistics_init:
+ { Lex->sp_chistics.init(); }
+ opt_create_package_chistics
+ ;
+
+
+package_implementation_executable_section:
+ END
+ {
+ if (unlikely(Lex->sp_block_with_exceptions_add_empty(thd)))
+ MYSQL_YYABORT;
+ $$.init(0);
+ }
+ | BEGIN_ORACLE_SYM sp_block_statements_and_exceptions END { $$= $2; }
+ ;
+
+
+// Inside CREATE PACKAGE BODY, package-wide items (e.g. variables)
+// must be declared before routine definitions.
+
+package_implementation_declare_section:
+ package_implementation_declare_section_list1
+ | package_implementation_declare_section_list2
+ | package_implementation_declare_section_list1
+ package_implementation_declare_section_list2
+ { $$.join($1, $2); }
+ ;
+
+package_implementation_declare_section_list1:
+ package_implementation_item_declaration
+ | package_implementation_declare_section_list1
+ package_implementation_item_declaration
+ { $$.join($1, $2); }
+ ;
+
+package_implementation_declare_section_list2:
+ package_implementation_routine_definition
+ | package_implementation_declare_section_list2
+ package_implementation_routine_definition
+ { $$.join($1, $2); }
+ ;
+
+package_routine_lex:
+ {
+ if (unlikely(!($$= new (thd->mem_root)
+ sp_lex_local(thd, thd->lex))))
+ MYSQL_YYABORT;
+ thd->m_parser_state->m_yacc.reset_before_substatement();
+ }
+ ;
+
+
+package_specification_function:
+ remember_lex package_routine_lex ident
+ {
+ DBUG_ASSERT($1->sphead->get_package());
+ $2->sql_command= SQLCOM_CREATE_FUNCTION;
+ sp_name *spname= $1->make_sp_name_package_routine(thd, &$3);
+ if (unlikely(!spname))
+ MYSQL_YYABORT;
+ thd->lex= $2;
+ if (unlikely(!$2->make_sp_head_no_recursive(thd, spname,
+ &sp_handler_package_function,
+ NOT_AGGREGATE)))
+ MYSQL_YYABORT;
+ $1->sphead->get_package()->m_current_routine= $2;
+ (void) is_native_function_with_warn(thd, &$3);
+ }
+ opt_sp_parenthesized_fdparam_list
+ RETURN_ORACLE_SYM sf_return_type
+ sp_c_chistics
+ {
+ sp_head *sp= thd->lex->sphead;
+ sp->restore_thd_mem_root(thd);
+ thd->lex= $1;
+ $$= $2;
+ }
+ ;
+
+package_specification_procedure:
+ remember_lex package_routine_lex ident
+ {
+ DBUG_ASSERT($1->sphead->get_package());
+ $2->sql_command= SQLCOM_CREATE_PROCEDURE;
+ sp_name *spname= $1->make_sp_name_package_routine(thd, &$3);
+ if (unlikely(!spname))
+ MYSQL_YYABORT;
+ thd->lex= $2;
+ if (unlikely(!$2->make_sp_head_no_recursive(thd, spname,
+ &sp_handler_package_procedure,
+ DEFAULT_AGGREGATE)))
+ MYSQL_YYABORT;
+ $1->sphead->get_package()->m_current_routine= $2;
+ }
+ opt_sp_parenthesized_pdparam_list
+ sp_c_chistics
+ {
+ sp_head *sp= thd->lex->sphead;
+ sp->restore_thd_mem_root(thd);
+ thd->lex= $1;
+ $$= $2;
+ }
+ ;
+
+
+package_implementation_routine_definition:
+ FUNCTION_SYM package_specification_function
+ package_implementation_function_body ';'
+ {
+ sp_package *pkg= Lex->get_sp_package();
+ if (unlikely(pkg->add_routine_implementation($2)))
+ MYSQL_YYABORT;
+ pkg->m_current_routine= NULL;
+ $$.init();
+ }
+ | PROCEDURE_SYM package_specification_procedure
+ package_implementation_procedure_body ';'
+ {
+ sp_package *pkg= Lex->get_sp_package();
+ if (unlikely(pkg->add_routine_implementation($2)))
+ MYSQL_YYABORT;
+ pkg->m_current_routine= NULL;
+ $$.init();
+ }
+ | package_specification_element { $$.init(); }
+ ;
+
+
+package_implementation_function_body:
+ sp_tail_is remember_lex
+ {
+ sp_package *pkg= Lex->get_sp_package();
+ sp_head *sp= pkg->m_current_routine->sphead;
+ thd->lex= pkg->m_current_routine;
+ sp->reset_thd_mem_root(thd);
+ sp->set_body_start(thd, YYLIP->get_cpp_tok_start());
+ }
+ sp_body opt_package_routine_end_name
+ {
+ if (unlikely(thd->lex->sp_body_finalize_function(thd) ||
+ thd->lex->sphead->check_package_routine_end_name($5)))
+ MYSQL_YYABORT;
+ thd->lex= $2;
+ }
+ ;
+
+package_implementation_procedure_body:
+ sp_tail_is remember_lex
+ {
+ sp_package *pkg= Lex->get_sp_package();
+ sp_head *sp= pkg->m_current_routine->sphead;
+ thd->lex= pkg->m_current_routine;
+ sp->reset_thd_mem_root(thd);
+ sp->set_body_start(thd, YYLIP->get_cpp_tok_start());
+ }
+ sp_body opt_package_routine_end_name
+ {
+ if (unlikely(thd->lex->sp_body_finalize_procedure(thd) ||
+ thd->lex->sphead->check_package_routine_end_name($5)))
+ MYSQL_YYABORT;
+ thd->lex= $2;
+ }
+ ;
+
+
+package_implementation_item_declaration:
+ sp_decl_variable_list ';'
+ ;
+
+opt_package_specification_element_list:
+ _empty
+ | package_specification_element_list
+ ;
+
+package_specification_element_list:
+ package_specification_element
+ | package_specification_element_list package_specification_element
+ ;
+
+package_specification_element:
+ FUNCTION_SYM package_specification_function ';'
+ {
+ sp_package *pkg= Lex->get_sp_package();
+ if (unlikely(pkg->add_routine_declaration($2)))
+ MYSQL_YYABORT;
+ pkg->m_current_routine= NULL;
+ }
+ | PROCEDURE_SYM package_specification_procedure ';'
+ {
+ sp_package *pkg= Lex->get_sp_package();
+ if (unlikely(pkg->add_routine_declaration($2)))
+ MYSQL_YYABORT;
+ pkg->m_current_routine= NULL;
+ }
+ ;
+
+sp_decl_variable_list_anchored:
+ sp_decl_idents_init_vars
+ optionally_qualified_column_ident PERCENT_ORACLE_SYM TYPE_SYM
+ sp_opt_default
+ {
+ if (unlikely(Lex->sp_variable_declarations_with_ref_finalize(thd, $1, $2, $5)))
+ MYSQL_YYABORT;
+ $$.init_using_vars($1);
+ }
+ | sp_decl_idents_init_vars
+ optionally_qualified_column_ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM
+ sp_opt_default
+ {
+ if (unlikely(Lex->sp_variable_declarations_rowtype_finalize(thd, $1, $2, $5)))
+ MYSQL_YYABORT;
+ $$.init_using_vars($1);
+ }
+ ;
+
+sp_param_name_and_type_anchored:
+ sp_param_name sp_decl_ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM
+ {
+ if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $$= $1, $2, $4)))
+ MYSQL_YYABORT;
+ }
+ | sp_param_name sp_decl_ident '.' ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM
+ {
+ if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $$= $1, $2, $4, $6)))
+ MYSQL_YYABORT;
+ }
+ | sp_param_name sp_decl_ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM
+ {
+ if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $2)))
+ MYSQL_YYABORT;
+ }
+ | sp_param_name sp_decl_ident '.' ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM
+ {
+ if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $2, $4)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+
+sf_c_chistics_and_body_standalone:
+ sp_c_chistics
+ {
+ LEX *lex= thd->lex;
+ lex->sphead->set_c_chistics(lex->sp_chistics);
+ lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start());
+ }
+ sp_tail_is
+ sp_body
+ {
+ if (unlikely(Lex->sp_body_finalize_function(thd)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+sp_tail_standalone:
+ sp_name
+ {
+ if (unlikely(!Lex->make_sp_head_no_recursive(thd, $1,
+ &sp_handler_procedure,
+ DEFAULT_AGGREGATE)))
+ MYSQL_YYABORT;
+ }
+ opt_sp_parenthesized_pdparam_list
+ sp_c_chistics
+ {
+ Lex->sphead->set_c_chistics(Lex->sp_chistics);
+ Lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start());
+ }
+ sp_tail_is
+ sp_body
+ opt_sp_name
+ {
+ if (unlikely(Lex->sp_body_finalize_procedure_standalone(thd, $8)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+drop_routine:
+ DROP FUNCTION_SYM opt_if_exists ident '.' ident
+ {
+ if (Lex->stmt_drop_function($3, $4, $6))
+ MYSQL_YYABORT;
+ }
+ | DROP FUNCTION_SYM opt_if_exists ident
+ {
+ if (Lex->stmt_drop_function($3, $4))
+ MYSQL_YYABORT;
+ }
+ | DROP PROCEDURE_SYM opt_if_exists sp_name
+ {
+ if (Lex->stmt_drop_procedure($3, $4))
+ MYSQL_YYABORT;
+ }
+ | DROP PACKAGE_ORACLE_SYM opt_if_exists sp_name
+ {
+ LEX *lex= Lex;
+ lex->set_command(SQLCOM_DROP_PACKAGE, $3);
+ if (unlikely(lex->sphead))
+ my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PACKAGE"));
+ lex->spname= $4;
+ }
+ | DROP PACKAGE_ORACLE_SYM BODY_ORACLE_SYM opt_if_exists sp_name
+ {
+ LEX *lex= Lex;
+ lex->set_command(SQLCOM_DROP_PACKAGE_BODY, $4);
+ if (unlikely(lex->sphead))
+ my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PACKAGE BODY"));
+ lex->spname= $5;
+ }
+ ;
+
+
+create_routine:
+ create_or_replace definer_opt PROCEDURE_SYM opt_if_not_exists
+ {
+ if (Lex->stmt_create_procedure_start($1 | $4))
+ MYSQL_YYABORT;
+ }
+ sp_tail_standalone
+ {
+ Lex->stmt_create_routine_finalize();
+ }
+ | create_or_replace definer opt_aggregate FUNCTION_SYM opt_if_not_exists
+ sp_name
+ {
+ if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6))
+ MYSQL_YYABORT;
+ }
+ opt_sp_parenthesized_fdparam_list
+ RETURN_ORACLE_SYM sf_return_type
+ sf_c_chistics_and_body_standalone
+ opt_sp_name
+ {
+ if (Lex->stmt_create_stored_function_finalize_standalone($12))
+ MYSQL_YYABORT;
+ }
+ | create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists
+ sp_name
+ {
+ if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6))
+ MYSQL_YYABORT;
+ }
+ opt_sp_parenthesized_fdparam_list
+ RETURN_ORACLE_SYM sf_return_type
+ sf_c_chistics_and_body_standalone
+ opt_sp_name
+ {
+ if (Lex->stmt_create_stored_function_finalize_standalone($12))
+ MYSQL_YYABORT;
+ }
+ | create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists
+ ident RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
+ {
+ if (Lex->stmt_create_udf_function($1 | $5, $3, $6,
+ (Item_result) $8, $10))
+ MYSQL_YYABORT;
+ }
+ | create_or_replace definer_opt PACKAGE_ORACLE_SYM
+ opt_if_not_exists sp_name opt_create_package_chistics_init
+ sp_tail_is
+ remember_name
+ {
+ sp_package *pkg;
+ if (unlikely(!(pkg= Lex->
+ create_package_start(thd,
+ SQLCOM_CREATE_PACKAGE,
+ &sp_handler_package_spec,
+ $5, $1 | $4))))
+ MYSQL_YYABORT;
+ pkg->set_c_chistics(Lex->sp_chistics);
+ }
+ opt_package_specification_element_list END
+ remember_end_opt opt_sp_name
+ {
+ if (unlikely(Lex->create_package_finalize(thd, $5, $13, $8, $12)))
+ MYSQL_YYABORT;
+ }
+ | create_or_replace definer_opt PACKAGE_ORACLE_SYM BODY_ORACLE_SYM
+ opt_if_not_exists sp_name opt_create_package_chistics_init
+ sp_tail_is
+ remember_name
+ {
+ sp_package *pkg;
+ if (unlikely(!(pkg= Lex->
+ create_package_start(thd,
+ SQLCOM_CREATE_PACKAGE_BODY,
+ &sp_handler_package_body,
+ $6, $1 | $5))))
+ MYSQL_YYABORT;
+ pkg->set_c_chistics(Lex->sp_chistics);
+ Lex->sp_block_init(thd);
+ }
+ package_implementation_declare_section
+ {
+ if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd)))
+ MYSQL_YYABORT;
+ }
+ package_implementation_executable_section
+ {
+ $11.hndlrs+= $13.hndlrs;
+ if (unlikely(Lex->sp_block_finalize(thd, $11)))
+ MYSQL_YYABORT;
+ }
+ remember_end_opt opt_sp_name
+ {
+ if (unlikely(Lex->create_package_finalize(thd, $6, $16, $9, $15)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+opt_sp_decl_body_list:
+ _empty
+ {
+ $$.init();
+ }
+ | sp_decl_body_list { $$= $1; }
+ ;
+
+sp_decl_body_list:
+ sp_decl_non_handler_list
+ {
+ if (unlikely(Lex->sphead->sp_add_instr_cpush_for_cursors(thd, Lex->spcont)))
+ MYSQL_YYABORT;
+ }
+ opt_sp_decl_handler_list
+ {
+ $$.join($1, $3);
+ }
+ | sp_decl_handler_list
+ ;
+
+sp_decl_non_handler_list:
+ sp_decl_non_handler ';' { $$= $1; }
+ | sp_decl_non_handler_list sp_decl_non_handler ';'
+ {
+ $$.join($1, $2);
+ }
+ ;
+
+sp_decl_handler_list:
+ sp_decl_handler ';' { $$= $1; }
+ | sp_decl_handler_list sp_decl_handler ';'
+ {
+ $$.join($1, $2);
+ }
+ ;
+
+opt_sp_decl_handler_list:
+ _empty { $$.init(); }
+ | sp_decl_handler_list
+ ;
+
+sp_decl_non_handler:
+ sp_decl_variable_list
+ | ident_directly_assignable CONDITION_SYM FOR_SYM sp_cond
+ {
+ if (unlikely(Lex->spcont->declare_condition(thd, &$1, $4)))
+ MYSQL_YYABORT;
+ $$.vars= $$.hndlrs= $$.curs= 0;
+ $$.conds= 1;
+ }
+ | ident_directly_assignable EXCEPTION_ORACLE_SYM
+ {
+ sp_condition_value *spcond= new (thd->mem_root)
+ sp_condition_value_user_defined();
+ if (unlikely(!spcond) ||
+ unlikely(Lex->spcont->declare_condition(thd, &$1, spcond)))
+ MYSQL_YYABORT;
+ $$.vars= $$.hndlrs= $$.curs= 0;
+ $$.conds= 1;
+ }
+ | CURSOR_SYM ident_directly_assignable
+ {
+ Lex->sp_block_init(thd);
+ }
+ opt_parenthesized_cursor_formal_parameters
+ IS sp_cursor_stmt
+ {
+ sp_pcontext *param_ctx= Lex->spcont;
+ if (unlikely(Lex->sp_block_finalize(thd)))
+ MYSQL_YYABORT;
+ if (unlikely(Lex->sp_declare_cursor(thd, &$2, $6, param_ctx, false)))
+ MYSQL_YYABORT;
+ $$.vars= $$.conds= $$.hndlrs= 0;
+ $$.curs= 1;
+ }
+ ;
+
+
+sp_proc_stmt:
+ sp_labeled_block
+ | sp_unlabeled_block
+ | sp_labeled_control
+ | sp_unlabeled_control
+ | sp_labelable_stmt
+ | labels_declaration_oracle sp_labelable_stmt {}
+ ;
+
+sp_labelable_stmt:
+ sp_proc_stmt_statement
+ | sp_proc_stmt_continue_oracle
+ | sp_proc_stmt_exit_oracle
+ | sp_proc_stmt_leave
+ | sp_proc_stmt_iterate
+ | sp_proc_stmt_goto_oracle
+ | sp_proc_stmt_with_cursor
+ | sp_proc_stmt_return
+ | sp_proc_stmt_if
+ | case_stmt_specification
+ | NULL_SYM { }
+ ;
+
+sp_proc_stmt_compound_ok:
+ sp_proc_stmt_if
+ | case_stmt_specification
+ | sp_unlabeled_block
+ | sp_unlabeled_control
+ ;
+
+
+sp_labeled_block:
+ sp_block_label
+ BEGIN_ORACLE_SYM
+ {
+ Lex->sp_block_init(thd, &$1);
+ if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd)))
+ MYSQL_YYABORT;
+ }
+ sp_block_statements_and_exceptions
+ END
+ sp_opt_label
+ {
+ if (unlikely(Lex->sp_block_finalize(thd, Lex_spblock($4), &$6)))
+ MYSQL_YYABORT;
+ }
+ | sp_block_label
+ DECLARE_ORACLE_SYM
+ {
+ Lex->sp_block_init(thd, &$1);
+ }
+ sp_decl_body_list
+ {
+ if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd)))
+ MYSQL_YYABORT;
+ }
+ BEGIN_ORACLE_SYM
+ sp_block_statements_and_exceptions
+ END
+ sp_opt_label
+ {
+ $4.hndlrs+= $7.hndlrs;
+ if (unlikely(Lex->sp_block_finalize(thd, $4, &$9)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+opt_not_atomic:
+ _empty
+ | not ATOMIC_SYM // TODO: BEGIN ATOMIC (not -> opt_not)
+ ;
+
+sp_unlabeled_block:
+ BEGIN_ORACLE_SYM opt_not_atomic
+ {
+ if (unlikely(Lex->maybe_start_compound_statement(thd)))
+ MYSQL_YYABORT;
+ Lex->sp_block_init(thd);
+ if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd)))
+ MYSQL_YYABORT;
+ }
+ sp_block_statements_and_exceptions
+ END
+ {
+ if (unlikely(Lex->sp_block_finalize(thd, Lex_spblock($4))))
+ MYSQL_YYABORT;
+ }
+ | DECLARE_ORACLE_SYM
+ {
+ if (unlikely(Lex->maybe_start_compound_statement(thd)))
+ MYSQL_YYABORT;
+ Lex->sp_block_init(thd);
+ }
+ sp_decl_body_list
+ {
+ if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd)))
+ MYSQL_YYABORT;
+ }
+ BEGIN_ORACLE_SYM
+ sp_block_statements_and_exceptions
+ END
+ {
+ $3.hndlrs+= $6.hndlrs;
+ if (unlikely(Lex->sp_block_finalize(thd, $3)))
+ MYSQL_YYABORT;
+ }
+ ;
+
+sp_block_statements_and_exceptions:
+ sp_instr_addr
+ sp_proc_stmts
+ {
+ if (unlikely(Lex->sp_block_with_exceptions_finalize_executable_section(thd, $1)))
+ MYSQL_YYABORT;
+ }
+ opt_exception_clause
+ {
+ if (unlikely(Lex->sp_block_with_exceptions_finalize_exceptions(thd, $1, $4)))
+ MYSQL_YYABORT;
+ $$.init($4);
+ }
+ ;
+
+End SQL_MODE_ORACLE_SPECIFIC */
+
/**
@} (end of group Parser)
*/
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
deleted file mode 100644
index 01ef3da3ba9..00000000000
--- a/sql/sql_yacc_ora.yy
+++ /dev/null
@@ -1,18369 +0,0 @@
-/*
- Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2010, 2019, 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 St, Fifth Floor, Boston, MA 02110-1335 USA */
-
-/* sql_yacc.yy */
-
-/**
- @defgroup Parser Parser
- @{
-*/
-
-%{
-#define YYLIP (& thd->m_parser_state->m_lip)
-#define YYPS (& thd->m_parser_state->m_yacc)
-#define YYCSCL (thd->variables.character_set_client)
-
-#define MYSQL_YACC
-#define YYINITDEPTH 100
-#define YYMAXDEPTH 3200 /* Because of 64K stack */
-#define Lex (thd->lex)
-
-#define Select Lex->current_select
-#include "mariadb.h"
-#include "sql_priv.h"
-#include "sql_parse.h" /* comp_*_creator */
-#include "sql_table.h" /* primary_key_name */
-#include "sql_partition.h" /* partition_info, HASH_PARTITION */
-#include "sql_acl.h" /* *_ACL */
-#include "sql_class.h" /* Key_part_spec, enum_filetype, Diag_condition_item_name */
-#include "slave.h"
-#include "lex_symbol.h"
-#include "item_create.h"
-#include "sp_head.h"
-#include "sp_rcontext.h"
-#include "sp.h"
-#include "sql_show.h"
-#include "sql_alter.h" // Sql_cmd_alter_table*
-#include "sql_truncate.h" // Sql_cmd_truncate_table
-#include "sql_admin.h" // Sql_cmd_analyze/Check..._table
-#include "sql_partition_admin.h" // Sql_cmd_alter_table_*_part.
-#include "sql_handler.h" // Sql_cmd_handler_*
-#include "sql_signal.h"
-#include "sql_get_diagnostics.h" // Sql_cmd_get_diagnostics
-#include "sql_cte.h"
-#include "sql_window.h"
-#include "item_windowfunc.h"
-#include "event_parse_data.h"
-#include "create_options.h"
-#include <myisam.h>
-#include <myisammrg.h>
-#include "keycaches.h"
-#include "set_var.h"
-#include "rpl_mi.h"
-#include "lex_token.h"
-#include "sql_lex.h"
-#include "sql_sequence.h"
-#include "my_base.h"
-#include "sql_type_json.h"
-
-/* this is to get the bison compilation windows warnings out */
-#ifdef _MSC_VER
-/* warning C4065: switch statement contains 'default' but no 'case' labels */
-#pragma warning (disable : 4065)
-#endif
-
-int yylex(void *yylval, void *yythd);
-
-#define yyoverflow(A,B,C,D,E,F) \
- { \
- size_t val= *(F); \
- if (unlikely(my_yyoverflow((B), (D), &val))) \
- { \
- yyerror(thd, (char*) (A)); \
- return 2; \
- } \
- else \
- { \
- *(F)= (YYSIZE_T)val; \
- } \
- }
-
-#define MYSQL_YYABORT \
- do \
- { \
- LEX::cleanup_lex_after_parse_error(thd); \
- YYABORT; \
- } while (0)
-
-#define MYSQL_YYABORT_UNLESS(A) \
- if (unlikely(!(A))) \
- { \
- thd->parse_error(); \
- MYSQL_YYABORT; \
- }
-
-#define my_yyabort_error(A) \
- do { my_error A; MYSQL_YYABORT; } while(0)
-
-#ifndef DBUG_OFF
-#define YYDEBUG 1
-#else
-#define YYDEBUG 0
-#endif
-
-
-/**
- @brief Bison callback to report a syntax/OOM error
-
- This function is invoked by the bison-generated parser
- when a syntax error, a parse error or an out-of-memory
- condition occurs. This function is not invoked when the
- parser is requested to abort by semantic action code
- by means of YYABORT or YYACCEPT macros. This is why these
- macros should not be used (use MYSQL_YYABORT/MYSQL_YYACCEPT
- instead).
-
- The parser will abort immediately after invoking this callback.
-
- This function is not for use in semantic actions and is internal to
- the parser, as it performs some pre-return cleanup.
- In semantic actions, please use thd->parse_error() or my_error to
- push an error into the error stack and MYSQL_YYABORT
- to abort from the parser.
-*/
-
-void ORAerror(THD *thd, const char *s)
-{
- /*
- Restore the original LEX if it was replaced when parsing
- a stored procedure. We must ensure that a parsing error
- does not leave any side effects in the THD.
- */
- LEX::cleanup_lex_after_parse_error(thd);
-
- /* "parse error" changed into "syntax error" between bison 1.75 and 1.875 */
- if (strcmp(s,"parse error") == 0 || strcmp(s,"syntax error") == 0)
- s= ER_THD(thd, ER_SYNTAX_ERROR);
- thd->parse_error(s, 0);
-}
-
-
-
-
-#define bincmp_collation(X,Y) \
- do \
- { \
- if (unlikely(Lex->set_bincmp(X,Y))) \
- MYSQL_YYABORT; \
- } while(0)
-
-%}
-%union {
- int num;
- ulong ulong_num;
- ulonglong ulonglong_number;
- longlong longlong_number;
- uint sp_instr_addr;
-
- /* structs */
- LEX_CSTRING lex_str;
- Lex_ident_cli_st kwd;
- Lex_ident_cli_st ident_cli;
- Lex_ident_sys_st ident_sys;
- Lex_string_with_metadata_st lex_string_with_metadata;
- Lex_spblock_st spblock;
- Lex_spblock_handlers_st spblock_handlers;
- Lex_length_and_dec_st Lex_length_and_dec;
- Lex_cast_type_st Lex_cast_type;
- Lex_field_type_st Lex_field_type;
- Lex_dyncol_type_st Lex_dyncol_type;
- Lex_for_loop_st for_loop;
- Lex_for_loop_bounds_st for_loop_bounds;
- Lex_trim_st trim;
- vers_history_point_t vers_history_point;
- struct
- {
- enum sub_select_type unit_type;
- bool distinct;
- } unit_operation;
- struct
- {
- SELECT_LEX *first;
- SELECT_LEX *prev_last;
- } select_list;
- SQL_I_List<ORDER> *select_order;
- Lex_select_lock select_lock;
- Lex_select_limit select_limit;
- Lex_order_limit_lock *order_limit_lock;
-
- /* pointers */
- Create_field *create_field;
- Spvar_definition *spvar_definition;
- Row_definition_list *spvar_definition_list;
- const Type_handler *type_handler;
- CHARSET_INFO *charset;
- Condition_information_item *cond_info_item;
- DYNCALL_CREATE_DEF *dyncol_def;
- Diagnostics_information *diag_info;
- Item *item;
- Item_num *item_num;
- Item_param *item_param;
- Item_basic_constant *item_basic_constant;
- Key_part_spec *key_part;
- LEX *lex;
- sp_assignment_lex *assignment_lex;
- class sp_lex_cursor *sp_cursor_stmt;
- LEX_CSTRING *lex_str_ptr;
- LEX_USER *lex_user;
- USER_AUTH *user_auth;
- List<Condition_information_item> *cond_info_list;
- List<DYNCALL_CREATE_DEF> *dyncol_def_list;
- List<Item> *item_list;
- List<sp_assignment_lex> *sp_assignment_lex_list;
- List<Statement_information_item> *stmt_info_list;
- List<String> *string_list;
- List<LEX_CSTRING> *lex_str_list;
- Statement_information_item *stmt_info_item;
- String *string;
- TABLE_LIST *table_list;
- Table_ident *table;
- Qualified_column_ident *qualified_column_ident;
- char *simple_string;
- const char *const_simple_string;
- chooser_compare_func_creator boolfunc2creator;
- class my_var *myvar;
- class sp_condition_value *spcondvalue;
- class sp_head *sphead;
- class sp_name *spname;
- class sp_variable *spvar;
- class With_clause *with_clause;
- class Virtual_column_info *virtual_column;
-
- handlerton *db_type;
- st_select_lex *select_lex;
- st_select_lex_unit *select_lex_unit;
- struct p_elem_val *p_elem_value;
- class Window_frame *window_frame;
- class Window_frame_bound *window_frame_bound;
- udf_func *udf;
- st_trg_execution_order trg_execution_order;
-
- /* enums */
- enum enum_sp_suid_behaviour sp_suid;
- enum enum_sp_aggregate_type sp_aggregate_type;
- enum enum_view_suid view_suid;
- enum Condition_information_item::Name cond_info_item_name;
- enum enum_diag_condition_item_name diag_condition_item_name;
- enum Diagnostics_information::Which_area diag_area;
- enum Field::geometry_type geom_type;
- enum enum_fk_option m_fk_option;
- enum Item_udftype udf_type;
- enum Key::Keytype key_type;
- enum Statement_information_item::Name stmt_info_item_name;
- enum enum_filetype filetype;
- enum enum_tx_isolation tx_isolation;
- enum enum_var_type var_type;
- enum enum_yes_no_unknown m_yes_no_unk;
- enum ha_choice choice;
- enum ha_key_alg key_alg;
- enum ha_rkey_function ha_rkey_mode;
- enum index_hint_type index_hint;
- enum interval_type interval, interval_time_st;
- enum row_type row_type;
- enum sp_variable::enum_mode spvar_mode;
- enum thr_lock_type lock_type;
- enum enum_mysql_timestamp_type date_time_type;
- enum Window_frame_bound::Bound_precedence_type bound_precedence_type;
- enum Window_frame::Frame_units frame_units;
- enum Window_frame::Frame_exclusion frame_exclusion;
- enum trigger_order_type trigger_action_order_type;
- DDL_options_st object_ddl_options;
- enum vers_sys_type_t vers_range_unit;
- enum Column_definition::enum_column_versioning vers_column_versioning;
- enum plsql_cursor_attr_t plsql_cursor_attr;
-}
-
-%{
-bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
-%}
-
-%pure-parser /* We have threads */
-%parse-param { THD *thd }
-%lex-param { THD *thd }
-/*
- Currently there are 41 shift/reduce conflicts.
- We should not introduce new conflicts any more.
-*/
-%expect 41
-
-/*
- Comments for TOKENS.
- For each token, please include in the same line a comment that contains
- the following tags:
- SQL-2011-R : Reserved keyword as per SQL-2011
- SQL-2011-N : Non Reserved keyword as per SQL-2011
- SQL-2003-R : Reserved keyword as per SQL-2003
- SQL-2003-N : Non Reserved keyword as per SQL-2003
- SQL-1999-R : Reserved keyword as per SQL-1999
- SQL-1999-N : Non Reserved keyword as per SQL-1999
- MYSQL : MySQL extention (unspecified)
- MYSQL-FUNC : MySQL extention, function
- INTERNAL : Not a real token, lex optimization
- OPERATOR : SQL operator
- FUTURE-USE : Reserved for future use
-
- This makes the code grep-able, and helps maintenance.
-*/
-
-
-/*
- Reserved keywords and operators
-*/
-%token ABORT_SYM /* INTERNAL (used in lex) */
-%token ACCESSIBLE_SYM
-%token ADD /* SQL-2003-R */
-%token ALL /* SQL-2003-R */
-%token ALTER /* SQL-2003-R */
-%token ANALYZE_SYM
-%token AND_AND_SYM /* OPERATOR */
-%token AND_SYM /* SQL-2003-R */
-%token AS /* SQL-2003-R */
-%token ASC /* SQL-2003-N */
-%token ASENSITIVE_SYM /* FUTURE-USE */
-%token BEFORE_SYM /* SQL-2003-N */
-%token BETWEEN_SYM /* SQL-2003-R */
-%token BIGINT /* SQL-2003-R */
-%token BINARY /* SQL-2003-R */
-%token BIN_NUM
-%token BIT_AND /* MYSQL-FUNC */
-%token BIT_OR /* MYSQL-FUNC */
-%token BIT_XOR /* MYSQL-FUNC */
-%token BLOB_MARIADB_SYM /* SQL-2003-R */
-%token BLOB_ORACLE_SYM /* Oracle-R */
-%token BODY_ORACLE_SYM /* Oracle-R */
-%token BOTH /* SQL-2003-R */
-%token BY /* SQL-2003-R */
-%token CALL_SYM /* SQL-2003-R */
-%token CASCADE /* SQL-2003-N */
-%token CASE_SYM /* SQL-2003-R */
-%token CAST_SYM /* SQL-2003-R */
-%token CHANGE
-%token CHAR_SYM /* SQL-2003-R */
-%token CHECK_SYM /* SQL-2003-R */
-%token COLLATE_SYM /* SQL-2003-R */
-%token CONDITION_SYM /* SQL-2003-R, SQL-2008-R */
-%token CONSTRAINT /* SQL-2003-R */
-%token CONTINUE_MARIADB_SYM /* SQL-2003-R, Oracle-R */
-%token CONTINUE_ORACLE_SYM /* SQL-2003-R, Oracle-R */
-%token CONVERT_SYM /* SQL-2003-N */
-%token COUNT_SYM /* SQL-2003-N */
-%token CREATE /* SQL-2003-R */
-%token CROSS /* SQL-2003-R */
-%token CUME_DIST_SYM
-%token CURDATE /* MYSQL-FUNC */
-%token CURRENT_USER /* SQL-2003-R */
-%token CURRENT_ROLE /* SQL-2003-R */
-%token CURSOR_SYM /* SQL-2003-R */
-%token CURTIME /* MYSQL-FUNC */
-%token DATABASE
-%token DATABASES
-%token DATE_ADD_INTERVAL /* MYSQL-FUNC */
-%token DATE_SUB_INTERVAL /* MYSQL-FUNC */
-%token DAY_HOUR_SYM
-%token DAY_MICROSECOND_SYM
-%token DAY_MINUTE_SYM
-%token DAY_SECOND_SYM
-%token DECIMAL_NUM
-%token DECIMAL_SYM /* SQL-2003-R */
-%token DECLARE_MARIADB_SYM /* SQL-2003-R */
-%token DECLARE_ORACLE_SYM /* Oracle-R */
-%token DEFAULT /* SQL-2003-R */
-%token DELETE_DOMAIN_ID_SYM
-%token DELETE_SYM /* SQL-2003-R */
-%token DENSE_RANK_SYM
-%token DESC /* SQL-2003-N */
-%token DESCRIBE /* SQL-2003-R */
-%token DETERMINISTIC_SYM /* SQL-2003-R */
-%token DISTINCT /* SQL-2003-R */
-%token DIV_SYM
-%token DOUBLE_SYM /* SQL-2003-R */
-%token DO_DOMAIN_IDS_SYM
-%token DOT_DOT_SYM
-%token DROP /* SQL-2003-R */
-%token DUAL_SYM
-%token EACH_SYM /* SQL-2003-R */
-%token ELSE /* SQL-2003-R */
-%token ELSEIF_MARIADB_SYM
-%token ELSIF_ORACLE_SYM /* PLSQL-R */
-%token ENCLOSED
-%token END_OF_INPUT /* INTERNAL */
-%token EQUAL_SYM /* OPERATOR */
-%token ESCAPED
-%token EXCEPT_SYM /* SQL-2003-R */
-%token EXISTS /* SQL-2003-R */
-%token EXTRACT_SYM /* SQL-2003-N */
-%token FALSE_SYM /* SQL-2003-R */
-%token FETCH_SYM /* SQL-2003-R */
-%token FIRST_VALUE_SYM /* SQL-2011 */
-%token FLOAT_NUM
-%token FLOAT_SYM /* SQL-2003-R */
-%token FOREIGN /* SQL-2003-R */
-%token FOR_SYM /* SQL-2003-R */
-%token FOR_SYSTEM_TIME_SYM /* INTERNAL */
-%token FROM
-%token FULLTEXT_SYM
-%token GE
-%token GOTO_ORACLE_SYM /* Oracle-R */
-%token GRANT /* SQL-2003-R */
-%token GROUP_SYM /* SQL-2003-R */
-%token GROUP_CONCAT_SYM
-%token LAG_SYM /* SQL-2011 */
-%token LEAD_SYM /* SQL-2011 */
-%token HAVING /* SQL-2003-R */
-%token HEX_NUM
-%token HEX_STRING
-%token HOUR_MICROSECOND_SYM
-%token HOUR_MINUTE_SYM
-%token HOUR_SECOND_SYM
-%token IDENT
-%token IDENT_QUOTED
-%token IF_SYM
-%token IGNORE_DOMAIN_IDS_SYM
-%token IGNORE_SYM
-%token INDEX_SYM
-%token INFILE
-%token INNER_SYM /* SQL-2003-R */
-%token INOUT_SYM /* SQL-2003-R */
-%token INSENSITIVE_SYM /* SQL-2003-R */
-%token INSERT /* SQL-2003-R */
-%token INTERSECT_SYM /* SQL-2003-R */
-%token INTERVAL_SYM /* SQL-2003-R */
-%token INTO /* SQL-2003-R */
-%token INT_SYM /* SQL-2003-R */
-%token IN_SYM /* SQL-2003-R */
-%token IS /* SQL-2003-R */
-%token ITERATE_SYM
-%token JOIN_SYM /* SQL-2003-R */
-%token KEYS
-%token KEY_SYM /* SQL-2003-N */
-%token KILL_SYM
-%token LE /* OPERATOR */
-%token LEADING /* SQL-2003-R */
-%token LEAVE_SYM
-%token LEFT /* SQL-2003-R */
-%token LEFT_PAREN_ALT /* INTERNAL */
-%token LEFT_PAREN_WITH /* INTERNAL */
-%token LEFT_PAREN_LIKE /* INTERNAL */
-%token LEX_HOSTNAME
-%token LIKE /* SQL-2003-R */
-%token LIMIT
-%token LINEAR_SYM
-%token LINES
-%token LOAD
-%token LOCATOR_SYM /* SQL-2003-N */
-%token LOCK_SYM
-%token LONGBLOB
-%token LONGTEXT
-%token LONG_NUM
-%token LONG_SYM
-%token LOOP_SYM
-%token LOW_PRIORITY
-%token MASTER_SSL_VERIFY_SERVER_CERT_SYM
-%token MATCH /* SQL-2003-R */
-%token MAX_SYM /* SQL-2003-N */
-%token MAXVALUE_SYM /* SQL-2003-N */
-%token MEDIAN_SYM
-%token MEDIUMBLOB
-%token MEDIUMINT
-%token MEDIUMTEXT
-%token MINUTE_MICROSECOND_SYM
-%token MINUTE_SECOND_SYM
-%token MIN_SYM /* SQL-2003-N */
-%token MODIFIES_SYM /* SQL-2003-R */
-%token MOD_SYM /* SQL-2003-N */
-%token MYSQL_CONCAT_SYM /* OPERATOR */
-%token NATURAL /* SQL-2003-R */
-%token NCHAR_STRING
-%token NE /* OPERATOR */
-%token NEG
-%token NOT2_SYM
-%token NOT_SYM /* SQL-2003-R */
-%token NOW_SYM
-%token NO_WRITE_TO_BINLOG
-%token NTILE_SYM
-%token NULL_SYM /* SQL-2003-R */
-%token NUM
-%token NUMERIC_SYM /* SQL-2003-R */
-%token NTH_VALUE_SYM /* SQL-2011 */
-%token ON /* SQL-2003-R */
-%token OPTIMIZE
-%token OPTIONALLY
-%token ORACLE_CONCAT_SYM /* INTERNAL */
-%token OR2_SYM
-%token ORDER_SYM /* SQL-2003-R */
-%token OR_SYM /* SQL-2003-R */
-%token OTHERS_ORACLE_SYM /* SQL-2011-N, PLSQL-R */
-%token OUTER
-%token OUTFILE
-%token OUT_SYM /* SQL-2003-R */
-%token OVER_SYM
-%token PACKAGE_ORACLE_SYM /* Oracle-R */
-%token PAGE_CHECKSUM_SYM
-%token PARAM_MARKER
-%token PARSE_VCOL_EXPR_SYM
-%token PARTITION_SYM /* SQL-2003-R */
-%token PERCENT_ORACLE_SYM /* INTERNAL */
-%token PERCENT_RANK_SYM
-%token PERCENTILE_CONT_SYM
-%token PERCENTILE_DISC_SYM
-%token PORTION_SYM /* SQL-2016-R */
-%token POSITION_SYM /* SQL-2003-N */
-%token PRECISION /* SQL-2003-R */
-%token PRIMARY_SYM /* SQL-2003-R */
-%token PROCEDURE_SYM /* SQL-2003-R */
-%token PURGE
-%token RAISE_ORACLE_SYM /* PLSQL-R */
-%token RANGE_SYM /* SQL-2003-R */
-%token RANK_SYM
-%token READS_SYM /* SQL-2003-R */
-%token READ_SYM /* SQL-2003-N */
-%token READ_WRITE_SYM
-%token REAL /* SQL-2003-R */
-%token RECURSIVE_SYM
-%token REF_SYSTEM_ID_SYM
-%token REFERENCES /* SQL-2003-R */
-%token REGEXP
-%token RELEASE_SYM /* SQL-2003-R */
-%token RENAME
-%token REPEAT_SYM /* MYSQL-FUNC */
-%token REPLACE /* MYSQL-FUNC */
-%token REQUIRE_SYM
-%token RESIGNAL_SYM /* SQL-2003-R */
-%token RESTRICT
-%token RETURNING_SYM
-%token RETURN_MARIADB_SYM /* SQL-2003-R, PLSQL-R */
-%token RETURN_ORACLE_SYM /* SQL-2003-R, PLSQL-R */
-%token REVOKE /* SQL-2003-R */
-%token RIGHT /* SQL-2003-R */
-%token ROWS_SYM /* SQL-2003-R */
-%token ROWTYPE_ORACLE_SYM /* PLSQL-R */
-%token ROW_NUMBER_SYM
-%token SECOND_MICROSECOND_SYM
-%token SELECT_SYM /* SQL-2003-R */
-%token SENSITIVE_SYM /* FUTURE-USE */
-%token SEPARATOR_SYM
-%token SERVER_OPTIONS
-%token SET /* SQL-2003-R */
-%token SET_VAR
-%token SHIFT_LEFT /* OPERATOR */
-%token SHIFT_RIGHT /* OPERATOR */
-%token SHOW
-%token SIGNAL_SYM /* SQL-2003-R */
-%token SMALLINT /* SQL-2003-R */
-%token SPATIAL_SYM
-%token SPECIFIC_SYM /* SQL-2003-R */
-%token SQLEXCEPTION_SYM /* SQL-2003-R */
-%token SQLSTATE_SYM /* SQL-2003-R */
-%token SQLWARNING_SYM /* SQL-2003-R */
-%token SQL_BIG_RESULT
-%token SQL_SMALL_RESULT
-%token SQL_SYM /* SQL-2003-R */
-%token SSL_SYM
-%token STARTING
-%token STATS_AUTO_RECALC_SYM
-%token STATS_PERSISTENT_SYM
-%token STATS_SAMPLE_PAGES_SYM
-%token STDDEV_SAMP_SYM /* SQL-2003-N */
-%token STD_SYM
-%token STRAIGHT_JOIN
-%token SUBSTRING /* SQL-2003-N */
-%token SUM_SYM /* SQL-2003-N */
-%token SYSDATE
-%token TABLE_REF_PRIORITY
-%token TABLE_SYM /* SQL-2003-R */
-%token TERMINATED
-%token TEXT_STRING
-%token THEN_SYM /* SQL-2003-R */
-%token TINYBLOB
-%token TINYINT
-%token TINYTEXT
-%token TO_SYM /* SQL-2003-R */
-%token TRAILING /* SQL-2003-R */
-%token TRIGGER_SYM /* SQL-2003-R */
-%token TRIM /* SQL-2003-N */
-%token TRUE_SYM /* SQL-2003-R */
-%token ULONGLONG_NUM
-%token UNDERSCORE_CHARSET
-%token UNDO_SYM /* FUTURE-USE */
-%token UNION_SYM /* SQL-2003-R */
-%token UNIQUE_SYM
-%token UNLOCK_SYM
-%token UNSIGNED
-%token UPDATE_SYM /* SQL-2003-R */
-%token USAGE /* SQL-2003-N */
-%token USE_SYM
-%token USING /* SQL-2003-R */
-%token UTC_DATE_SYM
-%token UTC_TIMESTAMP_SYM
-%token UTC_TIME_SYM
-%token VALUES /* SQL-2003-R */
-%token VALUES_IN_SYM
-%token VALUES_LESS_SYM
-%token VARBINARY
-%token VARCHAR /* SQL-2003-R */
-%token VARIANCE_SYM
-%token VARYING /* SQL-2003-R */
-%token VAR_SAMP_SYM
-%token WHEN_SYM /* SQL-2003-R */
-%token WHERE /* SQL-2003-R */
-%token WHILE_SYM
-%token WITH /* SQL-2003-R */
-%token WITH_CUBE_SYM /* INTERNAL */
-%token WITH_ROLLUP_SYM /* INTERNAL */
-%token WITH_SYSTEM_SYM /* INTERNAL */
-%token XOR
-%token YEAR_MONTH_SYM
-%token ZEROFILL
-
-%token IMPOSSIBLE_ACTION /* To avoid warning for yyerrlab1 */
-
-
-/*
- Keywords that have different reserved status in std/oracle modes.
-*/
-%token <kwd> BODY_MARIADB_SYM // Oracle-R
-%token <kwd> ELSEIF_ORACLE_SYM
-%token <kwd> ELSIF_MARIADB_SYM // PLSQL-R
-%token <kwd> EXCEPTION_ORACLE_SYM // SQL-2003-N, PLSQL-R
-%token <kwd> GOTO_MARIADB_SYM // Oracle-R
-%token <kwd> OTHERS_MARIADB_SYM // SQL-2011-N, PLSQL-R
-%token <kwd> PACKAGE_MARIADB_SYM // Oracle-R
-%token <kwd> RAISE_MARIADB_SYM // PLSQL-R
-%token <kwd> ROWTYPE_MARIADB_SYM // PLSQL-R
-
-/*
- Non-reserved keywords
-*/
-
-%token <kwd> ACCOUNT_SYM /* MYSQL */
-%token <kwd> ACTION /* SQL-2003-N */
-%token <kwd> ADMIN_SYM /* SQL-2003-N */
-%token <kwd> ADDDATE_SYM /* MYSQL-FUNC */
-%token <kwd> AFTER_SYM /* SQL-2003-N */
-%token <kwd> AGAINST
-%token <kwd> AGGREGATE_SYM
-%token <kwd> ALGORITHM_SYM
-%token <kwd> ALWAYS_SYM
-%token <kwd> ANY_SYM /* SQL-2003-R */
-%token <kwd> ASCII_SYM /* MYSQL-FUNC */
-%token <kwd> AT_SYM /* SQL-2003-R */
-%token <kwd> ATOMIC_SYM /* SQL-2003-R */
-%token <kwd> AUTHORS_SYM
-%token <kwd> AUTOEXTEND_SIZE_SYM
-%token <kwd> AUTO_INC
-%token <kwd> AUTO_SYM
-%token <kwd> AVG_ROW_LENGTH
-%token <kwd> AVG_SYM /* SQL-2003-N */
-%token <kwd> BACKUP_SYM
-%token <kwd> BEGIN_MARIADB_SYM /* SQL-2003-R, PLSQL-R */
-%token <kwd> BEGIN_ORACLE_SYM /* SQL-2003-R, PLSQL-R */
-%token <kwd> BINLOG_SYM
-%token <kwd> BIT_SYM /* MYSQL-FUNC */
-%token <kwd> BLOCK_SYM
-%token <kwd> BOOL_SYM
-%token <kwd> BOOLEAN_SYM /* SQL-2003-R, PLSQL-R */
-%token <kwd> BTREE_SYM
-%token <kwd> BYTE_SYM
-%token <kwd> CACHE_SYM
-%token <kwd> CASCADED /* SQL-2003-R */
-%token <kwd> CATALOG_NAME_SYM /* SQL-2003-N */
-%token <kwd> CHAIN_SYM /* SQL-2003-N */
-%token <kwd> CHANGED
-%token <kwd> CHARSET
-%token <kwd> CHECKPOINT_SYM
-%token <kwd> CHECKSUM_SYM
-%token <kwd> CIPHER_SYM
-%token <kwd> CLASS_ORIGIN_SYM /* SQL-2003-N */
-%token <kwd> CLIENT_SYM
-%token <kwd> CLOB_MARIADB_SYM /* SQL-2003-R */
-%token <kwd> CLOB_ORACLE_SYM /* Oracle-R */
-%token <kwd> CLOSE_SYM /* SQL-2003-R */
-%token <kwd> COALESCE /* SQL-2003-N */
-%token <kwd> CODE_SYM
-%token <kwd> COLLATION_SYM /* SQL-2003-N */
-%token <kwd> COLON_ORACLE_SYM /* INTERNAL */
-%token <kwd> COLUMNS
-%token <kwd> COLUMN_ADD_SYM
-%token <kwd> COLUMN_CHECK_SYM
-%token <kwd> COLUMN_CREATE_SYM
-%token <kwd> COLUMN_DELETE_SYM
-%token <kwd> COLUMN_GET_SYM
-%token <kwd> COLUMN_SYM /* SQL-2003-R */
-%token <kwd> COLUMN_NAME_SYM /* SQL-2003-N */
-%token <kwd> COMMENT_SYM /* Oracle-R */
-%token <kwd> COMMITTED_SYM /* SQL-2003-N */
-%token <kwd> COMMIT_SYM /* SQL-2003-R */
-%token <kwd> COMPACT_SYM
-%token <kwd> COMPLETION_SYM
-%token <kwd> COMPRESSED_SYM
-%token <kwd> CONCURRENT
-%token <kwd> CONNECTION_SYM
-%token <kwd> CONSISTENT_SYM
-%token <kwd> CONSTRAINT_CATALOG_SYM /* SQL-2003-N */
-%token <kwd> CONSTRAINT_NAME_SYM /* SQL-2003-N */
-%token <kwd> CONSTRAINT_SCHEMA_SYM /* SQL-2003-N */
-%token <kwd> CONTAINS_SYM /* SQL-2003-N */
-%token <kwd> CONTEXT_SYM
-%token <kwd> CONTRIBUTORS_SYM
-%token <kwd> CPU_SYM
-%token <kwd> CUBE_SYM /* SQL-2003-R */
-%token <kwd> CURRENT_SYM /* SQL-2003-R */
-%token <kwd> CURRENT_POS_SYM
-%token <kwd> CURSOR_NAME_SYM /* SQL-2003-N */
-%token <kwd> CYCLE_SYM
-%token <kwd> DATAFILE_SYM
-%token <kwd> DATA_SYM /* SQL-2003-N */
-%token <kwd> DATETIME
-%token <kwd> DATE_FORMAT_SYM /* MYSQL-FUNC */
-%token <kwd> DATE_SYM /* SQL-2003-R, Oracle-R, PLSQL-R */
-%token <kwd> DAY_SYM /* SQL-2003-R */
-%token <kwd> DEALLOCATE_SYM /* SQL-2003-R */
-%token <kwd> DECODE_MARIADB_SYM /* Function, non-reserved */
-%token <kwd> DECODE_ORACLE_SYM /* Function, non-reserved */
-%token <kwd> DEFINER_SYM
-%token <kwd> DELAYED_SYM
-%token <kwd> DELAY_KEY_WRITE_SYM
-%token <kwd> DES_KEY_FILE
-%token <kwd> DIAGNOSTICS_SYM /* SQL-2003-N */
-%token <kwd> DIRECTORY_SYM
-%token <kwd> DISABLE_SYM
-%token <kwd> DISCARD
-%token <kwd> DISK_SYM
-%token <kwd> DO_SYM
-%token <kwd> DUMPFILE
-%token <kwd> DUPLICATE_SYM
-%token <kwd> DYNAMIC_SYM /* SQL-2003-R */
-%token <kwd> ENABLE_SYM
-%token <kwd> END /* SQL-2003-R, PLSQL-R */
-%token <kwd> ENDS_SYM
-%token <kwd> ENGINES_SYM
-%token <kwd> ENGINE_SYM
-%token <kwd> ENUM
-%token <kwd> ERROR_SYM
-%token <kwd> ERRORS
-%token <kwd> ESCAPE_SYM /* SQL-2003-R */
-%token <kwd> EVENTS_SYM
-%token <kwd> EVENT_SYM
-%token <kwd> EVERY_SYM /* SQL-2003-N */
-%token <kwd> EXCHANGE_SYM
-%token <kwd> EXAMINED_SYM
-%token <kwd> EXCLUDE_SYM /* SQL-2011-N */
-%token <kwd> EXECUTE_SYM /* SQL-2003-R */
-%token <kwd> EXCEPTION_MARIADB_SYM /* SQL-2003-N, PLSQL-R */
-%token <kwd> EXIT_MARIADB_SYM /* PLSQL-R */
-%token <kwd> EXIT_ORACLE_SYM /* PLSQL-R */
-%token <kwd> EXPANSION_SYM
-%token <kwd> EXPIRE_SYM /* MySQL */
-%token <kwd> EXPORT_SYM
-%token <kwd> EXTENDED_SYM
-%token <kwd> EXTENT_SIZE_SYM
-%token <kwd> FAST_SYM
-%token <kwd> FAULTS_SYM
-%token <kwd> FILE_SYM
-%token <kwd> FIRST_SYM /* SQL-2003-N */
-%token <kwd> FIXED_SYM
-%token <kwd> FLUSH_SYM
-%token <kwd> FOLLOWS_SYM /* MYSQL trigger*/
-%token <kwd> FOLLOWING_SYM /* SQL-2011-N */
-%token <kwd> FORCE_SYM
-%token <kwd> FORMAT_SYM
-%token <kwd> FOUND_SYM /* SQL-2003-R */
-%token <kwd> FULL /* SQL-2003-R */
-%token <kwd> FUNCTION_SYM /* SQL-2003-R, Oracle-R */
-%token <kwd> GENERAL
-%token <kwd> GENERATED_SYM
-%token <kwd> GEOMETRYCOLLECTION
-%token <kwd> GEOMETRY_SYM
-%token <kwd> GET_FORMAT /* MYSQL-FUNC */
-%token <kwd> GET_SYM /* SQL-2003-R */
-%token <kwd> GLOBAL_SYM /* SQL-2003-R */
-%token <kwd> GRANTS
-%token <kwd> HANDLER_SYM
-%token <kwd> HARD_SYM
-%token <kwd> HASH_SYM
-%token <kwd> HELP_SYM
-%token <kwd> HIGH_PRIORITY
-%token <kwd> HISTORY_SYM /* MYSQL */
-%token <kwd> HOST_SYM
-%token <kwd> HOSTS_SYM
-%token <kwd> HOUR_SYM /* SQL-2003-R */
-%token <kwd> ID_SYM /* MYSQL */
-%token <kwd> IDENTIFIED_SYM
-%token <kwd> IGNORE_SERVER_IDS_SYM
-%token <kwd> IMMEDIATE_SYM /* SQL-2003-R */
-%token <kwd> IMPORT
-%token <kwd> INCREMENT_SYM
-%token <kwd> INDEXES
-%token <kwd> INITIAL_SIZE_SYM
-%token <kwd> INSERT_METHOD
-%token <kwd> INSTALL_SYM
-%token <kwd> INVOKER_SYM
-%token <kwd> IO_SYM
-%token <kwd> IPC_SYM
-%token <kwd> ISOLATION /* SQL-2003-R */
-%token <kwd> ISOPEN_SYM /* Oracle-N */
-%token <kwd> ISSUER_SYM
-%token <kwd> INVISIBLE_SYM
-%token <kwd> JSON_SYM
-%token <kwd> KEY_BLOCK_SIZE
-%token <kwd> LANGUAGE_SYM /* SQL-2003-R */
-%token <kwd> LAST_SYM /* SQL-2003-N */
-%token <kwd> LAST_VALUE
-%token <kwd> LASTVAL_SYM /* PostgreSQL sequence function */
-%token <kwd> LEAVES
-%token <kwd> LESS_SYM
-%token <kwd> LEVEL_SYM
-%token <kwd> LINESTRING
-%token <kwd> LIST_SYM
-%token <kwd> LOCAL_SYM /* SQL-2003-R */
-%token <kwd> LOCKS_SYM
-%token <kwd> LOGFILE_SYM
-%token <kwd> LOGS_SYM
-%token <kwd> MASTER_CONNECT_RETRY_SYM
-%token <kwd> MASTER_DELAY_SYM
-%token <kwd> MASTER_GTID_POS_SYM
-%token <kwd> MASTER_HOST_SYM
-%token <kwd> MASTER_LOG_FILE_SYM
-%token <kwd> MASTER_LOG_POS_SYM
-%token <kwd> MASTER_PASSWORD_SYM
-%token <kwd> MASTER_PORT_SYM
-%token <kwd> MASTER_SERVER_ID_SYM
-%token <kwd> MASTER_SSL_CAPATH_SYM
-%token <kwd> MASTER_SSL_CA_SYM
-%token <kwd> MASTER_SSL_CERT_SYM
-%token <kwd> MASTER_SSL_CIPHER_SYM
-%token <kwd> MASTER_SSL_CRL_SYM
-%token <kwd> MASTER_SSL_CRLPATH_SYM
-%token <kwd> MASTER_SSL_KEY_SYM
-%token <kwd> MASTER_SSL_SYM
-%token <kwd> MASTER_SYM
-%token <kwd> MASTER_USER_SYM
-%token <kwd> MASTER_USE_GTID_SYM
-%token <kwd> MASTER_HEARTBEAT_PERIOD_SYM
-%token <kwd> MAX_CONNECTIONS_PER_HOUR
-%token <kwd> MAX_QUERIES_PER_HOUR
-%token <kwd> MAX_ROWS
-%token <kwd> MAX_SIZE_SYM
-%token <kwd> MAX_UPDATES_PER_HOUR
-%token <kwd> MAX_STATEMENT_TIME_SYM
-%token <kwd> MAX_USER_CONNECTIONS_SYM
-%token <kwd> MEDIUM_SYM
-%token <kwd> MEMORY_SYM
-%token <kwd> MERGE_SYM /* SQL-2003-R */
-%token <kwd> MESSAGE_TEXT_SYM /* SQL-2003-N */
-%token <kwd> MICROSECOND_SYM /* MYSQL-FUNC */
-%token <kwd> MIGRATE_SYM
-%token <kwd> MINUTE_SYM /* SQL-2003-R */
-%token <kwd> MINVALUE_SYM
-%token <kwd> MIN_ROWS
-%token <kwd> MODE_SYM
-%token <kwd> MODIFY_SYM
-%token <kwd> MONTH_SYM /* SQL-2003-R */
-%token <kwd> MULTILINESTRING
-%token <kwd> MULTIPOINT
-%token <kwd> MULTIPOLYGON
-%token <kwd> MUTEX_SYM
-%token <kwd> MYSQL_SYM
-%token <kwd> MYSQL_ERRNO_SYM
-%token <kwd> NAMES_SYM /* SQL-2003-N */
-%token <kwd> NAME_SYM /* SQL-2003-N */
-%token <kwd> NATIONAL_SYM /* SQL-2003-R */
-%token <kwd> NCHAR_SYM /* SQL-2003-R */
-%token <kwd> NEVER_SYM /* MySQL */
-%token <kwd> NEW_SYM /* SQL-2003-R */
-%token <kwd> NEXT_SYM /* SQL-2003-N */
-%token <kwd> NEXTVAL_SYM /* PostgreSQL sequence function */
-%token <kwd> NOCACHE_SYM
-%token <kwd> NOCYCLE_SYM
-%token <kwd> NODEGROUP_SYM
-%token <kwd> NONE_SYM /* SQL-2003-R */
-%token <kwd> NOTFOUND_SYM /* Oracle-R */
-%token <kwd> NO_SYM /* SQL-2003-R */
-%token <kwd> NOMAXVALUE_SYM
-%token <kwd> NOMINVALUE_SYM
-%token <kwd> NO_WAIT_SYM
-%token <kwd> NOWAIT_SYM
-%token <kwd> NUMBER_MARIADB_SYM /* SQL-2003-N */
-%token <kwd> NUMBER_ORACLE_SYM /* Oracle-R, PLSQL-R */
-%token <kwd> NVARCHAR_SYM
-%token <kwd> OF_SYM /* SQL-1992-R, Oracle-R */
-%token <kwd> OFFSET_SYM
-%token <kwd> OLD_PASSWORD_SYM
-%token <kwd> ONE_SYM
-%token <kwd> ONLY_SYM /* SQL-2003-R */
-%token <kwd> ONLINE_SYM
-%token <kwd> OPEN_SYM /* SQL-2003-R */
-%token <kwd> OPTIONS_SYM
-%token <kwd> OPTION /* SQL-2003-N */
-%token <kwd> OWNER_SYM
-%token <kwd> PACK_KEYS_SYM
-%token <kwd> PAGE_SYM
-%token <kwd> PARSER_SYM
-%token <kwd> PARTIAL /* SQL-2003-N */
-%token <kwd> PARTITIONS_SYM
-%token <kwd> PARTITIONING_SYM
-%token <kwd> PASSWORD_SYM
-%token <kwd> PERIOD_SYM /* SQL-2011-R */
-%token <kwd> PERSISTENT_SYM
-%token <kwd> PHASE_SYM
-%token <kwd> PLUGINS_SYM
-%token <kwd> PLUGIN_SYM
-%token <kwd> POINT_SYM
-%token <kwd> POLYGON
-%token <kwd> PORT_SYM
-%token <kwd> PRECEDES_SYM /* MYSQL */
-%token <kwd> PRECEDING_SYM /* SQL-2011-N */
-%token <kwd> PREPARE_SYM /* SQL-2003-R */
-%token <kwd> PRESERVE_SYM
-%token <kwd> PREV_SYM
-%token <kwd> PREVIOUS_SYM
-%token <kwd> PRIVILEGES /* SQL-2003-N */
-%token <kwd> PROCESS
-%token <kwd> PROCESSLIST_SYM
-%token <kwd> PROFILE_SYM
-%token <kwd> PROFILES_SYM
-%token <kwd> PROXY_SYM
-%token <kwd> QUARTER_SYM
-%token <kwd> QUERY_SYM
-%token <kwd> QUICK
-%token <kwd> RAW_MARIADB_SYM
-%token <kwd> RAW_ORACLE_SYM /* Oracle-R */
-%token <kwd> READ_ONLY_SYM
-%token <kwd> REBUILD_SYM
-%token <kwd> RECOVER_SYM
-%token <kwd> REDOFILE_SYM
-%token <kwd> REDO_BUFFER_SIZE_SYM
-%token <kwd> REDUNDANT_SYM
-%token <kwd> RELAY
-%token <kwd> RELAYLOG_SYM
-%token <kwd> RELAY_LOG_FILE_SYM
-%token <kwd> RELAY_LOG_POS_SYM
-%token <kwd> RELAY_THREAD
-%token <kwd> RELOAD
-%token <kwd> REMOVE_SYM
-%token <kwd> REORGANIZE_SYM
-%token <kwd> REPAIR
-%token <kwd> REPEATABLE_SYM /* SQL-2003-N */
-%token <kwd> REPLICATION
-%token <kwd> RESET_SYM
-%token <kwd> RESTART_SYM
-%token <kwd> RESOURCES
-%token <kwd> RESTORE_SYM
-%token <kwd> RESUME_SYM
-%token <kwd> RETURNED_SQLSTATE_SYM /* SQL-2003-N */
-%token <kwd> RETURNS_SYM /* SQL-2003-R */
-%token <kwd> REUSE_SYM /* Oracle-R */
-%token <kwd> REVERSE_SYM
-%token <kwd> ROLE_SYM
-%token <kwd> ROLLBACK_SYM /* SQL-2003-R */
-%token <kwd> ROLLUP_SYM /* SQL-2003-R */
-%token <kwd> ROUTINE_SYM /* SQL-2003-N */
-%token <kwd> ROWCOUNT_SYM /* Oracle-N */
-%token <kwd> ROW_SYM /* SQL-2003-R */
-%token <kwd> ROW_COUNT_SYM /* SQL-2003-N */
-%token <kwd> ROW_FORMAT_SYM
-%token <kwd> RTREE_SYM
-%token <kwd> SAVEPOINT_SYM /* SQL-2003-R */
-%token <kwd> SCHEDULE_SYM
-%token <kwd> SCHEMA_NAME_SYM /* SQL-2003-N */
-%token <kwd> SECOND_SYM /* SQL-2003-R */
-%token <kwd> SECURITY_SYM /* SQL-2003-N */
-%token <kwd> SEQUENCE_SYM
-%token <kwd> SERIALIZABLE_SYM /* SQL-2003-N */
-%token <kwd> SERIAL_SYM
-%token <kwd> SESSION_SYM /* SQL-2003-N */
-%token <kwd> SERVER_SYM
-%token <kwd> SETVAL_SYM /* PostgreSQL sequence function */
-%token <kwd> SHARE_SYM
-%token <kwd> SHUTDOWN
-%token <kwd> SIGNED_SYM
-%token <kwd> SIMPLE_SYM /* SQL-2003-N */
-%token <kwd> SLAVE
-%token <kwd> SLAVES
-%token <kwd> SLAVE_POS_SYM
-%token <kwd> SLOW
-%token <kwd> SNAPSHOT_SYM
-%token <kwd> SOCKET_SYM
-%token <kwd> SOFT_SYM
-%token <kwd> SONAME_SYM
-%token <kwd> SOUNDS_SYM
-%token <kwd> SOURCE_SYM
-%token <kwd> SQL_BUFFER_RESULT
-%token <kwd> SQL_CACHE_SYM
-%token <kwd> SQL_CALC_FOUND_ROWS
-%token <kwd> SQL_NO_CACHE_SYM
-%token <kwd> SQL_THREAD
-%token <kwd> STAGE_SYM
-%token <kwd> STARTS_SYM
-%token <kwd> START_SYM /* SQL-2003-R */
-%token <kwd> STATEMENT_SYM
-%token <kwd> STATUS_SYM
-%token <kwd> STOP_SYM
-%token <kwd> STORAGE_SYM
-%token <kwd> STORED_SYM
-%token <kwd> STRING_SYM
-%token <kwd> SUBCLASS_ORIGIN_SYM /* SQL-2003-N */
-%token <kwd> SUBDATE_SYM
-%token <kwd> SUBJECT_SYM
-%token <kwd> SUBPARTITIONS_SYM
-%token <kwd> SUBPARTITION_SYM
-%token <kwd> SUPER_SYM
-%token <kwd> SUSPEND_SYM
-%token <kwd> SWAPS_SYM
-%token <kwd> SWITCHES_SYM
-%token <kwd> SYSTEM /* SQL-2011-R */
-%token <kwd> SYSTEM_TIME_SYM /* SQL-2011-R */
-%token <kwd> TABLES
-%token <kwd> TABLESPACE
-%token <kwd> TABLE_CHECKSUM_SYM
-%token <kwd> TABLE_NAME_SYM /* SQL-2003-N */
-%token <kwd> TEMPORARY /* SQL-2003-N */
-%token <kwd> TEMPTABLE_SYM
-%token <kwd> TEXT_SYM
-%token <kwd> THAN_SYM
-%token <kwd> TIES_SYM /* SQL-2011-N */
-%token <kwd> TIMESTAMP /* SQL-2003-R */
-%token <kwd> TIMESTAMP_ADD
-%token <kwd> TIMESTAMP_DIFF
-%token <kwd> TIME_SYM /* SQL-2003-R, Oracle-R */
-%token <kwd> TRANSACTION_SYM
-%token <kwd> TRANSACTIONAL_SYM
-%token <kwd> TRIGGERS_SYM
-%token <kwd> TRIM_ORACLE
-%token <kwd> TRUNCATE_SYM
-%token <kwd> TYPES_SYM
-%token <kwd> TYPE_SYM /* SQL-2003-N */
-%token <kwd> UDF_RETURNS_SYM
-%token <kwd> UNBOUNDED_SYM /* SQL-2011-N */
-%token <kwd> UNCOMMITTED_SYM /* SQL-2003-N */
-%token <kwd> UNDEFINED_SYM
-%token <kwd> UNDOFILE_SYM
-%token <kwd> UNDO_BUFFER_SIZE_SYM
-%token <kwd> UNICODE_SYM
-%token <kwd> UNINSTALL_SYM
-%token <kwd> UNKNOWN_SYM /* SQL-2003-R */
-%token <kwd> UNTIL_SYM
-%token <kwd> UPGRADE_SYM
-%token <kwd> USER_SYM /* SQL-2003-R */
-%token <kwd> USE_FRM
-%token <kwd> VALUE_SYM /* SQL-2003-R */
-%token <kwd> VARCHAR2_MARIADB_SYM
-%token <kwd> VARCHAR2_ORACLE_SYM /* Oracle-R, PLSQL-R */
-%token <kwd> VARIABLES
-%token <kwd> VERSIONING_SYM /* SQL-2011-R */
-%token <kwd> VIA_SYM
-%token <kwd> VIEW_SYM /* SQL-2003-N */
-%token <kwd> VIRTUAL_SYM
-%token <kwd> WAIT_SYM
-%token <kwd> WARNINGS
-%token <kwd> WEEK_SYM
-%token <kwd> WEIGHT_STRING_SYM
-%token <kwd> WINDOW_SYM /* SQL-2003-R */
-%token <kwd> WITHIN
-%token <kwd> WITHOUT /* SQL-2003-R */
-%token <kwd> WORK_SYM /* SQL-2003-N */
-%token <kwd> WRAPPER_SYM
-%token <kwd> WRITE_SYM /* SQL-2003-N */
-%token <kwd> X509_SYM
-%token <kwd> XA_SYM
-%token <kwd> XML_SYM
-%token <kwd> YEAR_SYM /* SQL-2003-R */
-
-
-/*
- 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
-
-/* A dummy token to force the priority of table_ref production in a join. */
-%left CONDITIONLESS_JOIN
-%left JOIN_SYM INNER_SYM STRAIGHT_JOIN CROSS LEFT RIGHT ON_SYM USING
-
-%left SET_VAR
-%left OR_SYM OR2_SYM
-%left XOR
-%left AND_SYM AND_AND_SYM
-
-%left PREC_BELOW_NOT
-%left NOT_SYM
-
-%left BETWEEN_SYM CASE_SYM WHEN_SYM THEN_SYM ELSE
-%left '=' EQUAL_SYM GE '>' LE '<' NE IS LIKE SOUNDS_SYM REGEXP IN_SYM
-%left '|'
-%left '&'
-%left SHIFT_LEFT SHIFT_RIGHT
-%left '-' '+' ORACLE_CONCAT_SYM
-%left '*' '/' '%' DIV_SYM MOD_SYM
-%left '^'
-%left MYSQL_CONCAT_SYM
-%left NEG '~' NOT2_SYM BINARY
-%left SUBQUERY_AS_EXPR
-%left COLLATE_SYM
-
-/*
- Tokens that can change their meaning from identifier to something else
- in certain context.
-
- - TRANSACTION: identifier, history unit:
- SELECT transaction FROM t1;
- SELECT * FROM t1 FOR SYSTEM_TIME AS OF TRANSACTION @var;
-
- - TIMESTAMP: identifier, literal, history unit:
- SELECT timestamp FROM t1;
- SELECT TIMESTAMP '2001-01-01 10:20:30';
- SELECT * FROM t1 FOR SYSTEM_TIME AS OF TIMESTAMP CONCAT(@date,' ',@time);
-
- - PERIOD: identifier, period for system time:
- SELECT period FROM t1;
- ALTER TABLE DROP PERIOD FOR SYSTEM TIME;
-
- - SYSTEM: identifier, system versioning:
- 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 shift/reduce conflicts
- with keyword identifiers. For example:
- opt_clause1: %empty | KEYWORD ... ;
- clause2: opt_clause1 ident;
- KEYWORD can appear both in opt_clause1 and in "ident" through the "keyword"
- rule. So the parser reports a conflict on how to interpret KEYWORD:
- - as a start of non-empty branch in opt_clause1, or
- - as an identifier which follows the empty branch in opt_clause1.
-
- Example#1:
- alter_list_item:
- DROP opt_column opt_if_exists_table_element field_ident
- | DROP SYSTEM VERSIONING_SYM
- SYSTEM can be a keyword in field_ident, or can be a start of
- SYSTEM VERSIONING.
-
- Example#2:
- system_time_expr: AS OF_SYM history_point
- history_point: opt_history_unit bit_expr
- opt_history_unit: | TRANSACTION_SYM
- TRANSACTION can be a non-empty history unit, or can be an identifier
- in bit_expr.
-
- In the grammar below we use %prec to explicitely tell Bison to go
- through the empty branch in the optional rule only when the lookahead
- token does not belong to a small set of selected tokens.
-
- Tokens NEXT_SYM and PREVIOUS_SYM also change their meaning from
- identifiers to sequence operations when followed by VALUE_SYM:
- SELECT NEXT VALUE FOR s1, PREVIOUS VALUE FOR s1;
- but we don't need to list them here as they do not seem to cause
- conflicts (according to bison -v), as both meanings
- (as identifier, and as a sequence operation) are parts of the same target
- column_default_non_parenthesized_expr, and there are no any optional
- clauses between the start of column_default_non_parenthesized_expr
- and until NEXT_SYM / PREVIOUS_SYM.
-*/
-%left PREC_BELOW_IDENTIFIER_OPT_SPECIAL_CASE
-%left TRANSACTION_SYM TIMESTAMP PERIOD_SYM SYSTEM USER
-
-
-/*
- Tokens that can appear in a token contraction on the second place
- and change the meaning of the previous token.
-
- - TEXT_STRING: changes the meaning of TIMESTAMP/TIME/DATE
- from identifier to literal:
- SELECT timestamp FROM t1;
- SELECT TIMESTAMP'2001-01-01 00:00:00' FROM t1;
-
- - Parenthesis: changes the meaning of TIMESTAMP/TIME/DATE
- from identifiers to CAST-alike functions:
- SELECT timestamp FROM t1;
- SELECT timestamp(1) FROM t1;
-
- - VALUE: changes NEXT and PREVIOUS from identifier to sequence operation:
- SELECT next, previous FROM t1;
- SELECT NEXT VALUE FOR s1, PREVIOUS VALUE FOR s1;
-
- - VERSIONING: changes SYSTEM from identifier to SYSTEM VERSIONING
- SELECT system FROM t1;
- ALTER TABLE t1 ADD SYSTEM VERSIONING;
-*/
-%left PREC_BELOW_CONTRACTION_TOKEN2
-%left TEXT_STRING '(' ')' VALUE_SYM VERSIONING_SYM
-%left EMPTY_FROM_CLAUSE
-%right INTO
-
-%type <lex_str>
- DECIMAL_NUM FLOAT_NUM NUM LONG_NUM
- HEX_NUM HEX_STRING
- LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident_or_text
- TEXT_STRING_sys TEXT_STRING_literal
- key_cache_name
- sp_opt_label BIN_NUM TEXT_STRING_filesystem
- opt_constraint constraint opt_ident
- opt_package_routine_end_name
- sp_block_label opt_place opt_db
-
-%type <lex_str>
- label_declaration_oracle
- labels_declaration_oracle
-
-%type <ident_sys>
- IDENT_sys
- ident
- label_ident
- sp_decl_ident
- ident_set_usual_case
- ident_or_empty
- ident_table_alias
- ident_sysvar_name
- ident_directly_assignable
-
-%type <lex_string_with_metadata>
- TEXT_STRING
- NCHAR_STRING
-
-%type <lex_str_ptr>
- opt_table_alias_clause
- table_alias_clause
-
-%type <ident_cli>
- IDENT
- IDENT_QUOTED
- IDENT_cli
- ident_cli
-
-%type <kwd>
- keyword_data_type
- keyword_ident
- keyword_label
- keyword_set_special_case
- keyword_set_usual_case
- keyword_sp_block_section
- keyword_sp_decl
- keyword_sp_head
- keyword_sp_var_and_label
- keyword_sp_var_not_label
- keyword_sysvar_name
- keyword_sysvar_type
- keyword_table_alias
- keyword_verb_clause
- keyword_directly_assignable
-
-%type <table>
- table_ident table_ident_nodb references xid
- table_ident_opt_wild create_like
-
-%type <qualified_column_ident>
- optionally_qualified_column_ident
-
-%type <simple_string>
- remember_name remember_end remember_end_opt
- remember_tok_start
- wild_and_where
-
-%type <const_simple_string>
- field_length opt_field_length opt_field_length_default_1
- opt_compression_method
-
-%type <string>
- text_string hex_or_bin_String opt_gconcat_separator
-
-%type <type_handler> int_type real_type
-
-%type <Lex_field_type> type_with_opt_collate field_type
- sp_param_type_with_opt_collate
- sp_param_field_type
- sp_param_field_type_string
- field_type_numeric
- field_type_string
- field_type_lob
- field_type_temporal
- field_type_misc
-
-%type <Lex_dyncol_type> opt_dyncol_type dyncol_type
- numeric_dyncol_type temporal_dyncol_type string_dyncol_type
-
-%type <create_field> field_spec column_def
-
-%type <geom_type> spatial_type
-
-%type <num>
- order_dir lock_option
- udf_type opt_local opt_no_write_to_binlog
- opt_temporary all_or_any opt_distinct opt_glimit_clause
- opt_ignore_leaves fulltext_options union_option
- opt_not
- transaction_access_mode_types
- opt_natural_language_mode opt_query_expansion
- opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment
- ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt
- optional_flush_tables_arguments
- opt_time_precision kill_type kill_option int_num
- opt_default_time_precision
- case_stmt_body opt_bin_mod opt_for_system_time_clause
- opt_if_exists_table_element opt_if_not_exists_table_element
- opt_recursive opt_format_xid opt_for_portion_of_time_clause
-
-%type <object_ddl_options>
- create_or_replace
- opt_if_not_exists
- opt_if_exists
-
-/*
- Bit field of MYSQL_START_TRANS_OPT_* flags.
-*/
-%type <num> opt_start_transaction_option_list
-%type <num> start_transaction_option_list
-%type <num> start_transaction_option
-
-%type <m_yes_no_unk>
- opt_chain opt_release
-
-%type <m_fk_option>
- delete_option
-
-%type <ulong_num>
- ulong_num real_ulong_num merge_insert_types
- ws_nweights opt_versioning_interval_start
- ws_level_flag_desc ws_level_flag_reverse ws_level_flags
- opt_ws_levels ws_level_list ws_level_list_item ws_level_number
- ws_level_range ws_level_list_or_range bool
-
-%type <ulonglong_number>
- ulonglong_num real_ulonglong_num size_number
-
-%type <longlong_number>
- longlong_num
-
-%type <choice> choice
-
-%type <lock_type>
- replace_lock_option opt_low_priority insert_lock_option load_data_lock
-
-%type <item>
- literal insert_ident order_ident temporal_literal
- simple_ident expr sum_expr in_sum_expr
- variable variable_aux bool_pri
- predicate bit_expr parenthesized_expr
- table_wild simple_expr column_default_non_parenthesized_expr udf_expr
- primary_expr string_factor_expr mysql_concatenation_expr
- select_sublist_qualified_asterisk
- expr_or_default set_expr_or_default
- geometry_function signed_literal expr_or_literal
- opt_escape
- sp_opt_default
- simple_ident_nospvar
- field_or_var limit_option
- part_func_expr
- window_func_expr
- window_func
- simple_window_func
- inverse_distribution_function
- percentile_function
- inverse_distribution_function_def
- explicit_cursor_attr
- function_call_keyword
- function_call_keyword_timestamp
- function_call_nonkeyword
- function_call_generic
- function_call_conflict kill_expr
- signal_allowed_expr
- simple_target_specification
- condition_number
- reset_lex_expr
-
-%type <item_param> param_marker
-
-%type <item_num>
- NUM_literal
-
-%type <item_basic_constant> text_literal
-
-%type <item_list>
- expr_list opt_udf_expr_list udf_expr_list when_list when_list_opt_else
- ident_list ident_list_arg opt_expr_list
- decode_when_list_oracle
- execute_using
- execute_params
-
-%type <sp_cursor_stmt>
- sp_cursor_stmt_lex
- sp_cursor_stmt
-
-%type <assignment_lex>
- assignment_source_lex
- assignment_source_expr
- for_loop_bound_expr
-
-%type <sp_assignment_lex_list>
- cursor_actual_parameters
- opt_parenthesized_cursor_actual_parameters
-
-%type <var_type>
- option_type opt_var_type opt_var_ident_type
-
-%type <key_type>
- opt_unique constraint_key_type fulltext spatial
-
-%type <key_alg>
- btree_or_rtree opt_key_algorithm_clause opt_USING_key_algorithm
-
-%type <string_list>
- using_list opt_use_partition use_partition
-
-%type <key_part>
- key_part
-
-%type <table_list>
- join_table_list join_table
- table_factor table_ref esc_table_ref
- table_primary_ident table_primary_ident_opt_parens
- table_primary_derived table_primary_derived_opt_parens
- derived_table_list table_reference_list_parens
- nested_table_reference_list join_table_parens
- update_table_list
-%type <date_time_type> date_time_type;
-%type <interval> interval
-
-%type <interval_time_st> interval_time_stamp
-
-%type <db_type> storage_engines known_storage_engines
-
-%type <row_type> row_types
-
-%type <tx_isolation> isolation_types
-
-%type <ha_rkey_mode> handler_rkey_mode
-
-%type <Lex_cast_type> cast_type cast_type_numeric cast_type_temporal
-
-%type <Lex_length_and_dec> precision opt_precision float_options
- opt_field_length_default_sp_param_varchar
- opt_field_length_default_sp_param_char
-
-%type <lex_user> user grant_user grant_role user_or_role current_role
- admin_option_for_role user_maybe_role
-
-%type <user_auth> opt_auth_str auth_expression auth_token
-
-%type <charset>
- opt_collate
- charset_name
- charset_or_alias
- charset_name_or_default
- old_or_new_charset_name
- old_or_new_charset_name_or_default
- collation_name
- collation_name_or_default
- opt_load_data_charset
- UNDERSCORE_CHARSET
-
-%type <select_lex> subselect
- query_specification
- table_value_constructor
- simple_table
- query_simple
- query_primary
- subquery
- select_into_query_specification
-
-%type <select_lex_unit>
- query_expression
- query_expression_no_with_clause
- query_expression_body_ext
- query_expression_body_ext_parens
- query_expression_body
- query_specification_start
-
-%type <boolfunc2creator> comp_op
-
-%type <dyncol_def> dyncall_create_element
-
-%type <dyncol_def_list> dyncall_create_list
-
-%type <myvar> select_outvar
-
-%type <virtual_column> opt_check_constraint check_constraint virtual_column_func
- column_default_expr
-
-%type <unit_operation> unit_type_decl
-
-%type <select_lock>
- opt_procedure_or_into
- opt_select_lock_type
- select_lock_type
- opt_lock_wait_timeout_new
-
-%type <select_limit> opt_limit_clause limit_clause limit_options
-
-%type <order_limit_lock>
- query_expression_tail
- opt_query_expression_tail
- order_or_limit
- order_limit_lock
- opt_order_limit_lock
-
-%type <select_order> opt_order_clause order_clause order_list
-
-%type <NONE>
- analyze_stmt_command backup backup_statements
- query verb_clause create change select select_into
- do drop insert replace insert2
- insert_values update delete truncate rename compound_statement
- show describe load alter optimize keycache preload flush
- reset purge begin_stmt_mariadb commit rollback savepoint release
- slave master_def master_defs master_file_def slave_until_opts
- repair analyze opt_with_admin opt_with_admin_option
- analyze_table_list analyze_table_elem_spec
- opt_persistent_stat_clause persistent_stat_spec
- persistent_column_stat_spec persistent_index_stat_spec
- table_column_list table_index_list table_index_name
- check start checksum
- field_list field_list_item kill key_def constraint_def
- keycache_list keycache_list_or_parts assign_to_keycache
- assign_to_keycache_parts
- 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
- grant revoke set lock unlock string_list field_options
- opt_binary table_lock_list table_lock
- ref_list opt_match_clause opt_on_update_delete use
- opt_delete_options opt_delete_option varchar nchar nvarchar
- opt_outer table_list table_name table_alias_ref_list table_alias_ref
- attribute attribute_list
- compressed_deprecated_data_type_attribute
- compressed_deprecated_column_attribute
- column_list column_list_id
- opt_column_list grant_privileges grant_ident grant_list grant_option
- object_privilege object_privilege_list user_list user_and_role_list
- rename_list table_or_tables
- clear_privileges flush_options flush_option
- opt_flush_lock flush_lock flush_options_list
- equal optional_braces
- opt_mi_check_type opt_to mi_check_types
- table_to_table_list table_to_table opt_table_list opt_as
- handler_rkey_function handler_read_or_scan
- single_multi table_wild_list table_wild_one opt_wild
- opt_and charset
- select_var_list select_var_list_init help
- opt_extended_describe shutdown
- opt_format_json
- prepare execute deallocate
- statement
- sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
- opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
- view_list_opt view_list view_select
- trigger_tail event_tail
- install uninstall partition_entry binlog_base64_event
- normal_key_options normal_key_opts all_key_opt
- spatial_key_options fulltext_key_options normal_key_opt
- fulltext_key_opt spatial_key_opt fulltext_key_opts spatial_key_opts
- keep_gcc_happy
- key_using_alg
- part_column_list
- period_for_system_time
- period_for_application_time
- server_def server_options_list server_option
- definer_opt no_definer definer get_diagnostics
- parse_vcol_expr vcol_opt_specifier vcol_opt_attribute
- vcol_opt_attribute_list vcol_attribute
- opt_serial_attribute opt_serial_attribute_list serial_attribute
- explainable_command
- opt_lock_wait_timeout
- opt_delete_gtid_domain
- asrow_attribute
- set_assign
- sp_tail_standalone
- opt_constraint_no_id
-END_OF_INPUT
-
-%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
-%type <NONE> sp_proc_stmt_statement sp_proc_stmt_return
-%type <NONE> sp_proc_stmt_compound_ok
-%type <NONE> sp_proc_stmt_if
-%type <NONE> sp_labeled_control sp_unlabeled_control
-%type <NONE> sp_labeled_block sp_unlabeled_block
-%type <NONE> sp_labelable_stmt
-%type <NONE> sp_proc_stmt_continue_oracle
-%type <NONE> sp_proc_stmt_exit_oracle
-%type <NONE> sp_proc_stmt_leave
-%type <NONE> sp_proc_stmt_iterate
-%type <NONE> sp_proc_stmt_goto_oracle
-%type <NONE> sp_proc_stmt_open sp_proc_stmt_fetch sp_proc_stmt_close
-%type <NONE> case_stmt_specification
-%type <NONE> loop_body while_body repeat_body
-
-%type <num> view_algorithm view_check_option
-%type <view_suid> view_suid opt_view_suid
-
-%type <plsql_cursor_attr> plsql_cursor_attr
-%type <sp_suid> sp_suid
-%type <sp_aggregate_type> opt_aggregate
-
-%type <num> sp_decl_idents sp_decl_idents_init_vars
-%type <num> sp_handler_type sp_hcond_list
-%type <spcondvalue> sp_cond sp_hcond sqlstate signal_value opt_signal_value
-%type <spblock> sp_decl_body_list opt_sp_decl_body_list
-%type <spblock> sp_decl_vars
-%type <spblock> sp_decl_non_handler sp_decl_non_handler_list
-%type <spblock> sp_decl_handler sp_decl_handler_list opt_sp_decl_handler_list
-%type <spblock> package_implementation_routine_definition
-%type <spblock> package_implementation_item_declaration
-%type <spblock> package_implementation_declare_section
-%type <spblock> package_implementation_declare_section_list1
-%type <spblock> package_implementation_declare_section_list2
-%type <spblock_handlers> sp_block_statements_and_exceptions
-%type <spblock_handlers> package_implementation_executable_section
-%type <sp_instr_addr> sp_instr_addr
-%type <num> opt_exception_clause exception_handlers
-%type <lex> remember_lex package_routine_lex
- package_specification_function
- package_specification_procedure
-%type <spname> sp_name opt_sp_name
-%type <spvar> sp_param_name sp_param_name_and_type
-%type <for_loop> sp_for_loop_index_and_bounds
-%type <for_loop_bounds> sp_for_loop_bounds
-%type <trim> trim_operands
-%type <num> opt_sp_for_loop_direction
-%type <spvar_mode> sp_opt_inout
-%type <index_hint> index_hint_type
-%type <num> index_hint_clause normal_join inner_join
-%type <filetype> data_or_xml
-
-%type <NONE> signal_stmt resignal_stmt raise_stmt_oracle
-%type <diag_condition_item_name> signal_condition_information_item_name
-
-%type <trg_execution_order> trigger_follows_precedes_clause;
-%type <trigger_action_order_type> trigger_action_order;
-
-%type <diag_area> which_area;
-%type <diag_info> diagnostics_information;
-%type <stmt_info_item> statement_information_item;
-%type <stmt_info_item_name> statement_information_item_name;
-%type <stmt_info_list> statement_information;
-%type <cond_info_item> condition_information_item;
-%type <cond_info_item_name> condition_information_item_name;
-%type <cond_info_list> condition_information;
-
-%type <spvar_definition> row_field_name row_field_definition
-%type <spvar_definition_list> row_field_definition_list row_type_body
-
-%type <NONE> opt_window_clause window_def_list window_def window_spec
-%type <lex_str_ptr> window_name
-%type <NONE> opt_window_ref opt_window_frame_clause
-%type <frame_units> window_frame_units;
-%type <NONE> window_frame_extent;
-%type <frame_exclusion> opt_window_frame_exclusion;
-%type <window_frame_bound> window_frame_start window_frame_bound;
-
-%type <kwd>
- '-' '+' '*' '/' '%' '(' ')'
- ',' '!' '{' '}' '&' '|'
-
-%type <NONE>
- AND_SYM OR_SYM BETWEEN_SYM CASE_SYM
- THEN_SYM WHEN_SYM DIV_SYM MOD_SYM OR2_SYM AND_AND_SYM DELETE_SYM
- MYSQL_CONCAT_SYM ORACLE_CONCAT_SYM
-
-%type <with_clause> with_clause
-
-%type <lex_str_ptr> query_name
-
-%type <lex_str_list> opt_with_column_list
-
-%type <vers_range_unit> opt_history_unit
-%type <vers_history_point> history_point
-%type <vers_column_versioning> with_or_without_system
-%%
-
-
-/*
- Indentation of grammar rules:
-
-rule: <-- starts at col 1
- rule1a rule1b rule1c <-- starts at col 11
- { <-- starts at col 11
- code <-- starts at col 13, indentation is 2 spaces
- }
- | rule2a rule2b
- {
- code
- }
- ; <-- on a line by itself, starts at col 9
-
- Also, please do not use any <TAB>, but spaces.
- Having a uniform indentation in this file helps
- code reviews, patches, merges, and make maintenance easier.
- Tip: grep [[:cntrl:]] sql_yacc.yy
- Thanks.
-*/
-
-query:
- END_OF_INPUT
- {
- if (!thd->bootstrap &&
- (!(thd->lex->lex_options & OPTION_LEX_FOUND_COMMENT)))
- my_yyabort_error((ER_EMPTY_QUERY, MYF(0)));
-
- thd->lex->sql_command= SQLCOM_EMPTY_QUERY;
- YYLIP->found_semicolon= NULL;
- }
- | verb_clause
- {
- Lex_input_stream *lip = YYLIP;
-
- if ((thd->client_capabilities & CLIENT_MULTI_QUERIES) &&
- lip->multi_statements &&
- ! lip->eof())
- {
- /*
- We found a well formed query, and multi queries are allowed:
- - force the parser to stop after the ';'
- - mark the start of the next query for the next invocation
- of the parser.
- */
- lip->next_state= MY_LEX_END;
- lip->found_semicolon= lip->get_ptr();
- }
- else
- {
- /* Single query, terminated. */
- lip->found_semicolon= NULL;
- }
- }
- ';'
- opt_end_of_input
- | verb_clause END_OF_INPUT
- {
- /* Single query, not terminated. */
- YYLIP->found_semicolon= NULL;
- }
- ;
-
-opt_end_of_input:
- /* empty */
- | END_OF_INPUT
- ;
-
-verb_clause:
- statement
- | begin_stmt_mariadb
- | compound_statement
- ;
-
-/* Verb clauses, except begin and compound_statement */
-statement:
- alter
- | analyze
- | analyze_stmt_command
- | backup
- | binlog_base64_event
- | call
- | change
- | check
- | checksum
- | commit
- | create
- | deallocate
- | delete
- | describe
- | do
- | drop
- | execute
- | flush
- | get_diagnostics
- | grant
- | handler
- | help
- | insert
- | install
- | keep_gcc_happy
- | keycache
- | kill
- | load
- | lock
- | optimize
- | parse_vcol_expr
- | partition_entry
- | preload
- | prepare
- | purge
- | raise_stmt_oracle
- | release
- | rename
- | repair
- | replace
- | reset
- | resignal_stmt
- | revoke
- | rollback
- | savepoint
- | select
- | select_into
- | set
- | set_assign
- | signal_stmt
- | show
- | shutdown
- | slave
- | start
- | truncate
- | uninstall
- | unlock
- | update
- | use
- | xa
- ;
-
-deallocate:
- deallocate_or_drop PREPARE_SYM ident
- {
- Lex->stmt_deallocate_prepare($3);
- }
- ;
-
-deallocate_or_drop:
- DEALLOCATE_SYM
- | DROP
- ;
-
-prepare:
- PREPARE_SYM ident FROM
- { Lex->clause_that_disallows_subselect= "PREPARE..FROM"; }
- expr
- {
- Lex->clause_that_disallows_subselect= NULL;
- if (Lex->stmt_prepare($2, $5))
- MYSQL_YYABORT;
- }
- ;
-
-execute:
- EXECUTE_SYM ident execute_using
- {
- if (Lex->stmt_execute($2, $3))
- MYSQL_YYABORT;
- }
- | EXECUTE_SYM IMMEDIATE_SYM
- { Lex->clause_that_disallows_subselect= "EXECUTE IMMEDIATE"; }
- expr
- { Lex->clause_that_disallows_subselect= NULL; }
- execute_using
- {
- if (Lex->stmt_execute_immediate($4, $6))
- MYSQL_YYABORT;
- }
- ;
-
-execute_using:
- /* nothing */ { $$= NULL; }
- | USING
- { Lex->clause_that_disallows_subselect= "EXECUTE..USING"; }
- execute_params
- {
- $$= $3;
- Lex->clause_that_disallows_subselect= NULL;
- }
- ;
-
-execute_params:
- expr_or_default
- {
- if (unlikely(!($$= List<Item>::make(thd->mem_root, $1))))
- MYSQL_YYABORT;
- }
- | execute_params ',' expr_or_default
- {
- if (($$= $1)->push_back($3, thd->mem_root))
- MYSQL_YYABORT;
- }
- ;
-
-
-/* help */
-
-help:
- HELP_SYM
- {
- if (unlikely(Lex->sphead))
- my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HELP"));
- }
- ident_or_text
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_HELP;
- lex->help_arg= $3.str;
- }
- ;
-
-/* change master */
-
-change:
- CHANGE MASTER_SYM optional_connection_name TO_SYM
- {
- Lex->sql_command = SQLCOM_CHANGE_MASTER;
- }
- master_defs
- {}
- ;
-
-master_defs:
- master_def
- | master_defs ',' master_def
- ;
-
-master_def:
- MASTER_HOST_SYM '=' TEXT_STRING_sys
- {
- Lex->mi.host = $3.str;
- }
- | MASTER_USER_SYM '=' TEXT_STRING_sys
- {
- Lex->mi.user = $3.str;
- }
- | MASTER_PASSWORD_SYM '=' TEXT_STRING_sys
- {
- Lex->mi.password = $3.str;
- }
- | MASTER_PORT_SYM '=' ulong_num
- {
- Lex->mi.port = $3;
- }
- | MASTER_CONNECT_RETRY_SYM '=' ulong_num
- {
- Lex->mi.connect_retry = $3;
- }
- | MASTER_DELAY_SYM '=' ulong_num
- {
- if ($3 > MASTER_DELAY_MAX)
- {
- my_error(ER_MASTER_DELAY_VALUE_OUT_OF_RANGE, MYF(0),
- (ulong) $3, (ulong) MASTER_DELAY_MAX);
- }
- else
- Lex->mi.sql_delay = $3;
- }
- | MASTER_SSL_SYM '=' ulong_num
- {
- Lex->mi.ssl= $3 ?
- LEX_MASTER_INFO::LEX_MI_ENABLE : LEX_MASTER_INFO::LEX_MI_DISABLE;
- }
- | MASTER_SSL_CA_SYM '=' TEXT_STRING_sys
- {
- Lex->mi.ssl_ca= $3.str;
- }
- | MASTER_SSL_CAPATH_SYM '=' TEXT_STRING_sys
- {
- Lex->mi.ssl_capath= $3.str;
- }
- | MASTER_SSL_CERT_SYM '=' TEXT_STRING_sys
- {
- Lex->mi.ssl_cert= $3.str;
- }
- | MASTER_SSL_CIPHER_SYM '=' TEXT_STRING_sys
- {
- Lex->mi.ssl_cipher= $3.str;
- }
- | MASTER_SSL_KEY_SYM '=' TEXT_STRING_sys
- {
- Lex->mi.ssl_key= $3.str;
- }
- | MASTER_SSL_VERIFY_SERVER_CERT_SYM '=' ulong_num
- {
- Lex->mi.ssl_verify_server_cert= $3 ?
- LEX_MASTER_INFO::LEX_MI_ENABLE : LEX_MASTER_INFO::LEX_MI_DISABLE;
- }
- | MASTER_SSL_CRL_SYM '=' TEXT_STRING_sys
- {
- Lex->mi.ssl_crl= $3.str;
- }
- | MASTER_SSL_CRLPATH_SYM '=' TEXT_STRING_sys
- {
- Lex->mi.ssl_crlpath= $3.str;
- }
-
- | MASTER_HEARTBEAT_PERIOD_SYM '=' NUM_literal
- {
- Lex->mi.heartbeat_period= (float) $3->val_real();
- if (unlikely(Lex->mi.heartbeat_period >
- SLAVE_MAX_HEARTBEAT_PERIOD) ||
- unlikely(Lex->mi.heartbeat_period < 0.0))
- my_yyabort_error((ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE, MYF(0),
- SLAVE_MAX_HEARTBEAT_PERIOD));
-
- if (unlikely(Lex->mi.heartbeat_period > slave_net_timeout))
- {
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX,
- ER_THD(thd, ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX));
- }
- if (unlikely(Lex->mi.heartbeat_period < 0.001))
- {
- if (unlikely(Lex->mi.heartbeat_period != 0.0))
- {
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN,
- ER_THD(thd, ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN));
- Lex->mi.heartbeat_period= 0.0;
- }
- Lex->mi.heartbeat_opt= LEX_MASTER_INFO::LEX_MI_DISABLE;
- }
- Lex->mi.heartbeat_opt= LEX_MASTER_INFO::LEX_MI_ENABLE;
- }
- | IGNORE_SERVER_IDS_SYM '=' '(' ignore_server_id_list ')'
- {
- Lex->mi.repl_ignore_server_ids_opt= LEX_MASTER_INFO::LEX_MI_ENABLE;
- }
- | DO_DOMAIN_IDS_SYM '=' '(' do_domain_id_list ')'
- {
- Lex->mi.repl_do_domain_ids_opt= LEX_MASTER_INFO::LEX_MI_ENABLE;
- }
- | IGNORE_DOMAIN_IDS_SYM '=' '(' ignore_domain_id_list ')'
- {
- Lex->mi.repl_ignore_domain_ids_opt= LEX_MASTER_INFO::LEX_MI_ENABLE;
- }
- |
- master_file_def
- ;
-
-ignore_server_id_list:
- /* Empty */
- | ignore_server_id
- | ignore_server_id_list ',' ignore_server_id
- ;
-
-ignore_server_id:
- ulong_num
- {
- insert_dynamic(&Lex->mi.repl_ignore_server_ids, (uchar*) &($1));
- }
- ;
-
-do_domain_id_list:
- /* Empty */
- | do_domain_id
- | do_domain_id_list ',' do_domain_id
- ;
-
-do_domain_id:
- ulong_num
- {
- insert_dynamic(&Lex->mi.repl_do_domain_ids, (uchar*) &($1));
- }
- ;
-
-ignore_domain_id_list:
- /* Empty */
- | ignore_domain_id
- | ignore_domain_id_list ',' ignore_domain_id
- ;
-
-ignore_domain_id:
- ulong_num
- {
- insert_dynamic(&Lex->mi.repl_ignore_domain_ids, (uchar*) &($1));
- }
- ;
-
-master_file_def:
- MASTER_LOG_FILE_SYM '=' TEXT_STRING_sys
- {
- Lex->mi.log_file_name = $3.str;
- }
- | MASTER_LOG_POS_SYM '=' ulonglong_num
- {
- /*
- If the user specified a value < BIN_LOG_HEADER_SIZE, adjust it
- instead of causing subsequent errors.
- We need to do it in this file, because only there we know that
- MASTER_LOG_POS has been explicitly specified. On the contrary
- in change_master() (sql_repl.cc) we cannot distinguish between 0
- (MASTER_LOG_POS explicitly specified as 0) and 0 (unspecified),
- whereas we want to distinguish (specified 0 means "read the binlog
- from 0" (4 in fact), unspecified means "don't change the position
- (keep the preceding value)").
- */
- Lex->mi.pos= MY_MAX(BIN_LOG_HEADER_SIZE, $3);
- }
- | RELAY_LOG_FILE_SYM '=' TEXT_STRING_sys
- {
- Lex->mi.relay_log_name = $3.str;
- }
- | RELAY_LOG_POS_SYM '=' ulong_num
- {
- Lex->mi.relay_log_pos = $3;
- /* Adjust if < BIN_LOG_HEADER_SIZE (same comment as Lex->mi.pos) */
- Lex->mi.relay_log_pos= MY_MAX(BIN_LOG_HEADER_SIZE, Lex->mi.relay_log_pos);
- }
- | MASTER_USE_GTID_SYM '=' CURRENT_POS_SYM
- {
- if (unlikely(Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED))
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid"));
- Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_CURRENT_POS;
- }
- | MASTER_USE_GTID_SYM '=' SLAVE_POS_SYM
- {
- if (unlikely(Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED))
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid"));
- Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_SLAVE_POS;
- }
- | MASTER_USE_GTID_SYM '=' NO_SYM
- {
- if (unlikely(Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED))
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid"));
- Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_NO;
- }
- ;
-
-optional_connection_name:
- /* empty */
- {
- LEX *lex= thd->lex;
- lex->mi.connection_name= null_clex_str;
- }
- | connection_name
- ;
-
-connection_name:
- TEXT_STRING_sys
- {
- Lex->mi.connection_name= $1;
-#ifdef HAVE_REPLICATION
- if (unlikely(check_master_connection_name(&$1)))
- my_yyabort_error((ER_WRONG_ARGUMENTS, MYF(0), "MASTER_CONNECTION_NAME"));
-#endif
- }
- ;
-
-/* create a table */
-
-create:
- create_or_replace opt_temporary TABLE_SYM opt_if_not_exists
- {
- LEX *lex= thd->lex;
- if (!(lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_create_table()))
- MYSQL_YYABORT;
- lex->create_info.init();
- if (lex->main_select_push())
- MYSQL_YYABORT;
- lex->current_select->parsing_place= BEFORE_OPT_LIST;
- if (lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2, $1 | $4))
- MYSQL_YYABORT;
- }
- table_ident
- {
- LEX *lex= thd->lex;
- if (!lex->first_select_lex()->
- add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING,
- TL_WRITE, MDL_SHARED_UPGRADABLE))
- MYSQL_YYABORT;
- lex->alter_info.reset();
- /*
- For CREATE TABLE we should not open the table even if it exists.
- If the table exists, we should either not create it or replace it
- */
- lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB;
- lex->create_info.default_table_charset= NULL;
- lex->name= null_clex_str;
- lex->create_last_non_select_table= lex->last_table();
- }
- create_body
- {
- LEX *lex= thd->lex;
- create_table_set_open_action_and_adjust_tables(lex);
- Lex->pop_select(); //main select
- }
- | create_or_replace opt_temporary SEQUENCE_SYM opt_if_not_exists table_ident
- {
- LEX *lex= thd->lex;
- if (lex->main_select_push())
- MYSQL_YYABORT;
- if (!(lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_create_sequence()))
- MYSQL_YYABORT;
- lex->create_info.init();
- if (unlikely(lex->set_command_with_check(SQLCOM_CREATE_SEQUENCE, $2,
- $1 | $4)))
- MYSQL_YYABORT;
-
- if (!lex->first_select_lex()->
- add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING,
- TL_WRITE, MDL_EXCLUSIVE))
- MYSQL_YYABORT;
-
- /*
- For CREATE TABLE, an non-existing table is not an error.
- Instruct open_tables() to just take an MDL lock if the
- table does not exist.
- */
- lex->alter_info.reset();
- lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB;
- lex->name= null_clex_str;
- lex->create_last_non_select_table= lex->last_table();
- if (unlikely(!(lex->create_info.seq_create_info=
- new (thd->mem_root) sequence_definition())))
- MYSQL_YYABORT;
- }
- opt_sequence opt_create_table_options
- {
- LEX *lex= thd->lex;
-
- if (unlikely(lex->create_info.seq_create_info->check_and_adjust(1)))
- {
- my_error(ER_SEQUENCE_INVALID_DATA, MYF(0),
- lex->first_select_lex()->table_list.first->db.str,
- lex->first_select_lex()->table_list.first->
- table_name.str);
- MYSQL_YYABORT;
- }
-
- /* No fields specified, generate them */
- if (unlikely(prepare_sequence_fields(thd,
- &lex->alter_info.create_list)))
- MYSQL_YYABORT;
-
- /* CREATE SEQUENCE always creates a sequence */
- Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE;
- Lex->create_info.sequence= 1;
-
- create_table_set_open_action_and_adjust_tables(lex);
- Lex->pop_select(); //main select
- }
- | create_or_replace opt_unique INDEX_SYM opt_if_not_exists
- {
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- }
- ident
- opt_key_algorithm_clause
- ON table_ident
- {
- if (Lex->add_create_index_prepare($9))
- MYSQL_YYABORT;
- if (Lex->add_create_index($2, &$6, $7, $1 | $4))
- MYSQL_YYABORT;
- }
- '(' key_list ')' opt_lock_wait_timeout normal_key_options
- opt_index_lock_algorithm
- {
- Lex->pop_select(); //main select
- }
- | create_or_replace fulltext INDEX_SYM
- {
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- }
- opt_if_not_exists ident
- ON table_ident
- {
- if (Lex->add_create_index_prepare($8))
- MYSQL_YYABORT;
- if (Lex->add_create_index($2, &$6, HA_KEY_ALG_UNDEF, $1 | $5))
- MYSQL_YYABORT;
- }
- '(' key_list ')' opt_lock_wait_timeout fulltext_key_options
- opt_index_lock_algorithm
- {
- Lex->pop_select(); //main select
- }
- | create_or_replace spatial INDEX_SYM
- {
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- }
- opt_if_not_exists ident
- ON table_ident
- {
- if (Lex->add_create_index_prepare($8))
- MYSQL_YYABORT;
- if (Lex->add_create_index($2, &$6, HA_KEY_ALG_UNDEF, $1 | $5))
- MYSQL_YYABORT;
- }
- '(' key_list ')' opt_lock_wait_timeout spatial_key_options
- opt_index_lock_algorithm
- {
- Lex->pop_select(); //main select
- }
- | create_or_replace DATABASE opt_if_not_exists ident
- {
- Lex->create_info.default_table_charset= NULL;
- Lex->create_info.used_fields= 0;
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- }
- opt_create_database_options
- {
- LEX *lex=Lex;
- if (unlikely(lex->set_command_with_check(SQLCOM_CREATE_DB, 0,
- $1 | $3)))
- MYSQL_YYABORT;
- lex->name= $4;
- Lex->pop_select(); //main select
- }
- | create_or_replace definer_opt opt_view_suid VIEW_SYM
- opt_if_not_exists table_ident
- {
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- if (Lex->add_create_view(thd, $1 | $5,
- DTYPE_ALGORITHM_UNDEFINED, $3, $6))
- MYSQL_YYABORT;
- }
- view_list_opt AS view_select
- {
- Lex->pop_select(); //main select
- }
- | create_or_replace view_algorithm definer_opt opt_view_suid VIEW_SYM
- opt_if_not_exists table_ident
- {
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- if (Lex->add_create_view(thd, $1 | $6, $2, $4, $7))
- MYSQL_YYABORT;
- }
- view_list_opt AS view_select
- {
- Lex->pop_select(); //main select
- }
- | create_or_replace definer_opt TRIGGER_SYM
- {
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- Lex->create_info.set($1);
- }
- trigger_tail
- {
- Lex->pop_select(); //main select
- }
- | create_or_replace definer_opt PROCEDURE_SYM opt_if_not_exists
- {
- if (Lex->stmt_create_procedure_start($1 | $4))
- MYSQL_YYABORT;
- }
- sp_tail_standalone
- {
- Lex->stmt_create_routine_finalize();
- }
- | create_or_replace definer_opt EVENT_SYM
- {
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- Lex->create_info.set($1);
- }
- event_tail
- {
- Lex->pop_select(); //main select
- }
- | create_or_replace definer opt_aggregate FUNCTION_SYM opt_if_not_exists
- sp_name RETURN_ORACLE_SYM
- {
- if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6))
- MYSQL_YYABORT;
- }
- sf_return_type
- sf_c_chistics_and_body_standalone
- opt_sp_name
- {
- if (Lex->stmt_create_stored_function_finalize_standalone($11))
- MYSQL_YYABORT;
- }
- | create_or_replace definer opt_aggregate FUNCTION_SYM opt_if_not_exists
- sp_name '('
- {
- if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6))
- MYSQL_YYABORT;
- }
- sp_fdparam_list ')'
- RETURN_ORACLE_SYM sf_return_type
- sf_c_chistics_and_body_standalone
- opt_sp_name
- {
- if (Lex->stmt_create_stored_function_finalize_standalone($14))
- MYSQL_YYABORT;
- }
- | create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists
- sp_name RETURN_ORACLE_SYM
- {
- if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6))
- MYSQL_YYABORT;
- }
- sf_return_type
- sf_c_chistics_and_body_standalone
- opt_sp_name
- {
- if (Lex->stmt_create_stored_function_finalize_standalone($11))
- MYSQL_YYABORT;
- }
- | create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists
- sp_name '('
- {
- if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6))
- MYSQL_YYABORT;
- }
- sp_fdparam_list ')'
- RETURN_ORACLE_SYM sf_return_type
- sf_c_chistics_and_body_standalone
- opt_sp_name
- {
- if (Lex->stmt_create_stored_function_finalize_standalone($14))
- MYSQL_YYABORT;
- }
- | create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists
- ident RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
- {
- if (Lex->stmt_create_udf_function($1 | $5, $3, $6,
- (Item_result) $8, $10))
- MYSQL_YYABORT;
- }
- | create_or_replace USER_SYM opt_if_not_exists clear_privileges
- grant_list opt_require_clause opt_resource_options opt_account_locking opt_password_expiration
- {
- if (unlikely(Lex->set_command_with_check(SQLCOM_CREATE_USER,
- $1 | $3)))
- MYSQL_YYABORT;
- }
- | create_or_replace ROLE_SYM opt_if_not_exists
- clear_privileges role_list opt_with_admin
- {
- if (unlikely(Lex->set_command_with_check(SQLCOM_CREATE_ROLE,
- $1 | $3)))
- MYSQL_YYABORT;
- }
- | CREATE LOGFILE_SYM GROUP_SYM logfile_group_info
- {
- Lex->alter_tablespace_info->ts_cmd_type= CREATE_LOGFILE_GROUP;
- }
- | CREATE TABLESPACE tablespace_info
- {
- Lex->alter_tablespace_info->ts_cmd_type= CREATE_TABLESPACE;
- }
- | create_or_replace { Lex->set_command(SQLCOM_CREATE_SERVER, $1); }
- server_def
- { }
- | create_or_replace definer_opt PACKAGE_ORACLE_SYM
- opt_if_not_exists sp_name opt_create_package_chistics_init
- sp_tail_is
- remember_name
- {
- sp_package *pkg;
- if (unlikely(!(pkg= Lex->
- create_package_start(thd,
- SQLCOM_CREATE_PACKAGE,
- &sp_handler_package_spec,
- $5, $1 | $4))))
- MYSQL_YYABORT;
- pkg->set_c_chistics(Lex->sp_chistics);
- }
- opt_package_specification_element_list END
- remember_end_opt opt_sp_name
- {
- if (unlikely(Lex->create_package_finalize(thd, $5, $13, $8, $12)))
- MYSQL_YYABORT;
- }
- | create_or_replace definer_opt PACKAGE_ORACLE_SYM BODY_ORACLE_SYM
- opt_if_not_exists sp_name opt_create_package_chistics_init
- sp_tail_is
- remember_name
- {
- sp_package *pkg;
- if (unlikely(!(pkg= Lex->
- create_package_start(thd,
- SQLCOM_CREATE_PACKAGE_BODY,
- &sp_handler_package_body,
- $6, $1 | $5))))
- MYSQL_YYABORT;
- pkg->set_c_chistics(Lex->sp_chistics);
- Lex->sp_block_init(thd);
- }
- package_implementation_declare_section
- {
- if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd)))
- MYSQL_YYABORT;
- }
- package_implementation_executable_section
- {
- $11.hndlrs+= $13.hndlrs;
- if (unlikely(Lex->sp_block_finalize(thd, $11)))
- MYSQL_YYABORT;
- }
- remember_end_opt opt_sp_name
- {
- if (unlikely(Lex->create_package_finalize(thd, $6, $16, $9, $15)))
- MYSQL_YYABORT;
- }
- ;
-
-package_implementation_executable_section:
- END
- {
- if (unlikely(Lex->sp_block_with_exceptions_add_empty(thd)))
- MYSQL_YYABORT;
- $$.init(0);
- }
- | BEGIN_ORACLE_SYM sp_block_statements_and_exceptions END { $$= $2; }
- ;
-
-/*
- Inside CREATE PACKAGE BODY, package-wide items (e.g. variables)
- must be declared before routine definitions.
-*/
-package_implementation_declare_section:
- package_implementation_declare_section_list1
- | package_implementation_declare_section_list2
- | package_implementation_declare_section_list1
- package_implementation_declare_section_list2
- { $$.join($1, $2); }
- ;
-
-package_implementation_declare_section_list1:
- package_implementation_item_declaration
- | package_implementation_declare_section_list1
- package_implementation_item_declaration
- { $$.join($1, $2); }
- ;
-
-package_implementation_declare_section_list2:
- package_implementation_routine_definition
- | package_implementation_declare_section_list2
- package_implementation_routine_definition
- { $$.join($1, $2); }
- ;
-
-package_routine_lex:
- {
- if (unlikely(!($$= new (thd->mem_root)
- sp_lex_local(thd, thd->lex))))
- MYSQL_YYABORT;
- thd->m_parser_state->m_yacc.reset_before_substatement();
- }
- ;
-
-
-package_specification_function:
- remember_lex package_routine_lex ident
- {
- DBUG_ASSERT($1->sphead->get_package());
- $2->sql_command= SQLCOM_CREATE_FUNCTION;
- sp_name *spname= $1->make_sp_name_package_routine(thd, &$3);
- if (unlikely(!spname))
- MYSQL_YYABORT;
- thd->lex= $2;
- if (unlikely(!$2->make_sp_head_no_recursive(thd, spname,
- &sp_handler_package_function,
- NOT_AGGREGATE)))
- MYSQL_YYABORT;
- $1->sphead->get_package()->m_current_routine= $2;
- (void) is_native_function_with_warn(thd, &$3);
- }
- opt_sp_parenthesized_fdparam_list
- RETURN_ORACLE_SYM sf_return_type
- sp_c_chistics
- {
- sp_head *sp= thd->lex->sphead;
- sp->restore_thd_mem_root(thd);
- thd->lex= $1;
- $$= $2;
- }
- ;
-
-package_specification_procedure:
- remember_lex package_routine_lex ident
- {
- DBUG_ASSERT($1->sphead->get_package());
- $2->sql_command= SQLCOM_CREATE_PROCEDURE;
- sp_name *spname= $1->make_sp_name_package_routine(thd, &$3);
- if (unlikely(!spname))
- MYSQL_YYABORT;
- thd->lex= $2;
- if (unlikely(!$2->make_sp_head_no_recursive(thd, spname,
- &sp_handler_package_procedure,
- DEFAULT_AGGREGATE)))
- MYSQL_YYABORT;
- $1->sphead->get_package()->m_current_routine= $2;
- }
- opt_sp_parenthesized_pdparam_list
- sp_c_chistics
- {
- sp_head *sp= thd->lex->sphead;
- sp->restore_thd_mem_root(thd);
- thd->lex= $1;
- $$= $2;
-
- }
- ;
-
-
-package_implementation_routine_definition:
- FUNCTION_SYM package_specification_function
- package_implementation_function_body ';'
- {
- sp_package *pkg= Lex->get_sp_package();
- if (unlikely(pkg->add_routine_implementation($2)))
- MYSQL_YYABORT;
- pkg->m_current_routine= NULL;
- $$.init();
- }
- | PROCEDURE_SYM package_specification_procedure
- package_implementation_procedure_body ';'
- {
- sp_package *pkg= Lex->get_sp_package();
- if (unlikely(pkg->add_routine_implementation($2)))
- MYSQL_YYABORT;
- pkg->m_current_routine= NULL;
- $$.init();
- }
- | package_specification_element { $$.init(); }
- ;
-
-
-package_implementation_function_body:
- sp_tail_is remember_lex
- {
- sp_package *pkg= Lex->get_sp_package();
- sp_head *sp= pkg->m_current_routine->sphead;
- thd->lex= pkg->m_current_routine;
- sp->reset_thd_mem_root(thd);
- sp->set_body_start(thd, YYLIP->get_cpp_tok_start());
- }
- sp_body opt_package_routine_end_name
- {
- if (unlikely(thd->lex->sp_body_finalize_function(thd) ||
- thd->lex->sphead->check_package_routine_end_name($5)))
- MYSQL_YYABORT;
- thd->lex= $2;
- }
- ;
-
-package_implementation_procedure_body:
- sp_tail_is remember_lex
- {
- sp_package *pkg= Lex->get_sp_package();
- sp_head *sp= pkg->m_current_routine->sphead;
- thd->lex= pkg->m_current_routine;
- sp->reset_thd_mem_root(thd);
- sp->set_body_start(thd, YYLIP->get_cpp_tok_start());
- }
- sp_body opt_package_routine_end_name
- {
- if (unlikely(thd->lex->sp_body_finalize_procedure(thd) ||
- thd->lex->sphead->check_package_routine_end_name($5)))
- MYSQL_YYABORT;
- thd->lex= $2;
- }
- ;
-
-
-package_implementation_item_declaration:
- sp_decl_vars ';'
- ;
-
-opt_package_specification_element_list:
- /* Empty */
- | package_specification_element_list
- ;
-
-package_specification_element_list:
- package_specification_element
- | package_specification_element_list package_specification_element
- ;
-
-package_specification_element:
- FUNCTION_SYM package_specification_function ';'
- {
- sp_package *pkg= Lex->get_sp_package();
- if (unlikely(pkg->add_routine_declaration($2)))
- MYSQL_YYABORT;
- pkg->m_current_routine= NULL;
- }
- | PROCEDURE_SYM package_specification_procedure ';'
- {
- sp_package *pkg= Lex->get_sp_package();
- if (unlikely(pkg->add_routine_declaration($2)))
- MYSQL_YYABORT;
- pkg->m_current_routine= NULL;
- }
- ;
-
-
-opt_sequence:
- /* empty */ { }
- | sequence_defs
- ;
-
-sequence_defs:
- sequence_def
- | sequence_defs sequence_def
- ;
-
-sequence_def:
- MINVALUE_SYM opt_equal longlong_num
- {
- Lex->create_info.seq_create_info->min_value= $3;
- Lex->create_info.seq_create_info->used_fields|= seq_field_used_min_value;
- }
- | NO_SYM MINVALUE_SYM
- {
- if (unlikely(Lex->create_info.seq_create_info->used_fields & seq_field_used_min_value))
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MINVALUE"));
- Lex->create_info.seq_create_info->used_fields|= seq_field_used_min_value;
- }
- | NOMINVALUE_SYM
- {
- if (unlikely(Lex->create_info.seq_create_info->used_fields & seq_field_used_min_value))
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MINVALUE"));
- Lex->create_info.seq_create_info->used_fields|= seq_field_used_min_value;
- }
- | MAXVALUE_SYM opt_equal longlong_num
- {
- if (unlikely(Lex->create_info.seq_create_info->used_fields &
- seq_field_used_max_value))
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MAXVALUE"));
- Lex->create_info.seq_create_info->max_value= $3;
- Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value;
- }
- | NO_SYM MAXVALUE_SYM
- {
- if (unlikely(Lex->create_info.seq_create_info->used_fields & seq_field_used_max_value))
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MAXVALUE"));
- Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value;
- }
- | NOMAXVALUE_SYM
- {
- if (unlikely(Lex->create_info.seq_create_info->used_fields & seq_field_used_max_value))
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MAXVALUE"));
- Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value;
- }
- | START_SYM opt_with longlong_num
- {
- if (unlikely(Lex->create_info.seq_create_info->used_fields &
- seq_field_used_start))
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "START"));
- Lex->create_info.seq_create_info->start= $3;
- Lex->create_info.seq_create_info->used_fields|= seq_field_used_start;
- }
- | INCREMENT_SYM opt_by longlong_num
- {
- if (unlikely(Lex->create_info.seq_create_info->used_fields &
- seq_field_used_increment))
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "INCREMENT"));
- Lex->create_info.seq_create_info->increment= $3;
- Lex->create_info.seq_create_info->used_fields|= seq_field_used_increment;
- }
- | CACHE_SYM opt_equal longlong_num
- {
- if (unlikely(Lex->create_info.seq_create_info->used_fields &
- seq_field_used_cache))
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "CACHE"));
- Lex->create_info.seq_create_info->cache= $3;
- Lex->create_info.seq_create_info->used_fields|= seq_field_used_cache;
- }
- | NOCACHE_SYM
- {
- if (unlikely(Lex->create_info.seq_create_info->used_fields &
- seq_field_used_cache))
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "CACHE"));
- Lex->create_info.seq_create_info->cache= 0;
- Lex->create_info.seq_create_info->used_fields|= seq_field_used_cache;
- }
- | CYCLE_SYM
- {
- if (unlikely(Lex->create_info.seq_create_info->used_fields &
- seq_field_used_cycle))
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "CYCLE"));
- Lex->create_info.seq_create_info->cycle= 1;
- Lex->create_info.seq_create_info->used_fields|= seq_field_used_cycle;
- }
- | NOCYCLE_SYM
- {
- if (unlikely(Lex->create_info.seq_create_info->used_fields &
- seq_field_used_cycle))
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "CYCLE"));
- Lex->create_info.seq_create_info->cycle= 0;
- Lex->create_info.seq_create_info->used_fields|= seq_field_used_cycle;
- }
- | RESTART_SYM
- {
- if (unlikely(Lex->sql_command != SQLCOM_ALTER_SEQUENCE))
- {
- thd->parse_error(ER_SYNTAX_ERROR, "RESTART");
- YYABORT;
- }
- if (unlikely(Lex->create_info.seq_create_info->used_fields &
- seq_field_used_restart))
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "RESTART"));
- Lex->create_info.seq_create_info->used_fields|= seq_field_used_restart;
- }
- | RESTART_SYM opt_with longlong_num
- {
- if (unlikely(Lex->sql_command != SQLCOM_ALTER_SEQUENCE))
- {
- thd->parse_error(ER_SYNTAX_ERROR, "RESTART");
- YYABORT;
- }
- if (unlikely(Lex->create_info.seq_create_info->used_fields &
- seq_field_used_restart))
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "RESTART"));
- Lex->create_info.seq_create_info->restart= $3;
- Lex->create_info.seq_create_info->used_fields|= seq_field_used_restart | seq_field_used_restart_value;
- }
- ;
-
-server_def:
- SERVER_SYM opt_if_not_exists ident_or_text
- {
- if (unlikely(Lex->add_create_options_with_check($2)))
- MYSQL_YYABORT;
- Lex->server_options.reset($3);
- }
- FOREIGN DATA_SYM WRAPPER_SYM ident_or_text
- OPTIONS_SYM '(' server_options_list ')'
- { Lex->server_options.scheme= $8; }
- ;
-
-server_options_list:
- server_option
- | server_options_list ',' server_option
- ;
-
-server_option:
- USER_SYM TEXT_STRING_sys
- {
- MYSQL_YYABORT_UNLESS(Lex->server_options.username.str == 0);
- Lex->server_options.username= $2;
- }
- | HOST_SYM TEXT_STRING_sys
- {
- MYSQL_YYABORT_UNLESS(Lex->server_options.host.str == 0);
- Lex->server_options.host= $2;
- }
- | DATABASE TEXT_STRING_sys
- {
- MYSQL_YYABORT_UNLESS(Lex->server_options.db.str == 0);
- Lex->server_options.db= $2;
- }
- | OWNER_SYM TEXT_STRING_sys
- {
- MYSQL_YYABORT_UNLESS(Lex->server_options.owner.str == 0);
- Lex->server_options.owner= $2;
- }
- | PASSWORD_SYM TEXT_STRING_sys
- {
- MYSQL_YYABORT_UNLESS(Lex->server_options.password.str == 0);
- Lex->server_options.password= $2;
- }
- | SOCKET_SYM TEXT_STRING_sys
- {
- MYSQL_YYABORT_UNLESS(Lex->server_options.socket.str == 0);
- Lex->server_options.socket= $2;
- }
- | PORT_SYM ulong_num
- {
- Lex->server_options.port= $2;
- }
- ;
-
-event_tail:
- remember_name opt_if_not_exists sp_name
- {
- LEX *lex=Lex;
-
- lex->stmt_definition_begin= $1;
- if (unlikely(lex->add_create_options_with_check($2)))
- MYSQL_YYABORT;
- if (unlikely(!(lex->event_parse_data=
- Event_parse_data::new_instance(thd))))
- MYSQL_YYABORT;
- lex->event_parse_data->identifier= $3;
- lex->event_parse_data->on_completion=
- Event_parse_data::ON_COMPLETION_DROP;
-
- lex->sql_command= SQLCOM_CREATE_EVENT;
- /* We need that for disallowing subqueries */
- }
- ON SCHEDULE_SYM ev_schedule_time
- opt_ev_on_completion
- opt_ev_status
- opt_ev_comment
- DO_SYM ev_sql_stmt
- {
- /*
- sql_command is set here because some rules in ev_sql_stmt
- can overwrite it
- */
- Lex->sql_command= SQLCOM_CREATE_EVENT;
- }
- ;
-
-ev_schedule_time:
- EVERY_SYM expr interval
- {
- Lex->event_parse_data->item_expression= $2;
- Lex->event_parse_data->interval= $3;
- }
- ev_starts
- ev_ends
- | AT_SYM expr
- {
- Lex->event_parse_data->item_execute_at= $2;
- }
- ;
-
-opt_ev_status:
- /* empty */ { $$= 0; }
- | ENABLE_SYM
- {
- Lex->event_parse_data->status= Event_parse_data::ENABLED;
- Lex->event_parse_data->status_changed= true;
- $$= 1;
- }
- | DISABLE_SYM ON SLAVE
- {
- Lex->event_parse_data->status= Event_parse_data::SLAVESIDE_DISABLED;
- Lex->event_parse_data->status_changed= true;
- $$= 1;
- }
- | DISABLE_SYM
- {
- Lex->event_parse_data->status= Event_parse_data::DISABLED;
- Lex->event_parse_data->status_changed= true;
- $$= 1;
- }
- ;
-
-ev_starts:
- /* empty */
- {
- Item *item= new (thd->mem_root) Item_func_now_local(thd, 0);
- if (unlikely(item == NULL))
- MYSQL_YYABORT;
- Lex->event_parse_data->item_starts= item;
- }
- | STARTS_SYM expr
- {
- Lex->event_parse_data->item_starts= $2;
- }
- ;
-
-ev_ends:
- /* empty */
- | ENDS_SYM expr
- {
- Lex->event_parse_data->item_ends= $2;
- }
- ;
-
-opt_ev_on_completion:
- /* empty */ { $$= 0; }
- | ev_on_completion
- ;
-
-ev_on_completion:
- ON COMPLETION_SYM opt_not PRESERVE_SYM
- {
- Lex->event_parse_data->on_completion= $3
- ? Event_parse_data::ON_COMPLETION_DROP
- : Event_parse_data::ON_COMPLETION_PRESERVE;
- $$= 1;
- }
- ;
-
-opt_ev_comment:
- /* empty */ { $$= 0; }
- | COMMENT_SYM TEXT_STRING_sys
- {
- Lex->comment= Lex->event_parse_data->comment= $2;
- $$= 1;
- }
- ;
-
-ev_sql_stmt:
- {
- LEX *lex= thd->lex;
- Lex_input_stream *lip= YYLIP;
-
- /*
- This stops the following :
- - CREATE EVENT ... DO CREATE EVENT ...;
- - ALTER EVENT ... DO CREATE EVENT ...;
- - CREATE EVENT ... DO ALTER EVENT DO ....;
- - CREATE PROCEDURE ... BEGIN CREATE EVENT ... END|
- This allows:
- - CREATE EVENT ... DO DROP EVENT yyy;
- - CREATE EVENT ... DO ALTER EVENT yyy;
- (the nested ALTER EVENT can have anything but DO clause)
- - ALTER EVENT ... DO ALTER EVENT yyy;
- (the nested ALTER EVENT can have anything but DO clause)
- - ALTER EVENT ... DO DROP EVENT yyy;
- - CREATE PROCEDURE ... BEGIN ALTER EVENT ... END|
- (the nested ALTER EVENT can have anything but DO clause)
- - CREATE PROCEDURE ... BEGIN DROP EVENT ... END|
- */
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_EVENT_RECURSION_FORBIDDEN, MYF(0)));
-
- if (unlikely(!lex->make_sp_head(thd,
- lex->event_parse_data->identifier,
- &sp_handler_procedure,
- DEFAULT_AGGREGATE)))
- MYSQL_YYABORT;
-
- lex->sphead->set_body_start(thd, lip->get_cpp_ptr());
- }
- sp_proc_stmt
- {
- /* return back to the original memory root ASAP */
- if (Lex->sp_body_finalize_event(thd))
- MYSQL_YYABORT;
- }
- ;
-
-clear_privileges:
- /* Nothing */
- {
- LEX *lex=Lex;
- lex->users_list.empty();
- lex->columns.empty();
- lex->grant= lex->grant_tot_col= 0;
- lex->all_privileges= 0;
- lex->first_select_lex()->db= null_clex_str;
- lex->account_options.reset();
- }
- ;
-
-opt_aggregate:
- /* Empty */ { $$= NOT_AGGREGATE; }
- | AGGREGATE_SYM { $$= GROUP_AGGREGATE; }
- ;
-
-sp_name:
- ident '.' ident
- {
- if (unlikely(!($$= Lex->make_sp_name(thd, &$1, &$3))))
- MYSQL_YYABORT;
- }
- | ident
- {
- if (unlikely(!($$= Lex->make_sp_name(thd, &$1))))
- MYSQL_YYABORT;
- }
- ;
-
-opt_sp_name:
- /* Empty */ { $$= NULL; }
- | sp_name { $$= $1; }
- ;
-
-sp_a_chistics:
- /* Empty */ {}
- | sp_a_chistics sp_chistic {}
- ;
-
-sp_c_chistics:
- /* Empty */ {}
- | sp_c_chistics sp_c_chistic {}
- ;
-
-/* Characteristics for both create and alter */
-sp_chistic:
- COMMENT_SYM TEXT_STRING_sys
- { Lex->sp_chistics.comment= $2; }
- | LANGUAGE_SYM SQL_SYM
- { /* Just parse it, we only have one language for now. */ }
- | NO_SYM SQL_SYM
- { Lex->sp_chistics.daccess= SP_NO_SQL; }
- | CONTAINS_SYM SQL_SYM
- { Lex->sp_chistics.daccess= SP_CONTAINS_SQL; }
- | READS_SYM SQL_SYM DATA_SYM
- { Lex->sp_chistics.daccess= SP_READS_SQL_DATA; }
- | MODIFIES_SYM SQL_SYM DATA_SYM
- { Lex->sp_chistics.daccess= SP_MODIFIES_SQL_DATA; }
- | sp_suid
- { Lex->sp_chistics.suid= $1; }
- ;
-
-create_package_chistic:
- COMMENT_SYM TEXT_STRING_sys
- { Lex->sp_chistics.comment= $2; }
- | sp_suid
- { Lex->sp_chistics.suid= $1; }
- ;
-
-create_package_chistics:
- create_package_chistic {}
- | create_package_chistics create_package_chistic { }
- ;
-
-opt_create_package_chistics:
- /* Empty */
- | create_package_chistics { }
- ;
-
-opt_create_package_chistics_init:
- { Lex->sp_chistics.init(); }
- opt_create_package_chistics
- ;
-
-/* Create characteristics */
-sp_c_chistic:
- sp_chistic { }
- | opt_not DETERMINISTIC_SYM { Lex->sp_chistics.detistic= ! $1; }
- ;
-
-sp_suid:
- SQL_SYM SECURITY_SYM DEFINER_SYM { $$= SP_IS_SUID; }
- | SQL_SYM SECURITY_SYM INVOKER_SYM { $$= SP_IS_NOT_SUID; }
- ;
-
-call:
- CALL_SYM sp_name
- {
- if (unlikely(Lex->call_statement_start(thd, $2)))
- MYSQL_YYABORT;
- }
- opt_sp_cparam_list {}
- ;
-
-/* CALL parameters */
-opt_sp_cparam_list:
- /* Empty */
- | '(' opt_sp_cparams ')'
- ;
-
-opt_sp_cparams:
- /* Empty */
- | sp_cparams
- ;
-
-sp_cparams:
- sp_cparams ',' expr
- {
- Lex->value_list.push_back($3, thd->mem_root);
- }
- | expr
- {
- Lex->value_list.push_back($1, thd->mem_root);
- }
- ;
-
-/* Stored FUNCTION parameter declaration list */
-sp_fdparam_list:
- /* Empty */
- {
- Lex->sphead->m_param_begin= YYLIP->get_cpp_tok_start();
- Lex->sphead->m_param_end= Lex->sphead->m_param_begin;
- }
- |
- {
- Lex->sphead->m_param_begin= YYLIP->get_cpp_tok_start();
- }
- sp_fdparams
- {
- Lex->sphead->m_param_end= YYLIP->get_cpp_tok_start();
- }
- ;
-
-sp_fdparams:
- sp_fdparams ',' sp_param_name_and_type
- | sp_param_name_and_type
- ;
-
-sp_param_name:
- ident
- {
- if (unlikely(!($$= Lex->sp_param_init(&$1))))
- MYSQL_YYABORT;
- }
- ;
-
-sp_param_name_and_type:
- sp_param_name sp_param_type_with_opt_collate
- {
- if (unlikely(Lex->sp_param_fill_definition($$= $1)))
- MYSQL_YYABORT;
- }
- | sp_param_name sp_decl_ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM
- {
- if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $$= $1, $2, $4)))
- MYSQL_YYABORT;
- }
- | sp_param_name sp_decl_ident '.' ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM
- {
- if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $$= $1, $2, $4, $6)))
- MYSQL_YYABORT;
- }
- | sp_param_name sp_decl_ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM
- {
- if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $2)))
- MYSQL_YYABORT;
- }
- | sp_param_name sp_decl_ident '.' ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM
- {
- if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $2, $4)))
- MYSQL_YYABORT;
- }
- | sp_param_name ROW_SYM row_type_body
- {
- if (unlikely(Lex->sphead->spvar_fill_row(thd, $$= $1, $3)))
- MYSQL_YYABORT;
- }
- ;
-
-/* Stored PROCEDURE parameter declaration list */
-sp_pdparam_list:
- /* Empty */
- | sp_pdparams
- ;
-
-sp_pdparams:
- sp_pdparams ',' sp_pdparam
- | sp_pdparam
- ;
-
-sp_pdparam:
- sp_param_name sp_opt_inout sp_param_type_with_opt_collate
- {
- $1->mode= $2;
- if (unlikely(Lex->sp_param_fill_definition($1)))
- MYSQL_YYABORT;
- }
- | sp_param_name sp_opt_inout sp_decl_ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM
- {
- $1->mode= $2;
- if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $1, $3, $5)))
- MYSQL_YYABORT;
- }
- | sp_param_name sp_opt_inout sp_decl_ident '.' ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM
- {
- $1->mode= $2;
- if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $1, $3, $5, $7)))
- MYSQL_YYABORT;
- }
- | sp_param_name sp_opt_inout sp_decl_ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM
- {
- $1->mode= $2;
- if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $1, $3)))
- MYSQL_YYABORT;
- }
- | sp_param_name sp_opt_inout sp_decl_ident '.' ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM
- {
- $1->mode= $2;
- if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $1, $3, $5)))
- MYSQL_YYABORT;
- }
- | sp_param_name sp_opt_inout ROW_SYM row_type_body
- {
- $1->mode= $2;
- if (unlikely(Lex->sphead->spvar_fill_row(thd, $1, $4)))
- MYSQL_YYABORT;
- }
- ;
-
-sp_opt_inout:
- /* Empty */ { $$= sp_variable::MODE_IN; }
- | IN_SYM { $$= sp_variable::MODE_IN; }
- | OUT_SYM { $$= sp_variable::MODE_OUT; }
- | INOUT_SYM { $$= sp_variable::MODE_INOUT; }
- | IN_SYM OUT_SYM { $$= sp_variable::MODE_INOUT; }
- ;
-
-sp_parenthesized_pdparam_list:
- '('
- {
- Lex->sphead->m_param_begin= YYLIP->get_cpp_tok_start() + 1;
- }
- sp_pdparam_list
- ')'
- {
- Lex->sphead->m_param_end= YYLIP->get_cpp_tok_start();
- }
- ;
-
-sp_no_param:
- /* Empty */
- {
- Lex->sphead->m_param_begin= Lex->sphead->m_param_end=
- YYLIP->get_cpp_tok_start() + 1;
- }
- ;
-
-opt_sp_parenthesized_fdparam_list:
- sp_no_param
- | '(' sp_fdparam_list ')'
- ;
-
-opt_sp_parenthesized_pdparam_list:
- sp_no_param
- | sp_parenthesized_pdparam_list
- ;
-
-sp_proc_stmts:
- /* Empty */ {}
- | sp_proc_stmts sp_proc_stmt ';'
- ;
-
-sp_proc_stmts1:
- sp_proc_stmt ';' {}
- | sp_proc_stmts1 sp_proc_stmt ';'
- ;
-
-sp_proc_stmts1_implicit_block:
- {
- Lex->sp_block_init(thd);
- }
- sp_proc_stmts1
- {
- if (unlikely(Lex->sp_block_finalize(thd)))
- MYSQL_YYABORT;
- }
- ;
-
-opt_sp_decl_body_list:
- /* Empty */
- {
- $$.init();
- }
- | sp_decl_body_list { $$= $1; }
- ;
-
-sp_decl_body_list:
- sp_decl_non_handler_list
- {
- if (unlikely(Lex->sphead->sp_add_instr_cpush_for_cursors(thd, Lex->spcont)))
- MYSQL_YYABORT;
- }
- opt_sp_decl_handler_list
- {
- $$.join($1, $3);
- }
- | sp_decl_handler_list
- ;
-
-sp_decl_non_handler_list:
- sp_decl_non_handler ';' { $$= $1; }
- | sp_decl_non_handler_list sp_decl_non_handler ';'
- {
- $$.join($1, $2);
- }
- ;
-
-sp_decl_handler_list:
- sp_decl_handler ';' { $$= $1; }
- | sp_decl_handler_list sp_decl_handler ';'
- {
- $$.join($1, $2);
- }
- ;
-
-opt_sp_decl_handler_list:
- /* Empty*/ { $$.init(); }
- | sp_decl_handler_list
- ;
-
-optionally_qualified_column_ident:
- sp_decl_ident
- {
- if (unlikely(!($$= new (thd->mem_root)
- Qualified_column_ident(&$1))))
- MYSQL_YYABORT;
- }
- | sp_decl_ident '.' ident
- {
- if (unlikely(!($$= new (thd->mem_root)
- Qualified_column_ident(&$1, &$3))))
- MYSQL_YYABORT;
- }
- | sp_decl_ident '.' ident '.' ident
- {
- if (unlikely(!($$= new (thd->mem_root)
- Qualified_column_ident(thd, &$1, &$3, &$5))))
- MYSQL_YYABORT;
- }
- ;
-
-row_field_name:
- ident_directly_assignable
- {
- if (!($$= Lex->row_field_name(thd, $1)))
- MYSQL_YYABORT;
- }
- ;
-
-row_field_definition:
- row_field_name type_with_opt_collate
- ;
-
-row_field_definition_list:
- row_field_definition
- {
- if (!($$= Row_definition_list::make(thd->mem_root, $1)))
- MYSQL_YYABORT;
- }
- | row_field_definition_list ',' row_field_definition
- {
- if (($$= $1)->append_uniq(thd->mem_root, $3))
- MYSQL_YYABORT;
- }
- ;
-
-row_type_body:
- '(' row_field_definition_list ')' { $$= $2; }
- ;
-
-sp_decl_idents_init_vars:
- sp_decl_idents
- {
- Lex->sp_variable_declarations_init(thd, $1);
- }
- ;
-
-sp_decl_vars:
- sp_decl_idents_init_vars
- type_with_opt_collate
- sp_opt_default
- {
- if (unlikely(Lex->sp_variable_declarations_finalize(thd, $1,
- &Lex->last_field[0],
- $3)))
- MYSQL_YYABORT;
- $$.init_using_vars($1);
- }
- | sp_decl_idents_init_vars
- optionally_qualified_column_ident PERCENT_ORACLE_SYM TYPE_SYM
- sp_opt_default
- {
- if (unlikely(Lex->sp_variable_declarations_with_ref_finalize(thd, $1, $2, $5)))
- MYSQL_YYABORT;
- $$.init_using_vars($1);
- }
- | sp_decl_idents_init_vars
- optionally_qualified_column_ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM
- sp_opt_default
- {
- if (unlikely(Lex->sp_variable_declarations_rowtype_finalize(thd, $1, $2, $5)))
- MYSQL_YYABORT;
- $$.init_using_vars($1);
- }
- | sp_decl_idents_init_vars
- ROW_SYM row_type_body
- sp_opt_default
- {
- if (unlikely(Lex->sp_variable_declarations_row_finalize(thd, $1, $3, $4)))
- MYSQL_YYABORT;
- $$.init_using_vars($1);
- }
- ;
-
-sp_decl_non_handler:
- sp_decl_vars
- | ident_directly_assignable CONDITION_SYM FOR_SYM sp_cond
- {
- if (unlikely(Lex->spcont->declare_condition(thd, &$1, $4)))
- MYSQL_YYABORT;
- $$.vars= $$.hndlrs= $$.curs= 0;
- $$.conds= 1;
- }
- | ident_directly_assignable EXCEPTION_ORACLE_SYM
- {
- sp_condition_value *spcond= new (thd->mem_root)
- sp_condition_value_user_defined();
- if (unlikely(!spcond) ||
- unlikely(Lex->spcont->declare_condition(thd, &$1, spcond)))
- MYSQL_YYABORT;
- $$.vars= $$.hndlrs= $$.curs= 0;
- $$.conds= 1;
- }
- | CURSOR_SYM ident_directly_assignable
- {
- Lex->sp_block_init(thd);
- }
- opt_parenthesized_cursor_formal_parameters
- IS sp_cursor_stmt
- {
- sp_pcontext *param_ctx= Lex->spcont;
- if (unlikely(Lex->sp_block_finalize(thd)))
- MYSQL_YYABORT;
- if (unlikely(Lex->sp_declare_cursor(thd, &$2, $6, param_ctx, false)))
- MYSQL_YYABORT;
- $$.vars= $$.conds= $$.hndlrs= 0;
- $$.curs= 1;
- }
- ;
-
-sp_decl_handler:
- sp_handler_type HANDLER_SYM FOR_SYM
- {
- if (unlikely(Lex->sp_handler_declaration_init(thd, $1)))
- MYSQL_YYABORT;
- }
- sp_hcond_list sp_proc_stmt
- {
- if (unlikely(Lex->sp_handler_declaration_finalize(thd, $1)))
- MYSQL_YYABORT;
- $$.vars= $$.conds= $$.curs= 0;
- $$.hndlrs= 1;
- }
- ;
-
-opt_parenthesized_cursor_formal_parameters:
- /* Empty */
- | '(' sp_fdparams ')'
- ;
-
-
-sp_cursor_stmt_lex:
- {
- DBUG_ASSERT(thd->lex->sphead);
- if (unlikely(!($$= new (thd->mem_root)
- sp_lex_cursor(thd, thd->lex))))
- MYSQL_YYABORT;
- }
- ;
-
-sp_cursor_stmt:
- sp_cursor_stmt_lex
- {
- DBUG_ASSERT(thd->free_list == NULL);
- Lex->sphead->reset_lex(thd, $1);
- }
- select
- {
- DBUG_ASSERT(Lex == $1);
- if (unlikely($1->stmt_finalize(thd)) ||
- unlikely($1->sphead->restore_lex(thd)))
- MYSQL_YYABORT;
- $$= $1;
- }
- ;
-
-sp_handler_type:
- EXIT_MARIADB_SYM { $$= sp_handler::EXIT; }
- | CONTINUE_MARIADB_SYM { $$= sp_handler::CONTINUE; }
- | EXIT_ORACLE_SYM { $$= sp_handler::EXIT; }
- | CONTINUE_ORACLE_SYM { $$= sp_handler::CONTINUE; }
- /*| UNDO_SYM { QQ No yet } */
- ;
-
-sp_hcond_list:
- sp_hcond_element
- { $$= 1; }
- | sp_hcond_list ',' sp_hcond_element
- { $$+= 1; }
- ;
-
-sp_hcond_element:
- sp_hcond
- {
- LEX *lex= Lex;
- sp_head *sp= lex->sphead;
- sp_pcontext *ctx= lex->spcont->parent_context();
-
- if (unlikely(ctx->check_duplicate_handler($1)))
- my_yyabort_error((ER_SP_DUP_HANDLER, MYF(0)));
-
- sp_instr_hpush_jump *i= (sp_instr_hpush_jump *)sp->last_instruction();
- i->add_condition($1);
- }
- ;
-
-sp_cond:
- ulong_num
- { /* mysql errno */
- if (unlikely($1 == 0))
- my_yyabort_error((ER_WRONG_VALUE, MYF(0), "CONDITION", "0"));
- $$= new (thd->mem_root) sp_condition_value($1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | sqlstate
- ;
-
-sqlstate:
- SQLSTATE_SYM opt_value TEXT_STRING_literal
- { /* SQLSTATE */
-
- /*
- An error is triggered:
- - if the specified string is not a valid SQLSTATE,
- - or if it represents the completion condition -- it is not
- allowed to SIGNAL, or declare a handler for the completion
- condition.
- */
- if (unlikely(!is_sqlstate_valid(&$3) ||
- is_sqlstate_completion($3.str)))
- my_yyabort_error((ER_SP_BAD_SQLSTATE, MYF(0), $3.str));
- $$= new (thd->mem_root) sp_condition_value($3.str);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-opt_value:
- /* Empty */ {}
- | VALUE_SYM {}
- ;
-
-sp_hcond:
- sp_cond
- {
- $$= $1;
- }
- | ident /* CONDITION name */
- {
- $$= Lex->spcont->find_declared_or_predefined_condition(thd, &$1);
- if (unlikely($$ == NULL))
- my_yyabort_error((ER_SP_COND_MISMATCH, MYF(0), $1.str));
- }
- | SQLWARNING_SYM /* SQLSTATEs 01??? */
- {
- $$= new (thd->mem_root) sp_condition_value(sp_condition_value::WARNING);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | not FOUND_SYM /* SQLSTATEs 02??? */
- {
- $$= new (thd->mem_root) sp_condition_value(sp_condition_value::NOT_FOUND);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | SQLEXCEPTION_SYM /* All other SQLSTATEs */
- {
- $$= new (thd->mem_root) sp_condition_value(sp_condition_value::EXCEPTION);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | OTHERS_ORACLE_SYM /* All other SQLSTATEs */
- {
- $$= new (thd->mem_root) sp_condition_value(sp_condition_value::EXCEPTION);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-
-raise_stmt_oracle:
- RAISE_ORACLE_SYM opt_set_signal_information
- {
- if (unlikely(Lex->add_resignal_statement(thd, NULL)))
- MYSQL_YYABORT;
- }
- | RAISE_ORACLE_SYM signal_value opt_set_signal_information
- {
- if (unlikely(Lex->add_signal_statement(thd, $2)))
- MYSQL_YYABORT;
- }
- ;
-
-signal_stmt:
- SIGNAL_SYM signal_value opt_set_signal_information
- {
- if (Lex->add_signal_statement(thd, $2))
- MYSQL_YYABORT;
- }
- ;
-
-signal_value:
- ident
- {
- LEX *lex= Lex;
- sp_condition_value *cond;
-
- /* SIGNAL foo cannot be used outside of stored programs */
- if (unlikely(lex->spcont == NULL))
- my_yyabort_error((ER_SP_COND_MISMATCH, MYF(0), $1.str));
- cond= lex->spcont->find_declared_or_predefined_condition(thd, &$1);
- if (unlikely(cond == NULL))
- my_yyabort_error((ER_SP_COND_MISMATCH, MYF(0), $1.str));
- if (unlikely(!cond->has_sql_state()))
- my_yyabort_error((ER_SIGNAL_BAD_CONDITION_TYPE, MYF(0)));
- $$= cond;
- }
- | sqlstate
- { $$= $1; }
- ;
-
-opt_signal_value:
- /* empty */
- { $$= NULL; }
- | signal_value
- { $$= $1; }
- ;
-
-opt_set_signal_information:
- /* empty */
- {
- thd->m_parser_state->m_yacc.m_set_signal_info.clear();
- }
- | SET signal_information_item_list
- ;
-
-signal_information_item_list:
- signal_condition_information_item_name '=' signal_allowed_expr
- {
- Set_signal_information *info;
- info= &thd->m_parser_state->m_yacc.m_set_signal_info;
- int index= (int) $1;
- info->clear();
- info->m_item[index]= $3;
- }
- | signal_information_item_list ','
- signal_condition_information_item_name '=' signal_allowed_expr
- {
- Set_signal_information *info;
- info= &thd->m_parser_state->m_yacc.m_set_signal_info;
- int index= (int) $3;
- if (unlikely(info->m_item[index] != NULL))
- my_yyabort_error((ER_DUP_SIGNAL_SET, MYF(0),
- Diag_condition_item_names[index].str));
- info->m_item[index]= $5;
- }
- ;
-
-/*
- Only a limited subset of <expr> are allowed in SIGNAL/RESIGNAL.
-*/
-signal_allowed_expr:
- literal
- { $$= $1; }
- | variable
- {
- if ($1->type() == Item::FUNC_ITEM)
- {
- Item_func *item= (Item_func*) $1;
- if (unlikely(item->functype() == Item_func::SUSERVAR_FUNC))
- {
- /*
- Don't allow the following syntax:
- SIGNAL/RESIGNAL ...
- SET <signal condition item name> = @foo := expr
- */
- thd->parse_error();
- MYSQL_YYABORT;
- }
- }
- $$= $1;
- }
- | simple_ident
- { $$= $1; }
- ;
-
-/* conditions that can be set in signal / resignal */
-signal_condition_information_item_name:
- CLASS_ORIGIN_SYM
- { $$= DIAG_CLASS_ORIGIN; }
- | SUBCLASS_ORIGIN_SYM
- { $$= DIAG_SUBCLASS_ORIGIN; }
- | CONSTRAINT_CATALOG_SYM
- { $$= DIAG_CONSTRAINT_CATALOG; }
- | CONSTRAINT_SCHEMA_SYM
- { $$= DIAG_CONSTRAINT_SCHEMA; }
- | CONSTRAINT_NAME_SYM
- { $$= DIAG_CONSTRAINT_NAME; }
- | CATALOG_NAME_SYM
- { $$= DIAG_CATALOG_NAME; }
- | SCHEMA_NAME_SYM
- { $$= DIAG_SCHEMA_NAME; }
- | TABLE_NAME_SYM
- { $$= DIAG_TABLE_NAME; }
- | COLUMN_NAME_SYM
- { $$= DIAG_COLUMN_NAME; }
- | CURSOR_NAME_SYM
- { $$= DIAG_CURSOR_NAME; }
- | MESSAGE_TEXT_SYM
- { $$= DIAG_MESSAGE_TEXT; }
- | MYSQL_ERRNO_SYM
- { $$= DIAG_MYSQL_ERRNO; }
- ;
-
-resignal_stmt:
- RESIGNAL_SYM opt_signal_value opt_set_signal_information
- {
- if (unlikely(Lex->add_resignal_statement(thd, $2)))
- MYSQL_YYABORT;
- }
- ;
-
-get_diagnostics:
- GET_SYM which_area DIAGNOSTICS_SYM diagnostics_information
- {
- Diagnostics_information *info= $4;
-
- info->set_which_da($2);
-
- Lex->sql_command= SQLCOM_GET_DIAGNOSTICS;
- Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_get_diagnostics(info);
-
- if (unlikely(Lex->m_sql_cmd == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-which_area:
- /* If <which area> is not specified, then CURRENT is implicit. */
- { $$= Diagnostics_information::CURRENT_AREA; }
- | CURRENT_SYM
- { $$= Diagnostics_information::CURRENT_AREA; }
- ;
-
-diagnostics_information:
- statement_information
- {
- $$= new (thd->mem_root) Statement_information($1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | CONDITION_SYM condition_number condition_information
- {
- $$= new (thd->mem_root) Condition_information($2, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-statement_information:
- statement_information_item
- {
- $$= new (thd->mem_root) List<Statement_information_item>;
- if (unlikely($$ == NULL) ||
- unlikely($$->push_back($1, thd->mem_root)))
- MYSQL_YYABORT;
- }
- | statement_information ',' statement_information_item
- {
- if (unlikely($1->push_back($3, thd->mem_root)))
- MYSQL_YYABORT;
- $$= $1;
- }
- ;
-
-statement_information_item:
- simple_target_specification '=' statement_information_item_name
- {
- $$= new (thd->mem_root) Statement_information_item($3, $1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-simple_target_specification:
- ident_cli
- {
- if (unlikely(!($$= thd->lex->create_item_for_sp_var(&$1, NULL))))
- MYSQL_YYABORT;
- }
- | '@' ident_or_text
- {
- $$= new (thd->mem_root) Item_func_get_user_var(thd, &$2);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-statement_information_item_name:
- NUMBER_MARIADB_SYM
- { $$= Statement_information_item::NUMBER; }
- | NUMBER_ORACLE_SYM
- { $$= Statement_information_item::NUMBER; }
- | ROW_COUNT_SYM
- { $$= Statement_information_item::ROW_COUNT; }
- ;
-
-/*
- Only a limited subset of <expr> are allowed in GET DIAGNOSTICS
- <condition number>, same subset as for SIGNAL/RESIGNAL.
-*/
-condition_number:
- signal_allowed_expr
- { $$= $1; }
- ;
-
-condition_information:
- condition_information_item
- {
- $$= new (thd->mem_root) List<Condition_information_item>;
- if (unlikely($$ == NULL) ||
- unlikely($$->push_back($1, thd->mem_root)))
- MYSQL_YYABORT;
- }
- | condition_information ',' condition_information_item
- {
- if (unlikely($1->push_back($3, thd->mem_root)))
- MYSQL_YYABORT;
- $$= $1;
- }
- ;
-
-condition_information_item:
- simple_target_specification '=' condition_information_item_name
- {
- $$= new (thd->mem_root) Condition_information_item($3, $1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-condition_information_item_name:
- CLASS_ORIGIN_SYM
- { $$= Condition_information_item::CLASS_ORIGIN; }
- | SUBCLASS_ORIGIN_SYM
- { $$= Condition_information_item::SUBCLASS_ORIGIN; }
- | CONSTRAINT_CATALOG_SYM
- { $$= Condition_information_item::CONSTRAINT_CATALOG; }
- | CONSTRAINT_SCHEMA_SYM
- { $$= Condition_information_item::CONSTRAINT_SCHEMA; }
- | CONSTRAINT_NAME_SYM
- { $$= Condition_information_item::CONSTRAINT_NAME; }
- | CATALOG_NAME_SYM
- { $$= Condition_information_item::CATALOG_NAME; }
- | SCHEMA_NAME_SYM
- { $$= Condition_information_item::SCHEMA_NAME; }
- | TABLE_NAME_SYM
- { $$= Condition_information_item::TABLE_NAME; }
- | COLUMN_NAME_SYM
- { $$= Condition_information_item::COLUMN_NAME; }
- | CURSOR_NAME_SYM
- { $$= Condition_information_item::CURSOR_NAME; }
- | MESSAGE_TEXT_SYM
- { $$= Condition_information_item::MESSAGE_TEXT; }
- | MYSQL_ERRNO_SYM
- { $$= Condition_information_item::MYSQL_ERRNO; }
- | RETURNED_SQLSTATE_SYM
- { $$= Condition_information_item::RETURNED_SQLSTATE; }
- ;
-
-sp_decl_ident:
- IDENT_sys
- | keyword_sp_decl
- {
- if (unlikely($$.copy_ident_cli(thd, &$1)))
- MYSQL_YYABORT;
- }
- ;
-
-sp_decl_idents:
- sp_decl_ident
- {
- /* NOTE: field definition is filled in sp_decl section. */
-
- LEX *lex= Lex;
- sp_pcontext *spc= lex->spcont;
-
- if (unlikely(spc->find_variable(&$1, TRUE)))
- my_yyabort_error((ER_SP_DUP_VAR, MYF(0), $1.str));
- spc->add_variable(thd, &$1);
- $$= 1;
- }
- | sp_decl_idents ',' ident
- {
- /* NOTE: field definition is filled in sp_decl section. */
-
- LEX *lex= Lex;
- sp_pcontext *spc= lex->spcont;
-
- if (unlikely(spc->find_variable(&$3, TRUE)))
- my_yyabort_error((ER_SP_DUP_VAR, MYF(0), $3.str));
- spc->add_variable(thd, &$3);
- $$= $1 + 1;
- }
- ;
-
-sp_opt_default:
- /* Empty */ { $$ = NULL; }
- | DEFAULT expr { $$ = $2; }
- | SET_VAR expr { $$ = $2; }
- ;
-
-sp_proc_stmt:
- sp_labeled_block
- | sp_unlabeled_block
- | sp_labeled_control
- | sp_unlabeled_control
- | sp_labelable_stmt
- | labels_declaration_oracle sp_labelable_stmt {}
- ;
-
-sp_labelable_stmt:
- sp_proc_stmt_statement
- | sp_proc_stmt_continue_oracle
- | sp_proc_stmt_exit_oracle
- | sp_proc_stmt_leave
- | sp_proc_stmt_iterate
- | sp_proc_stmt_goto_oracle
- | sp_proc_stmt_open
- | sp_proc_stmt_fetch
- | sp_proc_stmt_close
- | sp_proc_stmt_return
- | sp_proc_stmt_if
- | case_stmt_specification
- | NULL_SYM { }
- ;
-
-sp_proc_stmt_compound_ok:
- sp_proc_stmt_if
- | case_stmt_specification
- | sp_unlabeled_block
- | sp_unlabeled_control
- ;
-
-sp_proc_stmt_if:
- IF_SYM
- {
- if (unlikely(Lex->maybe_start_compound_statement(thd)))
- MYSQL_YYABORT;
- Lex->sphead->new_cont_backpatch(NULL);
- }
- sp_if END IF_SYM
- { Lex->sphead->do_cont_backpatch(); }
- ;
-
-sp_statement:
- statement
- | ident_directly_assignable
- {
- // Direct procedure call (without the CALL keyword)
- if (unlikely(Lex->call_statement_start(thd, &$1)))
- MYSQL_YYABORT;
- }
- opt_sp_cparam_list
- | ident_directly_assignable '.' ident
- {
- if (unlikely(Lex->call_statement_start(thd, &$1, &$3)))
- MYSQL_YYABORT;
- }
- opt_sp_cparam_list
- ;
-
-sp_proc_stmt_statement:
- {
- LEX *lex= thd->lex;
- Lex_input_stream *lip= YYLIP;
-
- lex->sphead->reset_lex(thd);
- lex->sphead->m_tmp_query= lip->get_tok_start();
- }
- sp_statement
- {
- if (Lex->sp_proc_stmt_statement_finalize(thd, yychar == YYEMPTY) ||
- Lex->sphead->restore_lex(thd))
- MYSQL_YYABORT;
- }
- ;
-
-
-RETURN_ALLMODES_SYM:
- RETURN_MARIADB_SYM
- | RETURN_ORACLE_SYM
- ;
-
-sp_proc_stmt_return:
- RETURN_ALLMODES_SYM
- { Lex->sphead->reset_lex(thd); }
- expr
- {
- LEX *lex= Lex;
- sp_head *sp= lex->sphead;
- if (unlikely(sp->m_handler->add_instr_freturn(thd, sp, lex->spcont,
- $3, lex)) ||
- unlikely(sp->restore_lex(thd)))
- MYSQL_YYABORT;
- }
- | RETURN_ORACLE_SYM
- {
- LEX *lex= Lex;
- sp_head *sp= lex->sphead;
- if (unlikely(sp->m_handler->add_instr_preturn(thd, sp,
- lex->spcont)))
- MYSQL_YYABORT;
- }
- ;
-
-reset_lex_expr:
- { Lex->sphead->reset_lex(thd); }
- expr
- { $$= $2; }
- ;
-
-sp_proc_stmt_exit_oracle:
- EXIT_ORACLE_SYM
- {
- if (unlikely(Lex->sp_exit_statement(thd, NULL)))
- MYSQL_YYABORT;
- }
- | EXIT_ORACLE_SYM label_ident
- {
- if (unlikely(Lex->sp_exit_statement(thd, &$2, NULL)))
- MYSQL_YYABORT;
- }
- | EXIT_ORACLE_SYM WHEN_SYM reset_lex_expr
- {
- if (Lex->sp_exit_statement(thd, $3) ||
- Lex->sphead->restore_lex(thd))
- MYSQL_YYABORT;
- }
- | EXIT_ORACLE_SYM label_ident WHEN_SYM reset_lex_expr
- {
- if (Lex->sp_exit_statement(thd, &$2, $4) ||
- Lex->sphead->restore_lex(thd))
- MYSQL_YYABORT;
- }
- ;
-
-sp_proc_stmt_continue_oracle:
- CONTINUE_ORACLE_SYM
- {
- if (unlikely(Lex->sp_continue_statement(thd, NULL)))
- MYSQL_YYABORT;
- }
- | CONTINUE_ORACLE_SYM label_ident
- {
- if (unlikely(Lex->sp_continue_statement(thd, &$2, NULL)))
- MYSQL_YYABORT;
- }
- | CONTINUE_ORACLE_SYM WHEN_SYM reset_lex_expr
- {
- if (Lex->sp_continue_statement(thd, $3) ||
- Lex->sphead->restore_lex(thd))
- MYSQL_YYABORT;
- }
- | CONTINUE_ORACLE_SYM label_ident WHEN_SYM reset_lex_expr
- {
- if (Lex->sp_continue_statement(thd, &$2, $4) ||
- Lex->sphead->restore_lex(thd))
- MYSQL_YYABORT;
- }
- ;
-
-
-sp_proc_stmt_leave:
- LEAVE_SYM label_ident
- {
- if (unlikely(Lex->sp_leave_statement(thd, &$2)))
- MYSQL_YYABORT;
- }
- ;
-
-sp_proc_stmt_iterate:
- ITERATE_SYM label_ident
- {
- if (unlikely(Lex->sp_iterate_statement(thd, &$2)))
- MYSQL_YYABORT;
- }
- ;
-
-sp_proc_stmt_goto_oracle:
- GOTO_ORACLE_SYM label_ident
- {
- if (unlikely(Lex->sp_goto_statement(thd, &$2)))
- MYSQL_YYABORT;
- }
- ;
-
-
-remember_lex:
- {
- $$= thd->lex;
- }
- ;
-
-assignment_source_lex:
- {
- DBUG_ASSERT(Lex->sphead);
- if (unlikely(!($$= new (thd->mem_root)
- sp_assignment_lex(thd, thd->lex))))
- MYSQL_YYABORT;
- }
- ;
-
-assignment_source_expr:
- assignment_source_lex
- {
- DBUG_ASSERT(thd->free_list == NULL);
- Lex->sphead->reset_lex(thd, $1);
- }
- expr
- {
- DBUG_ASSERT($1 == thd->lex);
- $$= $1;
- $$->sp_lex_in_use= true;
- $$->set_item_and_free_list($3, thd->free_list);
- thd->free_list= NULL;
- if ($$->sphead->restore_lex(thd))
- MYSQL_YYABORT;
- }
- ;
-
-for_loop_bound_expr:
- assignment_source_lex
- {
- Lex->sphead->reset_lex(thd, $1);
- Lex->current_select->parsing_place= FOR_LOOP_BOUND;
- }
- expr
- {
- DBUG_ASSERT($1 == thd->lex);
- $$= $1;
- $$->sp_lex_in_use= true;
- $$->set_item_and_free_list($3, NULL);
- if (unlikely($$->sphead->restore_lex(thd)))
- MYSQL_YYABORT;
- Lex->current_select->parsing_place= NO_MATTER;
- }
- ;
-
-cursor_actual_parameters:
- assignment_source_expr
- {
- if (unlikely(!($$= new (thd->mem_root) List<sp_assignment_lex>)))
- MYSQL_YYABORT;
- $$->push_back($1, thd->mem_root);
- }
- | cursor_actual_parameters ',' assignment_source_expr
- {
- $$= $1;
- $$->push_back($3, thd->mem_root);
- }
- ;
-
-opt_parenthesized_cursor_actual_parameters:
- /* Empty */ { $$= NULL; }
- | '(' cursor_actual_parameters ')' { $$= $2; }
- ;
-
-sp_proc_stmt_open:
- OPEN_SYM ident opt_parenthesized_cursor_actual_parameters
- {
- if (unlikely(Lex->sp_open_cursor(thd, &$2, $3)))
- MYSQL_YYABORT;
- }
- ;
-
-sp_proc_stmt_fetch_head:
- FETCH_SYM ident INTO
- {
- if (unlikely(Lex->sp_add_cfetch(thd, &$2)))
- MYSQL_YYABORT;
- }
- | FETCH_SYM FROM ident INTO
- {
- if (unlikely(Lex->sp_add_cfetch(thd, &$3)))
- MYSQL_YYABORT;
- }
- | FETCH_SYM NEXT_SYM FROM ident INTO
- {
- if (unlikely(Lex->sp_add_cfetch(thd, &$4)))
- MYSQL_YYABORT;
- }
- ;
-
-sp_proc_stmt_fetch:
- sp_proc_stmt_fetch_head sp_fetch_list { }
- | FETCH_SYM GROUP_SYM NEXT_SYM ROW_SYM
- {
- if (unlikely(Lex->sp_add_agg_cfetch()))
- MYSQL_YYABORT;
- }
- ;
-
-sp_proc_stmt_close:
- CLOSE_SYM ident
- {
- LEX *lex= Lex;
- sp_head *sp= lex->sphead;
- uint offset;
- sp_instr_cclose *i;
-
- if (unlikely(!lex->spcont->find_cursor(&$2, &offset, false)))
- my_yyabort_error((ER_SP_CURSOR_MISMATCH, MYF(0), $2.str));
- i= new (thd->mem_root)
- sp_instr_cclose(sp->instructions(), lex->spcont, offset);
- if (unlikely(i == NULL) ||
- unlikely(sp->add_instr(i)))
- MYSQL_YYABORT;
- }
- ;
-
-sp_fetch_list:
- ident
- {
- LEX *lex= Lex;
- sp_head *sp= lex->sphead;
- sp_pcontext *spc= lex->spcont;
- sp_variable *spv;
-
- if (unlikely(!spc || !(spv = spc->find_variable(&$1, false))))
- my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $1.str));
-
- /* An SP local variable */
- sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction();
- i->add_to_varlist(spv);
- }
- | sp_fetch_list ',' ident
- {
- LEX *lex= Lex;
- sp_head *sp= lex->sphead;
- sp_pcontext *spc= lex->spcont;
- sp_variable *spv;
-
- if (unlikely(!spc || !(spv = spc->find_variable(&$3, false))))
- my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $3.str));
-
- /* An SP local variable */
- sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction();
- i->add_to_varlist(spv);
- }
- ;
-
-sp_if:
- { Lex->sphead->reset_lex(thd); }
- expr THEN_SYM
- {
- LEX *lex= Lex;
- sp_head *sp= lex->sphead;
- sp_pcontext *ctx= lex->spcont;
- uint ip= sp->instructions();
- sp_instr_jump_if_not *i= new (thd->mem_root)
- sp_instr_jump_if_not(ip, ctx, $2, lex);
- if (unlikely(i == NULL) ||
- unlikely(sp->push_backpatch(thd, i, ctx->push_label(thd, &empty_clex_str, 0))) ||
- unlikely(sp->add_cont_backpatch(i)) ||
- unlikely(sp->add_instr(i)))
- MYSQL_YYABORT;
- if (unlikely(sp->restore_lex(thd)))
- MYSQL_YYABORT;
- }
- sp_proc_stmts1_implicit_block
- {
- sp_head *sp= Lex->sphead;
- sp_pcontext *ctx= Lex->spcont;
- uint ip= sp->instructions();
- sp_instr_jump *i= new (thd->mem_root) sp_instr_jump(ip, ctx);
- if (unlikely(i == NULL) ||
- unlikely(sp->add_instr(i)))
- MYSQL_YYABORT;
- sp->backpatch(ctx->pop_label());
- sp->push_backpatch(thd, i, ctx->push_label(thd, &empty_clex_str, 0));
- }
- sp_elseifs
- {
- LEX *lex= Lex;
-
- lex->sphead->backpatch(lex->spcont->pop_label());
- }
- ;
-
-sp_elseifs:
- /* Empty */
- | ELSIF_ORACLE_SYM sp_if
- | ELSE sp_proc_stmts1_implicit_block
- ;
-
-case_stmt_specification:
- CASE_SYM
- {
- if (unlikely(Lex->maybe_start_compound_statement(thd)))
- MYSQL_YYABORT;
-
- /**
- An example of the CASE statement in use is
- <pre>
- CREATE PROCEDURE proc_19194_simple(i int)
- BEGIN
- DECLARE str CHAR(10);
-
- CASE i
- WHEN 1 THEN SET str="1";
- WHEN 2 THEN SET str="2";
- WHEN 3 THEN SET str="3";
- ELSE SET str="unknown";
- END CASE;
-
- SELECT str;
- END
- </pre>
- The actions are used to generate the following code:
- <pre>
- SHOW PROCEDURE CODE proc_19194_simple;
- Pos Instruction
- 0 set str@1 NULL
- 1 set_case_expr (12) 0 i@0
- 2 jump_if_not 5(12) (case_expr@0 = 1)
- 3 set str@1 _latin1'1'
- 4 jump 12
- 5 jump_if_not 8(12) (case_expr@0 = 2)
- 6 set str@1 _latin1'2'
- 7 jump 12
- 8 jump_if_not 11(12) (case_expr@0 = 3)
- 9 set str@1 _latin1'3'
- 10 jump 12
- 11 set str@1 _latin1'unknown'
- 12 stmt 0 "SELECT str"
- </pre>
- */
-
- Lex->sphead->new_cont_backpatch(NULL);
-
- /*
- BACKPATCH: Creating target label for the jump to after END CASE
- (instruction 12 in the example)
- */
- Lex->spcont->push_label(thd, &empty_clex_str, Lex->sphead->instructions());
- }
- case_stmt_body
- else_clause_opt
- END
- CASE_SYM
- {
- /*
- BACKPATCH: Resolving forward jump from
- "case_stmt_action_then" to after END CASE
- (jump from instruction 4 to 12, 7 to 12 ... in the example)
- */
- Lex->sphead->backpatch(Lex->spcont->pop_label());
-
- if ($3)
- Lex->spcont->pop_case_expr_id();
-
- Lex->sphead->do_cont_backpatch();
- }
- ;
-
-case_stmt_body:
- { Lex->sphead->reset_lex(thd); /* For expr $2 */ }
- expr
- {
- if (unlikely(Lex->case_stmt_action_expr($2)))
- MYSQL_YYABORT;
-
- if (Lex->sphead->restore_lex(thd))
- MYSQL_YYABORT;
- }
- simple_when_clause_list
- { $$= 1; }
- | searched_when_clause_list
- { $$= 0; }
- ;
-
-simple_when_clause_list:
- simple_when_clause
- | simple_when_clause_list simple_when_clause
- ;
-
-searched_when_clause_list:
- searched_when_clause
- | searched_when_clause_list searched_when_clause
- ;
-
-simple_when_clause:
- WHEN_SYM
- {
- Lex->sphead->reset_lex(thd); /* For expr $3 */
- }
- expr
- {
- /* Simple case: <caseval> = <whenval> */
-
- LEX *lex= Lex;
- if (unlikely(lex->case_stmt_action_when($3, true)))
- MYSQL_YYABORT;
- /* For expr $3 */
- if (unlikely(lex->sphead->restore_lex(thd)))
- MYSQL_YYABORT;
- }
- THEN_SYM
- sp_proc_stmts1_implicit_block
- {
- if (unlikely(Lex->case_stmt_action_then()))
- MYSQL_YYABORT;
- }
- ;
-
-searched_when_clause:
- WHEN_SYM
- {
- Lex->sphead->reset_lex(thd); /* For expr $3 */
- }
- expr
- {
- LEX *lex= Lex;
- if (unlikely(lex->case_stmt_action_when($3, false)))
- MYSQL_YYABORT;
- /* For expr $3 */
- if (unlikely(lex->sphead->restore_lex(thd)))
- MYSQL_YYABORT;
- }
- THEN_SYM
- sp_proc_stmts1_implicit_block
- {
- if (unlikely(Lex->case_stmt_action_then()))
- MYSQL_YYABORT;
- }
- ;
-
-else_clause_opt:
- /* empty */
- {
- LEX *lex= Lex;
- sp_head *sp= lex->sphead;
- uint ip= sp->instructions();
- sp_instr_error *i= new (thd->mem_root)
- sp_instr_error(ip, lex->spcont, ER_SP_CASE_NOT_FOUND);
- if (unlikely(i == NULL) ||
- unlikely(sp->add_instr(i)))
- MYSQL_YYABORT;
- }
- | ELSE sp_proc_stmts1_implicit_block
- ;
-
-sp_opt_label:
- /* Empty */ { $$= null_clex_str; }
- | label_ident { $$= $1; }
- ;
-
-sp_block_label:
- labels_declaration_oracle
- {
- if (unlikely(Lex->spcont->block_label_declare(&$1)))
- MYSQL_YYABORT;
- $$= $1;
- }
- ;
-
-sp_labeled_block:
- sp_block_label
- BEGIN_ORACLE_SYM
- {
- Lex->sp_block_init(thd, &$1);
- if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd)))
- MYSQL_YYABORT;
- }
- sp_block_statements_and_exceptions
- END
- sp_opt_label
- {
- if (unlikely(Lex->sp_block_finalize(thd, Lex_spblock($4), &$6)))
- MYSQL_YYABORT;
- }
- | sp_block_label
- DECLARE_ORACLE_SYM
- {
- Lex->sp_block_init(thd, &$1);
- }
- sp_decl_body_list
- {
- if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd)))
- MYSQL_YYABORT;
- }
- BEGIN_ORACLE_SYM
- sp_block_statements_and_exceptions
- END
- sp_opt_label
- {
- $4.hndlrs+= $7.hndlrs;
- if (unlikely(Lex->sp_block_finalize(thd, $4, &$9)))
- MYSQL_YYABORT;
- }
- ;
-
-opt_not_atomic:
- /* Empty */
- | not ATOMIC_SYM /* TODO: BEGIN ATOMIC (not -> opt_not) */
- ;
-
-sp_unlabeled_block:
- BEGIN_ORACLE_SYM opt_not_atomic
- {
- if (unlikely(Lex->maybe_start_compound_statement(thd)))
- MYSQL_YYABORT;
- Lex->sp_block_init(thd);
- if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd)))
- MYSQL_YYABORT;
- }
- sp_block_statements_and_exceptions
- END
- {
- if (unlikely(Lex->sp_block_finalize(thd, Lex_spblock($4))))
- MYSQL_YYABORT;
- }
- | DECLARE_ORACLE_SYM
- {
- if (unlikely(Lex->maybe_start_compound_statement(thd)))
- MYSQL_YYABORT;
- Lex->sp_block_init(thd);
- }
- sp_decl_body_list
- {
- if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd)))
- MYSQL_YYABORT;
- }
- BEGIN_ORACLE_SYM
- sp_block_statements_and_exceptions
- END
- {
- $3.hndlrs+= $6.hndlrs;
- if (unlikely(Lex->sp_block_finalize(thd, $3)))
- MYSQL_YYABORT;
- }
- ;
-
-sp_instr_addr:
- { $$= Lex->sphead->instructions(); }
- ;
-
-sp_body:
- {
- Lex->sp_block_init(thd);
- }
- opt_sp_decl_body_list
- {
- if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd)))
- MYSQL_YYABORT;
- }
- BEGIN_ORACLE_SYM
- sp_block_statements_and_exceptions
- {
- $2.hndlrs+= $5.hndlrs;
- if (unlikely(Lex->sp_block_finalize(thd, $2)))
- MYSQL_YYABORT;
- }
- END
- ;
-
-sp_block_statements_and_exceptions:
- sp_instr_addr
- sp_proc_stmts
- {
- if (unlikely(Lex->sp_block_with_exceptions_finalize_executable_section(thd, $1)))
- MYSQL_YYABORT;
- }
- opt_exception_clause
- {
- if (unlikely(Lex->sp_block_with_exceptions_finalize_exceptions(thd, $1, $4)))
- MYSQL_YYABORT;
- $$.init($4);
- }
- ;
-
-opt_exception_clause:
- /* Empty */ { $$= 0; }
- | EXCEPTION_ORACLE_SYM exception_handlers { $$= $2; }
- ;
-
-exception_handlers:
- exception_handler { $$= 1; }
- | exception_handlers exception_handler { $$= $1 + 1; }
- ;
-
-exception_handler:
- WHEN_SYM
- {
- if (unlikely(Lex->sp_handler_declaration_init(thd, sp_handler::EXIT)))
- MYSQL_YYABORT;
- }
- sp_hcond_list
- THEN_SYM
- sp_proc_stmts1_implicit_block
- {
- if (unlikely(Lex->sp_handler_declaration_finalize(thd, sp_handler::EXIT)))
- MYSQL_YYABORT;
- }
- ;
-
-/* This adds one shift/reduce conflict */
-opt_sp_for_loop_direction:
- /* Empty */ { $$= 1; }
- | REVERSE_SYM { $$= -1; }
- ;
-
-sp_for_loop_index_and_bounds:
- ident_directly_assignable sp_for_loop_bounds
- {
- if (unlikely(Lex->sp_for_loop_declarations(thd, &$$, &$1, $2)))
- MYSQL_YYABORT;
- }
- ;
-
-sp_for_loop_bounds:
- IN_SYM opt_sp_for_loop_direction for_loop_bound_expr
- DOT_DOT_SYM for_loop_bound_expr
- {
- $$= Lex_for_loop_bounds_intrange($2, $3, $5);
- }
- | IN_SYM opt_sp_for_loop_direction for_loop_bound_expr
- {
- $$.m_direction= $2;
- $$.m_index= $3;
- $$.m_target_bound= NULL;
- $$.m_implicit_cursor= false;
- }
- | IN_SYM opt_sp_for_loop_direction '(' sp_cursor_stmt ')'
- {
- if (unlikely(Lex->sp_for_loop_implicit_cursor_statement(thd, &$$,
- $4)))
- MYSQL_YYABORT;
- }
- ;
-
-loop_body:
- sp_proc_stmts1 END LOOP_SYM
- {
- LEX *lex= Lex;
- uint ip= lex->sphead->instructions();
- sp_label *lab= lex->spcont->last_label(); /* Jumping back */
- sp_instr_jump *i= new (thd->mem_root)
- sp_instr_jump(ip, lex->spcont, lab->ip);
- if (unlikely(i == NULL) ||
- unlikely(lex->sphead->add_instr(i)))
- MYSQL_YYABORT;
- }
- ;
-
-while_body:
- expr LOOP_SYM
- {
- LEX *lex= Lex;
- if (unlikely(lex->sp_while_loop_expression(thd, $1)))
- MYSQL_YYABORT;
- if (lex->sphead->restore_lex(thd))
- MYSQL_YYABORT;
- }
- sp_proc_stmts1 END LOOP_SYM
- {
- if (unlikely(Lex->sp_while_loop_finalize(thd)))
- MYSQL_YYABORT;
- }
- ;
-
-repeat_body:
- sp_proc_stmts1 UNTIL_SYM
- { Lex->sphead->reset_lex(thd); }
- expr END REPEAT_SYM
- {
- LEX *lex= Lex;
- uint ip= lex->sphead->instructions();
- sp_label *lab= lex->spcont->last_label(); /* Jumping back */
- sp_instr_jump_if_not *i= new (thd->mem_root)
- sp_instr_jump_if_not(ip, lex->spcont, $4, lab->ip, lex);
- if (unlikely(i == NULL) ||
- unlikely(lex->sphead->add_instr(i)))
- MYSQL_YYABORT;
- if (lex->sphead->restore_lex(thd))
- MYSQL_YYABORT;
- /* We can shortcut the cont_backpatch here */
- i->m_cont_dest= ip+1;
- }
- ;
-
-pop_sp_loop_label:
- sp_opt_label
- {
- if (unlikely(Lex->sp_pop_loop_label(thd, &$1)))
- MYSQL_YYABORT;
- }
- ;
-
-sp_labeled_control:
- labels_declaration_oracle LOOP_SYM
- {
- if (unlikely(Lex->sp_push_loop_label(thd, &$1)))
- MYSQL_YYABORT;
- }
- loop_body pop_sp_loop_label
- { }
- | labels_declaration_oracle WHILE_SYM
- {
- if (unlikely(Lex->sp_push_loop_label(thd, &$1)))
- MYSQL_YYABORT;
- Lex->sphead->reset_lex(thd);
- }
- while_body pop_sp_loop_label
- { }
- | labels_declaration_oracle FOR_SYM
- {
- // See "The FOR LOOP statement" comments in sql_lex.cc
- Lex->sp_block_init(thd); // The outer DECLARE..BEGIN..END block
- }
- sp_for_loop_index_and_bounds
- {
- if (unlikely(Lex->sp_push_loop_label(thd, &$1))) // The inner WHILE block
- MYSQL_YYABORT;
- if (unlikely(Lex->sp_for_loop_condition_test(thd, $4)))
- MYSQL_YYABORT;
- }
- LOOP_SYM
- sp_proc_stmts1
- END LOOP_SYM
- {
- if (unlikely(Lex->sp_for_loop_finalize(thd, $4)))
- MYSQL_YYABORT;
- }
- pop_sp_loop_label // The inner WHILE block
- {
- if (unlikely(Lex->sp_for_loop_outer_block_finalize(thd, $4)))
- MYSQL_YYABORT;
- }
- | labels_declaration_oracle REPEAT_SYM
- {
- if (unlikely(Lex->sp_push_loop_label(thd, &$1)))
- MYSQL_YYABORT;
- }
- repeat_body pop_sp_loop_label
- { }
- ;
-
-sp_unlabeled_control:
- LOOP_SYM
- {
- if (unlikely(Lex->sp_push_loop_empty_label(thd)))
- MYSQL_YYABORT;
- }
- loop_body
- {
- Lex->sp_pop_loop_empty_label(thd);
- }
- | WHILE_SYM
- {
- if (unlikely(Lex->sp_push_loop_empty_label(thd)))
- MYSQL_YYABORT;
- Lex->sphead->reset_lex(thd);
- }
- while_body
- {
- Lex->sp_pop_loop_empty_label(thd);
- }
- | FOR_SYM
- {
- // See "The FOR LOOP statement" comments in sql_lex.cc
- if (unlikely(Lex->maybe_start_compound_statement(thd)))
- MYSQL_YYABORT;
- Lex->sp_block_init(thd); // The outer DECLARE..BEGIN..END block
- }
- sp_for_loop_index_and_bounds
- {
- if (unlikely(Lex->sp_push_loop_empty_label(thd))) // The inner WHILE block
- MYSQL_YYABORT;
- if (unlikely(Lex->sp_for_loop_condition_test(thd, $3)))
- MYSQL_YYABORT;
- }
- LOOP_SYM
- sp_proc_stmts1
- END LOOP_SYM
- {
- if (unlikely(Lex->sp_for_loop_finalize(thd, $3)))
- MYSQL_YYABORT;
- Lex->sp_pop_loop_empty_label(thd); // The inner WHILE block
- if (unlikely(Lex->sp_for_loop_outer_block_finalize(thd, $3)))
- MYSQL_YYABORT;
- }
- | REPEAT_SYM
- {
- if (unlikely(Lex->sp_push_loop_empty_label(thd)))
- MYSQL_YYABORT;
- }
- repeat_body
- {
- Lex->sp_pop_loop_empty_label(thd);
- }
- ;
-
-trg_action_time:
- BEFORE_SYM
- { Lex->trg_chistics.action_time= TRG_ACTION_BEFORE; }
- | AFTER_SYM
- { Lex->trg_chistics.action_time= TRG_ACTION_AFTER; }
- ;
-
-trg_event:
- INSERT
- { Lex->trg_chistics.event= TRG_EVENT_INSERT; }
- | UPDATE_SYM
- { Lex->trg_chistics.event= TRG_EVENT_UPDATE; }
- | DELETE_SYM
- { Lex->trg_chistics.event= TRG_EVENT_DELETE; }
- ;
-/*
- This part of the parser contains common code for all TABLESPACE
- commands.
- CREATE TABLESPACE name ...
- ALTER TABLESPACE name CHANGE DATAFILE ...
- ALTER TABLESPACE name ADD DATAFILE ...
- ALTER TABLESPACE name access_mode
- CREATE LOGFILE GROUP_SYM name ...
- ALTER LOGFILE GROUP_SYM name ADD UNDOFILE ..
- ALTER LOGFILE GROUP_SYM name ADD REDOFILE ..
- DROP TABLESPACE name
- DROP LOGFILE GROUP_SYM name
-*/
-change_tablespace_access:
- tablespace_name
- ts_access_mode
- ;
-
-change_tablespace_info:
- tablespace_name
- CHANGE ts_datafile
- change_ts_option_list
- ;
-
-tablespace_info:
- tablespace_name
- ADD ts_datafile
- opt_logfile_group_name
- tablespace_option_list
- ;
-
-opt_logfile_group_name:
- /* empty */ {}
- | USE_SYM LOGFILE_SYM GROUP_SYM ident
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->logfile_group_name= $4.str;
- }
- ;
-
-alter_tablespace_info:
- tablespace_name
- ADD ts_datafile
- alter_tablespace_option_list
- {
- Lex->alter_tablespace_info->ts_alter_tablespace_type= ALTER_TABLESPACE_ADD_FILE;
- }
- | tablespace_name
- DROP ts_datafile
- alter_tablespace_option_list
- {
- Lex->alter_tablespace_info->ts_alter_tablespace_type= ALTER_TABLESPACE_DROP_FILE;
- }
- ;
-
-logfile_group_info:
- logfile_group_name
- add_log_file
- logfile_group_option_list
- ;
-
-alter_logfile_group_info:
- logfile_group_name
- add_log_file
- alter_logfile_group_option_list
- ;
-
-add_log_file:
- ADD lg_undofile
- | ADD lg_redofile
- ;
-
-change_ts_option_list:
- /* empty */ {}
- change_ts_options
- ;
-
-change_ts_options:
- change_ts_option
- | change_ts_options change_ts_option
- | change_ts_options ',' change_ts_option
- ;
-
-change_ts_option:
- opt_ts_initial_size
- | opt_ts_autoextend_size
- | opt_ts_max_size
- ;
-
-tablespace_option_list:
- tablespace_options
- ;
-
-tablespace_options:
- tablespace_option
- | tablespace_options tablespace_option
- | tablespace_options ',' tablespace_option
- ;
-
-tablespace_option:
- opt_ts_initial_size
- | opt_ts_autoextend_size
- | opt_ts_max_size
- | opt_ts_extent_size
- | opt_ts_nodegroup
- | opt_ts_engine
- | ts_wait
- | opt_ts_comment
- ;
-
-alter_tablespace_option_list:
- alter_tablespace_options
- ;
-
-alter_tablespace_options:
- alter_tablespace_option
- | alter_tablespace_options alter_tablespace_option
- | alter_tablespace_options ',' alter_tablespace_option
- ;
-
-alter_tablespace_option:
- opt_ts_initial_size
- | opt_ts_autoextend_size
- | opt_ts_max_size
- | opt_ts_engine
- | ts_wait
- ;
-
-logfile_group_option_list:
- logfile_group_options
- ;
-
-logfile_group_options:
- logfile_group_option
- | logfile_group_options logfile_group_option
- | logfile_group_options ',' logfile_group_option
- ;
-
-logfile_group_option:
- opt_ts_initial_size
- | opt_ts_undo_buffer_size
- | opt_ts_redo_buffer_size
- | opt_ts_nodegroup
- | opt_ts_engine
- | ts_wait
- | opt_ts_comment
- ;
-
-alter_logfile_group_option_list:
- alter_logfile_group_options
- ;
-
-alter_logfile_group_options:
- alter_logfile_group_option
- | alter_logfile_group_options alter_logfile_group_option
- | alter_logfile_group_options ',' alter_logfile_group_option
- ;
-
-alter_logfile_group_option:
- opt_ts_initial_size
- | opt_ts_engine
- | ts_wait
- ;
-
-
-ts_datafile:
- DATAFILE_SYM TEXT_STRING_sys
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->data_file_name= $2.str;
- }
- ;
-
-lg_undofile:
- UNDOFILE_SYM TEXT_STRING_sys
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->undo_file_name= $2.str;
- }
- ;
-
-lg_redofile:
- REDOFILE_SYM TEXT_STRING_sys
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->redo_file_name= $2.str;
- }
- ;
-
-tablespace_name:
- ident
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info= (new (thd->mem_root)
- st_alter_tablespace());
- if (unlikely(lex->alter_tablespace_info == NULL))
- MYSQL_YYABORT;
- lex->alter_tablespace_info->tablespace_name= $1.str;
- lex->sql_command= SQLCOM_ALTER_TABLESPACE;
- }
- ;
-
-logfile_group_name:
- ident
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info= (new (thd->mem_root)
- st_alter_tablespace());
- if (unlikely(lex->alter_tablespace_info == NULL))
- MYSQL_YYABORT;
- lex->alter_tablespace_info->logfile_group_name= $1.str;
- lex->sql_command= SQLCOM_ALTER_TABLESPACE;
- }
- ;
-
-ts_access_mode:
- READ_ONLY_SYM
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_access_mode= TS_READ_ONLY;
- }
- | READ_WRITE_SYM
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_access_mode= TS_READ_WRITE;
- }
- | NOT_SYM ACCESSIBLE_SYM
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_access_mode= TS_NOT_ACCESSIBLE;
- }
- ;
-
-opt_ts_initial_size:
- INITIAL_SIZE_SYM opt_equal size_number
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->initial_size= $3;
- }
- ;
-
-opt_ts_autoextend_size:
- AUTOEXTEND_SIZE_SYM opt_equal size_number
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->autoextend_size= $3;
- }
- ;
-
-opt_ts_max_size:
- MAX_SIZE_SYM opt_equal size_number
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->max_size= $3;
- }
- ;
-
-opt_ts_extent_size:
- EXTENT_SIZE_SYM opt_equal size_number
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->extent_size= $3;
- }
- ;
-
-opt_ts_undo_buffer_size:
- UNDO_BUFFER_SIZE_SYM opt_equal size_number
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->undo_buffer_size= $3;
- }
- ;
-
-opt_ts_redo_buffer_size:
- REDO_BUFFER_SIZE_SYM opt_equal size_number
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->redo_buffer_size= $3;
- }
- ;
-
-opt_ts_nodegroup:
- NODEGROUP_SYM opt_equal real_ulong_num
- {
- LEX *lex= Lex;
- if (unlikely(lex->alter_tablespace_info->nodegroup_id != UNDEF_NODEGROUP))
- my_yyabort_error((ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NODEGROUP"));
- lex->alter_tablespace_info->nodegroup_id= $3;
- }
- ;
-
-opt_ts_comment:
- COMMENT_SYM opt_equal TEXT_STRING_sys
- {
- LEX *lex= Lex;
- if (unlikely(lex->alter_tablespace_info->ts_comment != NULL))
- my_yyabort_error((ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"COMMENT"));
- lex->alter_tablespace_info->ts_comment= $3.str;
- }
- ;
-
-opt_ts_engine:
- opt_storage ENGINE_SYM opt_equal storage_engines
- {
- LEX *lex= Lex;
- if (unlikely(lex->alter_tablespace_info->storage_engine != NULL))
- my_yyabort_error((ER_FILEGROUP_OPTION_ONLY_ONCE, MYF(0),
- "STORAGE ENGINE"));
- lex->alter_tablespace_info->storage_engine= $4;
- }
- ;
-
-opt_ts_wait:
- /* empty */
- | ts_wait
- ;
-
-ts_wait:
- WAIT_SYM
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->wait_until_completed= TRUE;
- }
- | NO_WAIT_SYM
- {
- LEX *lex= Lex;
- if (unlikely(!(lex->alter_tablespace_info->wait_until_completed)))
- my_yyabort_error((ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NO_WAIT"));
- lex->alter_tablespace_info->wait_until_completed= FALSE;
- }
- ;
-
-size_number:
- real_ulonglong_num { $$= $1;}
- | IDENT_sys
- {
- if ($1.to_size_number(&$$))
- MYSQL_YYABORT;
- }
- ;
-
-/*
- End tablespace part
-*/
-
-create_body:
- create_field_list_parens
- { Lex->create_info.option_list= NULL; }
- opt_create_table_options opt_create_partitioning opt_create_select {}
- | opt_create_table_options opt_create_partitioning opt_create_select {}
- | create_like
- {
-
- Lex->create_info.add(DDL_options_st::OPT_LIKE);
- TABLE_LIST *src_table= Lex->first_select_lex()->
- add_table_to_list(thd, $1, NULL, 0, TL_READ, MDL_SHARED_READ);
- if (unlikely(! src_table))
- MYSQL_YYABORT;
- /* CREATE TABLE ... LIKE is not allowed for views. */
- src_table->required_type= TABLE_TYPE_NORMAL;
- }
- ;
-
-create_like:
- LIKE table_ident { $$= $2; }
- | LEFT_PAREN_LIKE LIKE table_ident ')' { $$= $3; }
- ;
-
-opt_create_select:
- /* empty */ {}
- | opt_duplicate opt_as create_select_query_expression opt_versioning_option
- ;
-
-create_select_query_expression:
- query_expression
- {
- if (Lex->parsed_insert_select($1->first_select()))
- MYSQL_YYABORT;
- }
- | LEFT_PAREN_WITH with_clause query_expression_no_with_clause ')'
- {
- SELECT_LEX *first_select= $3->first_select();
- $3->set_with_clause($2);
- $2->attach_to(first_select);
- if (Lex->parsed_insert_select(first_select))
- MYSQL_YYABORT;
- }
- ;
-
-opt_create_partitioning:
- opt_partitioning
- {
- /*
- Remove all tables used in PARTITION clause from the global table
- list. Partitioning with subqueries is not allowed anyway.
- */
- TABLE_LIST *last_non_sel_table= Lex->create_last_non_select_table;
- last_non_sel_table->next_global= 0;
- Lex->query_tables_last= &last_non_sel_table->next_global;
- }
- ;
-
-/*
- This part of the parser is about handling of the partition information.
-
- It's first version was written by Mikael Ronstrm with lots of answers to
- questions provided by Antony Curtis.
-
- The partition grammar can be called from three places.
- 1) CREATE TABLE ... PARTITION ..
- 2) ALTER TABLE table_name PARTITION ...
- 3) PARTITION ...
-
- The first place is called when a new table is created from a MySQL client.
- The second place is called when a table is altered with the ALTER TABLE
- command from a MySQL client.
- The third place is called when opening an frm file and finding partition
- info in the .frm file. It is necessary to avoid allowing PARTITION to be
- an allowed entry point for SQL client queries. This is arranged by setting
- some state variables before arriving here.
-
- To be able to handle errors we will only set error code in this code
- and handle the error condition in the function calling the parser. This
- is necessary to ensure we can also handle errors when calling the parser
- from the openfrm function.
-*/
-opt_partitioning:
- /* empty */ {}
- | partitioning
- ;
-
-partitioning:
- PARTITION_SYM have_partitioning
- {
- LEX *lex= Lex;
- lex->part_info= new (thd->mem_root) partition_info();
- if (unlikely(!lex->part_info))
- MYSQL_YYABORT;
- if (lex->sql_command == SQLCOM_ALTER_TABLE)
- {
- lex->alter_info.partition_flags|= ALTER_PARTITION_INFO;
- }
- }
- partition
- ;
-
-have_partitioning:
- /* empty */
- {
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- LEX_CSTRING partition_name={STRING_WITH_LEN("partition")};
- if (unlikely(!plugin_is_ready(&partition_name, MYSQL_STORAGE_ENGINE_PLUGIN)))
- my_yyabort_error((ER_OPTION_PREVENTS_STATEMENT, MYF(0),
- "--skip-partition"));
-#else
- my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), "partitioning",
- "--with-plugin-partition"));
-#endif
- }
- ;
-
-partition_entry:
- PARTITION_SYM
- {
- if (unlikely(!Lex->part_info))
- {
- thd->parse_error(ER_PARTITION_ENTRY_ERROR);
- MYSQL_YYABORT;
- }
- DBUG_ASSERT(Lex->part_info->table);
- /*
- We enter here when opening the frm file to translate
- partition info string into part_info data structure.
- */
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- }
- partition
- {
- Lex->pop_select(); //main select
- }
- ;
-
-partition:
- BY
- { Lex->safe_to_cache_query= 1; }
- part_type_def opt_num_parts opt_sub_part part_defs
- ;
-
-part_type_def:
- opt_linear KEY_SYM opt_key_algo '(' part_field_list ')'
- {
- partition_info *part_info= Lex->part_info;
- part_info->list_of_part_fields= TRUE;
- part_info->column_list= FALSE;
- part_info->part_type= HASH_PARTITION;
- }
- | opt_linear HASH_SYM
- { Lex->part_info->part_type= HASH_PARTITION; }
- part_func {}
- | RANGE_SYM part_func
- { Lex->part_info->part_type= RANGE_PARTITION; }
- | RANGE_SYM part_column_list
- { Lex->part_info->part_type= RANGE_PARTITION; }
- | LIST_SYM
- {
- Select->parsing_place= IN_PART_FUNC;
- }
- part_func
- {
- Lex->part_info->part_type= LIST_PARTITION;
- Select->parsing_place= NO_MATTER;
- }
- | LIST_SYM part_column_list
- { Lex->part_info->part_type= LIST_PARTITION; }
- | SYSTEM_TIME_SYM
- {
- if (unlikely(Lex->part_info->vers_init_info(thd)))
- MYSQL_YYABORT;
- }
- opt_versioning_rotation
- ;
-
-opt_linear:
- /* empty */ {}
- | LINEAR_SYM
- { Lex->part_info->linear_hash_ind= TRUE;}
- ;
-
-opt_key_algo:
- /* empty */
- { Lex->part_info->key_algorithm= partition_info::KEY_ALGORITHM_NONE;}
- | ALGORITHM_SYM '=' real_ulong_num
- {
- switch ($3) {
- case 1:
- Lex->part_info->key_algorithm= partition_info::KEY_ALGORITHM_51;
- break;
- case 2:
- Lex->part_info->key_algorithm= partition_info::KEY_ALGORITHM_55;
- break;
- default:
- thd->parse_error();
- MYSQL_YYABORT;
- }
- }
- ;
-
-part_field_list:
- /* empty */ {}
- | part_field_item_list {}
- ;
-
-part_field_item_list:
- part_field_item {}
- | part_field_item_list ',' part_field_item {}
- ;
-
-part_field_item:
- ident
- {
- partition_info *part_info= Lex->part_info;
- part_info->num_columns++;
- if (unlikely(part_info->part_field_list.push_back($1.str,
- thd->mem_root)))
- MYSQL_YYABORT;
- if (unlikely(part_info->num_columns > MAX_REF_PARTS))
- my_yyabort_error((ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0),
- "list of partition fields"));
- }
- ;
-
-part_column_list:
- COLUMNS '(' part_field_list ')'
- {
- partition_info *part_info= Lex->part_info;
- part_info->column_list= TRUE;
- part_info->list_of_part_fields= TRUE;
- }
- ;
-
-
-part_func:
- '(' part_func_expr ')'
- {
- partition_info *part_info= Lex->part_info;
- if (unlikely(part_info->set_part_expr(thd, $2, FALSE)))
- MYSQL_YYABORT;
- part_info->num_columns= 1;
- part_info->column_list= FALSE;
- }
- ;
-
-sub_part_func:
- '(' part_func_expr ')'
- {
- if (unlikely(Lex->part_info->set_part_expr(thd, $2, TRUE)))
- MYSQL_YYABORT;
- }
- ;
-
-
-opt_num_parts:
- /* empty */ {}
- | PARTITIONS_SYM real_ulong_num
- {
- uint num_parts= $2;
- partition_info *part_info= Lex->part_info;
- if (unlikely(num_parts == 0))
- my_yyabort_error((ER_NO_PARTS_ERROR, MYF(0), "partitions"));
-
- part_info->num_parts= num_parts;
- part_info->use_default_num_partitions= FALSE;
- }
- ;
-
-opt_sub_part:
- /* empty */ {}
- | SUBPARTITION_SYM BY opt_linear HASH_SYM sub_part_func
- { Lex->part_info->subpart_type= HASH_PARTITION; }
- opt_num_subparts {}
- | SUBPARTITION_SYM BY opt_linear KEY_SYM opt_key_algo
- '(' sub_part_field_list ')'
- {
- partition_info *part_info= Lex->part_info;
- part_info->subpart_type= HASH_PARTITION;
- part_info->list_of_subpart_fields= TRUE;
- }
- opt_num_subparts {}
- ;
-
-sub_part_field_list:
- sub_part_field_item {}
- | sub_part_field_list ',' sub_part_field_item {}
- ;
-
-sub_part_field_item:
- ident
- {
- partition_info *part_info= Lex->part_info;
- if (unlikely(part_info->subpart_field_list.push_back($1.str,
- thd->mem_root)))
- MYSQL_YYABORT;
-
- if (unlikely(part_info->subpart_field_list.elements > MAX_REF_PARTS))
- my_yyabort_error((ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0),
- "list of subpartition fields"));
- }
- ;
-
-part_func_expr:
- bit_expr
- {
- if (unlikely(!Lex->safe_to_cache_query))
- {
- thd->parse_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR);
- MYSQL_YYABORT;
- }
- $$=$1;
- }
- ;
-
-opt_num_subparts:
- /* empty */ {}
- | SUBPARTITIONS_SYM real_ulong_num
- {
- uint num_parts= $2;
- LEX *lex= Lex;
- if (unlikely(num_parts == 0))
- my_yyabort_error((ER_NO_PARTS_ERROR, MYF(0), "subpartitions"));
- lex->part_info->num_subparts= num_parts;
- lex->part_info->use_default_num_subpartitions= FALSE;
- }
- ;
-
-part_defs:
- /* empty */
- {
- partition_info *part_info= Lex->part_info;
- if (unlikely(part_info->part_type == RANGE_PARTITION))
- my_yyabort_error((ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0),
- "RANGE"));
- if (unlikely(part_info->part_type == LIST_PARTITION))
- my_yyabort_error((ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0),
- "LIST"));
- }
- | '(' part_def_list ')'
- {
- partition_info *part_info= Lex->part_info;
- uint count_curr_parts= part_info->partitions.elements;
- if (part_info->num_parts != 0)
- {
- if (unlikely(part_info->num_parts !=
- count_curr_parts))
- {
- thd->parse_error(ER_PARTITION_WRONG_NO_PART_ERROR);
- MYSQL_YYABORT;
- }
- }
- else if (count_curr_parts > 0)
- {
- part_info->num_parts= count_curr_parts;
- }
- part_info->count_curr_subparts= 0;
- }
- ;
-
-part_def_list:
- part_definition {}
- | part_def_list ',' part_definition {}
- ;
-
-part_definition:
- PARTITION_SYM
- {
- partition_info *part_info= Lex->part_info;
- partition_element *p_elem= new (thd->mem_root) partition_element();
-
- if (unlikely(!p_elem) ||
- unlikely(part_info->partitions.push_back(p_elem, thd->mem_root)))
- MYSQL_YYABORT;
-
- p_elem->part_state= PART_NORMAL;
- p_elem->id= part_info->partitions.elements - 1;
- part_info->curr_part_elem= p_elem;
- part_info->current_partition= p_elem;
- part_info->use_default_partitions= FALSE;
- part_info->use_default_num_partitions= FALSE;
- }
- part_name
- opt_part_values
- opt_part_options
- opt_sub_partition
- {}
- ;
-
-part_name:
- ident
- {
- partition_info *part_info= Lex->part_info;
- partition_element *p_elem= part_info->curr_part_elem;
- if (unlikely(check_ident_length(&$1)))
- MYSQL_YYABORT;
- p_elem->partition_name= $1.str;
- }
- ;
-
-opt_part_values:
- /* empty */
- {
- LEX *lex= Lex;
- partition_info *part_info= lex->part_info;
- if (! lex->is_partition_management())
- {
- if (unlikely(part_info->error_if_requires_values()))
- MYSQL_YYABORT;
- if (unlikely(part_info->part_type == VERSIONING_PARTITION))
- my_yyabort_error((ER_VERS_WRONG_PARTS, MYF(0),
- lex->create_last_non_select_table->
- table_name.str));
- }
- else
- part_info->part_type= HASH_PARTITION;
- }
- | VALUES_LESS_SYM THAN_SYM
- {
- LEX *lex= Lex;
- partition_info *part_info= lex->part_info;
- if (! lex->is_partition_management())
- {
- if (unlikely(part_info->part_type != RANGE_PARTITION))
- my_yyabort_error((ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
- "RANGE", "LESS THAN"));
- }
- else
- part_info->part_type= RANGE_PARTITION;
- }
- part_func_max {}
- | VALUES_IN_SYM
- {
- LEX *lex= Lex;
- partition_info *part_info= lex->part_info;
- if (! lex->is_partition_management())
- {
- if (unlikely(part_info->part_type != LIST_PARTITION))
- my_yyabort_error((ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
- "LIST", "IN"));
- }
- else
- part_info->part_type= LIST_PARTITION;
- }
- part_values_in {}
- | CURRENT_SYM
- {
- if (Lex->part_values_current(thd))
- MYSQL_YYABORT;
- }
- | HISTORY_SYM
- {
- if (Lex->part_values_history(thd))
- MYSQL_YYABORT;
- }
- | DEFAULT
- {
- LEX *lex= Lex;
- partition_info *part_info= lex->part_info;
- if (! lex->is_partition_management())
- {
- if (unlikely(part_info->part_type != LIST_PARTITION))
- my_yyabort_error((ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
- "LIST", "DEFAULT"));
- }
- else
- part_info->part_type= LIST_PARTITION;
- if (unlikely(part_info->init_column_part(thd)))
- MYSQL_YYABORT;
- if (unlikely(part_info->add_max_value(thd)))
- MYSQL_YYABORT;
- }
- ;
-
-part_func_max:
- MAXVALUE_SYM
- {
- partition_info *part_info= Lex->part_info;
-
- if (unlikely(part_info->num_columns &&
- part_info->num_columns != 1U))
- {
- part_info->print_debug("Kilroy II", NULL);
- thd->parse_error(ER_PARTITION_COLUMN_LIST_ERROR);
- MYSQL_YYABORT;
- }
- else
- part_info->num_columns= 1U;
- if (unlikely(part_info->init_column_part(thd)))
- MYSQL_YYABORT;
- if (unlikely(part_info->add_max_value(thd)))
- MYSQL_YYABORT;
- }
- | part_value_item {}
- ;
-
-part_values_in:
- part_value_item
- {
- LEX *lex= Lex;
- partition_info *part_info= lex->part_info;
- part_info->print_debug("part_values_in: part_value_item", NULL);
-
- if (part_info->num_columns != 1U)
- {
- if (unlikely(!lex->is_partition_management() ||
- part_info->num_columns == 0 ||
- part_info->num_columns > MAX_REF_PARTS))
- {
- part_info->print_debug("Kilroy III", NULL);
- thd->parse_error(ER_PARTITION_COLUMN_LIST_ERROR);
- MYSQL_YYABORT;
- }
- /*
- Reorganize the current large array into a list of small
- arrays with one entry in each array. This can happen
- in the first partition of an ALTER TABLE statement where
- we ADD or REORGANIZE partitions. Also can only happen
- for LIST partitions.
- */
- if (unlikely(part_info->reorganize_into_single_field_col_val(thd)))
- MYSQL_YYABORT;
- }
- }
- | '(' part_value_list ')'
- {
- partition_info *part_info= Lex->part_info;
- if (unlikely(part_info->num_columns < 2U))
- {
- thd->parse_error(ER_ROW_SINGLE_PARTITION_FIELD_ERROR);
- MYSQL_YYABORT;
- }
- }
- ;
-
-part_value_list:
- part_value_item {}
- | part_value_list ',' part_value_item {}
- ;
-
-part_value_item:
- '('
- {
- partition_info *part_info= Lex->part_info;
- part_info->print_debug("( part_value_item", NULL);
- /* Initialisation code needed for each list of value expressions */
- if (unlikely(!(part_info->part_type == LIST_PARTITION &&
- part_info->num_columns == 1U) &&
- part_info->init_column_part(thd)))
- MYSQL_YYABORT;
- }
- part_value_item_list {}
- ')'
- {
- partition_info *part_info= Lex->part_info;
- part_info->print_debug(") part_value_item", NULL);
- if (part_info->num_columns == 0)
- part_info->num_columns= part_info->curr_list_object;
- if (unlikely(part_info->num_columns != part_info->curr_list_object))
- {
- /*
- All value items lists must be of equal length, in some cases
- which is covered by the above if-statement we don't know yet
- how many columns is in the partition so the assignment above
- ensures that we only report errors when we know we have an
- error.
- */
- part_info->print_debug("Kilroy I", NULL);
- thd->parse_error(ER_PARTITION_COLUMN_LIST_ERROR);
- MYSQL_YYABORT;
- }
- part_info->curr_list_object= 0;
- }
- ;
-
-part_value_item_list:
- part_value_expr_item {}
- | part_value_item_list ',' part_value_expr_item {}
- ;
-
-part_value_expr_item:
- MAXVALUE_SYM
- {
- partition_info *part_info= Lex->part_info;
- if (unlikely(part_info->part_type == LIST_PARTITION))
- {
- thd->parse_error(ER_MAXVALUE_IN_VALUES_IN);
- MYSQL_YYABORT;
- }
- if (unlikely(part_info->add_max_value(thd)))
- MYSQL_YYABORT;
- }
- | bit_expr
- {
- LEX *lex= Lex;
- partition_info *part_info= lex->part_info;
- Item *part_expr= $1;
-
- if (unlikely(!lex->safe_to_cache_query))
- {
- thd->parse_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR);
- MYSQL_YYABORT;
- }
- if (unlikely(part_info->add_column_list_value(thd, part_expr)))
- MYSQL_YYABORT;
- }
- ;
-
-
-opt_sub_partition:
- /* empty */
- {
- partition_info *part_info= Lex->part_info;
- if (unlikely(part_info->num_subparts != 0 &&
- !part_info->use_default_subpartitions))
- {
- /*
- We come here when we have defined subpartitions on the first
- partition but not on all the subsequent partitions.
- */
- thd->parse_error(ER_PARTITION_WRONG_NO_SUBPART_ERROR);
- MYSQL_YYABORT;
- }
- }
- | '(' sub_part_list ')'
- {
- partition_info *part_info= Lex->part_info;
- if (part_info->num_subparts != 0)
- {
- if (unlikely(part_info->num_subparts !=
- part_info->count_curr_subparts))
- {
- thd->parse_error(ER_PARTITION_WRONG_NO_SUBPART_ERROR);
- MYSQL_YYABORT;
- }
- }
- else if (part_info->count_curr_subparts > 0)
- {
- if (unlikely(part_info->partitions.elements > 1))
- {
- thd->parse_error(ER_PARTITION_WRONG_NO_SUBPART_ERROR);
- MYSQL_YYABORT;
- }
- part_info->num_subparts= part_info->count_curr_subparts;
- }
- part_info->count_curr_subparts= 0;
- }
- ;
-
-sub_part_list:
- sub_part_definition {}
- | sub_part_list ',' sub_part_definition {}
- ;
-
-sub_part_definition:
- SUBPARTITION_SYM
- {
- partition_info *part_info= Lex->part_info;
- partition_element *curr_part= part_info->current_partition;
- partition_element *sub_p_elem= new (thd->mem_root)
- partition_element(curr_part);
- if (unlikely(part_info->use_default_subpartitions &&
- part_info->partitions.elements >= 2))
- {
- /*
- create table t1 (a int)
- partition by list (a) subpartition by hash (a)
- (partition p0 values in (1),
- partition p1 values in (2) subpartition sp11);
- causes use to arrive since we are on the second
- partition, but still use_default_subpartitions
- is set. When we come here we're processing at least
- the second partition (the current partition processed
- have already been put into the partitions list.
- */
- thd->parse_error(ER_PARTITION_WRONG_NO_SUBPART_ERROR);
- MYSQL_YYABORT;
- }
- if (unlikely(!sub_p_elem) ||
- unlikely(curr_part->subpartitions.push_back(sub_p_elem, thd->mem_root)))
- MYSQL_YYABORT;
-
- sub_p_elem->id= curr_part->subpartitions.elements - 1;
- part_info->curr_part_elem= sub_p_elem;
- part_info->use_default_subpartitions= FALSE;
- part_info->use_default_num_subpartitions= FALSE;
- part_info->count_curr_subparts++;
- }
- sub_name opt_part_options {}
- ;
-
-sub_name:
- ident_or_text
- {
- if (unlikely(check_ident_length(&$1)))
- MYSQL_YYABORT;
- Lex->part_info->curr_part_elem->partition_name= $1.str;
- }
- ;
-
-opt_part_options:
- /* empty */ {}
- | opt_part_option_list {}
- ;
-
-opt_part_option_list:
- opt_part_option_list opt_part_option {}
- | opt_part_option {}
- ;
-
-opt_part_option:
- TABLESPACE opt_equal ident_or_text
- { Lex->part_info->curr_part_elem->tablespace_name= $3.str; }
- | opt_storage ENGINE_SYM opt_equal storage_engines
- {
- partition_info *part_info= Lex->part_info;
- part_info->curr_part_elem->engine_type= $4;
- part_info->default_engine_type= $4;
- }
- | CONNECTION_SYM opt_equal TEXT_STRING_sys
- {
- LEX *lex= Lex;
- lex->part_info->curr_part_elem->connect_string.str= $3.str;
- lex->part_info->curr_part_elem->connect_string.length= $3.length;
- }
- | NODEGROUP_SYM opt_equal real_ulong_num
- { Lex->part_info->curr_part_elem->nodegroup_id= (uint16) $3; }
- | MAX_ROWS opt_equal real_ulonglong_num
- { Lex->part_info->curr_part_elem->part_max_rows= (ha_rows) $3; }
- | MIN_ROWS opt_equal real_ulonglong_num
- { Lex->part_info->curr_part_elem->part_min_rows= (ha_rows) $3; }
- | DATA_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys
- { Lex->part_info->curr_part_elem->data_file_name= $4.str; }
- | INDEX_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys
- { Lex->part_info->curr_part_elem->index_file_name= $4.str; }
- | COMMENT_SYM opt_equal TEXT_STRING_sys
- { Lex->part_info->curr_part_elem->part_comment= $3.str; }
- ;
-
-opt_versioning_rotation:
- /* empty */ {}
- | INTERVAL_SYM expr interval opt_versioning_interval_start
- {
- partition_info *part_info= Lex->part_info;
- if (unlikely(part_info->vers_set_interval(thd, $2, $3, $4)))
- MYSQL_YYABORT;
- }
- | LIMIT ulonglong_num
- {
- partition_info *part_info= Lex->part_info;
- if (unlikely(part_info->vers_set_limit($2)))
- {
- my_error(ER_PART_WRONG_VALUE, MYF(0),
- Lex->create_last_non_select_table->table_name.str,
- "LIMIT");
- MYSQL_YYABORT;
- }
- }
- ;
-
-
-opt_versioning_interval_start:
- /* empty */
- {
- $$= thd->query_start();
- }
- | STARTS_SYM ulong_num
- {
- /* only allowed from mysql_unpack_partition() */
- if (unlikely(!Lex->part_info->table))
- {
- thd->parse_error(ER_SYNTAX_ERROR, $1.pos());
- MYSQL_YYABORT;
- }
- $$= (ulong)$2;
- }
- ;
-
-/*
- End of partition parser part
-*/
-
-opt_as:
- /* empty */ {}
- | AS {}
- ;
-
-opt_create_database_options:
- /* empty */ {}
- | create_database_options {}
- ;
-
-create_database_options:
- create_database_option {}
- | create_database_options create_database_option {}
- ;
-
-create_database_option:
- default_collation {}
- | default_charset {}
- ;
-
-opt_if_not_exists_table_element:
- /* empty */
- {
- Lex->check_exists= FALSE;
- }
- | IF_SYM not EXISTS
- {
- Lex->check_exists= TRUE;
- }
- ;
-
-opt_if_not_exists:
- /* empty */
- {
- $$.init();
- }
- | IF_SYM not EXISTS
- {
- $$.set(DDL_options_st::OPT_IF_NOT_EXISTS);
- }
- ;
-
-create_or_replace:
- CREATE /* empty */
- {
- $$.init();
- }
- | CREATE OR_SYM REPLACE
- {
- $$.set(DDL_options_st::OPT_OR_REPLACE);
- }
- ;
-
-opt_create_table_options:
- /* empty */
- | create_table_options
- ;
-
-create_table_options_space_separated:
- create_table_option
- | create_table_option create_table_options_space_separated
- ;
-
-create_table_options:
- create_table_option
- | create_table_option create_table_options
- | create_table_option ',' create_table_options
- ;
-
-create_table_option:
- ENGINE_SYM opt_equal ident_or_text
- {
- LEX *lex= Lex;
- if (!lex->m_sql_cmd)
- {
- DBUG_ASSERT(lex->sql_command == SQLCOM_ALTER_TABLE);
- if (!(lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_table()))
- MYSQL_YYABORT;
- }
- Storage_engine_name *opt=
- lex->m_sql_cmd->option_storage_engine_name();
- DBUG_ASSERT(opt); // Expect a proper Sql_cmd
- *opt= Storage_engine_name($3);
- lex->create_info.used_fields|= HA_CREATE_USED_ENGINE;
- }
- | MAX_ROWS opt_equal ulonglong_num
- {
- Lex->create_info.max_rows= $3;
- Lex->create_info.used_fields|= HA_CREATE_USED_MAX_ROWS;
- }
- | MIN_ROWS opt_equal ulonglong_num
- {
- Lex->create_info.min_rows= $3;
- Lex->create_info.used_fields|= HA_CREATE_USED_MIN_ROWS;
- }
- | AVG_ROW_LENGTH opt_equal ulong_num
- {
- Lex->create_info.avg_row_length=$3;
- Lex->create_info.used_fields|= HA_CREATE_USED_AVG_ROW_LENGTH;
- }
- | PASSWORD_SYM opt_equal TEXT_STRING_sys
- {
- Lex->create_info.password=$3.str;
- Lex->create_info.used_fields|= HA_CREATE_USED_PASSWORD;
- }
- | COMMENT_SYM opt_equal TEXT_STRING_sys
- {
- Lex->create_info.comment=$3;
- Lex->create_info.used_fields|= HA_CREATE_USED_COMMENT;
- }
- | AUTO_INC opt_equal ulonglong_num
- {
- Lex->create_info.auto_increment_value=$3;
- Lex->create_info.used_fields|= HA_CREATE_USED_AUTO;
- }
- | PACK_KEYS_SYM opt_equal ulong_num
- {
- switch($3) {
- case 0:
- Lex->create_info.table_options|= HA_OPTION_NO_PACK_KEYS;
- break;
- case 1:
- Lex->create_info.table_options|= HA_OPTION_PACK_KEYS;
- break;
- default:
- thd->parse_error();
- MYSQL_YYABORT;
- }
- Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;
- }
- | PACK_KEYS_SYM opt_equal DEFAULT
- {
- Lex->create_info.table_options&=
- ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS);
- Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;
- }
- | STATS_AUTO_RECALC_SYM opt_equal ulong_num
- {
- switch($3) {
- case 0:
- Lex->create_info.stats_auto_recalc= HA_STATS_AUTO_RECALC_OFF;
- break;
- case 1:
- Lex->create_info.stats_auto_recalc= HA_STATS_AUTO_RECALC_ON;
- break;
- default:
- thd->parse_error();
- MYSQL_YYABORT;
- }
- Lex->create_info.used_fields|= HA_CREATE_USED_STATS_AUTO_RECALC;
- }
- | STATS_AUTO_RECALC_SYM opt_equal DEFAULT
- {
- Lex->create_info.stats_auto_recalc= HA_STATS_AUTO_RECALC_DEFAULT;
- Lex->create_info.used_fields|= HA_CREATE_USED_STATS_AUTO_RECALC;
- }
- | STATS_PERSISTENT_SYM opt_equal ulong_num
- {
- switch($3) {
- case 0:
- Lex->create_info.table_options|= HA_OPTION_NO_STATS_PERSISTENT;
- break;
- case 1:
- Lex->create_info.table_options|= HA_OPTION_STATS_PERSISTENT;
- break;
- default:
- thd->parse_error();
- MYSQL_YYABORT;
- }
- Lex->create_info.used_fields|= HA_CREATE_USED_STATS_PERSISTENT;
- }
- | STATS_PERSISTENT_SYM opt_equal DEFAULT
- {
- Lex->create_info.table_options&=
- ~(HA_OPTION_STATS_PERSISTENT | HA_OPTION_NO_STATS_PERSISTENT);
- Lex->create_info.used_fields|= HA_CREATE_USED_STATS_PERSISTENT;
- }
- | STATS_SAMPLE_PAGES_SYM opt_equal ulong_num
- {
- /* From user point of view STATS_SAMPLE_PAGES can be specified as
- STATS_SAMPLE_PAGES=N (where 0<N<=65535, it does not make sense to
- scan 0 pages) or STATS_SAMPLE_PAGES=default. Internally we record
- =default as 0. See create_frm() in sql/table.cc, we use only two
- bytes for stats_sample_pages and this is why we do not allow
- larger values. 65535 pages, 16kb each means to sample 1GB, which
- is impractical. If at some point this needs to be extended, then
- we can store the higher bits from stats_sample_pages in .frm too. */
- if (unlikely($3 == 0 || $3 > 0xffff))
- {
- thd->parse_error();
- MYSQL_YYABORT;
- }
- Lex->create_info.stats_sample_pages=$3;
- Lex->create_info.used_fields|= HA_CREATE_USED_STATS_SAMPLE_PAGES;
- }
- | STATS_SAMPLE_PAGES_SYM opt_equal DEFAULT
- {
- Lex->create_info.stats_sample_pages=0;
- Lex->create_info.used_fields|= HA_CREATE_USED_STATS_SAMPLE_PAGES;
- }
- | CHECKSUM_SYM opt_equal ulong_num
- {
- Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM;
- Lex->create_info.used_fields|= HA_CREATE_USED_CHECKSUM;
- }
- | TABLE_CHECKSUM_SYM opt_equal ulong_num
- {
- Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM;
- Lex->create_info.used_fields|= HA_CREATE_USED_CHECKSUM;
- }
- | PAGE_CHECKSUM_SYM opt_equal choice
- {
- Lex->create_info.used_fields|= HA_CREATE_USED_PAGE_CHECKSUM;
- Lex->create_info.page_checksum= $3;
- }
- | DELAY_KEY_WRITE_SYM opt_equal ulong_num
- {
- Lex->create_info.table_options|= $3 ? HA_OPTION_DELAY_KEY_WRITE : HA_OPTION_NO_DELAY_KEY_WRITE;
- Lex->create_info.used_fields|= HA_CREATE_USED_DELAY_KEY_WRITE;
- }
- | ROW_FORMAT_SYM opt_equal row_types
- {
- Lex->create_info.row_type= $3;
- Lex->create_info.used_fields|= HA_CREATE_USED_ROW_FORMAT;
- }
- | UNION_SYM opt_equal
- {
- Lex->first_select_lex()->table_list.save_and_clear(&Lex->save_list);
- }
- '(' opt_table_list ')'
- {
- /*
- Move the union list to the merge_list and exclude its tables
- from the global list.
- */
- LEX *lex=Lex;
- lex->create_info.merge_list= lex->first_select_lex()->table_list.first;
- lex->first_select_lex()->table_list= lex->save_list;
- /*
- When excluding union list from the global list we assume that
- elements of the former immediately follow elements which represent
- table being created/altered and parent tables.
- */
- TABLE_LIST *last_non_sel_table= lex->create_last_non_select_table;
- DBUG_ASSERT(last_non_sel_table->next_global ==
- lex->create_info.merge_list);
- last_non_sel_table->next_global= 0;
- Lex->query_tables_last= &last_non_sel_table->next_global;
-
- lex->create_info.used_fields|= HA_CREATE_USED_UNION;
- }
- | default_charset
- | default_collation
- | INSERT_METHOD opt_equal merge_insert_types
- {
- Lex->create_info.merge_insert_method= $3;
- Lex->create_info.used_fields|= HA_CREATE_USED_INSERT_METHOD;
- }
- | DATA_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys
- {
- Lex->create_info.data_file_name= $4.str;
- Lex->create_info.used_fields|= HA_CREATE_USED_DATADIR;
- }
- | INDEX_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys
- {
- Lex->create_info.index_file_name= $4.str;
- Lex->create_info.used_fields|= HA_CREATE_USED_INDEXDIR;
- }
- | TABLESPACE ident
- {Lex->create_info.tablespace= $2.str;}
- | STORAGE_SYM DISK_SYM
- {Lex->create_info.storage_media= HA_SM_DISK;}
- | STORAGE_SYM MEMORY_SYM
- {Lex->create_info.storage_media= HA_SM_MEMORY;}
- | CONNECTION_SYM opt_equal TEXT_STRING_sys
- {
- Lex->create_info.connect_string.str= $3.str;
- Lex->create_info.connect_string.length= $3.length;
- Lex->create_info.used_fields|= HA_CREATE_USED_CONNECTION;
- }
- | KEY_BLOCK_SIZE opt_equal ulong_num
- {
- Lex->create_info.used_fields|= HA_CREATE_USED_KEY_BLOCK_SIZE;
- Lex->create_info.key_block_size= $3;
- }
- | TRANSACTIONAL_SYM opt_equal choice
- {
- Lex->create_info.used_fields|= HA_CREATE_USED_TRANSACTIONAL;
- Lex->create_info.transactional= $3;
- }
- | IDENT_sys equal TEXT_STRING_sys
- {
- if (unlikely($3.length > ENGINE_OPTION_MAX_LENGTH))
- my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str));
- (void) new (thd->mem_root)
- engine_option_value($1, $3, true,
- &Lex->create_info.option_list,
- &Lex->option_list_last);
- }
- | IDENT_sys equal ident
- {
- if (unlikely($3.length > ENGINE_OPTION_MAX_LENGTH))
- my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str));
- (void) new (thd->mem_root)
- engine_option_value($1, $3, false,
- &Lex->create_info.option_list,
- &Lex->option_list_last);
- }
- | IDENT_sys equal real_ulonglong_num
- {
- (void) new (thd->mem_root)
- engine_option_value($1, $3, &Lex->create_info.option_list,
- &Lex->option_list_last, thd->mem_root);
- }
- | IDENT_sys equal DEFAULT
- {
- (void) new (thd->mem_root)
- engine_option_value($1, &Lex->create_info.option_list,
- &Lex->option_list_last);
- }
- | SEQUENCE_SYM opt_equal choice
- {
- Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE;
- Lex->create_info.sequence= ($3 == HA_CHOICE_YES);
- }
- | versioning_option
- ;
-
-opt_versioning_option:
- /* empty */
- | versioning_option
- ;
-
-versioning_option:
- WITH_SYSTEM_SYM VERSIONING_SYM
- {
- if (unlikely(Lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
- {
- if (DBUG_EVALUATE_IF("sysvers_force", 0, 1))
- {
- my_error(ER_VERS_NOT_SUPPORTED, MYF(0), "CREATE TEMPORARY TABLE");
- MYSQL_YYABORT;
- }
- }
- else
- {
- Lex->alter_info.flags|= ALTER_ADD_SYSTEM_VERSIONING;
- Lex->create_info.options|= HA_VERSIONED_TABLE;
- }
- }
- ;
-
-default_charset:
- opt_default charset opt_equal charset_name_or_default
- {
- if (unlikely(Lex->create_info.add_table_option_default_charset($4)))
- MYSQL_YYABORT;
- }
- ;
-
-default_collation:
- opt_default COLLATE_SYM opt_equal collation_name_or_default
- {
- HA_CREATE_INFO *cinfo= &Lex->create_info;
- if (unlikely((cinfo->used_fields & HA_CREATE_USED_DEFAULT_CHARSET) &&
- cinfo->default_table_charset && $4 &&
- !($4= merge_charset_and_collation(cinfo->default_table_charset,
- $4))))
- MYSQL_YYABORT;
-
- Lex->create_info.default_table_charset= $4;
- Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
- }
- ;
-
-storage_engines:
- ident_or_text
- {
- if (Storage_engine_name($1).
- resolve_storage_engine_with_error(thd, &$$,
- thd->lex->create_info.tmp_table()))
- MYSQL_YYABORT;
- }
- ;
-
-known_storage_engines:
- ident_or_text
- {
- plugin_ref plugin;
- if (likely((plugin= ha_resolve_by_name(thd, &$1, false))))
- $$= plugin_hton(plugin);
- else
- my_yyabort_error((ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str));
- }
- ;
-
-row_types:
- DEFAULT { $$= ROW_TYPE_DEFAULT; }
- | FIXED_SYM { $$= ROW_TYPE_FIXED; }
- | DYNAMIC_SYM { $$= ROW_TYPE_DYNAMIC; }
- | COMPRESSED_SYM { $$= ROW_TYPE_COMPRESSED; }
- | REDUNDANT_SYM { $$= ROW_TYPE_REDUNDANT; }
- | COMPACT_SYM { $$= ROW_TYPE_COMPACT; }
- | PAGE_SYM { $$= ROW_TYPE_PAGE; }
- ;
-
-merge_insert_types:
- NO_SYM { $$= MERGE_INSERT_DISABLED; }
- | FIRST_SYM { $$= MERGE_INSERT_TO_FIRST; }
- | LAST_SYM { $$= MERGE_INSERT_TO_LAST; }
- ;
-
-udf_type:
- STRING_SYM {$$ = (int) STRING_RESULT; }
- | REAL {$$ = (int) REAL_RESULT; }
- | DECIMAL_SYM {$$ = (int) DECIMAL_RESULT; }
- | INT_SYM {$$ = (int) INT_RESULT; }
- ;
-
-
-create_field_list:
- field_list
- {
- Lex->create_last_non_select_table= Lex->last_table();
- }
- ;
-
-create_field_list_parens:
- LEFT_PAREN_ALT field_list ')'
- {
- Lex->create_last_non_select_table= Lex->last_table();
- }
- ;
-
-field_list:
- field_list_item
- | field_list ',' field_list_item
- ;
-
-field_list_item:
- column_def { }
- | key_def
- | constraint_def
- | period_for_system_time
- | PERIOD_SYM period_for_application_time { }
- ;
-
-column_def:
- field_spec
- { $$= $1; }
- | field_spec references
- { $$= $1; }
- ;
-
-key_def:
- key_or_index opt_if_not_exists opt_ident opt_USING_key_algorithm
- {
- Lex->option_list= NULL;
- if (unlikely(Lex->add_key(Key::MULTIPLE, &$3, $4, $2)))
- MYSQL_YYABORT;
- }
- '(' key_list ')' normal_key_options { }
- | key_or_index opt_if_not_exists ident TYPE_SYM btree_or_rtree
- {
- Lex->option_list= NULL;
- if (unlikely(Lex->add_key(Key::MULTIPLE, &$3, $5, $2)))
- MYSQL_YYABORT;
- }
- '(' key_list ')' normal_key_options { }
- | fulltext opt_key_or_index opt_if_not_exists opt_ident
- {
- Lex->option_list= NULL;
- if (unlikely(Lex->add_key($1, &$4, HA_KEY_ALG_UNDEF, $3)))
- MYSQL_YYABORT;
- }
- '(' key_list ')' fulltext_key_options { }
- | spatial opt_key_or_index opt_if_not_exists opt_ident
- {
- Lex->option_list= NULL;
- if (unlikely(Lex->add_key($1, &$4, HA_KEY_ALG_UNDEF, $3)))
- MYSQL_YYABORT;
- }
- '(' key_list ')' spatial_key_options { }
- | opt_constraint constraint_key_type
- opt_if_not_exists opt_ident
- opt_USING_key_algorithm
- {
- Lex->option_list= NULL;
- if (unlikely(Lex->add_key($2, $4.str ? &$4 : &$1, $5, $3)))
- MYSQL_YYABORT;
- }
- '(' key_list ')' normal_key_options { }
- | opt_constraint constraint_key_type opt_if_not_exists ident
- TYPE_SYM btree_or_rtree
- {
- Lex->option_list= NULL;
- if (unlikely(Lex->add_key($2, $4.str ? &$4 : &$1, $6, $3)))
- MYSQL_YYABORT;
- }
- '(' key_list ')' normal_key_options { }
- | opt_constraint FOREIGN KEY_SYM opt_if_not_exists opt_ident
- {
- if (unlikely(Lex->check_add_key($4)) ||
- unlikely(!(Lex->last_key= (new (thd->mem_root)
- Key(Key::MULTIPLE,
- $1.str ? &$1 : &$5,
- HA_KEY_ALG_UNDEF, true, $4)))))
- MYSQL_YYABORT;
- Lex->option_list= NULL;
- }
- '(' key_list ')' references
- {
- LEX *lex=Lex;
- Key *key= (new (thd->mem_root)
- Foreign_key($5.str ? &$5 : &$1,
- &lex->last_key->columns,
- &$10->db,
- &$10->table,
- &lex->ref_list,
- lex->fk_delete_opt,
- lex->fk_update_opt,
- lex->fk_match_option,
- $4));
- if (unlikely(key == NULL))
- MYSQL_YYABORT;
- /*
- handle_if_exists_options() expectes the two keys in this order:
- the Foreign_key, followed by its auto-generated Key.
- */
- lex->alter_info.key_list.push_back(key, thd->mem_root);
- lex->alter_info.key_list.push_back(Lex->last_key, thd->mem_root);
- lex->option_list= NULL;
-
- /* Only used for ALTER TABLE. Ignored otherwise. */
- lex->alter_info.flags|= ALTER_ADD_FOREIGN_KEY;
- }
- ;
-
-constraint_def:
- opt_constraint check_constraint
- {
- Lex->add_constraint($1, $2, FALSE);
- }
- ;
-
-period_for_system_time:
- // If FOR_SYM is followed by SYSTEM_TIME_SYM then they are merged to: FOR_SYSTEM_TIME_SYM .
- PERIOD_SYM FOR_SYSTEM_TIME_SYM '(' ident ',' ident ')'
- {
- Vers_parse_info &info= Lex->vers_get_info();
- info.set_period($4, $6);
- }
- ;
-
-period_for_application_time:
- FOR_SYM ident '(' ident ',' ident ')'
- {
- if (Lex->add_period($2, $4, $6))
- MYSQL_YYABORT;
- }
- ;
-
-opt_check_constraint:
- /* empty */ { $$= (Virtual_column_info*) 0; }
- | check_constraint { $$= $1;}
- ;
-
-check_constraint:
- CHECK_SYM '(' expr ')'
- {
- Virtual_column_info *v= add_virtual_expression(thd, $3);
- if (unlikely(!v))
- MYSQL_YYABORT;
- $$= v;
- }
- ;
-
-opt_constraint_no_id:
- /* Empty */ {}
- | CONSTRAINT {}
- ;
-
-opt_constraint:
- /* empty */ { $$= null_clex_str; }
- | constraint { $$= $1; }
- ;
-
-constraint:
- CONSTRAINT opt_ident { $$=$2; }
- ;
-
-field_spec:
- field_ident
- {
- LEX *lex=Lex;
- Create_field *f= new (thd->mem_root) Create_field();
-
- if (unlikely(check_string_char_length(&$1, 0, NAME_CHAR_LEN,
- system_charset_info, 1)))
- my_yyabort_error((ER_TOO_LONG_IDENT, MYF(0), $1.str));
-
- if (unlikely(!f))
- MYSQL_YYABORT;
-
- lex->init_last_field(f, &$1, NULL);
- $<create_field>$= f;
- }
- field_type_or_serial opt_check_constraint
- {
- LEX *lex=Lex;
- $$= $<create_field>2;
-
- $$->check_constraint= $4;
-
- if (unlikely($$->check(thd)))
- MYSQL_YYABORT;
-
- lex->alter_info.create_list.push_back($$, thd->mem_root);
-
- $$->create_if_not_exists= Lex->check_exists;
- if ($$->flags & PRI_KEY_FLAG)
- lex->add_key_to_list(&$1, Key::PRIMARY, lex->check_exists);
- else if ($$->flags & UNIQUE_KEY_FLAG)
- lex->add_key_to_list(&$1, Key::UNIQUE, lex->check_exists);
- }
- ;
-
-field_type_or_serial:
- field_type { Lex->last_field->set_attributes($1, Lex->charset); }
- field_def
- | SERIAL_SYM
- {
- Lex->last_field->set_handler(&type_handler_longlong);
- Lex->last_field->flags|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG
- | UNSIGNED_FLAG | UNIQUE_KEY_FLAG;
- }
- opt_serial_attribute
- ;
-
-opt_serial_attribute:
- /* empty */ {}
- | opt_serial_attribute_list {}
- ;
-
-opt_serial_attribute_list:
- opt_serial_attribute_list serial_attribute {}
- | serial_attribute
- ;
-
-opt_asrow_attribute:
- /* empty */ {}
- | opt_asrow_attribute_list {}
- ;
-
-opt_asrow_attribute_list:
- opt_asrow_attribute_list asrow_attribute {}
- | asrow_attribute
- ;
-
-field_def:
- /* empty */ { }
- | attribute_list
- | attribute_list compressed_deprecated_column_attribute
- | attribute_list compressed_deprecated_column_attribute attribute_list
- | opt_generated_always AS virtual_column_func
- {
- Lex->last_field->vcol_info= $3;
- Lex->last_field->flags&= ~NOT_NULL_FLAG; // undo automatic NOT NULL for timestamps
- }
- vcol_opt_specifier vcol_opt_attribute
- | opt_generated_always AS ROW_SYM START_SYM opt_asrow_attribute
- {
- if (Lex->last_field_generated_always_as_row_start())
- MYSQL_YYABORT;
- }
- | opt_generated_always AS ROW_SYM END opt_asrow_attribute
- {
- if (Lex->last_field_generated_always_as_row_end())
- MYSQL_YYABORT;
- }
- ;
-
-opt_generated_always:
- /* empty */ {}
- | GENERATED_SYM ALWAYS_SYM {}
- ;
-
-vcol_opt_specifier:
- /* empty */
- {
- Lex->last_field->vcol_info->set_stored_in_db_flag(FALSE);
- }
- | VIRTUAL_SYM
- {
- Lex->last_field->vcol_info->set_stored_in_db_flag(FALSE);
- }
- | PERSISTENT_SYM
- {
- Lex->last_field->vcol_info->set_stored_in_db_flag(TRUE);
- }
- | STORED_SYM
- {
- Lex->last_field->vcol_info->set_stored_in_db_flag(TRUE);
- }
- ;
-
-vcol_opt_attribute:
- /* empty */ {}
- | vcol_opt_attribute_list {}
- ;
-
-vcol_opt_attribute_list:
- vcol_opt_attribute_list vcol_attribute {}
- | vcol_attribute
- ;
-
-vcol_attribute:
- UNIQUE_SYM
- {
- LEX *lex=Lex;
- lex->last_field->flags|= UNIQUE_KEY_FLAG;
- lex->alter_info.flags|= ALTER_ADD_INDEX;
- }
- | UNIQUE_SYM KEY_SYM
- {
- LEX *lex=Lex;
- lex->last_field->flags|= UNIQUE_KEY_FLAG;
- lex->alter_info.flags|= ALTER_ADD_INDEX;
- }
- | COMMENT_SYM TEXT_STRING_sys { Lex->last_field->comment= $2; }
- | INVISIBLE_SYM
- {
- Lex->last_field->invisible= INVISIBLE_USER;
- }
- ;
-
-parse_vcol_expr:
- PARSE_VCOL_EXPR_SYM
- {
- /*
- "PARSE_VCOL_EXPR" can only be used by the SQL server
- when reading a '*.frm' file.
- Prevent the end user from invoking this command.
- */
- MYSQL_YYABORT_UNLESS(Lex->parse_vcol_expr);
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- }
- expr
- {
- Virtual_column_info *v= add_virtual_expression(thd, $3);
- if (unlikely(!v))
- MYSQL_YYABORT;
- Lex->last_field->vcol_info= v;
- Lex->pop_select(); //main select
- }
- ;
-
-parenthesized_expr:
- expr
- | expr ',' expr_list
- {
- $3->push_front($1, thd->mem_root);
- $$= new (thd->mem_root) Item_row(thd, *$3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-virtual_column_func:
- '(' parenthesized_expr ')'
- {
- Virtual_column_info *v=
- add_virtual_expression(thd, $2);
- if (unlikely(!v))
- MYSQL_YYABORT;
- $$= v;
- }
- | subquery
- {
- Item *item;
- if (!(item= new (thd->mem_root) Item_singlerow_subselect(thd, $1)))
- MYSQL_YYABORT;
- Virtual_column_info *v= add_virtual_expression(thd, item);
- if (unlikely(!v))
- MYSQL_YYABORT;
- $$= v;
- }
- ;
-
-expr_or_literal: column_default_non_parenthesized_expr | signed_literal ;
-
-column_default_expr:
- virtual_column_func
- | expr_or_literal
- {
- if (unlikely(!($$= add_virtual_expression(thd, $1))))
- MYSQL_YYABORT;
- }
- ;
-
-field_type:
- field_type_numeric
- | field_type_temporal
- | field_type_string
- | field_type_lob
- | field_type_misc
- ;
-
-
-sp_param_field_type:
- field_type_numeric
- | field_type_temporal
- | sp_param_field_type_string
- | field_type_lob
- | field_type_misc
- ;
-
-
-field_type_numeric:
- int_type opt_field_length field_options { $$.set($1, $2); }
- | real_type opt_precision field_options { $$.set($1, $2); }
- | FLOAT_SYM float_options field_options
- {
- $$.set(&type_handler_float, $2);
- if ($2.length() && !$2.dec())
- {
- int err;
- ulonglong tmp_length= my_strtoll10($2.length(), NULL, &err);
- if (unlikely(err || tmp_length > PRECISION_FOR_DOUBLE))
- my_yyabort_error((ER_WRONG_FIELD_SPEC, MYF(0),
- Lex->last_field->field_name.str));
- if (tmp_length > PRECISION_FOR_FLOAT)
- $$.set(&type_handler_double);
- else
- $$.set(&type_handler_float);
- }
- }
- | BIT_SYM opt_field_length_default_1
- {
- $$.set(&type_handler_bit, $2);
- }
- | BOOL_SYM
- {
- $$.set(&type_handler_tiny, "1");
- }
- | BOOLEAN_SYM
- {
- $$.set(&type_handler_tiny, "1");
- }
- | DECIMAL_SYM float_options field_options
- { $$.set(&type_handler_newdecimal, $2);}
- | NUMBER_ORACLE_SYM float_options field_options
- {
- if ($2.length() != 0)
- $$.set(&type_handler_newdecimal, $2);
- else
- $$.set(&type_handler_double);
- }
- | NUMERIC_SYM float_options field_options
- { $$.set(&type_handler_newdecimal, $2);}
- | FIXED_SYM float_options field_options
- { $$.set(&type_handler_newdecimal, $2);}
- ;
-
-
-opt_binary_and_compression:
- /* empty */
- | binary
- | binary compressed_deprecated_data_type_attribute
- | compressed opt_binary
- ;
-
-field_type_string:
- char opt_field_length_default_1 opt_binary
- {
- $$.set(&type_handler_string, $2);
- }
- | nchar opt_field_length_default_1 opt_bin_mod
- {
- $$.set(&type_handler_string, $2);
- bincmp_collation(national_charset_info, $3);
- }
- | BINARY opt_field_length_default_1
- {
- Lex->charset=&my_charset_bin;
- $$.set(&type_handler_string, $2);
- }
- | varchar field_length opt_binary_and_compression
- {
- $$.set(&type_handler_varchar, $2);
- }
- | VARCHAR2_ORACLE_SYM field_length opt_binary_and_compression
- {
- $$.set(&type_handler_varchar, $2);
- }
- | nvarchar field_length opt_compressed opt_bin_mod
- {
- $$.set(&type_handler_varchar, $2);
- bincmp_collation(national_charset_info, $4);
- }
- | VARBINARY field_length opt_compressed
- {
- Lex->charset=&my_charset_bin;
- $$.set(&type_handler_varchar, $2);
- }
- | RAW_ORACLE_SYM field_length opt_compressed
- {
- Lex->charset= &my_charset_bin;
- $$.set(&type_handler_varchar, $2);
- }
- ;
-
-
-sp_param_field_type_string:
- char opt_field_length_default_sp_param_char opt_binary
- {
- $$.set(&type_handler_varchar, $2);
- }
- | nchar opt_field_length_default_sp_param_char opt_bin_mod
- {
- $$.set(&type_handler_varchar, $2);
- bincmp_collation(national_charset_info, $3);
- }
- | BINARY opt_field_length_default_sp_param_char
- {
- Lex->charset=&my_charset_bin;
- $$.set(&type_handler_varchar, $2);
- }
- | varchar opt_field_length_default_sp_param_varchar opt_binary
- {
- $$.set(&type_handler_varchar, $2);
- }
- | VARCHAR2_ORACLE_SYM opt_field_length_default_sp_param_varchar opt_binary
- {
- $$.set(&type_handler_varchar, $2);
- }
- | nvarchar opt_field_length_default_sp_param_varchar opt_bin_mod
- {
- $$.set(&type_handler_varchar, $2);
- bincmp_collation(national_charset_info, $3);
- }
- | VARBINARY opt_field_length_default_sp_param_varchar
- {
- Lex->charset= &my_charset_bin;
- $$.set(&type_handler_varchar, $2);
- }
- | RAW_ORACLE_SYM opt_field_length_default_sp_param_varchar
- {
- Lex->charset= &my_charset_bin;
- $$.set(&type_handler_varchar, $2);
- }
- ;
-
-
-field_type_temporal:
- YEAR_SYM opt_field_length field_options
- {
- if ($2)
- {
- errno= 0;
- ulong length= strtoul($2, NULL, 10);
- if (errno == 0 && length <= MAX_FIELD_BLOBLENGTH && length != 4)
- {
- char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1];
- my_snprintf(buff, sizeof(buff), "YEAR(%lu)", length);
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_WARN_DEPRECATED_SYNTAX,
- ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX),
- buff, "YEAR(4)");
- }
- }
- $$.set(&type_handler_year, $2);
- }
- | DATE_SYM { $$.set(thd->type_handler_for_date()); }
- | TIME_SYM opt_field_length
- {
- $$.set(opt_mysql56_temporal_format ?
- static_cast<const Type_handler*>(&type_handler_time2) :
- static_cast<const Type_handler*>(&type_handler_time),
- $2);
- }
- | TIMESTAMP opt_field_length
- {
- if (thd->variables.sql_mode & MODE_MAXDB)
- $$.set(opt_mysql56_temporal_format ?
- static_cast<const Type_handler*>(&type_handler_datetime2) :
- static_cast<const Type_handler*>(&type_handler_datetime),
- $2);
- else
- {
- /*
- Unlike other types TIMESTAMP fields are NOT NULL by default.
- Unless --explicit-defaults-for-timestamp is given.
- */
- if (!opt_explicit_defaults_for_timestamp)
- Lex->last_field->flags|= NOT_NULL_FLAG;
- $$.set(opt_mysql56_temporal_format ?
- static_cast<const Type_handler*>(&type_handler_timestamp2):
- static_cast<const Type_handler*>(&type_handler_timestamp),
- $2);
- }
- }
- | DATETIME opt_field_length
- {
- $$.set(opt_mysql56_temporal_format ?
- static_cast<const Type_handler*>(&type_handler_datetime2) :
- static_cast<const Type_handler*>(&type_handler_datetime),
- $2);
- }
- ;
-
-
-field_type_lob:
- TINYBLOB opt_compressed
- {
- Lex->charset=&my_charset_bin;
- $$.set(&type_handler_tiny_blob);
- }
- | BLOB_MARIADB_SYM opt_field_length opt_compressed
- {
- Lex->charset=&my_charset_bin;
- $$.set(&type_handler_blob, $2);
- }
- | BLOB_ORACLE_SYM field_length opt_compressed
- {
- Lex->charset=&my_charset_bin;
- $$.set(&type_handler_blob, $2);
- }
- | BLOB_ORACLE_SYM opt_compressed
- {
- Lex->charset=&my_charset_bin;
- $$.set(&type_handler_long_blob);
- }
- | spatial_type float_options srid_option
- {
-#ifdef HAVE_SPATIAL
- Lex->charset=&my_charset_bin;
- Lex->last_field->geom_type= $1;
- $$.set(&type_handler_geometry, $2);
-#else
- my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name,
- sym_group_geom.needed_define));
-#endif
- }
- | MEDIUMBLOB opt_compressed
- {
- Lex->charset=&my_charset_bin;
- $$.set(&type_handler_medium_blob);
- }
- | LONGBLOB opt_compressed
- {
- Lex->charset=&my_charset_bin;
- $$.set(&type_handler_long_blob);
- }
- | LONG_SYM VARBINARY opt_compressed
- {
- Lex->charset=&my_charset_bin;
- $$.set(&type_handler_medium_blob);
- }
- | LONG_SYM varchar opt_binary_and_compression
- { $$.set(&type_handler_medium_blob); }
- | TINYTEXT opt_binary_and_compression
- { $$.set(&type_handler_tiny_blob); }
- | TEXT_SYM opt_field_length opt_binary_and_compression
- { $$.set(&type_handler_blob, $2); }
- | MEDIUMTEXT opt_binary_and_compression
- { $$.set(&type_handler_medium_blob); }
- | LONGTEXT opt_binary_and_compression
- { $$.set(&type_handler_long_blob); }
- | CLOB_ORACLE_SYM opt_binary_and_compression
- { $$.set(&type_handler_long_blob); }
- | LONG_SYM opt_binary_and_compression
- { $$.set(&type_handler_medium_blob); }
- | JSON_SYM opt_compressed
- {
- Lex->charset= &my_charset_utf8mb4_bin;
- $$.set(&type_handler_json_longtext);
- }
- ;
-
-field_type_misc:
- ENUM '(' string_list ')' opt_binary
- { $$.set(&type_handler_enum); }
- | SET '(' string_list ')' opt_binary
- { $$.set(&type_handler_set); }
- ;
-
-spatial_type:
- GEOMETRY_SYM { $$= Field::GEOM_GEOMETRY; }
- | GEOMETRYCOLLECTION { $$= Field::GEOM_GEOMETRYCOLLECTION; }
- | POINT_SYM { $$= Field::GEOM_POINT; }
- | MULTIPOINT { $$= Field::GEOM_MULTIPOINT; }
- | LINESTRING { $$= Field::GEOM_LINESTRING; }
- | MULTILINESTRING { $$= Field::GEOM_MULTILINESTRING; }
- | POLYGON { $$= Field::GEOM_POLYGON; }
- | MULTIPOLYGON { $$= Field::GEOM_MULTIPOLYGON; }
- ;
-
-char:
- CHAR_SYM {}
- ;
-
-nchar:
- NCHAR_SYM {}
- | NATIONAL_SYM CHAR_SYM {}
- ;
-
-varchar:
- char VARYING {}
- | VARCHAR {}
- ;
-
-nvarchar:
- NATIONAL_SYM VARCHAR {}
- | NVARCHAR_SYM {}
- | NCHAR_SYM VARCHAR {}
- | NATIONAL_SYM CHAR_SYM VARYING {}
- | NCHAR_SYM VARYING {}
- ;
-
-int_type:
- INT_SYM { $$= &type_handler_long; }
- | TINYINT { $$= &type_handler_tiny; }
- | SMALLINT { $$= &type_handler_short; }
- | MEDIUMINT { $$= &type_handler_int24; }
- | BIGINT { $$= &type_handler_longlong; }
- ;
-
-real_type:
- REAL
- {
- $$= thd->variables.sql_mode & MODE_REAL_AS_FLOAT ?
- static_cast<const Type_handler *>(&type_handler_float) :
- static_cast<const Type_handler *>(&type_handler_double);
- }
- | DOUBLE_SYM { $$= &type_handler_double; }
- | DOUBLE_SYM PRECISION { $$= &type_handler_double; }
- ;
-
-srid_option:
- /* empty */
- { Lex->last_field->srid= 0; }
- |
- REF_SYSTEM_ID_SYM '=' NUM
- {
- Lex->last_field->srid=atoi($3.str);
- }
- ;
-
-float_options:
- /* empty */ { $$.set(0, 0); }
- | field_length { $$.set($1, 0); }
- | precision { $$= $1; }
- ;
-
-precision:
- '(' NUM ',' NUM ')' { $$.set($2.str, $4.str); }
- ;
-
-field_options:
- /* empty */ {}
- | SIGNED_SYM {}
- | UNSIGNED { Lex->last_field->flags|= UNSIGNED_FLAG;}
- | ZEROFILL { Lex->last_field->flags|= UNSIGNED_FLAG | ZEROFILL_FLAG; }
- | UNSIGNED ZEROFILL { Lex->last_field->flags|= UNSIGNED_FLAG | ZEROFILL_FLAG; }
- | ZEROFILL UNSIGNED { Lex->last_field->flags|= UNSIGNED_FLAG | ZEROFILL_FLAG; }
- ;
-
-field_length:
- '(' LONG_NUM ')' { $$= $2.str; }
- | '(' ULONGLONG_NUM ')' { $$= $2.str; }
- | '(' DECIMAL_NUM ')' { $$= $2.str; }
- | '(' NUM ')' { $$= $2.str; }
- ;
-
-opt_field_length:
- /* empty */ { $$= (char*) 0; /* use default length */ }
- | field_length { $$= $1; }
- ;
-
-opt_field_length_default_1:
- /* empty */ { $$= (char*) "1"; }
- | field_length { $$= $1; }
- ;
-
-/*
- In sql_mode=ORACLE, real size of VARCHAR and CHAR with no length
- in SP parameters is fixed at runtime with the length of real args.
- Let's translate VARCHAR to VARCHAR(4000) for return value.
-
- Since Oracle 9, maximum size for VARCHAR in PL/SQL is 32767.
-
- In MariaDB the limit for VARCHAR is 65535 bytes.
- We could translate VARCHAR with no length to VARCHAR(65535), but
- it would mean that for multi-byte character sets we'd have to translate
- VARCHAR to MEDIUMTEXT, to guarantee 65535 characters.
-
- Also we could translate VARCHAR to VARCHAR(16383), where 16383 is
- the maximum possible length in characters in case of mbmaxlen=4
- (e.g. utf32, utf16, utf8mb4). However, we'll have character sets with
- mbmaxlen=5 soon (e.g. gb18030).
-*/
-opt_field_length_default_sp_param_varchar:
- /* empty */ { $$.set("4000", "4000"); }
- | field_length { $$.set($1, NULL); }
- ;
-
-opt_field_length_default_sp_param_char:
- /* empty */ { $$.set("2000", "2000"); }
- | field_length { $$.set($1, NULL); }
- ;
-
-opt_precision:
- /* empty */ { $$.set(0, 0); }
- | precision { $$= $1; }
- ;
-
-
-attribute_list:
- attribute_list attribute {}
- | attribute
- ;
-
-attribute:
- NULL_SYM { Lex->last_field->flags&= ~ NOT_NULL_FLAG; }
- | DEFAULT column_default_expr { Lex->last_field->default_value= $2; }
- | ON UPDATE_SYM NOW_SYM opt_default_time_precision
- {
- Item *item= new (thd->mem_root) Item_func_now_local(thd, $4);
- if (unlikely(item == NULL))
- MYSQL_YYABORT;
- Lex->last_field->on_update= item;
- }
- | AUTO_INC { Lex->last_field->flags|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG; }
- | SERIAL_SYM DEFAULT VALUE_SYM
- {
- LEX *lex=Lex;
- lex->last_field->flags|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNIQUE_KEY_FLAG;
- lex->alter_info.flags|= ALTER_ADD_INDEX;
- }
- | COLLATE_SYM collation_name
- {
- if (unlikely(Lex->charset && !my_charset_same(Lex->charset,$2)))
- my_yyabort_error((ER_COLLATION_CHARSET_MISMATCH, MYF(0),
- $2->name,Lex->charset->csname));
- Lex->last_field->charset= $2;
- }
- | serial_attribute
- ;
-
-opt_compression_method:
- /* empty */ { $$= NULL; }
- | equal ident { $$= $2.str; }
- ;
-
-opt_compressed:
- /* empty */ {}
- | compressed { }
- ;
-
-compressed:
- COMPRESSED_SYM opt_compression_method
- {
- if (unlikely(Lex->last_field->set_compressed($2)))
- MYSQL_YYABORT;
- }
- ;
-
-compressed_deprecated_data_type_attribute:
- COMPRESSED_SYM opt_compression_method
- {
- if (unlikely(Lex->last_field->set_compressed_deprecated(thd, $2)))
- MYSQL_YYABORT;
- }
- ;
-
-compressed_deprecated_column_attribute:
- COMPRESSED_SYM opt_compression_method
- {
- if (unlikely(Lex->last_field->
- set_compressed_deprecated_column_attribute(thd, $1.pos(), $2)))
- MYSQL_YYABORT;
- }
- ;
-
-asrow_attribute:
- not NULL_SYM
- {
- Lex->last_field->flags|= NOT_NULL_FLAG;
- }
- | opt_primary KEY_SYM
- {
- LEX *lex=Lex;
- lex->last_field->flags|= PRI_KEY_FLAG | NOT_NULL_FLAG;
- lex->alter_info.flags|= ALTER_ADD_INDEX;
- }
- | vcol_attribute
- ;
-
-serial_attribute:
- asrow_attribute
- | IDENT_sys equal TEXT_STRING_sys
- {
- if (unlikely($3.length > ENGINE_OPTION_MAX_LENGTH))
- my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str));
- (void) new (thd->mem_root)
- engine_option_value($1, $3, true,
- &Lex->last_field->option_list,
- &Lex->option_list_last);
- }
- | IDENT_sys equal ident
- {
- if (unlikely($3.length > ENGINE_OPTION_MAX_LENGTH))
- my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str));
- (void) new (thd->mem_root)
- engine_option_value($1, $3, false,
- &Lex->last_field->option_list,
- &Lex->option_list_last);
- }
- | IDENT_sys equal real_ulonglong_num
- {
- (void) new (thd->mem_root)
- engine_option_value($1, $3, &Lex->last_field->option_list,
- &Lex->option_list_last, thd->mem_root);
- }
- | IDENT_sys equal DEFAULT
- {
- (void) new (thd->mem_root)
- engine_option_value($1, &Lex->last_field->option_list,
- &Lex->option_list_last);
- }
- | with_or_without_system VERSIONING_SYM
- {
- Lex->last_field->versioning= $1;
- Lex->create_info.options|= HA_VERSIONED_TABLE;
- if (Lex->alter_info.flags & ALTER_DROP_SYSTEM_VERSIONING)
- {
- my_yyabort_error((ER_VERS_NOT_VERSIONED, MYF(0),
- Lex->create_last_non_select_table->table_name.str));
- }
- }
- ;
-
-with_or_without_system:
- WITH_SYSTEM_SYM
- {
- Lex->alter_info.flags|= ALTER_COLUMN_UNVERSIONED;
- Lex->create_info.vers_info.versioned_fields= true;
- $$= Column_definition::WITH_VERSIONING;
- }
- | WITHOUT SYSTEM
- {
- Lex->alter_info.flags|= ALTER_COLUMN_UNVERSIONED;
- Lex->create_info.vers_info.unversioned_fields= true;
- $$= Column_definition::WITHOUT_VERSIONING;
- }
- ;
-
-
-type_with_opt_collate:
- field_type opt_collate
- {
- $$= $1;
-
- if ($2)
- {
- if (unlikely(!(Lex->charset= merge_charset_and_collation(Lex->charset, $2))))
- MYSQL_YYABORT;
- }
- Lex->last_field->set_attributes($1, Lex->charset);
- }
- ;
-
-sp_param_type_with_opt_collate:
- sp_param_field_type opt_collate
- {
- $$= $1;
- if ($2)
- {
- if (unlikely(!(Lex->charset= merge_charset_and_collation(Lex->charset, $2))))
- MYSQL_YYABORT;
- }
- Lex->last_field->set_attributes($1, Lex->charset);
- }
- ;
-
-charset:
- CHAR_SYM SET {}
- | CHARSET {}
- ;
-
-charset_name:
- ident_or_text
- {
- if (unlikely(!($$=get_charset_by_csname($1.str,MY_CS_PRIMARY,MYF(0)))))
- my_yyabort_error((ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str));
- }
- | BINARY { $$= &my_charset_bin; }
- ;
-
-charset_name_or_default:
- charset_name { $$=$1; }
- | DEFAULT { $$=NULL; }
- ;
-
-opt_load_data_charset:
- /* Empty */ { $$= NULL; }
- | charset charset_name_or_default { $$= $2; }
- ;
-
-old_or_new_charset_name:
- ident_or_text
- {
- if (unlikely(!($$=get_charset_by_csname($1.str,
- MY_CS_PRIMARY,MYF(0))) &&
- !($$=get_old_charset_by_name($1.str))))
- my_yyabort_error((ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str));
- }
- | BINARY { $$= &my_charset_bin; }
- ;
-
-old_or_new_charset_name_or_default:
- old_or_new_charset_name { $$=$1; }
- | DEFAULT { $$=NULL; }
- ;
-
-collation_name:
- ident_or_text
- {
- if (unlikely(!($$= mysqld_collation_get_by_name($1.str))))
- MYSQL_YYABORT;
- }
- ;
-
-opt_collate:
- /* empty */ { $$=NULL; }
- | COLLATE_SYM collation_name_or_default { $$=$2; }
- ;
-
-collation_name_or_default:
- collation_name { $$=$1; }
- | DEFAULT { $$=NULL; }
- ;
-
-opt_default:
- /* empty */ {}
- | DEFAULT {}
- ;
-
-charset_or_alias:
- charset charset_name { $$= $2; }
- | ASCII_SYM { $$= &my_charset_latin1; }
- | UNICODE_SYM
- {
- if (unlikely(!($$= get_charset_by_csname("ucs2", MY_CS_PRIMARY,MYF(0)))))
- my_yyabort_error((ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2"));
- }
- ;
-
-opt_binary:
- /* empty */ { bincmp_collation(NULL, false); }
- | binary {}
- ;
-
-binary:
- BYTE_SYM { bincmp_collation(&my_charset_bin, false); }
- | charset_or_alias opt_bin_mod { bincmp_collation($1, $2); }
- | BINARY { bincmp_collation(NULL, true); }
- | BINARY charset_or_alias { bincmp_collation($2, true); }
- ;
-
-opt_bin_mod:
- /* empty */ { $$= false; }
- | BINARY { $$= true; }
- ;
-
-ws_nweights:
- '(' real_ulong_num
- {
- if (unlikely($2 == 0))
- {
- thd->parse_error();
- MYSQL_YYABORT;
- }
- }
- ')'
- { $$= $2; }
- ;
-
-ws_level_flag_desc:
- ASC { $$= 0; }
- | DESC { $$= 1 << MY_STRXFRM_DESC_SHIFT; }
- ;
-
-ws_level_flag_reverse:
- REVERSE_SYM { $$= 1 << MY_STRXFRM_REVERSE_SHIFT; } ;
-
-ws_level_flags:
- /* empty */ { $$= 0; }
- | ws_level_flag_desc { $$= $1; }
- | ws_level_flag_desc ws_level_flag_reverse { $$= $1 | $2; }
- | ws_level_flag_reverse { $$= $1 ; }
- ;
-
-ws_level_number:
- real_ulong_num
- {
- $$= $1 < 1 ? 1 : ($1 > MY_STRXFRM_NLEVELS ? MY_STRXFRM_NLEVELS : $1);
- $$--;
- }
- ;
-
-ws_level_list_item:
- ws_level_number ws_level_flags
- {
- $$= (1 | $2) << $1;
- }
- ;
-
-ws_level_list:
- ws_level_list_item { $$= $1; }
- | ws_level_list ',' ws_level_list_item { $$|= $3; }
- ;
-
-ws_level_range:
- ws_level_number '-' ws_level_number
- {
- uint start= $1;
- uint end= $3;
- for ($$= 0; start <= end; start++)
- $$|= (1 << start);
- }
- ;
-
-ws_level_list_or_range:
- ws_level_list { $$= $1; }
- | ws_level_range { $$= $1; }
- ;
-
-opt_ws_levels:
- /* empty*/ { $$= 0; }
- | LEVEL_SYM ws_level_list_or_range { $$= $2; }
- ;
-
-opt_primary:
- /* empty */
- | PRIMARY_SYM
- ;
-
-references:
- REFERENCES
- table_ident
- opt_ref_list
- opt_match_clause
- opt_on_update_delete
- {
- $$=$2;
- }
- ;
-
-opt_ref_list:
- /* empty */
- { Lex->ref_list.empty(); }
- | '(' ref_list ')'
- ;
-
-ref_list:
- ref_list ',' ident
- {
- Key_part_spec *key= new (thd->mem_root) Key_part_spec(&$3, 0);
- if (unlikely(key == NULL))
- MYSQL_YYABORT;
- Lex->ref_list.push_back(key, thd->mem_root);
- }
- | ident
- {
- Key_part_spec *key= new (thd->mem_root) Key_part_spec(&$1, 0);
- if (unlikely(key == NULL))
- MYSQL_YYABORT;
- LEX *lex= Lex;
- lex->ref_list.empty();
- lex->ref_list.push_back(key, thd->mem_root);
- }
- ;
-
-opt_match_clause:
- /* empty */
- { Lex->fk_match_option= Foreign_key::FK_MATCH_UNDEF; }
- | MATCH FULL
- { Lex->fk_match_option= Foreign_key::FK_MATCH_FULL; }
- | MATCH PARTIAL
- { Lex->fk_match_option= Foreign_key::FK_MATCH_PARTIAL; }
- | MATCH SIMPLE_SYM
- { Lex->fk_match_option= Foreign_key::FK_MATCH_SIMPLE; }
- ;
-
-opt_on_update_delete:
- /* empty */
- {
- LEX *lex= Lex;
- lex->fk_update_opt= FK_OPTION_UNDEF;
- lex->fk_delete_opt= FK_OPTION_UNDEF;
- }
- | ON UPDATE_SYM delete_option
- {
- LEX *lex= Lex;
- lex->fk_update_opt= $3;
- lex->fk_delete_opt= FK_OPTION_UNDEF;
- }
- | ON DELETE_SYM delete_option
- {
- LEX *lex= Lex;
- lex->fk_update_opt= FK_OPTION_UNDEF;
- lex->fk_delete_opt= $3;
- }
- | ON UPDATE_SYM delete_option
- ON DELETE_SYM delete_option
- {
- LEX *lex= Lex;
- lex->fk_update_opt= $3;
- lex->fk_delete_opt= $6;
- }
- | ON DELETE_SYM delete_option
- ON UPDATE_SYM delete_option
- {
- LEX *lex= Lex;
- lex->fk_update_opt= $6;
- lex->fk_delete_opt= $3;
- }
- ;
-
-delete_option:
- RESTRICT { $$= FK_OPTION_RESTRICT; }
- | CASCADE { $$= FK_OPTION_CASCADE; }
- | SET NULL_SYM { $$= FK_OPTION_SET_NULL; }
- | NO_SYM ACTION { $$= FK_OPTION_NO_ACTION; }
- | SET DEFAULT { $$= FK_OPTION_SET_DEFAULT; }
- ;
-
-constraint_key_type:
- PRIMARY_SYM KEY_SYM { $$= Key::PRIMARY; }
- | UNIQUE_SYM opt_key_or_index { $$= Key::UNIQUE; }
- ;
-
-key_or_index:
- KEY_SYM {}
- | INDEX_SYM {}
- ;
-
-opt_key_or_index:
- /* empty */ {}
- | key_or_index
- ;
-
-keys_or_index:
- KEYS {}
- | INDEX_SYM {}
- | INDEXES {}
- ;
-
-opt_unique:
- /* empty */ { $$= Key::MULTIPLE; }
- | UNIQUE_SYM { $$= Key::UNIQUE; }
- ;
-
-fulltext:
- FULLTEXT_SYM { $$= Key::FULLTEXT;}
- ;
-
-spatial:
- SPATIAL_SYM
- {
-#ifdef HAVE_SPATIAL
- $$= Key::SPATIAL;
-#else
- my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name,
- sym_group_geom.needed_define));
-#endif
- }
- ;
-
-normal_key_options:
- /* empty */ {}
- | normal_key_opts { Lex->last_key->option_list= Lex->option_list; }
- ;
-
-fulltext_key_options:
- /* empty */ {}
- | fulltext_key_opts { Lex->last_key->option_list= Lex->option_list; }
- ;
-
-spatial_key_options:
- /* empty */ {}
- | spatial_key_opts { Lex->last_key->option_list= Lex->option_list; }
- ;
-
-normal_key_opts:
- normal_key_opt
- | normal_key_opts normal_key_opt
- ;
-
-spatial_key_opts:
- spatial_key_opt
- | spatial_key_opts spatial_key_opt
- ;
-
-fulltext_key_opts:
- fulltext_key_opt
- | fulltext_key_opts fulltext_key_opt
- ;
-
-opt_USING_key_algorithm:
- /* Empty*/ { $$= HA_KEY_ALG_UNDEF; }
- | USING btree_or_rtree { $$= $2; }
- ;
-
-/* TYPE is a valid identifier, so it's handled differently than USING */
-opt_key_algorithm_clause:
- /* Empty*/ { $$= HA_KEY_ALG_UNDEF; }
- | USING btree_or_rtree { $$= $2; }
- | TYPE_SYM btree_or_rtree { $$= $2; }
- ;
-
-key_using_alg:
- USING btree_or_rtree
- { Lex->last_key->key_create_info.algorithm= $2; }
- | TYPE_SYM btree_or_rtree
- { Lex->last_key->key_create_info.algorithm= $2; }
- ;
-
-all_key_opt:
- KEY_BLOCK_SIZE opt_equal ulong_num
- {
- Lex->last_key->key_create_info.block_size= $3;
- Lex->last_key->key_create_info.flags|= HA_USES_BLOCK_SIZE;
- }
- | COMMENT_SYM TEXT_STRING_sys
- { Lex->last_key->key_create_info.comment= $2; }
- | IDENT_sys equal TEXT_STRING_sys
- {
- if (unlikely($3.length > ENGINE_OPTION_MAX_LENGTH))
- my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str));
- (void) new (thd->mem_root)
- engine_option_value($1, $3, true, &Lex->option_list,
- &Lex->option_list_last);
- }
- | IDENT_sys equal ident
- {
- if (unlikely($3.length > ENGINE_OPTION_MAX_LENGTH))
- my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str));
- (void) new (thd->mem_root)
- engine_option_value($1, $3, false, &Lex->option_list,
- &Lex->option_list_last);
- }
- | IDENT_sys equal real_ulonglong_num
- {
- (void) new (thd->mem_root)
- engine_option_value($1, $3, &Lex->option_list,
- &Lex->option_list_last, thd->mem_root);
- }
- | IDENT_sys equal DEFAULT
- {
- (void) new (thd->mem_root)
- engine_option_value($1, &Lex->option_list,
- &Lex->option_list_last);
- }
- ;
-
-normal_key_opt:
- all_key_opt
- | key_using_alg
- ;
-
-spatial_key_opt:
- all_key_opt
- ;
-
-fulltext_key_opt:
- all_key_opt
- | WITH PARSER_SYM IDENT_sys
- {
- if (likely(plugin_is_ready(&$3, MYSQL_FTPARSER_PLUGIN)))
- Lex->last_key->key_create_info.parser_name= $3;
- else
- my_yyabort_error((ER_FUNCTION_NOT_DEFINED, MYF(0), $3.str));
- }
- ;
-
-btree_or_rtree:
- BTREE_SYM { $$= HA_KEY_ALG_BTREE; }
- | RTREE_SYM { $$= HA_KEY_ALG_RTREE; }
- | HASH_SYM { $$= HA_KEY_ALG_HASH; }
- ;
-
-key_list:
- key_list ',' key_part order_dir
- {
- Lex->last_key->columns.push_back($3, thd->mem_root);
- }
- | key_part order_dir
- {
- Lex->last_key->columns.push_back($1, thd->mem_root);
- }
- ;
-
-key_part:
- ident
- {
- $$= new (thd->mem_root) Key_part_spec(&$1, 0);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | ident '(' NUM ')'
- {
- int key_part_len= atoi($3.str);
- if (unlikely(!key_part_len))
- my_yyabort_error((ER_KEY_PART_0, MYF(0), $1.str));
- $$= new (thd->mem_root) Key_part_spec(&$1, (uint) key_part_len);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-opt_ident:
- /* empty */ { $$= null_clex_str; }
- | field_ident { $$= $1; }
- ;
-
-string_list:
- text_string
- { Lex->last_field->interval_list.push_back($1, thd->mem_root); }
- | string_list ',' text_string
- { Lex->last_field->interval_list.push_back($3, thd->mem_root); }
- ;
-
-/*
-** Alter table
-*/
-
-alter:
- ALTER
- {
- Lex->name= null_clex_str;
- Lex->table_type= TABLE_TYPE_UNKNOWN;
- Lex->sql_command= SQLCOM_ALTER_TABLE;
- Lex->duplicates= DUP_ERROR;
- Lex->first_select_lex()->order_list.empty();
- Lex->create_info.init();
- Lex->create_info.row_type= ROW_TYPE_NOT_USED;
- Lex->alter_info.reset();
- Lex->no_write_to_binlog= 0;
- Lex->create_info.storage_media= HA_SM_DEFAULT;
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- DBUG_ASSERT(!Lex->m_sql_cmd);
- }
- alter_options TABLE_SYM table_ident opt_lock_wait_timeout
- {
- if (!Lex->first_select_lex()->
- add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING,
- TL_READ_NO_INSERT, MDL_SHARED_UPGRADABLE))
- MYSQL_YYABORT;
- Lex->first_select_lex()->db=
- (Lex->first_select_lex()->table_list.first)->db;
- Lex->create_last_non_select_table= Lex->last_table();
- Lex->mark_first_table_as_inserting();
- }
- alter_commands
- {
- if (likely(!Lex->m_sql_cmd))
- {
- /* Create a generic ALTER TABLE statment. */
- Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_table();
- if (unlikely(Lex->m_sql_cmd == NULL))
- MYSQL_YYABORT;
- }
- Lex->pop_select(); //main select
- }
- | ALTER DATABASE ident_or_empty
- {
- Lex->create_info.default_table_charset= NULL;
- Lex->create_info.used_fields= 0;
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- }
- create_database_options
- {
- LEX *lex=Lex;
- lex->sql_command=SQLCOM_ALTER_DB;
- lex->name= $3;
- if (lex->name.str == NULL &&
- unlikely(lex->copy_db_to(&lex->name)))
- MYSQL_YYABORT;
- Lex->pop_select(); //main select
- }
- | ALTER DATABASE ident UPGRADE_SYM DATA_SYM DIRECTORY_SYM NAME_SYM
- {
- LEX *lex= Lex;
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "DATABASE"));
- lex->sql_command= SQLCOM_ALTER_DB_UPGRADE;
- lex->name= $3;
- }
- | ALTER PROCEDURE_SYM sp_name
- {
- LEX *lex= Lex;
-
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE"));
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- lex->sp_chistics.init();
- }
- sp_a_chistics
- {
- LEX *lex=Lex;
-
- lex->sql_command= SQLCOM_ALTER_PROCEDURE;
- lex->spname= $3;
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
- | ALTER FUNCTION_SYM sp_name
- {
- LEX *lex= Lex;
-
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"));
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- lex->sp_chistics.init();
- }
- sp_a_chistics
- {
- LEX *lex=Lex;
-
- lex->sql_command= SQLCOM_ALTER_FUNCTION;
- lex->spname= $3;
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
- | ALTER view_algorithm definer_opt opt_view_suid VIEW_SYM table_ident
- {
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- if (Lex->add_alter_view(thd, $2, $4, $6))
- MYSQL_YYABORT;
- }
- view_list_opt AS view_select
- {
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
- | ALTER definer_opt opt_view_suid VIEW_SYM table_ident
- /*
- We have two separate rules for ALTER VIEW rather that
- optional view_algorithm above, to resolve the ambiguity
- with the ALTER EVENT below.
- */
- {
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- if (Lex->add_alter_view(thd, VIEW_ALGORITHM_INHERIT, $3, $5))
- MYSQL_YYABORT;
- }
- view_list_opt AS view_select
- {
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
- | ALTER definer_opt remember_name EVENT_SYM sp_name
- {
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- /*
- It is safe to use Lex->spname because
- ALTER EVENT xxx RENATE TO yyy DO ALTER EVENT RENAME TO
- is not allowed. Lex->spname is used in the case of RENAME TO
- If it had to be supported spname had to be added to
- Event_parse_data.
- */
-
- if (unlikely(!(Lex->event_parse_data= Event_parse_data::new_instance(thd))))
- MYSQL_YYABORT;
- Lex->event_parse_data->identifier= $5;
-
- Lex->sql_command= SQLCOM_ALTER_EVENT;
- Lex->stmt_definition_begin= $3;
- }
- ev_alter_on_schedule_completion
- opt_ev_rename_to
- opt_ev_status
- opt_ev_comment
- opt_ev_sql_stmt
- {
- if (unlikely(!($7 || $8 || $9 || $10 || $11)))
- {
- thd->parse_error();
- MYSQL_YYABORT;
- }
- /*
- sql_command is set here because some rules in ev_sql_stmt
- can overwrite it
- */
- Lex->sql_command= SQLCOM_ALTER_EVENT;
- Lex->stmt_definition_end= (char*)YYLIP->get_cpp_ptr();
-
- Lex->pop_select(); //main select
- }
- | ALTER TABLESPACE alter_tablespace_info
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_cmd_type= ALTER_TABLESPACE;
- }
- | ALTER LOGFILE_SYM GROUP_SYM alter_logfile_group_info
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_cmd_type= ALTER_LOGFILE_GROUP;
- }
- | ALTER TABLESPACE change_tablespace_info
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_cmd_type= CHANGE_FILE_TABLESPACE;
- }
- | ALTER TABLESPACE change_tablespace_access
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_cmd_type= ALTER_ACCESS_MODE_TABLESPACE;
- }
- | ALTER SERVER_SYM ident_or_text
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_ALTER_SERVER;
- lex->server_options.reset($3);
- } OPTIONS_SYM '(' server_options_list ')' { }
- /* ALTER USER foo is allowed for MySQL compatibility. */
- | ALTER USER_SYM opt_if_exists clear_privileges grant_list
- opt_require_clause opt_resource_options opt_account_locking opt_password_expiration
- {
- Lex->create_info.set($3);
- Lex->sql_command= SQLCOM_ALTER_USER;
- }
- | ALTER SEQUENCE_SYM opt_if_exists
- {
- LEX *lex= Lex;
- lex->name= null_clex_str;
- lex->table_type= TABLE_TYPE_UNKNOWN;
- lex->sql_command= SQLCOM_ALTER_SEQUENCE;
- lex->create_info.init();
- lex->no_write_to_binlog= 0;
- DBUG_ASSERT(!lex->m_sql_cmd);
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- }
- table_ident
- {
- LEX *lex= Lex;
- if (!(lex->create_info.seq_create_info= new (thd->mem_root)
- sequence_definition()) ||
- !lex->first_select_lex()->
- add_table_to_list(thd, $5, NULL, TL_OPTION_SEQUENCE,
- TL_WRITE, MDL_EXCLUSIVE))
- MYSQL_YYABORT;
- }
- sequence_defs
- {
- /* Create a generic ALTER SEQUENCE statment. */
- Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_sequence($3);
- if (unlikely(Lex->m_sql_cmd == NULL))
- MYSQL_YYABORT;
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
- ;
-
-opt_account_locking:
- /* Nothing */ {}
- | ACCOUNT_SYM LOCK_SYM
- {
- Lex->account_options.account_locked= ACCOUNTLOCK_LOCKED;
- }
- | ACCOUNT_SYM UNLOCK_SYM
- {
- Lex->account_options.account_locked= ACCOUNTLOCK_UNLOCKED;
- }
- ;
-opt_password_expiration:
- /* Nothing */ {}
- | PASSWORD_SYM EXPIRE_SYM
- {
- Lex->account_options.password_expire= PASSWORD_EXPIRE_NOW;
- }
- | PASSWORD_SYM EXPIRE_SYM NEVER_SYM
- {
- Lex->account_options.password_expire= PASSWORD_EXPIRE_NEVER;
- }
- | PASSWORD_SYM EXPIRE_SYM DEFAULT
- {
- Lex->account_options.password_expire= PASSWORD_EXPIRE_DEFAULT;
- }
- | PASSWORD_SYM EXPIRE_SYM INTERVAL_SYM NUM DAY_SYM
- {
- Lex->account_options.password_expire= PASSWORD_EXPIRE_INTERVAL;
- if (!(Lex->account_options.num_expiration_days= atoi($4.str)))
- my_yyabort_error((ER_WRONG_VALUE, MYF(0), "DAY", $4.str));
- }
- ;
-
-ev_alter_on_schedule_completion:
- /* empty */ { $$= 0;}
- | ON SCHEDULE_SYM ev_schedule_time { $$= 1; }
- | ev_on_completion { $$= 1; }
- | ON SCHEDULE_SYM ev_schedule_time ev_on_completion { $$= 1; }
- ;
-
-opt_ev_rename_to:
- /* empty */ { $$= 0;}
- | RENAME TO_SYM sp_name
- {
- /*
- Use lex's spname to hold the new name.
- The original name is in the Event_parse_data object
- */
- Lex->spname= $3;
- $$= 1;
- }
- ;
-
-opt_ev_sql_stmt:
- /* empty*/ { $$= 0;}
- | DO_SYM ev_sql_stmt { $$= 1; }
- ;
-
-ident_or_empty:
- /* empty */ { $$= Lex_ident_sys(); }
- | ident
- ;
-
-alter_commands:
- /* empty */
- | DISCARD TABLESPACE
- {
- Lex->m_sql_cmd= new (thd->mem_root)
- Sql_cmd_discard_import_tablespace(
- Sql_cmd_discard_import_tablespace::DISCARD_TABLESPACE);
- if (unlikely(Lex->m_sql_cmd == NULL))
- MYSQL_YYABORT;
- }
- | IMPORT TABLESPACE
- {
- Lex->m_sql_cmd= new (thd->mem_root)
- Sql_cmd_discard_import_tablespace(
- Sql_cmd_discard_import_tablespace::IMPORT_TABLESPACE);
- if (unlikely(Lex->m_sql_cmd == NULL))
- MYSQL_YYABORT;
- }
- | alter_list
- opt_partitioning
- | alter_list
- remove_partitioning
- | remove_partitioning
- | partitioning
-/*
- This part was added for release 5.1 by Mikael Ronstrm.
- From here we insert a number of commands to manage the partitions of a
- partitioned table such as adding partitions, dropping partitions,
- reorganising partitions in various manners. In future releases the list
- will be longer.
-*/
- | add_partition_rule
- | DROP PARTITION_SYM opt_if_exists alt_part_name_list
- {
- Lex->alter_info.partition_flags|= ALTER_PARTITION_DROP;
- DBUG_ASSERT(!Lex->if_exists());
- Lex->create_info.add($3);
- }
- | REBUILD_SYM PARTITION_SYM opt_no_write_to_binlog
- all_or_alt_part_name_list
- {
- LEX *lex= Lex;
- lex->alter_info.partition_flags|= ALTER_PARTITION_REBUILD;
- lex->no_write_to_binlog= $3;
- }
- | OPTIMIZE PARTITION_SYM opt_no_write_to_binlog
- all_or_alt_part_name_list
- {
- LEX *lex= thd->lex;
- lex->no_write_to_binlog= $3;
- lex->check_opt.init();
- DBUG_ASSERT(!lex->m_sql_cmd);
- lex->m_sql_cmd= new (thd->mem_root)
- Sql_cmd_alter_table_optimize_partition();
- if (unlikely(lex->m_sql_cmd == NULL))
- MYSQL_YYABORT;
- }
- opt_no_write_to_binlog
- | ANALYZE_SYM PARTITION_SYM opt_no_write_to_binlog
- all_or_alt_part_name_list
- {
- LEX *lex= thd->lex;
- lex->no_write_to_binlog= $3;
- lex->check_opt.init();
- DBUG_ASSERT(!lex->m_sql_cmd);
- lex->m_sql_cmd= new (thd->mem_root)
- Sql_cmd_alter_table_analyze_partition();
- if (unlikely(lex->m_sql_cmd == NULL))
- MYSQL_YYABORT;
- }
- | CHECK_SYM PARTITION_SYM all_or_alt_part_name_list
- {
- LEX *lex= thd->lex;
- lex->check_opt.init();
- DBUG_ASSERT(!lex->m_sql_cmd);
- lex->m_sql_cmd= new (thd->mem_root)
- Sql_cmd_alter_table_check_partition();
- if (unlikely(lex->m_sql_cmd == NULL))
- MYSQL_YYABORT;
- }
- opt_mi_check_type
- | REPAIR PARTITION_SYM opt_no_write_to_binlog
- all_or_alt_part_name_list
- {
- LEX *lex= thd->lex;
- lex->no_write_to_binlog= $3;
- lex->check_opt.init();
- DBUG_ASSERT(!lex->m_sql_cmd);
- lex->m_sql_cmd= new (thd->mem_root)
- Sql_cmd_alter_table_repair_partition();
- if (unlikely(lex->m_sql_cmd == NULL))
- MYSQL_YYABORT;
- }
- opt_mi_repair_type
- | COALESCE PARTITION_SYM opt_no_write_to_binlog real_ulong_num
- {
- LEX *lex= Lex;
- lex->alter_info.partition_flags|= ALTER_PARTITION_COALESCE;
- lex->no_write_to_binlog= $3;
- lex->alter_info.num_parts= $4;
- }
- | TRUNCATE_SYM PARTITION_SYM all_or_alt_part_name_list
- {
- LEX *lex= thd->lex;
- lex->check_opt.init();
- DBUG_ASSERT(!lex->m_sql_cmd);
- lex->m_sql_cmd= new (thd->mem_root)
- Sql_cmd_alter_table_truncate_partition();
- if (unlikely(lex->m_sql_cmd == NULL))
- MYSQL_YYABORT;
- }
- | reorg_partition_rule
- | EXCHANGE_SYM PARTITION_SYM alt_part_name_item
- WITH TABLE_SYM table_ident have_partitioning
- {
- if (Lex->stmt_alter_table_exchange_partition($6))
- MYSQL_YYABORT;
- }
- ;
-
-remove_partitioning:
- REMOVE_SYM PARTITIONING_SYM
- {
- Lex->alter_info.partition_flags|= ALTER_PARTITION_REMOVE;
- }
- ;
-
-all_or_alt_part_name_list:
- ALL
- {
- Lex->alter_info.partition_flags|= ALTER_PARTITION_ALL;
- }
- | alt_part_name_list
- ;
-
-add_partition_rule:
- ADD PARTITION_SYM opt_if_not_exists
- opt_no_write_to_binlog
- {
- LEX *lex= Lex;
- lex->part_info= new (thd->mem_root) partition_info();
- if (unlikely(!lex->part_info))
- MYSQL_YYABORT;
-
- lex->alter_info.partition_flags|= ALTER_PARTITION_ADD;
- DBUG_ASSERT(!Lex->create_info.if_not_exists());
- lex->create_info.set($3);
- lex->no_write_to_binlog= $4;
- }
- add_part_extra
- {}
- ;
-
-add_part_extra:
- /* empty */
- | '(' part_def_list ')'
- {
- LEX *lex= Lex;
- lex->part_info->num_parts= lex->part_info->partitions.elements;
- }
- | PARTITIONS_SYM real_ulong_num
- {
- Lex->part_info->num_parts= $2;
- }
- ;
-
-reorg_partition_rule:
- REORGANIZE_SYM PARTITION_SYM opt_no_write_to_binlog
- {
- LEX *lex= Lex;
- lex->part_info= new (thd->mem_root) partition_info();
- if (unlikely(!lex->part_info))
- MYSQL_YYABORT;
-
- lex->no_write_to_binlog= $3;
- }
- reorg_parts_rule
- ;
-
-reorg_parts_rule:
- /* empty */
- {
- Lex->alter_info.partition_flags|= ALTER_PARTITION_TABLE_REORG;
- }
- | alt_part_name_list
- {
- Lex->alter_info.partition_flags|= ALTER_PARTITION_REORGANIZE;
- }
- INTO '(' part_def_list ')'
- {
- partition_info *part_info= Lex->part_info;
- part_info->num_parts= part_info->partitions.elements;
- }
- ;
-
-alt_part_name_list:
- alt_part_name_item {}
- | alt_part_name_list ',' alt_part_name_item {}
- ;
-
-alt_part_name_item:
- ident
- {
- if (unlikely(Lex->alter_info.partition_names.push_back($1.str,
- thd->mem_root)))
- MYSQL_YYABORT;
- }
- ;
-
-/*
- End of management of partition commands
-*/
-
-alter_list:
- alter_list_item
- | alter_list ',' alter_list_item
- ;
-
-add_column:
- ADD opt_column opt_if_not_exists_table_element
- ;
-
-alter_list_item:
- add_column column_def opt_place
- {
- LEX *lex=Lex;
- lex->create_last_non_select_table= lex->last_table();
- lex->alter_info.flags|= ALTER_PARSER_ADD_COLUMN;
- $2->after= $3;
- }
- | ADD key_def
- {
- Lex->create_last_non_select_table= Lex->last_table();
- Lex->alter_info.flags|= ALTER_ADD_INDEX;
- }
- | ADD period_for_system_time
- {
- Lex->alter_info.flags|= ALTER_ADD_PERIOD;
- }
- | ADD
- PERIOD_SYM opt_if_not_exists_table_element period_for_application_time
- {
- Table_period_info &period= Lex->create_info.period_info;
- period.create_if_not_exists= Lex->check_exists;
- Lex->alter_info.flags|= ALTER_ADD_CHECK_CONSTRAINT;
- }
- | add_column '(' create_field_list ')'
- {
- LEX *lex=Lex;
- lex->alter_info.flags|= ALTER_PARSER_ADD_COLUMN;
- if (!lex->alter_info.key_list.is_empty())
- lex->alter_info.flags|= ALTER_ADD_INDEX;
- }
- | ADD constraint_def
- {
- Lex->alter_info.flags|= ALTER_ADD_CHECK_CONSTRAINT;
- }
- | ADD CONSTRAINT IF_SYM not EXISTS field_ident check_constraint
- {
- Lex->alter_info.flags|= ALTER_ADD_CHECK_CONSTRAINT;
- Lex->add_constraint($6, $7, TRUE);
- }
- | CHANGE opt_column opt_if_exists_table_element field_ident
- field_spec opt_place
- {
- Lex->alter_info.flags|= ALTER_CHANGE_COLUMN | ALTER_RENAME_COLUMN;
- Lex->create_last_non_select_table= Lex->last_table();
- $5->change= $4;
- $5->after= $6;
- }
- | MODIFY_SYM opt_column opt_if_exists_table_element
- field_spec opt_place
- {
- Lex->alter_info.flags|= ALTER_CHANGE_COLUMN;
- Lex->create_last_non_select_table= Lex->last_table();
- $4->change= $4->field_name;
- $4->after= $5;
- }
- | DROP opt_column opt_if_exists_table_element field_ident opt_restrict
- {
- LEX *lex=Lex;
- Alter_drop *ad= (new (thd->mem_root)
- Alter_drop(Alter_drop::COLUMN, $4.str, $3));
- if (unlikely(ad == NULL))
- MYSQL_YYABORT;
- lex->alter_info.drop_list.push_back(ad, thd->mem_root);
- lex->alter_info.flags|= ALTER_PARSER_DROP_COLUMN;
- }
- | DROP CONSTRAINT opt_if_exists_table_element field_ident
- {
- LEX *lex=Lex;
- Alter_drop *ad= (new (thd->mem_root)
- Alter_drop(Alter_drop::CHECK_CONSTRAINT,
- $4.str, $3));
- if (unlikely(ad == NULL))
- MYSQL_YYABORT;
- lex->alter_info.drop_list.push_back(ad, thd->mem_root);
- lex->alter_info.flags|= ALTER_DROP_CHECK_CONSTRAINT;
- }
- | DROP FOREIGN KEY_SYM opt_if_exists_table_element field_ident
- {
- LEX *lex=Lex;
- Alter_drop *ad= (new (thd->mem_root)
- Alter_drop(Alter_drop::FOREIGN_KEY, $5.str, $4));
- if (unlikely(ad == NULL))
- MYSQL_YYABORT;
- lex->alter_info.drop_list.push_back(ad, thd->mem_root);
- lex->alter_info.flags|= ALTER_DROP_FOREIGN_KEY;
- }
- | DROP opt_constraint_no_id PRIMARY_SYM KEY_SYM
- {
- LEX *lex=Lex;
- Alter_drop *ad= (new (thd->mem_root)
- Alter_drop(Alter_drop::KEY, primary_key_name,
- FALSE));
- if (unlikely(ad == NULL))
- MYSQL_YYABORT;
- lex->alter_info.drop_list.push_back(ad, thd->mem_root);
- lex->alter_info.flags|= ALTER_DROP_INDEX;
- }
- | DROP key_or_index opt_if_exists_table_element field_ident
- {
- LEX *lex=Lex;
- Alter_drop *ad= (new (thd->mem_root)
- Alter_drop(Alter_drop::KEY, $4.str, $3));
- if (unlikely(ad == NULL))
- MYSQL_YYABORT;
- lex->alter_info.drop_list.push_back(ad, thd->mem_root);
- lex->alter_info.flags|= ALTER_DROP_INDEX;
- }
- | DISABLE_SYM KEYS
- {
- LEX *lex=Lex;
- lex->alter_info.keys_onoff= Alter_info::DISABLE;
- lex->alter_info.flags|= ALTER_KEYS_ONOFF;
- }
- | ENABLE_SYM KEYS
- {
- LEX *lex=Lex;
- lex->alter_info.keys_onoff= Alter_info::ENABLE;
- lex->alter_info.flags|= ALTER_KEYS_ONOFF;
- }
- | ALTER opt_column opt_if_exists_table_element field_ident SET DEFAULT column_default_expr
- {
- if (unlikely(Lex->add_alter_list($4.str, $7, $3)))
- MYSQL_YYABORT;
- }
- | ALTER opt_column opt_if_exists_table_element field_ident DROP DEFAULT
- {
- if (unlikely(Lex->add_alter_list($4.str, (Virtual_column_info*) 0,
- $3)))
- MYSQL_YYABORT;
- }
- | RENAME opt_to table_ident
- {
- LEX *lex=Lex;
- lex->first_select_lex()->db= $3->db;
- if (lex->first_select_lex()->db.str == NULL &&
- lex->copy_db_to(&lex->first_select_lex()->db))
- MYSQL_YYABORT;
- if (unlikely(check_table_name($3->table.str,$3->table.length,
- FALSE)) ||
- ($3->db.str && unlikely(check_db_name((LEX_STRING*) &$3->db))))
- my_yyabort_error((ER_WRONG_TABLE_NAME, MYF(0), $3->table.str));
- lex->name= $3->table;
- lex->alter_info.flags|= ALTER_RENAME;
- }
- | CONVERT_SYM TO_SYM charset charset_name_or_default opt_collate
- {
- if (!$4)
- {
- $4= thd->variables.collation_database;
- }
- $5= $5 ? $5 : $4;
- if (unlikely(!my_charset_same($4,$5)))
- my_yyabort_error((ER_COLLATION_CHARSET_MISMATCH, MYF(0),
- $5->name, $4->csname));
- if (unlikely(Lex->create_info.add_alter_list_item_convert_to_charset($5)))
- MYSQL_YYABORT;
- Lex->alter_info.flags|= ALTER_CONVERT_TO;
- }
- | create_table_options_space_separated
- {
- LEX *lex=Lex;
- lex->alter_info.flags|= ALTER_OPTIONS;
- }
- | FORCE_SYM
- {
- Lex->alter_info.flags|= ALTER_RECREATE;
- }
- | alter_order_clause
- {
- LEX *lex=Lex;
- lex->alter_info.flags|= ALTER_ORDER;
- }
- | alter_algorithm_option
- | alter_lock_option
- | ADD SYSTEM VERSIONING_SYM
- {
- Lex->alter_info.flags|= ALTER_ADD_SYSTEM_VERSIONING;
- Lex->create_info.options|= HA_VERSIONED_TABLE;
- }
- | DROP SYSTEM VERSIONING_SYM
- {
- Lex->alter_info.flags|= ALTER_DROP_SYSTEM_VERSIONING;
- Lex->create_info.options&= ~HA_VERSIONED_TABLE;
- }
- | DROP PERIOD_SYM FOR_SYSTEM_TIME_SYM
- {
- Lex->alter_info.flags|= ALTER_DROP_PERIOD;
- }
- | DROP PERIOD_SYM opt_if_exists_table_element FOR_SYM ident
- {
- Alter_drop *ad= new Alter_drop(Alter_drop::PERIOD, $5.str, $3);
- if (unlikely(ad == NULL))
- MYSQL_YYABORT;
- Lex->alter_info.drop_list.push_back(ad, thd->mem_root);
- Lex->alter_info.flags|= ALTER_DROP_CHECK_CONSTRAINT;
- }
- ;
-
-opt_index_lock_algorithm:
- /* empty */
- | alter_lock_option
- | alter_algorithm_option
- | alter_lock_option alter_algorithm_option
- | alter_algorithm_option alter_lock_option
- ;
-
-alter_algorithm_option:
- ALGORITHM_SYM opt_equal DEFAULT
- {
- Lex->alter_info.requested_algorithm=
- Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT;
- }
- | ALGORITHM_SYM opt_equal ident
- {
- if (unlikely(Lex->alter_info.set_requested_algorithm(&$3)))
- my_yyabort_error((ER_UNKNOWN_ALTER_ALGORITHM, MYF(0), $3.str));
- }
- ;
-
-alter_lock_option:
- LOCK_SYM opt_equal DEFAULT
- {
- Lex->alter_info.requested_lock=
- Alter_info::ALTER_TABLE_LOCK_DEFAULT;
- }
- | LOCK_SYM opt_equal ident
- {
- if (unlikely(Lex->alter_info.set_requested_lock(&$3)))
- my_yyabort_error((ER_UNKNOWN_ALTER_LOCK, MYF(0), $3.str));
- }
- ;
-
-opt_column:
- /* empty */ {} %prec PREC_BELOW_IDENTIFIER_OPT_SPECIAL_CASE
- | COLUMN_SYM {}
- ;
-
-opt_ignore:
- /* empty */ { Lex->ignore= 0;}
- | IGNORE_SYM { Lex->ignore= 1;}
- ;
-
-alter_options:
- { Lex->ignore= 0;} alter_options_part2
- ;
-
-alter_options_part2:
- /* empty */
- | alter_option_list
- ;
-
-alter_option_list:
- alter_option_list alter_option
- | alter_option
- ;
-
-alter_option:
- IGNORE_SYM { Lex->ignore= 1;}
- | ONLINE_SYM
- {
- Lex->alter_info.requested_lock=
- Alter_info::ALTER_TABLE_LOCK_NONE;
- }
- ;
-
-opt_restrict:
- /* empty */ { Lex->drop_mode= DROP_DEFAULT; }
- | RESTRICT { Lex->drop_mode= DROP_RESTRICT; }
- | CASCADE { Lex->drop_mode= DROP_CASCADE; }
- ;
-
-opt_place:
- /* empty */ { $$= null_clex_str; }
- | AFTER_SYM ident
- {
- $$= $2;
- Lex->alter_info.flags |= ALTER_COLUMN_ORDER;
- }
- | FIRST_SYM
- {
- $$.str= first_keyword;
- $$.length= 5; /* Length of "first" */
- Lex->alter_info.flags |= ALTER_COLUMN_ORDER;
- }
- ;
-
-opt_to:
- /* empty */ {}
- | TO_SYM {}
- | '=' {}
- | AS {}
- ;
-
-slave:
- START_SYM SLAVE optional_connection_name slave_thread_opts
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_SLAVE_START;
- lex->type = 0;
- /* If you change this code don't forget to update SLAVE START too */
- }
- slave_until
- {}
- | START_SYM ALL SLAVES slave_thread_opts
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_SLAVE_ALL_START;
- lex->type = 0;
- /* If you change this code don't forget to update STOP SLAVE too */
- }
- {}
- | STOP_SYM SLAVE optional_connection_name slave_thread_opts
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_SLAVE_STOP;
- lex->type = 0;
- /* If you change this code don't forget to update SLAVE STOP too */
- }
- | STOP_SYM ALL SLAVES slave_thread_opts
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_SLAVE_ALL_STOP;
- lex->type = 0;
- /* If you change this code don't forget to update SLAVE STOP too */
- }
- ;
-
-start:
- START_SYM TRANSACTION_SYM opt_start_transaction_option_list
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_BEGIN;
- /* READ ONLY and READ WRITE are mutually exclusive. */
- if (unlikely(($3 & MYSQL_START_TRANS_OPT_READ_WRITE) &&
- ($3 & MYSQL_START_TRANS_OPT_READ_ONLY)))
- {
- thd->parse_error();
- MYSQL_YYABORT;
- }
- lex->start_transaction_opt= $3;
- }
- ;
-
-opt_start_transaction_option_list:
- /* empty */
- {
- $$= 0;
- }
- | start_transaction_option_list
- {
- $$= $1;
- }
- ;
-
-start_transaction_option_list:
- start_transaction_option
- {
- $$= $1;
- }
- | start_transaction_option_list ',' start_transaction_option
- {
- $$= $1 | $3;
- }
- ;
-
-start_transaction_option:
- WITH CONSISTENT_SYM SNAPSHOT_SYM
- {
- $$= MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT;
- }
- | READ_SYM ONLY_SYM
- {
- $$= MYSQL_START_TRANS_OPT_READ_ONLY;
- }
- | READ_SYM WRITE_SYM
- {
- $$= MYSQL_START_TRANS_OPT_READ_WRITE;
- }
- ;
-
-slave_thread_opts:
- { Lex->slave_thd_opt= 0; }
- slave_thread_opt_list
- {}
- ;
-
-slave_thread_opt_list:
- slave_thread_opt
- | slave_thread_opt_list ',' slave_thread_opt
- ;
-
-slave_thread_opt:
- /*empty*/ {}
- | SQL_THREAD { Lex->slave_thd_opt|=SLAVE_SQL; }
- | RELAY_THREAD { Lex->slave_thd_opt|=SLAVE_IO; }
- ;
-
-slave_until:
- /*empty*/ {}
- | UNTIL_SYM slave_until_opts
- {
- LEX *lex=Lex;
- if (unlikely(((lex->mi.log_file_name || lex->mi.pos) &&
- (lex->mi.relay_log_name || lex->mi.relay_log_pos)) ||
- !((lex->mi.log_file_name && lex->mi.pos) ||
- (lex->mi.relay_log_name && lex->mi.relay_log_pos))))
- my_yyabort_error((ER_BAD_SLAVE_UNTIL_COND, MYF(0)));
- }
- | UNTIL_SYM MASTER_GTID_POS_SYM '=' TEXT_STRING_sys
- {
- Lex->mi.gtid_pos_str = $4;
- }
- ;
-
-slave_until_opts:
- master_file_def
- | slave_until_opts ',' master_file_def
- ;
-
-checksum:
- CHECKSUM_SYM table_or_tables
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_CHECKSUM;
- /* Will be overridden during execution. */
- YYPS->m_lock_type= TL_UNLOCK;
- }
- table_list opt_checksum_type
- {}
- ;
-
-opt_checksum_type:
- /* nothing */ { Lex->check_opt.flags= 0; }
- | QUICK { Lex->check_opt.flags= T_QUICK; }
- | EXTENDED_SYM { Lex->check_opt.flags= T_EXTEND; }
- ;
-
-repair_table_or_view:
- table_or_tables table_list opt_mi_repair_type
- | VIEW_SYM
- { Lex->table_type= TABLE_TYPE_VIEW; }
- table_list opt_view_repair_type
- ;
-
-repair:
- REPAIR opt_no_write_to_binlog
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_REPAIR;
- lex->no_write_to_binlog= $2;
- lex->check_opt.init();
- lex->alter_info.reset();
- /* Will be overridden during execution. */
- YYPS->m_lock_type= TL_UNLOCK;
- }
- repair_table_or_view
- {
- LEX* lex= thd->lex;
- DBUG_ASSERT(!lex->m_sql_cmd);
- lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_repair_table();
- if (unlikely(lex->m_sql_cmd == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-opt_mi_repair_type:
- /* empty */ { Lex->check_opt.flags = T_MEDIUM; }
- | mi_repair_types {}
- ;
-
-mi_repair_types:
- mi_repair_type {}
- | mi_repair_type mi_repair_types {}
- ;
-
-mi_repair_type:
- QUICK { Lex->check_opt.flags|= T_QUICK; }
- | EXTENDED_SYM { Lex->check_opt.flags|= T_EXTEND; }
- | USE_FRM { Lex->check_opt.sql_flags|= TT_USEFRM; }
- ;
-
-opt_view_repair_type:
- /* empty */ { }
- | FROM MYSQL_SYM { Lex->check_opt.sql_flags|= TT_FROM_MYSQL; }
- ;
-
-analyze:
- ANALYZE_SYM opt_no_write_to_binlog table_or_tables
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_ANALYZE;
- lex->no_write_to_binlog= $2;
- lex->check_opt.init();
- lex->alter_info.reset();
- /* Will be overridden during execution. */
- YYPS->m_lock_type= TL_UNLOCK;
- }
- analyze_table_list
- {
- LEX* lex= thd->lex;
- DBUG_ASSERT(!lex->m_sql_cmd);
- lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_analyze_table();
- if (unlikely(lex->m_sql_cmd == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-analyze_table_list:
- analyze_table_elem_spec
- | analyze_table_list ',' analyze_table_elem_spec
- ;
-
-analyze_table_elem_spec:
- table_name opt_persistent_stat_clause
- ;
-
-opt_persistent_stat_clause:
- /* empty */
- {}
- | PERSISTENT_SYM FOR_SYM persistent_stat_spec
- {
- thd->lex->with_persistent_for_clause= TRUE;
- }
- ;
-
-persistent_stat_spec:
- ALL
- {}
- | COLUMNS persistent_column_stat_spec INDEXES persistent_index_stat_spec
- {}
- ;
-
-persistent_column_stat_spec:
- ALL {}
- | '('
- {
- LEX* lex= thd->lex;
- lex->column_list= new (thd->mem_root) List<LEX_STRING>;
- if (unlikely(lex->column_list == NULL))
- MYSQL_YYABORT;
- }
- table_column_list
- ')'
- { }
- ;
-
-persistent_index_stat_spec:
- ALL {}
- | '('
- {
- LEX* lex= thd->lex;
- lex->index_list= new (thd->mem_root) List<LEX_STRING>;
- if (unlikely(lex->index_list == NULL))
- MYSQL_YYABORT;
- }
- table_index_list
- ')'
- { }
- ;
-
-table_column_list:
- /* empty */
- {}
- | ident
- {
- Lex->column_list->push_back((LEX_STRING*)
- thd->memdup(&$1, sizeof(LEX_STRING)), thd->mem_root);
- }
- | table_column_list ',' ident
- {
- Lex->column_list->push_back((LEX_STRING*)
- thd->memdup(&$3, sizeof(LEX_STRING)), thd->mem_root);
- }
- ;
-
-table_index_list:
- /* empty */
- {}
- | table_index_name
- | table_index_list ',' table_index_name
- ;
-
-table_index_name:
- ident
- {
- Lex->index_list->push_back((LEX_STRING*)
- thd->memdup(&$1, sizeof(LEX_STRING)),
- thd->mem_root);
- }
- |
- PRIMARY_SYM
- {
- LEX_STRING str= {(char*) "PRIMARY", 7};
- Lex->index_list->push_back((LEX_STRING*)
- thd->memdup(&str, sizeof(LEX_STRING)),
- thd->mem_root);
- }
- ;
-
-binlog_base64_event:
- BINLOG_SYM TEXT_STRING_sys
- {
- Lex->sql_command = SQLCOM_BINLOG_BASE64_EVENT;
- Lex->comment= $2;
- Lex->ident.str= NULL;
- Lex->ident.length= 0;
- }
- |
- BINLOG_SYM '@' ident_or_text ',' '@' ident_or_text
- {
- Lex->sql_command = SQLCOM_BINLOG_BASE64_EVENT;
- Lex->comment= $3;
- Lex->ident= $6;
- }
- ;
-
-check_view_or_table:
- table_or_tables table_list opt_mi_check_type
- | VIEW_SYM
- { Lex->table_type= TABLE_TYPE_VIEW; }
- table_list opt_view_check_type
- ;
-
-check: CHECK_SYM
- {
- LEX *lex=Lex;
-
- lex->sql_command = SQLCOM_CHECK;
- lex->check_opt.init();
- lex->alter_info.reset();
- /* Will be overridden during execution. */
- YYPS->m_lock_type= TL_UNLOCK;
- }
- check_view_or_table
- {
- LEX* lex= thd->lex;
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "CHECK"));
- DBUG_ASSERT(!lex->m_sql_cmd);
- lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_check_table();
- if (unlikely(lex->m_sql_cmd == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-opt_mi_check_type:
- /* empty */ { Lex->check_opt.flags = T_MEDIUM; }
- | mi_check_types {}
- ;
-
-mi_check_types:
- mi_check_type {}
- | mi_check_type mi_check_types {}
- ;
-
-mi_check_type:
- QUICK { Lex->check_opt.flags|= T_QUICK; }
- | FAST_SYM { Lex->check_opt.flags|= T_FAST; }
- | MEDIUM_SYM { Lex->check_opt.flags|= T_MEDIUM; }
- | EXTENDED_SYM { Lex->check_opt.flags|= T_EXTEND; }
- | CHANGED { Lex->check_opt.flags|= T_CHECK_ONLY_CHANGED; }
- | FOR_SYM UPGRADE_SYM { Lex->check_opt.sql_flags|= TT_FOR_UPGRADE; }
- ;
-
-opt_view_check_type:
- /* empty */ { }
- | FOR_SYM UPGRADE_SYM { Lex->check_opt.sql_flags|= TT_FOR_UPGRADE; }
- ;
-
-optimize:
- OPTIMIZE opt_no_write_to_binlog table_or_tables
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_OPTIMIZE;
- lex->no_write_to_binlog= $2;
- lex->check_opt.init();
- lex->alter_info.reset();
- /* Will be overridden during execution. */
- YYPS->m_lock_type= TL_UNLOCK;
- }
- table_list opt_lock_wait_timeout
- {
- LEX* lex= thd->lex;
- DBUG_ASSERT(!lex->m_sql_cmd);
- lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_optimize_table();
- if (unlikely(lex->m_sql_cmd == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-opt_no_write_to_binlog:
- /* empty */ { $$= 0; }
- | NO_WRITE_TO_BINLOG { $$= 1; }
- | LOCAL_SYM { $$= 1; }
- ;
-
-rename:
- RENAME table_or_tables
- {
- Lex->sql_command= SQLCOM_RENAME_TABLE;
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- }
- table_to_table_list
- {
- Lex->pop_select(); //main select
- }
- | RENAME USER_SYM clear_privileges rename_list
- {
- Lex->sql_command = SQLCOM_RENAME_USER;
- }
- ;
-
-rename_list:
- user TO_SYM user
- {
- if (unlikely(Lex->users_list.push_back($1, thd->mem_root) ||
- Lex->users_list.push_back($3, thd->mem_root)))
- MYSQL_YYABORT;
- }
- | rename_list ',' user TO_SYM user
- {
- if (unlikely(Lex->users_list.push_back($3, thd->mem_root) ||
- Lex->users_list.push_back($5, thd->mem_root)))
- MYSQL_YYABORT;
- }
- ;
-
-table_to_table_list:
- table_to_table
- | table_to_table_list ',' table_to_table
- ;
-
-table_to_table:
- table_ident opt_lock_wait_timeout TO_SYM table_ident
- {
- LEX *lex=Lex;
- SELECT_LEX *sl= lex->current_select;
- if (unlikely(!sl->add_table_to_list(thd, $1,NULL,
- TL_OPTION_UPDATING,
- TL_IGNORE, MDL_EXCLUSIVE)) ||
- unlikely(!sl->add_table_to_list(thd, $4, NULL,
- TL_OPTION_UPDATING,
- TL_IGNORE, MDL_EXCLUSIVE)))
- MYSQL_YYABORT;
- }
- ;
-
-keycache:
- CACHE_SYM INDEX_SYM
- {
- Lex->alter_info.reset();
- }
- keycache_list_or_parts IN_SYM key_cache_name
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_ASSIGN_TO_KEYCACHE;
- lex->ident= $6;
- }
- ;
-
-keycache_list_or_parts:
- keycache_list
- | assign_to_keycache_parts
- ;
-
-keycache_list:
- assign_to_keycache
- | keycache_list ',' assign_to_keycache
- ;
-
-assign_to_keycache:
- table_ident cache_keys_spec
- {
- if (unlikely(!Select->add_table_to_list(thd, $1, NULL, 0, TL_READ,
- MDL_SHARED_READ,
- Select->
- pop_index_hints())))
- MYSQL_YYABORT;
- }
- ;
-
-assign_to_keycache_parts:
- table_ident adm_partition cache_keys_spec
- {
- if (unlikely(!Select->add_table_to_list(thd, $1, NULL, 0, TL_READ,
- MDL_SHARED_READ,
- Select->
- pop_index_hints())))
- MYSQL_YYABORT;
- }
- ;
-
-key_cache_name:
- ident { $$= $1; }
- | DEFAULT { $$ = default_key_cache_base; }
- ;
-
-preload:
- LOAD INDEX_SYM INTO CACHE_SYM
- {
- LEX *lex=Lex;
- lex->sql_command=SQLCOM_PRELOAD_KEYS;
- lex->alter_info.reset();
- if (lex->main_select_push())
- MYSQL_YYABORT;
- }
- preload_list_or_parts
- {
- Lex->pop_select(); //main select
- }
- ;
-
-preload_list_or_parts:
- preload_keys_parts
- | preload_list
- ;
-
-preload_list:
- preload_keys
- | preload_list ',' preload_keys
- ;
-
-preload_keys:
- table_ident cache_keys_spec opt_ignore_leaves
- {
- if (unlikely(!Select->add_table_to_list(thd, $1, NULL, $3, TL_READ,
- MDL_SHARED_READ,
- Select->
- pop_index_hints())))
- MYSQL_YYABORT;
- }
- ;
-
-preload_keys_parts:
- table_ident adm_partition cache_keys_spec opt_ignore_leaves
- {
- if (unlikely(!Select->add_table_to_list(thd, $1, NULL, $4, TL_READ,
- MDL_SHARED_READ,
- Select->
- pop_index_hints())))
- MYSQL_YYABORT;
- }
- ;
-
-adm_partition:
- PARTITION_SYM have_partitioning
- {
- Lex->alter_info.partition_flags|= ALTER_PARTITION_ADMIN;
- }
- '(' all_or_alt_part_name_list ')'
- ;
-
-cache_keys_spec:
- {
- Lex->first_select_lex()->alloc_index_hints(thd);
- Select->set_index_hint_type(INDEX_HINT_USE,
- INDEX_HINT_MASK_ALL);
- }
- cache_key_list_or_empty
- ;
-
-cache_key_list_or_empty:
- /* empty */ { }
- | key_or_index '(' opt_key_usage_list ')'
- ;
-
-opt_ignore_leaves:
- /* empty */
- { $$= 0; }
- | IGNORE_SYM LEAVES { $$= TL_OPTION_IGNORE_LEAVES; }
- ;
-
-/*
- Select : retrieve data from table
-*/
-
-select:
- query_expression_no_with_clause
- {
- if (Lex->push_select($1->fake_select_lex ?
- $1->fake_select_lex :
- $1->first_select()))
- MYSQL_YYABORT;
- }
- opt_procedure_or_into
- {
- Lex->pop_select();
- $1->set_with_clause(NULL);
- if (Lex->select_finalize($1, $3))
- MYSQL_YYABORT;
- }
- | with_clause query_expression_no_with_clause
- {
- if (Lex->push_select($2->fake_select_lex ?
- $2->fake_select_lex :
- $2->first_select()))
- MYSQL_YYABORT;
- }
- opt_procedure_or_into
- {
- Lex->pop_select();
- $2->set_with_clause($1);
- $1->attach_to($2->first_select());
- if (Lex->select_finalize($2, $4))
- MYSQL_YYABORT;
- }
- ;
-
-
-select_into:
- select_into_query_specification
- {
- if (Lex->push_select($1))
- MYSQL_YYABORT;
- }
- opt_order_limit_lock
- {
- SELECT_LEX_UNIT *unit;
- if (!(unit = Lex->create_unit($1)))
- MYSQL_YYABORT;
- if ($3)
- unit= Lex->add_tail_to_query_expression_body(unit, $3);
- if (Lex->select_finalize(unit))
- MYSQL_YYABORT;
- }
- | with_clause
- select_into_query_specification
- {
- if (Lex->push_select($2))
- MYSQL_YYABORT;
- }
- opt_order_limit_lock
- {
- SELECT_LEX_UNIT *unit;
- if (!(unit = Lex->create_unit($2)))
- MYSQL_YYABORT;
- if ($4)
- unit= Lex->add_tail_to_query_expression_body(unit, $4);
- unit->set_with_clause($1);
- $1->attach_to($2);
- if (Lex->select_finalize(unit))
- MYSQL_YYABORT;
- }
- ;
-
-
-simple_table:
- query_specification { $$= $1; }
- | table_value_constructor { $$= $1; }
- ;
-
-table_value_constructor:
- VALUES
- {
- if (Lex->parsed_TVC_start())
- MYSQL_YYABORT;
- }
- values_list
- {
- if (!($$= Lex->parsed_TVC_end()))
- MYSQL_YYABORT;
- }
- ;
-
-query_specification_start:
- SELECT_SYM
- {
- SELECT_LEX *sel;
- LEX *lex= Lex;
- if (!(sel= lex->alloc_select(TRUE)) ||
- lex->push_select(sel))
- MYSQL_YYABORT;
- sel->init_select();
- sel->braces= FALSE;
- }
- select_options
- {
- Select->parsing_place= SELECT_LIST;
- }
- select_item_list
- {
- Select->parsing_place= NO_MATTER;
- }
- ;
-
-query_specification:
- query_specification_start
- opt_from_clause
- opt_where_clause
- opt_group_clause
- opt_having_clause
- opt_window_clause
- {
- $$= Lex->pop_select();
- }
- ;
-
-select_into_query_specification:
- query_specification_start
- into
- opt_from_clause
- opt_where_clause
- opt_group_clause
- opt_having_clause
- opt_window_clause
- {
- $$= Lex->pop_select();
- }
- ;
-
-/**
-
- The following grammar for query expressions conformant to
- the latest SQL Standard is supported:
-
- <query expression> ::=
- [ <with clause> ] <query expression body>
- [ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ]
-
- <with clause> ::=
- WITH [ RECURSIVE ] <with_list
-
- <with list> ::=
- <with list element> [ { <comma> <with list element> }... ]
-
- <with list element> ::=
- <query name> [ '(' <with column list> ')' ]
- AS <table subquery>
-
- <with column list> ::=
- <column name list>
-
- <query expression body> ::
- <query term>
- | <query expression body> UNION [ ALL | DISTINCT ] <query term>
- | <query expression body> EXCEPT [ DISTINCT ] <query term>
-
- <query term> ::=
- <query primary>
- | <query term> INTERSECT [ DISTINCT ] <query primary>
-
- <query primary> ::=
- <simple table>
- | '(' <query expression body>
- [ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ]
- ')'
-
- <simple table>
- <query specification>
- | <table value constructor>
-
- <subquery>
- '(' <query_expression> ')'
-
-*/
-
-/*
- query_expression produces the same expressions as
- <query expression>
-*/
-
-query_expression:
- query_expression_no_with_clause
- {
- $1->set_with_clause(NULL);
- $$= $1;
- }
- | with_clause
- query_expression_no_with_clause
- {
- $2->set_with_clause($1);
- $1->attach_to($2->first_select());
- $$= $2;
- }
- ;
-
-/*
- query_expression_no_with_clause produces the same expressions as
- <query expression> without [ <with clause> ]
-*/
-
-query_expression_no_with_clause:
- query_expression_body_ext { $$= $1; }
- | query_expression_body_ext_parens { $$= $1; }
- ;
-
-/*
- query_expression_body_ext produces the same expressions as
- <query expression body>
- [ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ]
- | '('... <query expression body>
- [ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ]
- ')'...
- Note: number of ')' must be equal to the number of '(' in the rule above
-*/
-
-query_expression_body_ext:
- query_expression_body
- {
- if ($1->first_select()->next_select())
- {
- if (Lex->parsed_multi_operand_query_expression_body($1))
- MYSQL_YYABORT;
- }
- }
- opt_query_expression_tail
- {
- if (!$3)
- $$= $1;
- else
- $$= Lex->add_tail_to_query_expression_body($1, $3);
- }
- | query_expression_body_ext_parens
- {
- Lex->push_select(!$1->first_select()->next_select() ?
- $1->first_select() : $1->fake_select_lex);
- }
- query_expression_tail
- {
- if (!($$= Lex->add_tail_to_query_expression_body_ext_parens($1, $3)))
- MYSQL_YYABORT;
- }
- ;
-
-query_expression_body_ext_parens:
- '(' query_expression_body_ext_parens ')'
- { $$= $2; }
- | '(' query_expression_body_ext ')'
- {
- SELECT_LEX *sel= $2->first_select()->next_select() ?
- $2->fake_select_lex : $2->first_select();
- sel->braces= true;
- $$= $2;
- }
- ;
-
-/*
- query_expression_body produces the same expressions as
- <query expression body>
-*/
-
-query_expression_body:
- query_simple
- {
- Lex->push_select($1);
- if (!($$= Lex->create_unit($1)))
- MYSQL_YYABORT;
- }
- | query_expression_body
- unit_type_decl
- {
- if (!$1->first_select()->next_select())
- {
- Lex->pop_select();
- }
- }
- query_primary
- {
- if (!($$= Lex->add_primary_to_query_expression_body($1, $4,
- $2.unit_type,
- $2.distinct,
- TRUE)))
- MYSQL_YYABORT;
- }
- | query_expression_body_ext_parens
- unit_type_decl
- query_primary
- {
- if (!($$= Lex->add_primary_to_query_expression_body_ext_parens(
- $1, $3,
- $2.unit_type,
- $2.distinct)))
- MYSQL_YYABORT;
- }
- ;
-
-/*
- query_primary produces the same expressions as
- <query primary>
-*/
-
-query_primary:
- query_simple
- { $$= $1; }
- | query_expression_body_ext_parens
- { $$= $1->first_select(); }
- ;
-
-/*
- query_simple produces the same expressions as
- <simple table>
-*/
-
-query_simple:
- simple_table { $$= $1;}
- ;
-
-subselect:
- query_expression
- {
- if (!($$= Lex->parsed_subselect($1)))
- YYABORT;
- }
- ;
-
-/*
- subquery produces the same expressions as
- <subquery>
-
- Consider the production rule of the SQL Standard
- subquery:
- '(' query_expression ')'
-
- This rule is equivalent to the rule
- subquery:
- '(' query_expression_no_with_clause ')'
- | '(' with_clause query_expression_no_with_clause ')'
- that in its turn is equivalent to
- subquery:
- '(' query_expression_body_ext ')'
- | query_expression_body_ext_parens
- | '(' with_clause query_expression_no_with_clause ')'
-
- The latter can be re-written into
- subquery:
- query_expression_body_ext_parens
- | '(' with_clause query_expression_no_with_clause ')'
-
- The last rule allows us to resolve properly the shift/reduce conflict
- when subquery is used in expressions such as in the following queries
- select (select * from t1 limit 1) + t2.a from t2
- select * from t1 where t1.a [not] in (select t2.a from t2)
-
- In the rule below %prec SUBQUERY_AS_EXPR forces the parser to perform a shift
- operation rather then a reduce operation when ')' is encountered and can be
- considered as the last symbol a query expression.
-*/
-
-subquery:
- query_expression_body_ext_parens %prec SUBQUERY_AS_EXPR
- {
- if (!$1->fake_select_lex)
- $1->first_select()->braces= false;
- else
- $1->fake_select_lex->braces= false;
- if (!($$= Lex->parsed_subselect($1)))
- YYABORT;
- }
- | '(' with_clause query_expression_no_with_clause ')'
- {
- $3->set_with_clause($2);
- $2->attach_to($3->first_select());
- if (!($$= Lex->parsed_subselect($3)))
- YYABORT;
- }
- ;
-
-opt_from_clause:
- /* empty */ %prec EMPTY_FROM_CLAUSE
- | from_clause
- ;
-
-from_clause:
- FROM table_reference_list
- ;
-
-table_reference_list:
- join_table_list
- {
- Select->context.table_list=
- Select->context.first_name_resolution_table=
- Select->table_list.first;
- }
- | DUAL_SYM
- /* oracle compatibility: oracle always requires FROM clause,
- and DUAL is system table without fields.
- Is "SELECT 1 FROM DUAL" any better than "SELECT 1" ?
- Hmmm :) */
- ;
-
-select_options:
- /* empty*/
- | select_option_list
- {
- if (unlikely((Select->options & SELECT_DISTINCT) &&
- (Select->options & SELECT_ALL)))
- my_yyabort_error((ER_WRONG_USAGE, MYF(0), "ALL", "DISTINCT"));
- }
- ;
-
-opt_history_unit:
- /* empty*/ %prec PREC_BELOW_IDENTIFIER_OPT_SPECIAL_CASE
- {
- $$= VERS_UNDEFINED;
- }
- | TRANSACTION_SYM
- {
- $$= VERS_TRX_ID;
- }
- | TIMESTAMP
- {
- $$= VERS_TIMESTAMP;
- }
- ;
-
-history_point:
- TIMESTAMP TEXT_STRING
- {
- Item *item;
- if (!(item= type_handler_datetime2.create_literal_item(thd,
- $2.str, $2.length,
- YYCSCL, true)))
- MYSQL_YYABORT;
- $$= Vers_history_point(VERS_TIMESTAMP, item);
- }
- | function_call_keyword_timestamp
- {
- $$= Vers_history_point(VERS_TIMESTAMP, $1);
- }
- | opt_history_unit bit_expr
- {
- $$= Vers_history_point($1, $2);
- }
- ;
-
-for_portion_of_time_clause:
- FOR_SYM PORTION_SYM OF_SYM remember_tok_start ident FROM
- bit_expr TO_SYM bit_expr
- {
- if (unlikely(0 == strcasecmp($5.str, "SYSTEM_TIME")))
- {
- thd->parse_error(ER_SYNTAX_ERROR, $4);
- MYSQL_YYABORT;
- }
- Lex->period_conditions.init(SYSTEM_TIME_FROM_TO,
- Vers_history_point(VERS_TIMESTAMP, $7),
- Vers_history_point(VERS_TIMESTAMP, $9),
- $5);
- }
- ;
-
-opt_for_portion_of_time_clause:
- /* empty */
- {
- $$= false;
- }
- | for_portion_of_time_clause
- {
- $$= true;
- }
- ;
-
-opt_for_system_time_clause:
- /* empty */
- {
- $$= false;
- }
- | FOR_SYSTEM_TIME_SYM system_time_expr
- {
- $$= true;
- }
- ;
-
-system_time_expr:
- AS OF_SYM history_point
- {
- Lex->vers_conditions.init(SYSTEM_TIME_AS_OF, $3);
- }
- | ALL
- {
- Lex->vers_conditions.init(SYSTEM_TIME_ALL);
- }
- | FROM history_point TO_SYM history_point
- {
- Lex->vers_conditions.init(SYSTEM_TIME_FROM_TO, $2, $4);
- }
- | BETWEEN_SYM history_point AND_SYM history_point
- {
- Lex->vers_conditions.init(SYSTEM_TIME_BETWEEN, $2, $4);
- }
- ;
-
-select_option_list:
- select_option_list select_option
- | select_option
- ;
-
-select_option:
- query_expression_option
- | SQL_NO_CACHE_SYM
- {
- /*
- Allow this flag once per query.
- */
- if (Select->options & OPTION_NO_QUERY_CACHE)
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_NO_CACHE"));
- Select->options|= OPTION_NO_QUERY_CACHE;
- }
- | SQL_CACHE_SYM
- {
- /*
- Allow this flag once per query.
- */
- if (Select->options & OPTION_TO_QUERY_CACHE)
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_CACHE"));
- Select->options|= OPTION_TO_QUERY_CACHE;
- }
- ;
-
-
-select_lock_type:
- FOR_SYM UPDATE_SYM opt_lock_wait_timeout_new
- {
- $$= $3;
- $$.defined_lock= TRUE;
- $$.update_lock= TRUE;
- }
- | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM opt_lock_wait_timeout_new
- {
- $$= $5;
- $$.defined_lock= TRUE;
- $$.update_lock= FALSE;
- }
- ;
-
-opt_select_lock_type:
- /* empty */
- {
- $$.empty();
- }
- | select_lock_type
- {
- $$= $1;
- }
- ;
-
-opt_lock_wait_timeout_new:
- /* empty */
- {
- $$.empty();
- }
- | WAIT_SYM ulong_num
- {
- $$.defined_timeout= TRUE;
- $$.timeout= $2;
- }
- | NOWAIT_SYM
- {
- $$.defined_timeout= TRUE;
- $$.timeout= 0;
- }
- ;
-
-select_item_list:
- select_item_list ',' select_item
- | select_item
- | '*'
- {
- Item *item= new (thd->mem_root)
- Item_field(thd, &thd->lex->current_select->context,
- NULL, NULL, &star_clex_str);
- if (unlikely(item == NULL))
- MYSQL_YYABORT;
- if (unlikely(add_item_to_list(thd, item)))
- MYSQL_YYABORT;
- (thd->lex->current_select->with_wild)++;
- }
- ;
-
-select_item:
- remember_name select_sublist_qualified_asterisk remember_end
- {
- if (unlikely(add_item_to_list(thd, $2)))
- MYSQL_YYABORT;
- }
- | remember_name expr remember_end select_alias
- {
- DBUG_ASSERT($1 < $3);
-
- if (unlikely(add_item_to_list(thd, $2)))
- MYSQL_YYABORT;
- if ($4.str)
- {
- if (unlikely(Lex->sql_command == SQLCOM_CREATE_VIEW &&
- check_column_name($4.str)))
- my_yyabort_error((ER_WRONG_COLUMN_NAME, MYF(0), $4.str));
- $2->is_autogenerated_name= FALSE;
- $2->set_name(thd, $4.str, $4.length, system_charset_info);
- }
- else if (!$2->name.str || $2->name.str == item_empty_name)
- {
- $2->set_name(thd, $1, (uint) ($3 - $1), thd->charset());
- }
- }
- ;
-
-remember_tok_start:
- {
- $$= (char*) YYLIP->get_tok_start();
- }
- ;
-
-remember_name:
- {
- $$= (char*) YYLIP->get_cpp_tok_start();
- }
- ;
-
-remember_end:
- {
- $$= (char*) YYLIP->get_cpp_tok_end_rtrim();
- }
- ;
-
-remember_end_opt:
- {
- if (yychar == YYEMPTY)
- $$= (char*) YYLIP->get_cpp_ptr_rtrim();
- else
- $$= (char*) YYLIP->get_cpp_tok_end_rtrim();
- }
- ;
-
-select_alias:
- /* empty */ { $$=null_clex_str;}
- | AS ident { $$=$2; }
- | AS TEXT_STRING_sys { $$=$2; }
- | ident { $$=$1; }
- | TEXT_STRING_sys { $$=$1; }
- ;
-
-opt_default_time_precision:
- /* empty */ { $$= NOT_FIXED_DEC; }
- | '(' ')' { $$= NOT_FIXED_DEC; }
- | '(' real_ulong_num ')' { $$= $2; }
- ;
-
-opt_time_precision:
- /* empty */ { $$= 0; }
- | '(' ')' { $$= 0; }
- | '(' real_ulong_num ')' { $$= $2; }
- ;
-
-optional_braces:
- /* empty */ {}
- | '(' ')' {}
- ;
-
-/* all possible expressions */
-expr:
- expr or expr %prec OR_SYM
- {
- /*
- Design notes:
- Do not use a manually maintained stack like thd->lex->xxx_list,
- but use the internal bison stack ($$, $1 and $3) instead.
- Using the bison stack is:
- - more robust to changes in the grammar,
- - guaranteed to be in sync with the parser state,
- - better for performances (no memory allocation).
- */
- Item_cond_or *item1;
- Item_cond_or *item3;
- if (is_cond_or($1))
- {
- item1= (Item_cond_or*) $1;
- if (is_cond_or($3))
- {
- item3= (Item_cond_or*) $3;
- /*
- (X1 OR X2) OR (Y1 OR Y2) ==> OR (X1, X2, Y1, Y2)
- */
- item3->add_at_head(item1->argument_list());
- $$ = $3;
- }
- else
- {
- /*
- (X1 OR X2) OR Y ==> OR (X1, X2, Y)
- */
- item1->add($3, thd->mem_root);
- $$ = $1;
- }
- }
- else if (is_cond_or($3))
- {
- item3= (Item_cond_or*) $3;
- /*
- X OR (Y1 OR Y2) ==> OR (X, Y1, Y2)
- */
- item3->add_at_head($1, thd->mem_root);
- $$ = $3;
- }
- else
- {
- /* X OR Y */
- $$= new (thd->mem_root) Item_cond_or(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- }
- | expr XOR expr %prec XOR
- {
- /* XOR is a proprietary extension */
- $$= new (thd->mem_root) Item_func_xor(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | expr and expr %prec AND_SYM
- {
- /* See comments in rule expr: expr or expr */
- Item_cond_and *item1;
- Item_cond_and *item3;
- if (is_cond_and($1))
- {
- item1= (Item_cond_and*) $1;
- if (is_cond_and($3))
- {
- item3= (Item_cond_and*) $3;
- /*
- (X1 AND X2) AND (Y1 AND Y2) ==> AND (X1, X2, Y1, Y2)
- */
- item3->add_at_head(item1->argument_list());
- $$ = $3;
- }
- else
- {
- /*
- (X1 AND X2) AND Y ==> AND (X1, X2, Y)
- */
- item1->add($3, thd->mem_root);
- $$ = $1;
- }
- }
- else if (is_cond_and($3))
- {
- item3= (Item_cond_and*) $3;
- /*
- X AND (Y1 AND Y2) ==> AND (X, Y1, Y2)
- */
- item3->add_at_head($1, thd->mem_root);
- $$ = $3;
- }
- else
- {
- /* X AND Y */
- $$= new (thd->mem_root) Item_cond_and(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- }
- | NOT_SYM expr %prec NOT_SYM
- {
- $$= negate_expression(thd, $2);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bool_pri IS TRUE_SYM %prec IS
- {
- $$= new (thd->mem_root) Item_func_istrue(thd, $1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bool_pri IS not TRUE_SYM %prec IS
- {
- $$= new (thd->mem_root) Item_func_isnottrue(thd, $1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bool_pri IS FALSE_SYM %prec IS
- {
- $$= new (thd->mem_root) Item_func_isfalse(thd, $1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bool_pri IS not FALSE_SYM %prec IS
- {
- $$= new (thd->mem_root) Item_func_isnotfalse(thd, $1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bool_pri IS UNKNOWN_SYM %prec IS
- {
- $$= new (thd->mem_root) Item_func_isnull(thd, $1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bool_pri IS not UNKNOWN_SYM %prec IS
- {
- $$= new (thd->mem_root) Item_func_isnotnull(thd, $1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bool_pri %prec PREC_BELOW_NOT
- ;
-
-bool_pri:
- bool_pri IS NULL_SYM %prec IS
- {
- $$= new (thd->mem_root) Item_func_isnull(thd, $1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bool_pri IS not NULL_SYM %prec IS
- {
- $$= new (thd->mem_root) Item_func_isnotnull(thd, $1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bool_pri EQUAL_SYM predicate %prec EQUAL_SYM
- {
- $$= new (thd->mem_root) Item_func_equal(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bool_pri comp_op predicate %prec '='
- {
- $$= (*$2)(0)->create(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bool_pri comp_op all_or_any '(' subselect ')' %prec '='
- {
- $$= all_any_subquery_creator(thd, $1, $2, $3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | predicate
- ;
-
-predicate:
- bit_expr IN_SYM subquery
- {
- $$= new (thd->mem_root) Item_in_subselect(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr not IN_SYM subquery
- {
- Item *item= new (thd->mem_root) Item_in_subselect(thd, $1, $4);
- if (unlikely(item == NULL))
- MYSQL_YYABORT;
- $$= negate_expression(thd, item);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr IN_SYM '(' expr ')'
- {
- $$= handle_sql2003_note184_exception(thd, $1, true, $4);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr IN_SYM '(' expr ',' expr_list ')'
- {
- $6->push_front($4, thd->mem_root);
- $6->push_front($1, thd->mem_root);
- $$= new (thd->mem_root) Item_func_in(thd, *$6);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr not IN_SYM '(' expr ')'
- {
- $$= handle_sql2003_note184_exception(thd, $1, false, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr not IN_SYM '(' expr ',' expr_list ')'
- {
- $7->push_front($5, thd->mem_root);
- $7->push_front($1, thd->mem_root);
- Item_func_in *item= new (thd->mem_root) Item_func_in(thd, *$7);
- if (unlikely(item == NULL))
- MYSQL_YYABORT;
- $$= item->neg_transformer(thd);
- }
- | bit_expr BETWEEN_SYM bit_expr AND_SYM predicate
- {
- $$= new (thd->mem_root) Item_func_between(thd, $1, $3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate
- {
- Item_func_between *item;
- item= new (thd->mem_root) Item_func_between(thd, $1, $4, $6);
- if (unlikely(item == NULL))
- MYSQL_YYABORT;
- $$= item->neg_transformer(thd);
- }
- | bit_expr SOUNDS_SYM LIKE bit_expr
- {
- Item *item1= new (thd->mem_root) Item_func_soundex(thd, $1);
- Item *item4= new (thd->mem_root) Item_func_soundex(thd, $4);
- if (unlikely(item1 == NULL) || unlikely(item4 == NULL))
- MYSQL_YYABORT;
- $$= new (thd->mem_root) Item_func_eq(thd, item1, item4);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | 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 bit_expr opt_escape
- {
- Item *item= new (thd->mem_root) Item_func_like(thd, $1, $4, $5,
- Lex->escape_used);
- if (unlikely(item == NULL))
- MYSQL_YYABORT;
- $$= item->neg_transformer(thd);
- }
- | bit_expr REGEXP bit_expr
- {
- $$= new (thd->mem_root) Item_func_regex(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr not REGEXP bit_expr
- {
- Item *item= new (thd->mem_root) Item_func_regex(thd, $1, $4);
- if (unlikely(item == NULL))
- MYSQL_YYABORT;
- $$= negate_expression(thd, item);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr %prec PREC_BELOW_NOT
- ;
-
-bit_expr:
- bit_expr '|' bit_expr %prec '|'
- {
- $$= new (thd->mem_root) Item_func_bit_or(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr '&' bit_expr %prec '&'
- {
- $$= new (thd->mem_root) Item_func_bit_and(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr SHIFT_LEFT bit_expr %prec SHIFT_LEFT
- {
- $$= new (thd->mem_root) Item_func_shift_left(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr SHIFT_RIGHT bit_expr %prec SHIFT_RIGHT
- {
- $$= new (thd->mem_root) Item_func_shift_right(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr ORACLE_CONCAT_SYM bit_expr
- {
- $$= new (thd->mem_root) Item_func_concat_operator_oracle(thd,
- $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr '+' bit_expr %prec '+'
- {
- $$= new (thd->mem_root) Item_func_plus(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr '-' bit_expr %prec '-'
- {
- $$= new (thd->mem_root) Item_func_minus(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr '+' INTERVAL_SYM expr interval %prec '+'
- {
- $$= new (thd->mem_root) Item_date_add_interval(thd, $1, $4, $5, 0);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr '-' INTERVAL_SYM expr interval %prec '-'
- {
- $$= new (thd->mem_root) Item_date_add_interval(thd, $1, $4, $5, 1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | INTERVAL_SYM expr interval '+' expr
- /* we cannot put interval before - */
- {
- $$= new (thd->mem_root) Item_date_add_interval(thd, $5, $2, $3, 0);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | '+' INTERVAL_SYM expr interval '+' expr %prec NEG
- {
- $$= new (thd->mem_root) Item_date_add_interval(thd, $6, $3, $4, 0);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | '-' INTERVAL_SYM expr interval '+' expr %prec NEG
- {
- $$= new (thd->mem_root) Item_date_add_interval(thd, $6, $3, $4, 1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr '*' bit_expr %prec '*'
- {
- $$= new (thd->mem_root) Item_func_mul(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr '/' bit_expr %prec '/'
- {
- $$= new (thd->mem_root) Item_func_div(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr '%' bit_expr %prec '%'
- {
- $$= new (thd->mem_root) Item_func_mod(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr DIV_SYM bit_expr %prec DIV_SYM
- {
- $$= new (thd->mem_root) Item_func_int_div(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr MOD_SYM bit_expr %prec MOD_SYM
- {
- $$= new (thd->mem_root) Item_func_mod(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | bit_expr '^' bit_expr
- {
- $$= new (thd->mem_root) Item_func_bit_xor(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | mysql_concatenation_expr %prec '^'
- ;
-
-or:
- OR_SYM
- | OR2_SYM
- ;
-
-and:
- AND_SYM
- | AND_AND_SYM
- ;
-
-not:
- NOT_SYM
- | NOT2_SYM
- ;
-
-not2:
- '!'
- | NOT2_SYM
- ;
-
-comp_op:
- '=' { $$ = &comp_eq_creator; }
- | GE { $$ = &comp_ge_creator; }
- | '>' { $$ = &comp_gt_creator; }
- | LE { $$ = &comp_le_creator; }
- | '<' { $$ = &comp_lt_creator; }
- | NE { $$ = &comp_ne_creator; }
- ;
-
-all_or_any:
- ALL { $$ = 1; }
- | ANY_SYM { $$ = 0; }
- ;
-
-opt_dyncol_type:
- /* empty */
- {
- $$.set(DYN_COL_NULL); /* automatic type */
- Lex->charset= NULL;
- }
- | AS dyncol_type { $$= $2; }
- ;
-
-dyncol_type:
- numeric_dyncol_type { $$= $1; Lex->charset= NULL; }
- | temporal_dyncol_type { $$= $1; Lex->charset= NULL; }
- | string_dyncol_type { $$= $1; }
- ;
-
-numeric_dyncol_type:
- INT_SYM { $$.set(DYN_COL_INT); }
- | UNSIGNED INT_SYM { $$.set(DYN_COL_UINT); }
- | DOUBLE_SYM { $$.set(DYN_COL_DOUBLE); }
- | REAL { $$.set(DYN_COL_DOUBLE); }
- | FLOAT_SYM { $$.set(DYN_COL_DOUBLE); }
- | DECIMAL_SYM float_options { $$.set(DYN_COL_DECIMAL, $2); }
- ;
-
-temporal_dyncol_type:
- DATE_SYM { $$.set(DYN_COL_DATE); }
- | TIME_SYM opt_field_length { $$.set(DYN_COL_TIME, 0, $2); }
- | DATETIME opt_field_length { $$.set(DYN_COL_DATETIME, 0, $2); }
- ;
-
-string_dyncol_type:
- char
- { Lex->charset= thd->variables.collation_connection; }
- opt_binary
- {
- $$.set(DYN_COL_STRING);
- }
- | nchar
- {
- $$.set(DYN_COL_STRING);
- Lex->charset= national_charset_info;
- }
- ;
-
-dyncall_create_element:
- expr ',' expr opt_dyncol_type
- {
- LEX *lex= Lex;
- $$= (DYNCALL_CREATE_DEF *)
- alloc_root(thd->mem_root, sizeof(DYNCALL_CREATE_DEF));
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- $$->key= $1;
- $$->value= $3;
- $$->type= (DYNAMIC_COLUMN_TYPE)$4.dyncol_type();
- $$->cs= lex->charset;
- if ($4.length())
- $$->len= strtoul($4.length(), NULL, 10);
- else
- $$->len= 0;
- if ($4.dec())
- $$->frac= strtoul($4.dec(), NULL, 10);
- else
- $$->len= 0;
- }
- ;
-
-dyncall_create_list:
- dyncall_create_element
- {
- $$= new (thd->mem_root) List<DYNCALL_CREATE_DEF>;
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- $$->push_back($1, thd->mem_root);
- }
- | dyncall_create_list ',' dyncall_create_element
- {
- $1->push_back($3, thd->mem_root);
- $$= $1;
- }
- ;
-
-
-plsql_cursor_attr:
- ISOPEN_SYM { $$= PLSQL_CURSOR_ATTR_ISOPEN; }
- | FOUND_SYM { $$= PLSQL_CURSOR_ATTR_FOUND; }
- | NOTFOUND_SYM { $$= PLSQL_CURSOR_ATTR_NOTFOUND; }
- | ROWCOUNT_SYM { $$= PLSQL_CURSOR_ATTR_ROWCOUNT; }
- ;
-
-explicit_cursor_attr:
- ident PERCENT_ORACLE_SYM plsql_cursor_attr
- {
- if (unlikely(!($$= Lex->make_item_plsql_cursor_attr(thd, &$1, $3))))
- MYSQL_YYABORT;
- }
- ;
-
-
-trim_operands:
- expr { $$.set(TRIM_BOTH, $1); }
- | LEADING expr FROM expr { $$.set(TRIM_LEADING, $2, $4); }
- | TRAILING expr FROM expr { $$.set(TRIM_TRAILING, $2, $4); }
- | BOTH expr FROM expr { $$.set(TRIM_BOTH, $2, $4); }
- | LEADING FROM expr { $$.set(TRIM_LEADING, $3); }
- | TRAILING FROM expr { $$.set(TRIM_TRAILING, $3); }
- | BOTH FROM expr { $$.set(TRIM_BOTH, $3); }
- | expr FROM expr { $$.set(TRIM_BOTH, $1, $3); }
- ;
-
-/*
- Expressions that the parser allows in a column DEFAULT clause
- without parentheses. These expressions cannot end with a COLLATE clause.
-
- If we allowed any "expr" in DEFAULT clause, there would be a confusion
- in queries like this:
- CREATE TABLE t1 (a TEXT DEFAULT 'a' COLLATE latin1_bin);
- It would be not clear what COLLATE stands for:
- - the collation of the column `a`, or
- - the collation of the string literal 'a'
-
- This restriction allows to parse the above query unambiguiusly:
- COLLATE belongs to the column rather than the literal.
- If one needs COLLATE to belong to the literal, parentheses must be used:
- CREATE TABLE t1 (a TEXT DEFAULT ('a' COLLATE latin1_bin));
- Note: the COLLATE clause is rather meaningless here, but the query
- is syntactically correct.
-
- Note, some of the expressions are not actually allowed in DEFAULT,
- e.g. sum_expr, window_func_expr, ROW(...), VALUES().
- We could move them to simple_expr, but that would make
- these two queries return a different error messages:
- CREATE TABLE t1 (a INT DEFAULT AVG(1));
- CREATE TABLE t1 (a INT DEFAULT (AVG(1)));
- The first query would return "syntax error".
- Currenly both return:
- Function or expression 'avg(' is not allowed for 'DEFAULT' ...
-*/
-column_default_non_parenthesized_expr:
- simple_ident
- | function_call_keyword
- | function_call_nonkeyword
- | function_call_generic
- | function_call_conflict
- | literal
- | param_marker { $$= $1; }
- | variable
- | sum_expr
- {
- if (!Lex->select_stack_top)
- {
- my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0));
- MYSQL_YYABORT;
- }
- }
- | window_func_expr
- {
- if (!Lex->select_stack_top)
- {
- my_error(ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION, MYF(0));
- MYSQL_YYABORT;
- }
- }
- | inverse_distribution_function
- | ROW_SYM '(' expr ',' expr_list ')'
- {
- $5->push_front($3, thd->mem_root);
- $$= new (thd->mem_root) Item_row(thd, *$5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | EXISTS '(' subselect ')'
- {
- $$= new (thd->mem_root) Item_exists_subselect(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | '{' ident expr '}'
- {
- if (unlikely(!($$= $3->make_odbc_literal(thd, &$2))))
- MYSQL_YYABORT;
- }
- | MATCH ident_list_arg AGAINST '(' bit_expr fulltext_options ')'
- {
- $2->push_front($5, thd->mem_root);
- Item_func_match *i1= new (thd->mem_root) Item_func_match(thd, *$2,
- $6);
- if (unlikely(i1 == NULL))
- MYSQL_YYABORT;
- Select->add_ftfunc_to_list(thd, i1);
- $$= i1;
- }
- | CAST_SYM '(' expr AS cast_type ')'
- {
- if (unlikely(!($$= $5.create_typecast_item(thd, $3, Lex->charset))))
- MYSQL_YYABORT;
- }
- | CASE_SYM when_list_opt_else END
- {
- if (unlikely(!($$= new(thd->mem_root) Item_func_case_searched(thd, *$2))))
- MYSQL_YYABORT;
- }
- | CASE_SYM expr when_list_opt_else END
- {
- $3->push_front($2, thd->mem_root);
- if (unlikely(!($$= new (thd->mem_root) Item_func_case_simple(thd, *$3))))
- MYSQL_YYABORT;
- }
- | CONVERT_SYM '(' expr ',' cast_type ')'
- {
- if (unlikely(!($$= $5.create_typecast_item(thd, $3, Lex->charset))))
- MYSQL_YYABORT;
- }
- | CONVERT_SYM '(' expr USING charset_name ')'
- {
- $$= new (thd->mem_root) Item_func_conv_charset(thd, $3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | DEFAULT '(' simple_ident ')'
- {
- Item_splocal *il= $3->get_item_splocal();
- if (unlikely(il))
- my_yyabort_error((ER_WRONG_COLUMN_NAME, MYF(0), il->my_name()->str));
- $$= new (thd->mem_root) Item_default_value(thd, Lex->current_context(),
- $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- Lex->default_used= TRUE;
- }
- | VALUE_SYM '(' simple_ident_nospvar ')'
- {
- $$= new (thd->mem_root) Item_insert_value(thd, Lex->current_context(),
- $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | NEXT_SYM VALUE_SYM FOR_SYM table_ident
- {
- if (unlikely(!($$= Lex->create_item_func_nextval(thd, $4))))
- MYSQL_YYABORT;
- }
- | NEXTVAL_SYM '(' table_ident ')'
- {
- if (unlikely(!($$= Lex->create_item_func_nextval(thd, $3))))
- MYSQL_YYABORT;
- }
- | PREVIOUS_SYM VALUE_SYM FOR_SYM table_ident
- {
- if (unlikely(!($$= Lex->create_item_func_lastval(thd, $4))))
- MYSQL_YYABORT;
- }
- | LASTVAL_SYM '(' table_ident ')'
- {
- if (unlikely(!($$= Lex->create_item_func_lastval(thd, $3))))
- MYSQL_YYABORT;
- }
- | SETVAL_SYM '(' table_ident ',' longlong_num ')'
- {
- if (unlikely(!($$= Lex->create_item_func_setval(thd, $3, $5, 0, 1))))
- MYSQL_YYABORT;
- }
- | SETVAL_SYM '(' table_ident ',' longlong_num ',' bool ')'
- {
- if (unlikely(!($$= Lex->create_item_func_setval(thd, $3, $5, 0, $7))))
- MYSQL_YYABORT;
- }
- | SETVAL_SYM '(' table_ident ',' longlong_num ',' bool ',' ulonglong_num ')'
- {
- if (unlikely(!($$= Lex->create_item_func_setval(thd, $3, $5, $9, $7))))
- MYSQL_YYABORT;
- }
- ;
-
-primary_expr:
- column_default_non_parenthesized_expr
- | explicit_cursor_attr
- | '(' parenthesized_expr ')' { $$= $2; }
- | subquery
- {
- if (!($$= Lex->create_item_query_expression(thd, $1->master_unit())))
- MYSQL_YYABORT;
- }
- ;
-
-string_factor_expr:
- primary_expr
- | string_factor_expr COLLATE_SYM collation_name
- {
- if (unlikely(!($$= new (thd->mem_root) Item_func_set_collation(thd, $1, $3))))
- MYSQL_YYABORT;
- }
- ;
-
-simple_expr:
- string_factor_expr %prec NEG
- | BINARY simple_expr
- {
- Type_cast_attributes at(&my_charset_bin);
- if (unlikely(!($$= type_handler_long_blob.create_typecast_item(thd, $2, at))))
- MYSQL_YYABORT;
- }
- | '+' simple_expr %prec NEG
- {
- $$= $2;
- }
- | '-' simple_expr %prec NEG
- {
- $$= $2->neg(thd);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | '~' simple_expr %prec NEG
- {
- $$= new (thd->mem_root) Item_func_bit_neg(thd, $2);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | not2 simple_expr %prec NEG
- {
- $$= negate_expression(thd, $2);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-mysql_concatenation_expr:
- simple_expr
- | mysql_concatenation_expr MYSQL_CONCAT_SYM simple_expr
- {
- $$= new (thd->mem_root) Item_func_concat(thd, $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-function_call_keyword_timestamp:
- TIMESTAMP '(' expr ')'
- {
- $$= new (thd->mem_root) Item_datetime_typecast(thd, $3,
- AUTO_SEC_PART_DIGITS);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | TIMESTAMP '(' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_func_timestamp(thd, $3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-/*
- Function call syntax using official SQL 2003 keywords.
- Because the function name is an official token,
- a dedicated grammar rule is needed in the parser.
- There is no potential for conflicts
-*/
-function_call_keyword:
- CHAR_SYM '(' expr_list ')'
- {
- $$= new (thd->mem_root) Item_func_char(thd, *$3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | CHAR_SYM '(' expr_list USING charset_name ')'
- {
- $$= new (thd->mem_root) Item_func_char(thd, *$3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | CURRENT_USER optional_braces
- {
- $$= new (thd->mem_root) Item_func_current_user(thd,
- Lex->current_context());
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
- Lex->safe_to_cache_query= 0;
- }
- | CURRENT_ROLE optional_braces
- {
- $$= new (thd->mem_root) Item_func_current_role(thd,
- Lex->current_context());
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
- Lex->safe_to_cache_query= 0;
- }
- | DATE_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_date_typecast(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | DAY_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_func_dayofmonth(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | HOUR_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_func_hour(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | INSERT '(' expr ',' expr ',' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_func_insert(thd, $3, $5, $7, $9);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | INTERVAL_SYM '(' expr ',' expr ')'
- {
- List<Item> *list= new (thd->mem_root) List<Item>;
- if (unlikely(list == NULL))
- MYSQL_YYABORT;
- if (unlikely(list->push_front($5, thd->mem_root)) ||
- unlikely(list->push_front($3, thd->mem_root)))
- MYSQL_YYABORT;
- Item_row *item= new (thd->mem_root) Item_row(thd, *list);
- if (unlikely(item == NULL))
- MYSQL_YYABORT;
- $$= new (thd->mem_root) Item_func_interval(thd, item);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | INTERVAL_SYM '(' expr ',' expr ',' expr_list ')'
- {
- $7->push_front($5, thd->mem_root);
- $7->push_front($3, thd->mem_root);
- Item_row *item= new (thd->mem_root) Item_row(thd, *$7);
- if (unlikely(item == NULL))
- MYSQL_YYABORT;
- $$= new (thd->mem_root) Item_func_interval(thd, item);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | LEFT '(' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_func_left(thd, $3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | MINUTE_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_func_minute(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | MONTH_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_func_month(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | RIGHT '(' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_func_right(thd, $3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | SECOND_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_func_second(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | SQL_SYM PERCENT_ORACLE_SYM ROWCOUNT_SYM
- {
- $$= new (thd->mem_root) Item_func_oracle_sql_rowcount(thd);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
- Lex->safe_to_cache_query= 0;
- }
- | TIME_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_time_typecast(thd, $3,
- AUTO_SEC_PART_DIGITS);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | function_call_keyword_timestamp
- {
- $$= $1;
- }
- | TRIM '(' trim_operands ')'
- {
- if (unlikely(!($$= $3.make_item_func_trim(thd))))
- MYSQL_YYABORT;
- }
- | USER_SYM '(' ')'
- {
- $$= new (thd->mem_root) Item_func_user(thd);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
- Lex->safe_to_cache_query=0;
- }
- | YEAR_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_func_year(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-/*
- Function calls using non reserved keywords, with special syntaxic forms.
- Dedicated grammar rules are needed because of the syntax,
- but also have the potential to cause incompatibilities with other
- parts of the language.
- MAINTAINER:
- The only reasons a function should be added here are:
- - for compatibility reasons with another SQL syntax (CURDATE),
- - for typing reasons (GET_FORMAT)
- Any other 'Syntaxic sugar' enhancements should be *STRONGLY*
- discouraged.
-*/
-function_call_nonkeyword:
- ADDDATE_SYM '(' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $5,
- INTERVAL_DAY, 0);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | ADDDATE_SYM '(' expr ',' INTERVAL_SYM expr interval ')'
- {
- $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $6, $7, 0);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | CURDATE optional_braces
- {
- $$= new (thd->mem_root) Item_func_curdate_local(thd);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- Lex->safe_to_cache_query=0;
- }
- | CURTIME opt_time_precision
- {
- $$= new (thd->mem_root) Item_func_curtime_local(thd, $2);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- Lex->safe_to_cache_query=0;
- }
- | DATE_ADD_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')'
- {
- $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $6, $7, 0);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | DATE_SUB_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')'
- {
- $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $6, $7, 1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | DATE_FORMAT_SYM '(' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_func_date_format(thd, $3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | DATE_FORMAT_SYM '(' expr ',' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_func_date_format(thd, $3, $5, $7);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | DECODE_MARIADB_SYM '(' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_func_decode(thd, $3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | DECODE_ORACLE_SYM '(' expr ',' decode_when_list_oracle ')'
- {
- $5->push_front($3, thd->mem_root);
- if (unlikely(!($$= new (thd->mem_root) Item_func_decode_oracle(thd, *$5))))
- MYSQL_YYABORT;
- }
- | EXTRACT_SYM '(' interval FROM expr ')'
- {
- $$=new (thd->mem_root) Item_extract(thd, $3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | GET_FORMAT '(' date_time_type ',' expr ')'
- {
- $$= new (thd->mem_root) Item_func_get_format(thd, $3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | NOW_SYM opt_time_precision
- {
- $$= new (thd->mem_root) Item_func_now_local(thd, $2);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- Lex->safe_to_cache_query=0;
- }
- | POSITION_SYM '(' bit_expr IN_SYM expr ')'
- {
- $$= new (thd->mem_root) Item_func_locate(thd, $5, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | SUBDATE_SYM '(' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $5,
- INTERVAL_DAY, 1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | SUBDATE_SYM '(' expr ',' INTERVAL_SYM expr interval ')'
- {
- $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $6, $7, 1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | SUBSTRING '(' expr ',' expr ',' expr ')'
- {
- if (unlikely(!($$= Lex->make_item_func_substr(thd, $3, $5, $7))))
- MYSQL_YYABORT;
- }
- | SUBSTRING '(' expr ',' expr ')'
- {
- if (unlikely(!($$= Lex->make_item_func_substr(thd, $3, $5))))
- MYSQL_YYABORT;
- }
- | SUBSTRING '(' expr FROM expr FOR_SYM expr ')'
- {
- if (unlikely(!($$= Lex->make_item_func_substr(thd, $3, $5, $7))))
- MYSQL_YYABORT;
- }
- | SUBSTRING '(' expr FROM expr ')'
- {
- if (unlikely(!($$= Lex->make_item_func_substr(thd, $3, $5))))
- MYSQL_YYABORT;
- }
- | SYSDATE opt_time_precision
- {
- /*
- Unlike other time-related functions, SYSDATE() is
- replication-unsafe because it is not affected by the
- TIMESTAMP variable. It is unsafe even if
- sysdate_is_now=1, because the slave may have
- sysdate_is_now=0.
- */
- Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
- if (global_system_variables.sysdate_is_now == 0)
- $$= new (thd->mem_root) Item_func_sysdate_local(thd, $2);
- else
- $$= new (thd->mem_root) Item_func_now_local(thd, $2);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- Lex->safe_to_cache_query=0;
- }
- | TIMESTAMP_ADD '(' interval_time_stamp ',' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_date_add_interval(thd, $7, $5, $3, 0);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | TIMESTAMP_DIFF '(' interval_time_stamp ',' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_func_timestamp_diff(thd, $5, $7, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | TRIM_ORACLE '(' trim_operands ')'
- {
- if (unlikely(!($$= $3.make_item_func_trim_oracle(thd))))
- MYSQL_YYABORT;
- }
- | UTC_DATE_SYM optional_braces
- {
- $$= new (thd->mem_root) Item_func_curdate_utc(thd);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- Lex->safe_to_cache_query=0;
- }
- | UTC_TIME_SYM opt_time_precision
- {
- $$= new (thd->mem_root) Item_func_curtime_utc(thd, $2);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- Lex->safe_to_cache_query=0;
- }
- | UTC_TIMESTAMP_SYM opt_time_precision
- {
- $$= new (thd->mem_root) Item_func_now_utc(thd, $2);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- Lex->safe_to_cache_query=0;
- }
- |
- COLUMN_ADD_SYM '(' expr ',' dyncall_create_list ')'
- {
- $$= create_func_dyncol_add(thd, $3, *$5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- |
- COLUMN_DELETE_SYM '(' expr ',' expr_list ')'
- {
- $$= create_func_dyncol_delete(thd, $3, *$5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- |
- COLUMN_CHECK_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_func_dyncol_check(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- |
- COLUMN_CREATE_SYM '(' dyncall_create_list ')'
- {
- $$= create_func_dyncol_create(thd, *$3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- |
- COLUMN_GET_SYM '(' expr ',' expr AS cast_type ')'
- {
- LEX *lex= Lex;
- $$= create_func_dyncol_get(thd, $3, $5, $7.type_handler(),
- $7.length(), $7.dec(),
- lex->charset);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-/*
- Functions calls using a non reserved keyword, and using a regular syntax.
- Because the non reserved keyword is used in another part of the grammar,
- a dedicated rule is needed here.
-*/
-function_call_conflict:
- ASCII_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_func_ascii(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | CHARSET '(' expr ')'
- {
- $$= new (thd->mem_root) Item_func_charset(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | COALESCE '(' expr_list ')'
- {
- $$= new (thd->mem_root) Item_func_coalesce(thd, *$3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | COLLATION_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_func_collation(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | DATABASE '(' ')'
- {
- $$= new (thd->mem_root) Item_func_database(thd);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- Lex->safe_to_cache_query=0;
- }
- | IF_SYM '(' expr ',' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_func_if(thd, $3, $5, $7);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | FORMAT_SYM '(' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_func_format(thd, $3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | FORMAT_SYM '(' expr ',' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_func_format(thd, $3, $5, $7);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- /* LAST_VALUE here conflicts with the definition for window functions.
- We have these 2 separate rules to remove the shift/reduce conflict.
- */
- | LAST_VALUE '(' expr ')'
- {
- List<Item> *list= new (thd->mem_root) List<Item>;
- if (unlikely(list == NULL))
- MYSQL_YYABORT;
- list->push_back($3, thd->mem_root);
-
- $$= new (thd->mem_root) Item_func_last_value(thd, *list);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | LAST_VALUE '(' expr_list ',' expr ')'
- {
- $3->push_back($5, thd->mem_root);
- $$= new (thd->mem_root) Item_func_last_value(thd, *$3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | MICROSECOND_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_func_microsecond(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | MOD_SYM '(' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_func_mod(thd, $3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | OLD_PASSWORD_SYM '(' expr ')'
- {
- $$= new (thd->mem_root)
- Item_func_password(thd, $3, Item_func_password::OLD);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | PASSWORD_SYM '(' expr ')'
- {
- Item* i1;
- i1= new (thd->mem_root) Item_func_password(thd, $3);
- if (unlikely(i1 == NULL))
- MYSQL_YYABORT;
- $$= i1;
- }
- | QUARTER_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_func_quarter(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | REPEAT_SYM '(' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_func_repeat(thd, $3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | REPLACE '(' expr ',' expr ',' expr ')'
- {
- if (unlikely(!($$= Lex->make_item_func_replace(thd, $3, $5, $7))))
- MYSQL_YYABORT;
- }
- | REVERSE_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_func_reverse(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | ROW_COUNT_SYM '(' ')'
- {
- $$= new (thd->mem_root) Item_func_row_count(thd);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
- Lex->safe_to_cache_query= 0;
- }
- | TRUNCATE_SYM '(' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_func_round(thd, $3, $5, 1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | WEEK_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_func_week(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | WEEK_SYM '(' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_func_week(thd, $3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | WEIGHT_STRING_SYM '(' expr opt_ws_levels ')'
- {
- $$= new (thd->mem_root) Item_func_weight_string(thd, $3, 0, 0, $4);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | WEIGHT_STRING_SYM '(' expr AS CHAR_SYM ws_nweights opt_ws_levels ')'
- {
- $$= new (thd->mem_root)
- Item_func_weight_string(thd, $3, 0, $6,
- $7 | MY_STRXFRM_PAD_WITH_SPACE);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | WEIGHT_STRING_SYM '(' expr AS BINARY ws_nweights ')'
- {
- Item *item= new (thd->mem_root) Item_char_typecast(thd, $3, $6,
- &my_charset_bin);
- if (unlikely(item == NULL))
- MYSQL_YYABORT;
- $$= new (thd->mem_root)
- Item_func_weight_string(thd, item, 0, $6,
- MY_STRXFRM_PAD_WITH_SPACE);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | WEIGHT_STRING_SYM '(' expr ',' ulong_num ',' ulong_num ',' ulong_num ')'
- {
- $$= new (thd->mem_root) Item_func_weight_string(thd, $3, $5, $7,
- $9);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | geometry_function
- {
-#ifdef HAVE_SPATIAL
- $$= $1;
- /* $1 may be NULL, GEOM_NEW not tested for out of memory */
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
-#else
- my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name,
- sym_group_geom.needed_define));
-#endif
- }
- ;
-
-geometry_function:
- CONTAINS_SYM '(' expr ',' expr ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_precise_rel(thd, $3, $5,
- Item_func::SP_CONTAINS_FUNC));
- }
- | GEOMETRYCOLLECTION '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_geometrycollection,
- Geometry::wkb_point));
- }
- | LINESTRING '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_linestring,
- Geometry::wkb_point));
- }
- | MULTILINESTRING '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_multilinestring,
- Geometry::wkb_linestring));
- }
- | MULTIPOINT '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_multipoint,
- Geometry::wkb_point));
- }
- | MULTIPOLYGON '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_multipolygon,
- Geometry::wkb_polygon));
- }
- | POINT_SYM '(' expr ',' expr ')'
- {
- $$= GEOM_NEW(thd, Item_func_point(thd, $3, $5));
- }
- | POLYGON '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_polygon,
- Geometry::wkb_linestring));
- }
- | WITHIN '(' expr ',' expr ')'
- {
- $$= GEOM_NEW(thd, Item_func_spatial_precise_rel(thd, $3, $5,
- Item_func::SP_WITHIN_FUNC));
- }
- ;
-
-/*
- Regular function calls.
- The function name is *not* a token, and therefore is guaranteed to not
- introduce side effects to the language in general.
- MAINTAINER:
- All the new functions implemented for new features should fit into
- this category. The place to implement the function itself is
- in sql/item_create.cc
-*/
-function_call_generic:
- IDENT_sys '('
- {
-#ifdef HAVE_DLOPEN
- udf_func *udf= 0;
- LEX *lex= Lex;
- if (using_udf_functions &&
- (udf= find_udf($1.str, $1.length)) &&
- udf->type == UDFTYPE_AGGREGATE)
- {
- if (unlikely(lex->current_select->inc_in_sum_expr()))
- {
- thd->parse_error();
- MYSQL_YYABORT;
- }
- }
- /* Temporary placing the result of find_udf in $3 */
- $<udf>$= udf;
-#endif
- }
- opt_udf_expr_list ')'
- {
- Create_func *builder;
- Item *item= NULL;
-
- if (unlikely(check_routine_name(&$1)))
- MYSQL_YYABORT;
-
- /*
- Implementation note:
- names are resolved with the following order:
- - MySQL native functions,
- - User Defined Functions,
- - Stored Functions (assuming the current <use> database)
-
- This will be revised with WL#2128 (SQL PATH)
- */
- builder= find_native_function_builder(thd, &$1);
- if (builder)
- {
- item= builder->create_func(thd, &$1, $4);
- }
- else
- {
-#ifdef HAVE_DLOPEN
- /* Retrieving the result of find_udf */
- udf_func *udf= $<udf>3;
-
- if (udf)
- {
- if (udf->type == UDFTYPE_AGGREGATE)
- {
- Select->in_sum_expr--;
- }
-
- item= Create_udf_func::s_singleton.create(thd, udf, $4);
- }
- else
-#endif
- {
- builder= find_qualified_function_builder(thd);
- DBUG_ASSERT(builder);
- item= builder->create_func(thd, &$1, $4);
- }
- }
-
- if (unlikely(! ($$= item)))
- MYSQL_YYABORT;
- }
- | ident_cli '.' ident_cli '(' opt_expr_list ')'
- {
- if (unlikely(!($$= Lex->make_item_func_call_generic(thd, &$1, &$3, $5))))
- MYSQL_YYABORT;
- }
- ;
-
-fulltext_options:
- opt_natural_language_mode opt_query_expansion
- { $$= $1 | $2; }
- | IN_SYM BOOLEAN_SYM MODE_SYM
- { $$= FT_BOOL; }
- ;
-
-opt_natural_language_mode:
- /* nothing */ { $$= FT_NL; }
- | IN_SYM NATURAL LANGUAGE_SYM MODE_SYM { $$= FT_NL; }
- ;
-
-opt_query_expansion:
- /* nothing */ { $$= 0; }
- | WITH QUERY_SYM EXPANSION_SYM { $$= FT_EXPAND; }
- ;
-
-opt_udf_expr_list:
- /* empty */ { $$= NULL; }
- | udf_expr_list { $$= $1; }
- ;
-
-udf_expr_list:
- udf_expr
- {
- $$= new (thd->mem_root) List<Item>;
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- $$->push_back($1, thd->mem_root);
- }
- | udf_expr_list ',' udf_expr
- {
- $1->push_back($3, thd->mem_root);
- $$= $1;
- }
- ;
-
-udf_expr:
- remember_name expr remember_end select_alias
- {
- /*
- Use Item::name as a storage for the attribute value of user
- defined function argument. It is safe to use Item::name
- because the syntax will not allow having an explicit name here.
- See WL#1017 re. udf attributes.
- */
- if ($4.str)
- {
- $2->is_autogenerated_name= FALSE;
- $2->set_name(thd, $4.str, $4.length, system_charset_info);
- }
- /*
- A field has to have its proper name in order for name
- resolution to work, something we are only guaranteed if we
- parse it out. If we hijack the input stream with
- remember_name we may get quoted or escaped names.
- */
- else if ($2->type() != Item::FIELD_ITEM &&
- $2->type() != Item::REF_ITEM /* For HAVING */ )
- $2->set_name(thd, $1, (uint) ($3 - $1), thd->charset());
- $$= $2;
- }
- ;
-
-sum_expr:
- AVG_SYM '(' in_sum_expr ')'
- {
- $$= new (thd->mem_root) Item_sum_avg(thd, $3, FALSE);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | AVG_SYM '(' DISTINCT in_sum_expr ')'
- {
- $$= new (thd->mem_root) Item_sum_avg(thd, $4, TRUE);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | BIT_AND '(' in_sum_expr ')'
- {
- $$= new (thd->mem_root) Item_sum_and(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | BIT_OR '(' in_sum_expr ')'
- {
- $$= new (thd->mem_root) Item_sum_or(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | BIT_XOR '(' in_sum_expr ')'
- {
- $$= new (thd->mem_root) Item_sum_xor(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | COUNT_SYM '(' opt_all '*' ')'
- {
- Item *item= new (thd->mem_root) Item_int(thd, (int32) 0L, 1);
- if (unlikely(item == NULL))
- MYSQL_YYABORT;
- $$= new (thd->mem_root) Item_sum_count(thd, item);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | COUNT_SYM '(' in_sum_expr ')'
- {
- $$= new (thd->mem_root) Item_sum_count(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | COUNT_SYM '(' DISTINCT
- { Select->in_sum_expr++; }
- expr_list
- { Select->in_sum_expr--; }
- ')'
- {
- $$= new (thd->mem_root) Item_sum_count(thd, *$5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | MIN_SYM '(' in_sum_expr ')'
- {
- $$= new (thd->mem_root) Item_sum_min(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- /*
- According to ANSI SQL, DISTINCT is allowed and has
- no sense inside MIN and MAX grouping functions; so MIN|MAX(DISTINCT ...)
- is processed like an ordinary MIN | MAX()
- */
- | MIN_SYM '(' DISTINCT in_sum_expr ')'
- {
- $$= new (thd->mem_root) Item_sum_min(thd, $4);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | MAX_SYM '(' in_sum_expr ')'
- {
- $$= new (thd->mem_root) Item_sum_max(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | MAX_SYM '(' DISTINCT in_sum_expr ')'
- {
- $$= new (thd->mem_root) Item_sum_max(thd, $4);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | STD_SYM '(' in_sum_expr ')'
- {
- $$= new (thd->mem_root) Item_sum_std(thd, $3, 0);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | VARIANCE_SYM '(' in_sum_expr ')'
- {
- $$= new (thd->mem_root) Item_sum_variance(thd, $3, 0);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | STDDEV_SAMP_SYM '(' in_sum_expr ')'
- {
- $$= new (thd->mem_root) Item_sum_std(thd, $3, 1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | VAR_SAMP_SYM '(' in_sum_expr ')'
- {
- $$= new (thd->mem_root) Item_sum_variance(thd, $3, 1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | SUM_SYM '(' in_sum_expr ')'
- {
- $$= new (thd->mem_root) Item_sum_sum(thd, $3, FALSE);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | SUM_SYM '(' DISTINCT in_sum_expr ')'
- {
- $$= new (thd->mem_root) Item_sum_sum(thd, $4, TRUE);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | GROUP_CONCAT_SYM '(' opt_distinct
- { Select->in_sum_expr++; }
- expr_list opt_gorder_clause
- opt_gconcat_separator opt_glimit_clause
- ')'
- {
- SELECT_LEX *sel= Select;
- sel->in_sum_expr--;
- $$= new (thd->mem_root)
- Item_func_group_concat(thd, Lex->current_context(),
- $3, $5,
- sel->gorder_list, $7, $8,
- sel->select_limit,
- sel->offset_limit);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- sel->select_limit= NULL;
- sel->offset_limit= NULL;
- sel->explicit_limit= 0;
- $5->empty();
- sel->gorder_list.empty();
- }
- ;
-
-window_func_expr:
- window_func OVER_SYM window_name
- {
- $$= new (thd->mem_root) Item_window_func(thd, (Item_sum *) $1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- if (unlikely(Select->add_window_func((Item_window_func *) $$)))
- MYSQL_YYABORT;
- }
- |
- window_func OVER_SYM window_spec
- {
- LEX *lex= Lex;
- if (unlikely(Select->add_window_spec(thd, lex->win_ref,
- Select->group_list,
- Select->order_list,
- lex->win_frame)))
- MYSQL_YYABORT;
- $$= new (thd->mem_root) Item_window_func(thd, (Item_sum *) $1,
- thd->lex->win_spec);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- if (unlikely(Select->add_window_func((Item_window_func *) $$)))
- MYSQL_YYABORT;
- }
- ;
-
-window_func:
- simple_window_func
- |
- sum_expr
- {
- ((Item_sum *) $1)->mark_as_window_func_sum_expr();
- }
- |
- function_call_generic
- {
- Item* item = (Item*)$1;
- /* Only UDF aggregate here possible */
- if ((item == NULL) ||
- (item->type() != Item::SUM_FUNC_ITEM)
- || (((Item_sum *)item)->sum_func() != Item_sum::UDF_SUM_FUNC))
- {
- thd->parse_error();
- MYSQL_YYABORT;
- }
-
- ((Item_sum *) $1)->mark_as_window_func_sum_expr();
- }
- ;
-
-simple_window_func:
- ROW_NUMBER_SYM '(' ')'
- {
- $$= new (thd->mem_root) Item_sum_row_number(thd);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- |
- RANK_SYM '(' ')'
- {
- $$= new (thd->mem_root) Item_sum_rank(thd);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- |
- DENSE_RANK_SYM '(' ')'
- {
- $$= new (thd->mem_root) Item_sum_dense_rank(thd);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- |
- PERCENT_RANK_SYM '(' ')'
- {
- $$= new (thd->mem_root) Item_sum_percent_rank(thd);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- |
- CUME_DIST_SYM '(' ')'
- {
- $$= new (thd->mem_root) Item_sum_cume_dist(thd);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- |
- NTILE_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_sum_ntile(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- |
- FIRST_VALUE_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_sum_first_value(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- |
- LAST_VALUE '(' expr ')'
- {
- $$= new (thd->mem_root) Item_sum_last_value(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- |
- NTH_VALUE_SYM '(' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_sum_nth_value(thd, $3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- |
- LEAD_SYM '(' expr ')'
- {
- /* No second argument defaults to 1. */
- Item* item_offset= new (thd->mem_root) Item_uint(thd, 1);
- if (unlikely(item_offset == NULL))
- MYSQL_YYABORT;
- $$= new (thd->mem_root) Item_sum_lead(thd, $3, item_offset);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- |
- LEAD_SYM '(' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_sum_lead(thd, $3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- |
- LAG_SYM '(' expr ')'
- {
- /* No second argument defaults to 1. */
- Item* item_offset= new (thd->mem_root) Item_uint(thd, 1);
- if (unlikely(item_offset == NULL))
- MYSQL_YYABORT;
- $$= new (thd->mem_root) Item_sum_lag(thd, $3, item_offset);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- |
- LAG_SYM '(' expr ',' expr ')'
- {
- $$= new (thd->mem_root) Item_sum_lag(thd, $3, $5);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-
-
-inverse_distribution_function:
- percentile_function OVER_SYM
- '(' opt_window_partition_clause ')'
- {
- LEX *lex= Lex;
- if (unlikely(Select->add_window_spec(thd, lex->win_ref,
- Select->group_list,
- Select->order_list,
- NULL)))
- MYSQL_YYABORT;
- $$= new (thd->mem_root) Item_window_func(thd, (Item_sum *) $1,
- thd->lex->win_spec);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- if (unlikely(Select->add_window_func((Item_window_func *) $$)))
- MYSQL_YYABORT;
- }
- ;
-
-percentile_function:
- inverse_distribution_function_def WITHIN GROUP_SYM '('
- { Select->prepare_add_window_spec(thd); }
- order_by_single_element_list ')'
- {
- $$= $1;
- }
- | MEDIAN_SYM '(' expr ')'
- {
- Item *args= new (thd->mem_root) Item_decimal(thd, "0.5", 3,
- thd->charset());
- if (unlikely(args == NULL) || unlikely(thd->is_error()))
- MYSQL_YYABORT;
- Select->prepare_add_window_spec(thd);
- if (unlikely(add_order_to_list(thd, $3,FALSE)))
- MYSQL_YYABORT;
-
- $$= new (thd->mem_root) Item_sum_percentile_cont(thd, args);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-inverse_distribution_function_def:
- PERCENTILE_CONT_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_sum_percentile_cont(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | PERCENTILE_DISC_SYM '(' expr ')'
- {
- $$= new (thd->mem_root) Item_sum_percentile_disc(thd, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-order_by_single_element_list:
- ORDER_SYM BY order_ident order_dir
- {
- if (unlikely(add_order_to_list(thd, $3,(bool) $4)))
- MYSQL_YYABORT;
- }
- ;
-
-
-window_name:
- ident
- {
- $$= (LEX_CSTRING *) thd->memdup(&$1, sizeof(LEX_CSTRING));
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-variable:
- '@'
- {
- if (unlikely(! Lex->parsing_options.allows_variable))
- my_yyabort_error((ER_VIEW_SELECT_VARIABLE, MYF(0)));
- }
- variable_aux
- {
- $$= $3;
- }
- ;
-
-variable_aux:
- ident_or_text SET_VAR expr
- {
- Item_func_set_user_var *item;
- $$= item= new (thd->mem_root) Item_func_set_user_var(thd, &$1, $3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- LEX *lex= Lex;
- lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
- lex->set_var_list.push_back(item, thd->mem_root);
- }
- | ident_or_text
- {
- $$= new (thd->mem_root) Item_func_get_user_var(thd, &$1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- LEX *lex= Lex;
- lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
- }
- | '@' opt_var_ident_type ident_sysvar_name
- {
- if (unlikely(!($$= Lex->make_item_sysvar(thd, $2, &$3))))
- MYSQL_YYABORT;
- }
- | '@' opt_var_ident_type ident_sysvar_name '.' ident
- {
- if (unlikely(!($$= Lex->make_item_sysvar(thd, $2, &$3, &$5))))
- MYSQL_YYABORT;
- }
- ;
-
-opt_distinct:
- /* empty */ { $$ = 0; }
- | DISTINCT { $$ = 1; }
- ;
-
-opt_gconcat_separator:
- /* empty */
- {
- $$= new (thd->mem_root) String(",", 1, &my_charset_latin1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | SEPARATOR_SYM text_string { $$ = $2; }
- ;
-
-opt_gorder_clause:
- /* empty */
- | ORDER_SYM BY gorder_list
- ;
-
-gorder_list:
- gorder_list ',' order_ident order_dir
- {
- if (unlikely(add_gorder_to_list(thd, $3,(bool) $4)))
- MYSQL_YYABORT;
- }
- | order_ident order_dir
- {
- if (unlikely(add_gorder_to_list(thd, $1,(bool) $2)))
- MYSQL_YYABORT;
- }
- ;
-
-opt_glimit_clause:
- /* empty */ { $$ = 0; }
- | glimit_clause { $$ = 1; }
- ;
-
-glimit_clause_init:
- LIMIT{}
- ;
-
-glimit_clause:
- glimit_clause_init glimit_options
- {
- Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
- }
- ;
-
-glimit_options:
- limit_option
- {
- SELECT_LEX *sel= Select;
- sel->select_limit= $1;
- sel->offset_limit= 0;
- sel->explicit_limit= 1;
- }
- | limit_option ',' limit_option
- {
- SELECT_LEX *sel= Select;
- sel->select_limit= $3;
- sel->offset_limit= $1;
- sel->explicit_limit= 1;
- }
- | limit_option OFFSET_SYM limit_option
- {
- SELECT_LEX *sel= Select;
- sel->select_limit= $1;
- sel->offset_limit= $3;
- sel->explicit_limit= 1;
- }
- ;
-
-
-
-in_sum_expr:
- opt_all
- {
- LEX *lex= Lex;
- if (unlikely(lex->current_select->inc_in_sum_expr()))
- {
- thd->parse_error();
- MYSQL_YYABORT;
- }
- }
- expr
- {
- Select->in_sum_expr--;
- $$= $3;
- }
- ;
-
-cast_type:
- BINARY opt_field_length
- { $$.set(&type_handler_long_blob, $2); Lex->charset= &my_charset_bin; }
- | CHAR_SYM opt_field_length
- { Lex->charset= thd->variables.collation_connection; }
- opt_binary
- { $$.set(&type_handler_long_blob, $2); }
- | VARCHAR field_length
- { Lex->charset= thd->variables.collation_connection; }
- opt_binary
- { $$.set(&type_handler_long_blob, $2); }
- | VARCHAR2_ORACLE_SYM field_length
- { Lex->charset= thd->variables.collation_connection; }
- opt_binary
- { $$.set(&type_handler_long_blob, $2); }
- | NCHAR_SYM opt_field_length
- {
- Lex->charset= national_charset_info;
- $$.set(&type_handler_long_blob, $2, 0);
- }
- | cast_type_numeric { $$= $1; Lex->charset= NULL; }
- | cast_type_temporal { $$= $1; Lex->charset= NULL; }
- ;
-
-cast_type_numeric:
- INT_SYM { $$.set(&type_handler_longlong); }
- | SIGNED_SYM { $$.set(&type_handler_longlong); }
- | SIGNED_SYM INT_SYM { $$.set(&type_handler_longlong); }
- | UNSIGNED { $$.set(&type_handler_ulonglong); }
- | UNSIGNED INT_SYM { $$.set(&type_handler_ulonglong); }
- | DECIMAL_SYM float_options { $$.set(&type_handler_newdecimal, $2); }
- | FLOAT_SYM { $$.set(&type_handler_float); }
- | DOUBLE_SYM opt_precision { $$.set(&type_handler_double, $2); }
- ;
-
-cast_type_temporal:
- DATE_SYM { $$.set(&type_handler_newdate); }
- | TIME_SYM opt_field_length { $$.set(&type_handler_time2, 0, $2); }
- | DATETIME opt_field_length { $$.set(&type_handler_datetime2, 0, $2); }
- | INTERVAL_SYM DAY_SECOND_SYM field_length
- {
- $$.set(&type_handler_interval_DDhhmmssff, 0, $3);
- }
- ;
-
-opt_expr_list:
- /* empty */ { $$= NULL; }
- | expr_list { $$= $1;}
- ;
-
-expr_list:
- expr
- {
- if (unlikely(!($$= List<Item>::make(thd->mem_root, $1))))
- MYSQL_YYABORT;
- }
- | expr_list ',' expr
- {
- $1->push_back($3, thd->mem_root);
- $$= $1;
- }
- ;
-
-ident_list_arg:
- ident_list { $$= $1; }
- | '(' ident_list ')' { $$= $2; }
- ;
-
-ident_list:
- simple_ident
- {
- $$= new (thd->mem_root) List<Item>;
- if (unlikely($$ == NULL) ||
- unlikely($$->push_back($1, thd->mem_root)))
- MYSQL_YYABORT;
- }
- | ident_list ',' simple_ident
- {
- $1->push_back($3, thd->mem_root);
- $$= $1;
- }
- ;
-
-when_list:
- WHEN_SYM expr THEN_SYM expr
- {
- $$= new (thd->mem_root) List<Item>;
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- if (unlikely($$->push_back($2, thd->mem_root) ||
- $$->push_back($4, thd->mem_root)))
- MYSQL_YYABORT;
- }
- | when_list WHEN_SYM expr THEN_SYM expr
- {
- if (unlikely($1->push_back($3, thd->mem_root) ||
- $1->push_back($5, thd->mem_root)))
- MYSQL_YYABORT;
- $$= $1;
- }
- ;
-
-when_list_opt_else:
- when_list
- | when_list ELSE expr
- {
- if (unlikely($1->push_back($3, thd->mem_root)))
- MYSQL_YYABORT;
- $$= $1;
- }
- ;
-
-decode_when_list_oracle:
- expr ',' expr
- {
- $$= new (thd->mem_root) List<Item>;
- if (unlikely($$ == NULL) ||
- unlikely($$->push_back($1, thd->mem_root)) ||
- unlikely($$->push_back($3, thd->mem_root)))
- MYSQL_YYABORT;
-
- }
- | decode_when_list_oracle ',' expr
- {
- $$= $1;
- if (unlikely($$->push_back($3, thd->mem_root)))
- MYSQL_YYABORT;
- }
- ;
-
-
-/* Equivalent to <table reference> in the SQL:2003 standard. */
-/* Warning - may return NULL in case of incomplete SELECT */
-table_ref:
- table_factor { $$= $1; }
- | join_table
- {
- LEX *lex= Lex;
- if (unlikely(!($$= lex->current_select->nest_last_join(thd))))
- {
- thd->parse_error();
- MYSQL_YYABORT;
- }
- }
- ;
-
-join_table_list:
- derived_table_list { MYSQL_YYABORT_UNLESS($$=$1); }
- ;
-
-/*
- The ODBC escape syntax for Outer Join is: '{' OJ join_table '}'
- The parser does not define OJ as a token, any ident is accepted
- instead in $2 (ident). Also, all productions from table_ref can
- be escaped, not only join_table. Both syntax extensions are safe
- and are ignored.
-*/
-esc_table_ref:
- table_ref { $$=$1; }
- | '{' ident table_ref '}' { $$=$3; }
- ;
-
-/* Equivalent to <table reference list> in the SQL:2003 standard. */
-/* Warning - may return NULL in case of incomplete SELECT */
-derived_table_list:
- esc_table_ref
- {
- $$=$1;
- Select->add_joined_table($1);
- }
- | derived_table_list ',' esc_table_ref
- {
- MYSQL_YYABORT_UNLESS($1 && ($$=$3));
- Select->add_joined_table($3);
- }
- ;
-
-/*
- Notice that JOIN can be a left-associative operator in one context and
- a right-associative operator in another context (see the comment for
- st_select_lex::add_cross_joined_table).
-*/
-join_table:
- /* INNER JOIN variants */
- table_ref normal_join table_ref %prec CONDITIONLESS_JOIN
- {
- MYSQL_YYABORT_UNLESS($1 && ($$=$3));
- if (unlikely(Select->add_cross_joined_table($1, $3, $2)))
- MYSQL_YYABORT;
- }
- | table_ref normal_join table_ref
- ON
- {
- MYSQL_YYABORT_UNLESS($1 && $3);
- Select->add_joined_table($1);
- Select->add_joined_table($3);
- /* Change the current name resolution context to a local context. */
- if (unlikely(push_new_name_resolution_context(thd, $1, $3)))
- MYSQL_YYABORT;
- Select->parsing_place= IN_ON;
- }
- expr
- {
- $3->straight=$2;
- add_join_on(thd, $3, $6);
- $3->on_context= Lex->pop_context();
- Select->parsing_place= NO_MATTER;
- }
- | table_ref normal_join table_ref
- USING
- {
- MYSQL_YYABORT_UNLESS($1 && $3);
- Select->add_joined_table($1);
- Select->add_joined_table($3);
- }
- '(' using_list ')'
- {
- $3->straight=$2;
- add_join_natural($1,$3,$7,Select);
- $$=$3;
- }
- | table_ref NATURAL inner_join table_factor
- {
- MYSQL_YYABORT_UNLESS($1 && ($$=$4));
- Select->add_joined_table($1);
- Select->add_joined_table($4);
- $4->straight=$3;
- add_join_natural($1,$4,NULL,Select);
- }
-
- /* LEFT JOIN variants */
- | table_ref LEFT opt_outer JOIN_SYM table_ref
- ON
- {
- MYSQL_YYABORT_UNLESS($1 && $5);
- Select->add_joined_table($1);
- Select->add_joined_table($5);
- /* Change the current name resolution context to a local context. */
- if (unlikely(push_new_name_resolution_context(thd, $1, $5)))
- MYSQL_YYABORT;
- Select->parsing_place= IN_ON;
- }
- expr
- {
- add_join_on(thd, $5, $8);
- $5->on_context= Lex->pop_context();
- $5->outer_join|=JOIN_TYPE_LEFT;
- $$=$5;
- Select->parsing_place= NO_MATTER;
- }
- | table_ref LEFT opt_outer JOIN_SYM table_factor
- {
- MYSQL_YYABORT_UNLESS($1 && $5);
- Select->add_joined_table($1);
- Select->add_joined_table($5);
- }
- USING '(' using_list ')'
- {
- add_join_natural($1,$5,$9,Select);
- $5->outer_join|=JOIN_TYPE_LEFT;
- $$=$5;
- }
- | table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor
- {
- MYSQL_YYABORT_UNLESS($1 && $6);
- Select->add_joined_table($1);
- Select->add_joined_table($6);
- add_join_natural($1,$6,NULL,Select);
- $6->outer_join|=JOIN_TYPE_LEFT;
- $$=$6;
- }
-
- /* RIGHT JOIN variants */
- | table_ref RIGHT opt_outer JOIN_SYM table_ref
- ON
- {
- MYSQL_YYABORT_UNLESS($1 && $5);
- Select->add_joined_table($1);
- Select->add_joined_table($5);
- /* Change the current name resolution context to a local context. */
- if (unlikely(push_new_name_resolution_context(thd, $1, $5)))
- MYSQL_YYABORT;
- Select->parsing_place= IN_ON;
- }
- expr
- {
- LEX *lex= Lex;
- if (unlikely(!($$= lex->current_select->convert_right_join())))
- MYSQL_YYABORT;
- add_join_on(thd, $$, $8);
- $1->on_context= Lex->pop_context();
- Select->parsing_place= NO_MATTER;
- }
- | table_ref RIGHT opt_outer JOIN_SYM table_factor
- {
- MYSQL_YYABORT_UNLESS($1 && $5);
- Select->add_joined_table($1);
- Select->add_joined_table($5);
- }
- USING '(' using_list ')'
- {
- LEX *lex= Lex;
- if (unlikely(!($$= lex->current_select->convert_right_join())))
- MYSQL_YYABORT;
- add_join_natural($$,$5,$9,Select);
- }
- | table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor
- {
- MYSQL_YYABORT_UNLESS($1 && $6);
- Select->add_joined_table($1);
- Select->add_joined_table($6);
- add_join_natural($6,$1,NULL,Select);
- LEX *lex= Lex;
- if (unlikely(!($$= lex->current_select->convert_right_join())))
- MYSQL_YYABORT;
- }
- ;
-
-
-inner_join: /* $$ set if using STRAIGHT_JOIN, false otherwise */
- JOIN_SYM { $$ = 0; }
- | INNER_SYM JOIN_SYM { $$ = 0; }
- | STRAIGHT_JOIN { $$ = 1; }
- ;
-
-normal_join:
- inner_join { $$ = $1; }
- | CROSS JOIN_SYM { $$ = 0; }
- ;
-
-/*
- table PARTITION (list of partitions), reusing using_list instead of creating
- a new rule for partition_list.
-*/
-opt_use_partition:
- /* empty */ { $$= 0;}
- | use_partition
- ;
-
-use_partition:
- PARTITION_SYM '(' using_list ')' have_partitioning
- {
- $$= $3;
- Select->parsing_place= Select->save_parsing_place;
- Select->save_parsing_place= NO_MATTER;
- }
- ;
-
-table_factor:
- table_primary_ident_opt_parens { $$= $1; }
- | table_primary_derived_opt_parens { $$= $1; }
- | join_table_parens
- {
- $1->nested_join->nest_type= 0;
- $$= $1;
- }
- | table_reference_list_parens { $$= $1; }
- ;
-
-table_primary_ident_opt_parens:
- table_primary_ident { $$= $1; }
- | '(' table_primary_ident_opt_parens ')' { $$= $2; }
- ;
-
-table_primary_derived_opt_parens:
- table_primary_derived { $$= $1; }
- | '(' table_primary_derived_opt_parens ')' { $$= $2; }
- ;
-
-table_reference_list_parens:
- '(' table_reference_list_parens ')' { $$= $2; }
- | '(' nested_table_reference_list ')'
- {
- if (!($$= Select->end_nested_join(thd)))
- MYSQL_YYABORT;
- }
- ;
-
-nested_table_reference_list:
- table_ref ',' table_ref
- {
- if (Select->init_nested_join(thd))
- MYSQL_YYABORT;
- Select->add_joined_table($1);
- Select->add_joined_table($3);
- $$= $1->embedding;
- }
- | nested_table_reference_list ',' table_ref
- {
- Select->add_joined_table($3);
- $$= $1;
- }
- ;
-
-join_table_parens:
- '(' join_table_parens ')' { $$= $2; }
- | '(' join_table ')'
- {
- LEX *lex= Lex;
- if (!($$= lex->current_select->nest_last_join(thd)))
- {
- thd->parse_error();
- MYSQL_YYABORT;
- }
- }
- ;
-
-
-table_primary_ident:
- table_ident opt_use_partition opt_for_system_time_clause
- opt_table_alias_clause opt_key_definition
- {
- SELECT_LEX *sel= Select;
- sel->table_join_options= 0;
- if (!($$= Select->add_table_to_list(thd, $1, $4,
- Select->get_table_join_options(),
- YYPS->m_lock_type,
- YYPS->m_mdl_type,
- Select->pop_index_hints(),
- $2)))
- MYSQL_YYABORT;
- if ($3)
- $$->vers_conditions= Lex->vers_conditions;
- }
- ;
-
-table_primary_derived:
- subquery
- opt_for_system_time_clause table_alias_clause
- {
- if (!($$= Lex->parsed_derived_table($1->master_unit(), $2, $3)))
- MYSQL_YYABORT;
- }
- ;
- ;
-
-opt_outer:
- /* empty */ {}
- | OUTER {}
- ;
-
-index_hint_clause:
- /* empty */
- {
- $$= thd->variables.old_mode ? INDEX_HINT_MASK_JOIN : INDEX_HINT_MASK_ALL;
- }
- | FOR_SYM JOIN_SYM { $$= INDEX_HINT_MASK_JOIN; }
- | FOR_SYM ORDER_SYM BY { $$= INDEX_HINT_MASK_ORDER; }
- | FOR_SYM GROUP_SYM BY { $$= INDEX_HINT_MASK_GROUP; }
- ;
-
-index_hint_type:
- FORCE_SYM { $$= INDEX_HINT_FORCE; }
- | IGNORE_SYM { $$= INDEX_HINT_IGNORE; }
- ;
-
-index_hint_definition:
- index_hint_type key_or_index index_hint_clause
- {
- Select->set_index_hint_type($1, $3);
- }
- '(' key_usage_list ')'
- | USE_SYM key_or_index index_hint_clause
- {
- Select->set_index_hint_type(INDEX_HINT_USE, $3);
- }
- '(' opt_key_usage_list ')'
- ;
-
-index_hints_list:
- index_hint_definition
- | index_hints_list index_hint_definition
- ;
-
-opt_index_hints_list:
- /* empty */
- | { Select->alloc_index_hints(thd); } index_hints_list
- ;
-
-opt_key_definition:
- { Select->clear_index_hints(); }
- opt_index_hints_list
- ;
-
-opt_key_usage_list:
- /* empty */ { Select->add_index_hint(thd, NULL, 0); }
- | key_usage_list {}
- ;
-
-key_usage_element:
- ident
- { Select->add_index_hint(thd, $1.str, $1.length); }
- | PRIMARY_SYM
- { Select->add_index_hint(thd, "PRIMARY", 7); }
- ;
-
-key_usage_list:
- key_usage_element
- | key_usage_list ',' key_usage_element
- ;
-
-using_list:
- ident
- {
- if (unlikely(!($$= new (thd->mem_root) List<String>)))
- MYSQL_YYABORT;
- String *s= new (thd->mem_root) String((const char *) $1.str,
- $1.length,
- system_charset_info);
- if (unlikely(unlikely(s == NULL)))
- MYSQL_YYABORT;
- $$->push_back(s, thd->mem_root);
- }
- | using_list ',' ident
- {
- String *s= new (thd->mem_root) String((const char *) $3.str,
- $3.length,
- system_charset_info);
- if (unlikely(unlikely(s == NULL)))
- MYSQL_YYABORT;
- if (unlikely($1->push_back(s, thd->mem_root)))
- MYSQL_YYABORT;
- $$= $1;
- }
- ;
-
-interval:
- interval_time_stamp {}
- | DAY_HOUR_SYM { $$=INTERVAL_DAY_HOUR; }
- | DAY_MICROSECOND_SYM { $$=INTERVAL_DAY_MICROSECOND; }
- | DAY_MINUTE_SYM { $$=INTERVAL_DAY_MINUTE; }
- | DAY_SECOND_SYM { $$=INTERVAL_DAY_SECOND; }
- | HOUR_MICROSECOND_SYM { $$=INTERVAL_HOUR_MICROSECOND; }
- | HOUR_MINUTE_SYM { $$=INTERVAL_HOUR_MINUTE; }
- | HOUR_SECOND_SYM { $$=INTERVAL_HOUR_SECOND; }
- | MINUTE_MICROSECOND_SYM { $$=INTERVAL_MINUTE_MICROSECOND; }
- | MINUTE_SECOND_SYM { $$=INTERVAL_MINUTE_SECOND; }
- | SECOND_MICROSECOND_SYM { $$=INTERVAL_SECOND_MICROSECOND; }
- | YEAR_MONTH_SYM { $$=INTERVAL_YEAR_MONTH; }
- ;
-
-interval_time_stamp:
- DAY_SYM { $$=INTERVAL_DAY; }
- | WEEK_SYM { $$=INTERVAL_WEEK; }
- | HOUR_SYM { $$=INTERVAL_HOUR; }
- | MINUTE_SYM { $$=INTERVAL_MINUTE; }
- | MONTH_SYM { $$=INTERVAL_MONTH; }
- | QUARTER_SYM { $$=INTERVAL_QUARTER; }
- | SECOND_SYM { $$=INTERVAL_SECOND; }
- | MICROSECOND_SYM { $$=INTERVAL_MICROSECOND; }
- | YEAR_SYM { $$=INTERVAL_YEAR; }
- ;
-
-date_time_type:
- DATE_SYM {$$=MYSQL_TIMESTAMP_DATE;}
- | TIME_SYM {$$=MYSQL_TIMESTAMP_TIME;}
- | DATETIME {$$=MYSQL_TIMESTAMP_DATETIME;}
- | TIMESTAMP {$$=MYSQL_TIMESTAMP_DATETIME;}
- ;
-
-table_alias:
- /* empty */
- | AS
- | '='
- ;
-
-opt_table_alias_clause:
- /* empty */ { $$=0; }
- | table_alias_clause { $$= $1; }
- ;
-
-table_alias_clause:
- table_alias ident_table_alias
- {
- $$= (LEX_CSTRING*) thd->memdup(&$2,sizeof(LEX_STRING));
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-opt_all:
- /* empty */
- | ALL
- ;
-
-opt_where_clause:
- /* empty */ { Select->where= 0; }
- | WHERE
- {
- Select->parsing_place= IN_WHERE;
- }
- expr
- {
- SELECT_LEX *select= Select;
- select->where= normalize_cond(thd, $3);
- select->parsing_place= NO_MATTER;
- if ($3)
- $3->top_level_item();
- }
- ;
-
-opt_having_clause:
- /* empty */
- | HAVING
- {
- Select->parsing_place= IN_HAVING;
- }
- expr
- {
- SELECT_LEX *sel= Select;
- sel->having= normalize_cond(thd, $3);
- sel->parsing_place= NO_MATTER;
- if ($3)
- $3->top_level_item();
- }
- ;
-
-opt_escape:
- ESCAPE_SYM simple_expr
- {
- Lex->escape_used= TRUE;
- $$= $2;
- }
- | /* empty */ %prec PREC_BELOW_ESCAPE
- {
- Lex->escape_used= FALSE;
- $$= ((thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) ?
- new (thd->mem_root) Item_string_ascii(thd, "", 0) :
- new (thd->mem_root) Item_string_ascii(thd, "\\", 1));
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-/*
- group by statement in select
-*/
-
-opt_group_clause:
- /* empty */
- | GROUP_SYM BY group_list olap_opt
- ;
-
-group_list:
- group_list ',' order_ident order_dir
- {
- if (unlikely(add_group_to_list(thd, $3,(bool) $4)))
- MYSQL_YYABORT;
- }
- | order_ident order_dir
- {
- if (unlikely(add_group_to_list(thd, $1,(bool) $2)))
- MYSQL_YYABORT;
- }
- ;
-
-olap_opt:
- /* empty */ {}
- | WITH_CUBE_SYM
- {
- /*
- 'WITH CUBE' is reserved in the MySQL syntax, but not implemented,
- and cause LALR(2) conflicts.
- This syntax is not standard.
- MySQL syntax: GROUP BY col1, col2, col3 WITH CUBE
- SQL-2003: GROUP BY ... CUBE(col1, col2, col3)
- */
- LEX *lex=Lex;
- if (unlikely(lex->current_select->get_linkage() == GLOBAL_OPTIONS_TYPE))
- my_yyabort_error((ER_WRONG_USAGE, MYF(0), "WITH CUBE",
- "global union parameters"));
- lex->current_select->olap= CUBE_TYPE;
-
- my_yyabort_error((ER_NOT_SUPPORTED_YET, MYF(0), "CUBE"));
- }
- | WITH_ROLLUP_SYM
- {
- /*
- 'WITH ROLLUP' is needed for backward compatibility,
- and cause LALR(2) conflicts.
- This syntax is not standard.
- MySQL syntax: GROUP BY col1, col2, col3 WITH ROLLUP
- SQL-2003: GROUP BY ... ROLLUP(col1, col2, col3)
- */
- LEX *lex= Lex;
- if (unlikely(lex->current_select->get_linkage() == GLOBAL_OPTIONS_TYPE))
- my_yyabort_error((ER_WRONG_USAGE, MYF(0), "WITH ROLLUP",
- "global union parameters"));
- lex->current_select->olap= ROLLUP_TYPE;
- }
- ;
-
-/*
- optional window clause in select
-*/
-
-opt_window_clause:
- /* empty */
- {}
- | WINDOW_SYM
- window_def_list
- {}
- ;
-
-window_def_list:
- window_def_list ',' window_def
- | window_def
- ;
-
-window_def:
- window_name AS window_spec
- {
- LEX *lex= Lex;
- if (unlikely(Select->add_window_def(thd, $1, lex->win_ref,
- Select->group_list,
- Select->order_list,
- lex->win_frame)))
- MYSQL_YYABORT;
- }
- ;
-
-window_spec:
- '('
- { Select->prepare_add_window_spec(thd); }
- opt_window_ref opt_window_partition_clause
- opt_window_order_clause opt_window_frame_clause
- ')'
- { }
- ;
-
-opt_window_ref:
- /* empty */ {}
- | ident
- {
- thd->lex->win_ref= (LEX_CSTRING *) thd->memdup(&$1, sizeof(LEX_CSTRING));
- if (unlikely(thd->lex->win_ref == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-opt_window_partition_clause:
- /* empty */ { }
- | PARTITION_SYM BY group_list
- ;
-
-opt_window_order_clause:
- /* empty */ { }
- | ORDER_SYM BY order_list { Select->order_list= *($3); }
- ;
-
-opt_window_frame_clause:
- /* empty */ {}
- | window_frame_units window_frame_extent opt_window_frame_exclusion
- {
- LEX *lex= Lex;
- lex->win_frame=
- new (thd->mem_root) Window_frame($1,
- lex->frame_top_bound,
- lex->frame_bottom_bound,
- $3);
- if (unlikely(lex->win_frame == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-window_frame_units:
- ROWS_SYM { $$= Window_frame::UNITS_ROWS; }
- | RANGE_SYM { $$= Window_frame::UNITS_RANGE; }
- ;
-
-window_frame_extent:
- window_frame_start
- {
- LEX *lex= Lex;
- lex->frame_top_bound= $1;
- lex->frame_bottom_bound=
- new (thd->mem_root)
- Window_frame_bound(Window_frame_bound::CURRENT, NULL);
- if (unlikely(lex->frame_bottom_bound == NULL))
- MYSQL_YYABORT;
- }
- | BETWEEN_SYM window_frame_bound AND_SYM window_frame_bound
- {
- LEX *lex= Lex;
- lex->frame_top_bound= $2;
- lex->frame_bottom_bound= $4;
- }
- ;
-
-window_frame_start:
- UNBOUNDED_SYM PRECEDING_SYM
- {
- $$= new (thd->mem_root)
- Window_frame_bound(Window_frame_bound::PRECEDING, NULL);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | CURRENT_SYM ROW_SYM
- {
- $$= new (thd->mem_root)
- Window_frame_bound(Window_frame_bound::CURRENT, NULL);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | literal PRECEDING_SYM
- {
- $$= new (thd->mem_root)
- Window_frame_bound(Window_frame_bound::PRECEDING, $1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-window_frame_bound:
- window_frame_start { $$= $1; }
- | UNBOUNDED_SYM FOLLOWING_SYM
- {
- $$= new (thd->mem_root)
- Window_frame_bound(Window_frame_bound::FOLLOWING, NULL);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | literal FOLLOWING_SYM
- {
- $$= new (thd->mem_root)
- Window_frame_bound(Window_frame_bound::FOLLOWING, $1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-opt_window_frame_exclusion:
- /* empty */ { $$= Window_frame::EXCL_NONE; }
- | EXCLUDE_SYM CURRENT_SYM ROW_SYM
- { $$= Window_frame::EXCL_CURRENT_ROW; }
- | EXCLUDE_SYM GROUP_SYM
- { $$= Window_frame::EXCL_GROUP; }
- | EXCLUDE_SYM TIES_SYM
- { $$= Window_frame::EXCL_TIES; }
- | EXCLUDE_SYM NO_SYM OTHERS_MARIADB_SYM
- { $$= Window_frame::EXCL_NONE; }
- | EXCLUDE_SYM NO_SYM OTHERS_ORACLE_SYM
- { $$= Window_frame::EXCL_NONE; }
- ;
-
-/*
- Order by statement in ALTER TABLE
-*/
-
-alter_order_clause:
- ORDER_SYM BY alter_order_list
- ;
-
-alter_order_list:
- alter_order_list ',' alter_order_item
- | alter_order_item
- ;
-
-alter_order_item:
- simple_ident_nospvar order_dir
- {
- bool ascending= ($2 == 1) ? true : false;
- if (unlikely(add_order_to_list(thd, $1, ascending)))
- MYSQL_YYABORT;
- }
- ;
-
-/*
- Order by statement in select
-*/
-
-opt_order_clause:
- /* empty */
- { $$= NULL; }
- | order_clause
- { $$= $1; }
- ;
-
-order_clause:
- ORDER_SYM BY
- {
- thd->where= "ORDER clause";
- }
- order_list
- {
- $$= $4;
- }
- ;
-
-order_list:
- order_list ',' order_ident order_dir
- {
- $$= $1;
- if (add_to_list(thd, *$$, $3,(bool) $4))
- MYSQL_YYABORT;
- }
- | order_ident order_dir
- {
- $$= new (thd->mem_root) SQL_I_List<ORDER>();
- if (add_to_list(thd, *$$, $1, (bool) $2))
- MYSQL_YYABORT;
- }
- ;
-
-order_dir:
- /* empty */ { $$ = 1; }
- | ASC { $$ =1; }
- | DESC { $$ =0; }
- ;
-
-opt_limit_clause:
- /* empty */
- { $$.empty(); }
- | limit_clause
- { $$= $1; }
- ;
-
-limit_clause:
- LIMIT limit_options
- {
- $$= $2;
- if (!$$.select_limit->basic_const_item() ||
- $$.select_limit->val_int() > 0)
- Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
- }
- | LIMIT limit_options
- ROWS_SYM EXAMINED_SYM limit_rows_option
- {
- $$= $2;
- Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
- }
- | LIMIT ROWS_SYM EXAMINED_SYM limit_rows_option
- {
- $$.select_limit= 0;
- $$.offset_limit= 0;
- $$.explicit_limit= 1;
- Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
- }
- ;
-
-opt_global_limit_clause:
- opt_limit_clause
- {
- Select->explicit_limit= $1.explicit_limit;
- Select->select_limit= $1.select_limit;
- Select->offset_limit= $1.offset_limit;
- }
- ;
-
-limit_options:
- limit_option
- {
- $$.select_limit= $1;
- $$.offset_limit= 0;
- $$.explicit_limit= 1;
- }
- | limit_option ',' limit_option
- {
- $$.select_limit= $3;
- $$.offset_limit= $1;
- $$.explicit_limit= 1;
- }
- | limit_option OFFSET_SYM limit_option
- {
- $$.select_limit= $1;
- $$.offset_limit= $3;
- $$.explicit_limit= 1;
- }
- ;
-
-limit_option:
- ident_cli
- {
- if (unlikely(!($$= Lex->create_item_limit(thd, &$1))))
- MYSQL_YYABORT;
- }
- | ident_cli '.' ident_cli
- {
- if (unlikely(!($$= Lex->create_item_limit(thd, &$1, &$3))))
- MYSQL_YYABORT;
- }
- | param_marker
- {
- $1->limit_clause_param= TRUE;
- }
- | ULONGLONG_NUM
- {
- $$= new (thd->mem_root) Item_uint(thd, $1.str, $1.length);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | LONG_NUM
- {
- $$= new (thd->mem_root) Item_uint(thd, $1.str, $1.length);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | NUM
- {
- $$= new (thd->mem_root) Item_uint(thd, $1.str, $1.length);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-limit_rows_option:
- limit_option
- {
- LEX *lex=Lex;
- lex->limit_rows_examined= $1;
- }
- ;
-
-delete_limit_clause:
- /* empty */
- {
- LEX *lex=Lex;
- lex->current_select->select_limit= 0;
- }
- | LIMIT limit_option
- {
- SELECT_LEX *sel= Select;
- sel->select_limit= $2;
- Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
- sel->explicit_limit= 1;
- }
- | LIMIT ROWS_SYM EXAMINED_SYM { thd->parse_error(); MYSQL_YYABORT; }
- | LIMIT limit_option ROWS_SYM EXAMINED_SYM { thd->parse_error(); MYSQL_YYABORT; }
- ;
-
-order_limit_lock:
- order_or_limit
- {
- $$= $1;
- $$->lock.empty();
- }
- | order_or_limit select_lock_type
- {
- $$= $1;
- $$->lock= $2;
- }
- | select_lock_type
- {
- $$= new(thd->mem_root) Lex_order_limit_lock;
- if (!$$)
- YYABORT;
- $$->order_list= NULL;
- $$->limit.empty();
- $$->lock= $1;
- }
- ;
-opt_order_limit_lock:
- /* empty */
- {
- Lex->pop_select();
- $$= NULL;
- }
- | order_limit_lock { $$= $1; }
- ;
-
-query_expression_tail:
- order_limit_lock
- ;
-
-opt_query_expression_tail:
- opt_order_limit_lock
- ;
-
-opt_procedure_or_into:
- /* empty */
- {
- $$.empty();
- }
- | procedure_clause opt_select_lock_type
- {
- $$= $2;
- }
- | into opt_select_lock_type
- {
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WARN_DEPRECATED_SYNTAX,
- ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX),
- "<select expression> INTO <destination>;",
- "'SELECT <select list> INTO <destination>"
- " FROM...'");
- $$= $2;
- }
- ;
-
-
-order_or_limit:
- order_clause opt_limit_clause
- {
- $$= new(thd->mem_root) Lex_order_limit_lock;
- if (!$$)
- YYABORT;
- $$->order_list= $1;
- $$->limit= $2;
- }
- | limit_clause
- {
- Lex_order_limit_lock *op= $$= new(thd->mem_root) Lex_order_limit_lock;
- if (!$$)
- YYABORT;
- op->order_list= NULL;
- op->limit= $1;
- $$->order_list= NULL;
- $$->limit= $1;
- }
- ;
-
-
-opt_plus:
- /* empty */
- | '+'
- ;
-
-int_num:
- opt_plus NUM { int error; $$= (int) my_strtoll10($2.str, (char**) 0, &error); }
- | '-' NUM { int error; $$= -(int) my_strtoll10($2.str, (char**) 0, &error); }
- ;
-
-ulong_num:
- opt_plus NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); }
- | HEX_NUM { $$= (ulong) strtol($1.str, (char**) 0, 16); }
- | opt_plus LONG_NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); }
- | opt_plus ULONGLONG_NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); }
- | opt_plus DECIMAL_NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); }
- | opt_plus FLOAT_NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); }
- ;
-
-real_ulong_num:
- NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
- | HEX_NUM { $$= (ulong) strtol($1.str, (char**) 0, 16); }
- | LONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
- | ULONGLONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
- | dec_num_error { MYSQL_YYABORT; }
- ;
-
-longlong_num:
- opt_plus NUM { int error; $$= (longlong) my_strtoll10($2.str, (char**) 0, &error); }
- | LONG_NUM { int error; $$= (longlong) my_strtoll10($1.str, (char**) 0, &error); }
- | '-' NUM { int error; $$= -(longlong) my_strtoll10($2.str, (char**) 0, &error); }
- | '-' LONG_NUM { int error; $$= -(longlong) my_strtoll10($2.str, (char**) 0, &error); }
- ;
-
-ulonglong_num:
- opt_plus NUM { int error; $$= (ulonglong) my_strtoll10($2.str, (char**) 0, &error); }
- | opt_plus ULONGLONG_NUM { int error; $$= (ulonglong) my_strtoll10($2.str, (char**) 0, &error); }
- | opt_plus LONG_NUM { int error; $$= (ulonglong) my_strtoll10($2.str, (char**) 0, &error); }
- | opt_plus DECIMAL_NUM { int error; $$= (ulonglong) my_strtoll10($2.str, (char**) 0, &error); }
- | opt_plus FLOAT_NUM { int error; $$= (ulonglong) my_strtoll10($2.str, (char**) 0, &error); }
- ;
-
-real_ulonglong_num:
- NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
- | ULONGLONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
- | HEX_NUM { $$= strtoull($1.str, (char**) 0, 16); }
- | LONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
- | dec_num_error { MYSQL_YYABORT; }
- ;
-
-dec_num_error:
- dec_num
- { thd->parse_error(ER_ONLY_INTEGERS_ALLOWED); }
- ;
-
-dec_num:
- DECIMAL_NUM
- | FLOAT_NUM
- ;
-
-choice:
- ulong_num { $$= $1 != 0 ? HA_CHOICE_YES : HA_CHOICE_NO; }
- | DEFAULT { $$= HA_CHOICE_UNDEF; }
- ;
-
-bool:
- ulong_num { $$= $1 != 0; }
- | TRUE_SYM { $$= 1; }
- | FALSE_SYM { $$= 0; }
- ;
-
-procedure_clause:
- PROCEDURE_SYM ident /* Procedure name */
- {
- LEX *lex=Lex;
-
- lex->proc_list.elements=0;
- lex->proc_list.first=0;
- lex->proc_list.next= &lex->proc_list.first;
- Item_field *item= new (thd->mem_root)
- Item_field(thd, &lex->current_select->context,
- NULL, NULL, &$2);
- if (unlikely(item == NULL))
- MYSQL_YYABORT;
- if (unlikely(add_proc_to_list(thd, item)))
- MYSQL_YYABORT;
- Lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
-
- /*
- PROCEDURE CLAUSE cannot handle subquery as one of its parameter,
- so disallow any subqueries further.
- Alow subqueries back once the parameters are reduced.
- */
- Lex->clause_that_disallows_subselect= "PROCEDURE";
- Select->options|= OPTION_PROCEDURE_CLAUSE;
- }
- '(' procedure_list ')'
- {
- /* Subqueries are allowed from now.*/
- Lex->clause_that_disallows_subselect= NULL;
- }
- ;
-
-procedure_list:
- /* empty */ {}
- | procedure_list2 {}
- ;
-
-procedure_list2:
- procedure_list2 ',' procedure_item
- | procedure_item
- ;
-
-procedure_item:
- remember_name expr remember_end
- {
- if (unlikely(add_proc_to_list(thd, $2)))
- MYSQL_YYABORT;
- if (!$2->name.str || $2->name.str == item_empty_name)
- $2->set_name(thd, $1, (uint) ($3 - $1), thd->charset());
- }
- ;
-
-select_var_list_init:
- {
- LEX *lex=Lex;
- if (!lex->describe &&
- unlikely((!(lex->result= new (thd->mem_root)
- select_dumpvar(thd)))))
- MYSQL_YYABORT;
- }
- select_var_list
- {}
- ;
-
-select_var_list:
- select_var_list ',' select_var_ident
- | select_var_ident {}
- ;
-
-select_var_ident: select_outvar
- {
- if (Lex->result)
- {
- if (unlikely($1 == NULL))
- MYSQL_YYABORT;
- ((select_dumpvar *)Lex->result)->var_list.push_back($1, thd->mem_root);
- }
- else
- {
- /*
- The parser won't create select_result instance only
- if it's an EXPLAIN.
- */
- DBUG_ASSERT(Lex->describe);
- }
- }
- ;
-
-select_outvar:
- '@' ident_or_text
- {
- $$ = Lex->result ? new (thd->mem_root) my_var_user(&$2) : NULL;
- }
- | ident_or_text
- {
- if (unlikely(!($$= Lex->create_outvar(thd, &$1)) && Lex->result))
- MYSQL_YYABORT;
- }
- | ident '.' ident
- {
- if (unlikely(!($$= Lex->create_outvar(thd, &$1, &$3)) && Lex->result))
- MYSQL_YYABORT;
- }
- ;
-
-into:
- INTO into_destination
- {}
- ;
-
-into_destination:
- OUTFILE TEXT_STRING_filesystem
- {
- LEX *lex= Lex;
- lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
- if (unlikely(!(lex->exchange=
- new (thd->mem_root) sql_exchange($2.str, 0))) ||
- unlikely(!(lex->result=
- new (thd->mem_root)
- select_export(thd, lex->exchange))))
- MYSQL_YYABORT;
- }
- opt_load_data_charset
- { Lex->exchange->cs= $4; }
- opt_field_term opt_line_term
- | DUMPFILE TEXT_STRING_filesystem
- {
- LEX *lex=Lex;
- if (!lex->describe)
- {
- lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
- if (unlikely(!(lex->exchange=
- new (thd->mem_root) sql_exchange($2.str,1))))
- MYSQL_YYABORT;
- if (unlikely(!(lex->result=
- new (thd->mem_root)
- select_dump(thd, lex->exchange))))
- MYSQL_YYABORT;
- }
- }
- | select_var_list_init
- {
- Lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
- }
- ;
-
-/*
- DO statement
-*/
-
-do:
- DO_SYM
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_DO;
- if (lex->main_select_push())
- MYSQL_YYABORT;
- mysql_init_select(lex);
- }
- expr_list
- {
- Lex->insert_list= $3;
- Lex->pop_select(); //main select
- }
- ;
-
-/*
- Drop : delete tables or index or user
-*/
-
-drop:
- DROP opt_temporary table_or_tables opt_if_exists
- {
- LEX *lex=Lex;
- lex->set_command(SQLCOM_DROP_TABLE, $2, $4);
- YYPS->m_lock_type= TL_UNLOCK;
- YYPS->m_mdl_type= MDL_EXCLUSIVE;
- }
- table_list opt_lock_wait_timeout opt_restrict
- {}
- | DROP INDEX_SYM
- {
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- }
- opt_if_exists_table_element ident ON table_ident opt_lock_wait_timeout
- {
- LEX *lex=Lex;
- Alter_drop *ad= (new (thd->mem_root)
- Alter_drop(Alter_drop::KEY, $5.str, $4));
- if (unlikely(ad == NULL))
- MYSQL_YYABORT;
- lex->sql_command= SQLCOM_DROP_INDEX;
- lex->alter_info.reset();
- lex->alter_info.flags= ALTER_DROP_INDEX;
- lex->alter_info.drop_list.push_back(ad, thd->mem_root);
- if (unlikely(!lex->current_select->
- add_table_to_list(thd, $7, NULL, TL_OPTION_UPDATING,
- TL_READ_NO_INSERT,
- MDL_SHARED_UPGRADABLE)))
- MYSQL_YYABORT;
- Lex->pop_select(); //main select
- }
- | DROP DATABASE opt_if_exists ident
- {
- LEX *lex=Lex;
- lex->set_command(SQLCOM_DROP_DB, $3);
- lex->name= $4;
- }
- | DROP PACKAGE_ORACLE_SYM opt_if_exists sp_name
- {
- LEX *lex= Lex;
- lex->set_command(SQLCOM_DROP_PACKAGE, $3);
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PACKAGE"));
- lex->spname= $4;
- }
- | DROP PACKAGE_ORACLE_SYM BODY_ORACLE_SYM opt_if_exists sp_name
- {
- LEX *lex= Lex;
- lex->set_command(SQLCOM_DROP_PACKAGE_BODY, $4);
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PACKAGE BODY"));
- lex->spname= $5;
- }
- | DROP FUNCTION_SYM opt_if_exists ident '.' ident
- {
- LEX *lex= thd->lex;
- sp_name *spname;
- if (unlikely($4.str && check_db_name((LEX_STRING*) &$4)))
- my_yyabort_error((ER_WRONG_DB_NAME, MYF(0), $4.str));
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"));
- lex->set_command(SQLCOM_DROP_FUNCTION, $3);
- spname= new (thd->mem_root) sp_name(&$4, &$6, true);
- if (unlikely(spname == NULL))
- MYSQL_YYABORT;
- lex->spname= spname;
- }
- | DROP FUNCTION_SYM opt_if_exists ident
- {
- LEX *lex= thd->lex;
- LEX_CSTRING db= {0, 0};
- sp_name *spname;
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"));
- if (thd->db.str && unlikely(lex->copy_db_to(&db)))
- MYSQL_YYABORT;
- lex->set_command(SQLCOM_DROP_FUNCTION, $3);
- spname= new (thd->mem_root) sp_name(&db, &$4, false);
- if (unlikely(spname == NULL))
- MYSQL_YYABORT;
- lex->spname= spname;
- }
- | DROP PROCEDURE_SYM opt_if_exists sp_name
- {
- LEX *lex=Lex;
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE"));
- lex->set_command(SQLCOM_DROP_PROCEDURE, $3);
- lex->spname= $4;
- }
- | DROP USER_SYM opt_if_exists clear_privileges user_list
- {
- Lex->set_command(SQLCOM_DROP_USER, $3);
- }
- | DROP ROLE_SYM opt_if_exists clear_privileges role_list
- {
- Lex->set_command(SQLCOM_DROP_ROLE, $3);
- }
- | DROP VIEW_SYM opt_if_exists
- {
- LEX *lex= Lex;
- lex->set_command(SQLCOM_DROP_VIEW, $3);
- YYPS->m_lock_type= TL_UNLOCK;
- YYPS->m_mdl_type= MDL_EXCLUSIVE;
- }
- table_list opt_restrict
- {}
- | DROP EVENT_SYM opt_if_exists sp_name
- {
- Lex->spname= $4;
- Lex->set_command(SQLCOM_DROP_EVENT, $3);
- }
- | DROP TRIGGER_SYM opt_if_exists sp_name
- {
- LEX *lex= Lex;
- lex->set_command(SQLCOM_DROP_TRIGGER, $3);
- lex->spname= $4;
- }
- | DROP TABLESPACE tablespace_name opt_ts_engine opt_ts_wait
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_cmd_type= DROP_TABLESPACE;
- }
- | DROP LOGFILE_SYM GROUP_SYM logfile_group_name opt_ts_engine opt_ts_wait
- {
- LEX *lex= Lex;
- lex->alter_tablespace_info->ts_cmd_type= DROP_LOGFILE_GROUP;
- }
- | DROP SERVER_SYM opt_if_exists ident_or_text
- {
- Lex->set_command(SQLCOM_DROP_SERVER, $3);
- Lex->server_options.reset($4);
- }
- | DROP opt_temporary SEQUENCE_SYM opt_if_exists
-
- {
- LEX *lex= Lex;
- lex->set_command(SQLCOM_DROP_SEQUENCE, $2, $4);
- lex->table_type= TABLE_TYPE_SEQUENCE;
- YYPS->m_lock_type= TL_UNLOCK;
- YYPS->m_mdl_type= MDL_EXCLUSIVE;
- }
- table_list
- {}
- ;
-
-table_list:
- table_name
- | table_list ',' table_name
- ;
-
-table_name:
- table_ident
- {
- if (!thd->lex->current_select_or_default()->
- add_table_to_list(thd, $1, NULL,
- TL_OPTION_UPDATING,
- YYPS->m_lock_type,
- YYPS->m_mdl_type))
- MYSQL_YYABORT;
- }
- ;
-
-table_name_with_opt_use_partition:
- table_ident opt_use_partition
- {
- if (unlikely(!Select->add_table_to_list(thd, $1, NULL,
- TL_OPTION_UPDATING,
- YYPS->m_lock_type,
- YYPS->m_mdl_type,
- NULL,
- $2)))
- MYSQL_YYABORT;
- }
- ;
-
-table_alias_ref_list:
- table_alias_ref
- | table_alias_ref_list ',' table_alias_ref
- ;
-
-table_alias_ref:
- table_ident_opt_wild
- {
- if (unlikely(!Select->
- add_table_to_list(thd, $1, NULL,
- (TL_OPTION_UPDATING |
- TL_OPTION_ALIAS),
- YYPS->m_lock_type,
- YYPS->m_mdl_type)))
- MYSQL_YYABORT;
- }
- ;
-
-opt_if_exists_table_element:
- /* empty */
- {
- Lex->check_exists= FALSE;
- $$= 0;
- }
- | IF_SYM EXISTS
- {
- Lex->check_exists= TRUE;
- $$= 1;
- }
- ;
-
-opt_if_exists:
- /* empty */
- {
- $$.set(DDL_options_st::OPT_NONE);
- }
- | IF_SYM EXISTS
- {
- $$.set(DDL_options_st::OPT_IF_EXISTS);
- }
- ;
-
-opt_temporary:
- /* empty */ { $$= 0; }
- | TEMPORARY { $$= HA_LEX_CREATE_TMP_TABLE; }
- ;
-/*
-** Insert : add new data to table
-*/
-
-insert:
- INSERT
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_INSERT;
- lex->duplicates= DUP_ERROR;
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- mysql_init_select(lex);
- lex->current_select->parsing_place= BEFORE_OPT_LIST;
- }
- insert_lock_option
- opt_ignore insert2
- {
- Select->set_lock_for_tables($3, true);
- Lex->current_select= Lex->first_select_lex();
- }
- insert_field_spec opt_insert_update
- {
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- Lex->mark_first_table_as_inserting();
- }
- ;
-
-replace:
- REPLACE
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_REPLACE;
- lex->duplicates= DUP_REPLACE;
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- mysql_init_select(lex);
- lex->current_select->parsing_place= BEFORE_OPT_LIST;
- }
- replace_lock_option insert2
- {
- Select->set_lock_for_tables($3, true);
- Lex->current_select= Lex->first_select_lex();
- }
- insert_field_spec
- {
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- Lex->mark_first_table_as_inserting();
- }
- ;
-
-insert_lock_option:
- /* empty */
- {
- /*
- If it is SP we do not allow insert optimisation when result of
- insert visible only after the table unlocking but everyone can
- read table.
- */
- $$= (Lex->sphead ? TL_WRITE_DEFAULT : TL_WRITE_CONCURRENT_INSERT);
- }
- | LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; }
- | DELAYED_SYM
- {
- // QQ: why was +1?
- Lex->keyword_delayed_begin_offset= (uint)($1.pos() - thd->query());
- Lex->keyword_delayed_end_offset= (uint)($1.end() - thd->query());
- $$= TL_WRITE_DELAYED;
- }
- | HIGH_PRIORITY { $$= TL_WRITE; }
- ;
-
-replace_lock_option:
- opt_low_priority { $$= $1; }
- | DELAYED_SYM
- {
- Lex->keyword_delayed_begin_offset= (uint)($1.pos() - thd->query());
- Lex->keyword_delayed_end_offset= (uint)($1.end() - thd->query());
- $$= TL_WRITE_DELAYED;
- }
- ;
-
-insert2:
- INTO insert_table {}
- | insert_table {}
- ;
-
-insert_table:
- {
- Select->save_parsing_place= Select->parsing_place;
- }
- table_name_with_opt_use_partition
- {
- LEX *lex=Lex;
- //lex->field_list.empty();
- lex->many_values.empty();
- lex->insert_list=0;
- }
- ;
-
-insert_field_spec:
- insert_values {}
- | insert_field_list insert_values {}
- | SET
- {
- LEX *lex=Lex;
- if (unlikely(!(lex->insert_list= new (thd->mem_root) List_item)) ||
- unlikely(lex->many_values.push_back(lex->insert_list,
- thd->mem_root)))
- MYSQL_YYABORT;
- lex->current_select->parsing_place= NO_MATTER;
- }
- ident_eq_list
- ;
-
-insert_field_list:
- LEFT_PAREN_ALT opt_fields ')'
- {
- Lex->current_select->parsing_place= AFTER_LIST;
- }
- ;
-
-opt_fields:
- /* empty */
- | fields
- ;
-
-fields:
- fields ',' insert_ident
- { Lex->field_list.push_back($3, thd->mem_root); }
- | insert_ident { Lex->field_list.push_back($1, thd->mem_root); }
- ;
-
-
-
-insert_values:
- create_select_query_expression {}
- ;
-
-values_list:
- values_list ',' no_braces
- | no_braces_with_names
- ;
-
-ident_eq_list:
- ident_eq_list ',' ident_eq_value
- | ident_eq_value
- ;
-
-ident_eq_value:
- simple_ident_nospvar equal expr_or_default
- {
- LEX *lex=Lex;
- if (unlikely(lex->field_list.push_back($1, thd->mem_root)) ||
- unlikely(lex->insert_list->push_back($3, thd->mem_root)))
- MYSQL_YYABORT;
- }
- ;
-
-equal:
- '=' {}
- | SET_VAR {}
- ;
-
-opt_equal:
- /* empty */ {}
- | equal {}
- ;
-
-opt_with:
- opt_equal {}
- | WITH {}
- ;
-
-opt_by:
- opt_equal {}
- | BY {}
- ;
-
-no_braces:
- '('
- {
- if (unlikely(!(Lex->insert_list= new (thd->mem_root) List_item)))
- MYSQL_YYABORT;
- }
- opt_values ')'
- {
- LEX *lex=Lex;
- if (unlikely(lex->many_values.push_back(lex->insert_list,
- thd->mem_root)))
- MYSQL_YYABORT;
- }
- ;
-
-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
- {
- if (unlikely(Lex->insert_list->push_back($3, thd->mem_root)))
- MYSQL_YYABORT;
- }
- | expr_or_default
- {
- if (unlikely(Lex->insert_list->push_back($1, thd->mem_root)))
- MYSQL_YYABORT;
- }
- ;
-
-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
- {
- $$= new (thd->mem_root) Item_default_value(thd, Lex->current_context());
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | IGNORE_SYM
- {
- $$= new (thd->mem_root) Item_ignore_value(thd, Lex->current_context());
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-opt_insert_update:
- /* empty */
- | ON DUPLICATE_SYM { Lex->duplicates= DUP_UPDATE; }
- KEY_SYM UPDATE_SYM
- {
- Select->parsing_place= IN_UPDATE_ON_DUP_KEY;
- }
- insert_update_list
- {
- Select->parsing_place= NO_MATTER;
- }
- ;
-
-update_table_list:
- table_ident opt_use_partition for_portion_of_time_clause
- opt_table_alias_clause opt_key_definition
- {
- SELECT_LEX *sel= Select;
- sel->table_join_options= 0;
- if (!($$= Select->add_table_to_list(thd, $1, $4,
- Select->get_table_join_options(),
- YYPS->m_lock_type,
- YYPS->m_mdl_type,
- Select->pop_index_hints(),
- $2)))
- MYSQL_YYABORT;
- $$->period_conditions= Lex->period_conditions;
- }
- | join_table_list { $$= $1; }
- ;
-
-/* Update rows in a table */
-
-update:
- UPDATE_SYM
- {
- LEX *lex= Lex;
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- mysql_init_select(lex);
- lex->sql_command= SQLCOM_UPDATE;
- lex->duplicates= DUP_ERROR;
- }
- opt_low_priority opt_ignore update_table_list
- SET update_list
- {
- SELECT_LEX *slex= Lex->first_select_lex();
- if (slex->table_list.elements > 1)
- Lex->sql_command= SQLCOM_UPDATE_MULTI;
- else if (slex->get_table_list()->derived)
- {
- /* it is single table update and it is update of derived table */
- my_error(ER_NON_UPDATABLE_TABLE, MYF(0),
- slex->get_table_list()->alias.str, "UPDATE");
- MYSQL_YYABORT;
- }
- /*
- In case of multi-update setting write lock for all tables may
- be too pessimistic. We will decrease lock level if possible in
- mysql_multi_update().
- */
- slex->set_lock_for_tables($3, slex->table_list.elements == 1);
- }
- opt_where_clause opt_order_clause delete_limit_clause
- {
- if ($10)
- Select->order_list= *($10);
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
- ;
-
-update_list:
- update_list ',' update_elem
- | update_elem
- ;
-
-update_elem:
- simple_ident_nospvar equal expr_or_default
- {
- if (unlikely(add_item_to_list(thd, $1)) ||
- unlikely(add_value_to_list(thd, $3)))
- MYSQL_YYABORT;
- }
- ;
-
-insert_update_list:
- insert_update_list ',' insert_update_elem
- | insert_update_elem
- ;
-
-insert_update_elem:
- simple_ident_nospvar equal expr_or_default
- {
- LEX *lex= Lex;
- if (unlikely(lex->update_list.push_back($1, thd->mem_root)) ||
- unlikely(lex->value_list.push_back($3, thd->mem_root)))
- MYSQL_YYABORT;
- }
- ;
-
-opt_low_priority:
- /* empty */ { $$= TL_WRITE_DEFAULT; }
- | LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; }
- ;
-
-/* Delete rows from a table */
-
-delete:
- DELETE_SYM
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_DELETE;
- YYPS->m_lock_type= TL_WRITE_DEFAULT;
- YYPS->m_mdl_type= MDL_SHARED_WRITE;
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- mysql_init_select(lex);
- lex->ignore= 0;
- lex->first_select_lex()->order_list.empty();
- }
- delete_part2
- ;
-
-opt_delete_system_time:
- /* empty */
- {
- Lex->vers_conditions.init(SYSTEM_TIME_ALL);
- }
- | BEFORE_SYM SYSTEM_TIME_SYM history_point
- {
- Lex->vers_conditions.init(SYSTEM_TIME_BEFORE, $3);
- }
- ;
-
-delete_part2:
- opt_delete_options single_multi {}
- | HISTORY_SYM delete_single_table opt_delete_system_time
- {
- Lex->last_table()->vers_conditions= Lex->vers_conditions;
- Lex->pop_select(); //main select
- }
- ;
-
-delete_single_table:
- FROM table_ident opt_use_partition
- {
- if (unlikely(!Select->
- add_table_to_list(thd, $2, NULL, TL_OPTION_UPDATING,
- YYPS->m_lock_type,
- YYPS->m_mdl_type,
- NULL,
- $3)))
- MYSQL_YYABORT;
- YYPS->m_lock_type= TL_READ_DEFAULT;
- YYPS->m_mdl_type= MDL_SHARED_READ;
- }
- ;
-
-delete_single_table_for_period:
- delete_single_table opt_for_portion_of_time_clause
- {
- if ($2)
- Lex->last_table()->period_conditions= Lex->period_conditions;
- }
- ;
-
-single_multi:
- delete_single_table_for_period
- opt_where_clause
- opt_order_clause
- delete_limit_clause
- opt_select_expressions
- {
- if ($3)
- Select->order_list= *($3);
- Lex->pop_select(); //main select
- }
- | table_wild_list
- {
- mysql_init_multi_delete(Lex);
- YYPS->m_lock_type= TL_READ_DEFAULT;
- YYPS->m_mdl_type= MDL_SHARED_READ;
- }
- FROM join_table_list opt_where_clause
- {
- if (unlikely(multi_delete_set_locks_and_link_aux_tables(Lex)))
- MYSQL_YYABORT;
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
- | FROM table_alias_ref_list
- {
- mysql_init_multi_delete(Lex);
- YYPS->m_lock_type= TL_READ_DEFAULT;
- YYPS->m_mdl_type= MDL_SHARED_READ;
- }
- USING join_table_list opt_where_clause
- {
- if (unlikely(multi_delete_set_locks_and_link_aux_tables(Lex)))
- MYSQL_YYABORT;
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
- ;
-
-opt_select_expressions:
- /* empty */
- | RETURNING_SYM select_item_list
- ;
-
-table_wild_list:
- table_wild_one
- | table_wild_list ',' table_wild_one
- ;
-
-table_wild_one:
- ident opt_wild
- {
- Table_ident *ti= new (thd->mem_root) Table_ident(&$1);
- if (unlikely(ti == NULL))
- MYSQL_YYABORT;
- if (unlikely(!Select->
- add_table_to_list(thd,
- ti,
- NULL,
- (TL_OPTION_UPDATING |
- TL_OPTION_ALIAS),
- YYPS->m_lock_type,
- YYPS->m_mdl_type)))
- MYSQL_YYABORT;
- }
- | ident '.' ident opt_wild
- {
- Table_ident *ti= new (thd->mem_root) Table_ident(thd, &$1, &$3, 0);
- if (unlikely(ti == NULL))
- MYSQL_YYABORT;
- if (unlikely(!Select->
- add_table_to_list(thd,
- ti,
- NULL,
- (TL_OPTION_UPDATING |
- TL_OPTION_ALIAS),
- YYPS->m_lock_type,
- YYPS->m_mdl_type)))
- MYSQL_YYABORT;
- }
- ;
-
-opt_wild:
- /* empty */ {}
- | '.' '*' {}
- ;
-
-opt_delete_options:
- /* empty */ {}
- | opt_delete_option opt_delete_options {}
- ;
-
-opt_delete_option:
- QUICK { Select->options|= OPTION_QUICK; }
- | LOW_PRIORITY { YYPS->m_lock_type= TL_WRITE_LOW_PRIORITY; }
- | IGNORE_SYM { Lex->ignore= 1; }
- ;
-
-truncate:
- TRUNCATE_SYM
- {
- LEX* lex= Lex;
- lex->sql_command= SQLCOM_TRUNCATE;
- lex->alter_info.reset();
- lex->first_select_lex()->options= 0;
- lex->sql_cache= LEX::SQL_CACHE_UNSPECIFIED;
- lex->first_select_lex()->order_list.empty();
- YYPS->m_lock_type= TL_WRITE;
- YYPS->m_mdl_type= MDL_EXCLUSIVE;
- }
- opt_table_sym table_name opt_lock_wait_timeout
- {
- LEX* lex= thd->lex;
- DBUG_ASSERT(!lex->m_sql_cmd);
- lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_truncate_table();
- if (unlikely(lex->m_sql_cmd == NULL))
- MYSQL_YYABORT;
- }
- opt_truncate_table_storage_clause { }
- ;
-
-opt_truncate_table_storage_clause:
- /* Empty */
- | DROP STORAGE_SYM
- | REUSE_SYM STORAGE_SYM
- ;
-
-opt_table_sym:
- /* empty */
- | TABLE_SYM
- ;
-
-opt_profile_defs:
- /* empty */
- | profile_defs;
-
-profile_defs:
- profile_def
- | profile_defs ',' profile_def;
-
-profile_def:
- CPU_SYM
- {
- Lex->profile_options|= PROFILE_CPU;
- }
- | MEMORY_SYM
- {
- Lex->profile_options|= PROFILE_MEMORY;
- }
- | BLOCK_SYM IO_SYM
- {
- Lex->profile_options|= PROFILE_BLOCK_IO;
- }
- | CONTEXT_SYM SWITCHES_SYM
- {
- Lex->profile_options|= PROFILE_CONTEXT;
- }
- | PAGE_SYM FAULTS_SYM
- {
- Lex->profile_options|= PROFILE_PAGE_FAULTS;
- }
- | IPC_SYM
- {
- Lex->profile_options|= PROFILE_IPC;
- }
- | SWAPS_SYM
- {
- Lex->profile_options|= PROFILE_SWAPS;
- }
- | SOURCE_SYM
- {
- Lex->profile_options|= PROFILE_SOURCE;
- }
- | ALL
- {
- Lex->profile_options|= PROFILE_ALL;
- }
- ;
-
-opt_profile_args:
- /* empty */
- {
- Lex->profile_query_id= 0;
- }
- | FOR_SYM QUERY_SYM NUM
- {
- Lex->profile_query_id= atoi($3.str);
- }
- ;
-
-/* Show things */
-
-show:
- SHOW
- {
- LEX *lex=Lex;
- lex->wild=0;
- lex->ident= null_clex_str;
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- mysql_init_select(lex);
- lex->current_select->parsing_place= SELECT_LIST;
- lex->create_info.init();
- }
- show_param
- {
- Select->parsing_place= NO_MATTER;
- Lex->pop_select(); //main select
- }
- ;
-
-show_param:
- DATABASES wild_and_where
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_DATABASES;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_SCHEMATA)))
- MYSQL_YYABORT;
- }
- | opt_full TABLES opt_db wild_and_where
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_TABLES;
- lex->first_select_lex()->db= $3;
- if (prepare_schema_table(thd, lex, 0, SCH_TABLE_NAMES))
- MYSQL_YYABORT;
- }
- | opt_full TRIGGERS_SYM opt_db wild_and_where
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_TRIGGERS;
- lex->first_select_lex()->db= $3;
- if (prepare_schema_table(thd, lex, 0, SCH_TRIGGERS))
- MYSQL_YYABORT;
- }
- | EVENTS_SYM opt_db wild_and_where
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_EVENTS;
- lex->first_select_lex()->db= $2;
- if (prepare_schema_table(thd, lex, 0, SCH_EVENTS))
- MYSQL_YYABORT;
- }
- | TABLE_SYM STATUS_SYM opt_db wild_and_where
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_TABLE_STATUS;
- lex->first_select_lex()->db= $3;
- if (prepare_schema_table(thd, lex, 0, SCH_TABLES))
- MYSQL_YYABORT;
- }
- | OPEN_SYM TABLES opt_db wild_and_where
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_OPEN_TABLES;
- lex->first_select_lex()->db= $3;
- if (prepare_schema_table(thd, lex, 0, SCH_OPEN_TABLES))
- MYSQL_YYABORT;
- }
- | PLUGINS_SYM
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_PLUGINS;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_PLUGINS)))
- MYSQL_YYABORT;
- }
- | PLUGINS_SYM SONAME_SYM TEXT_STRING_sys
- {
- Lex->ident= $3;
- Lex->sql_command= SQLCOM_SHOW_PLUGINS;
- if (unlikely(prepare_schema_table(thd, Lex, 0, SCH_ALL_PLUGINS)))
- MYSQL_YYABORT;
- }
- | PLUGINS_SYM SONAME_SYM wild_and_where
- {
- Lex->sql_command= SQLCOM_SHOW_PLUGINS;
- if (unlikely(prepare_schema_table(thd, Lex, 0, SCH_ALL_PLUGINS)))
- MYSQL_YYABORT;
- }
- | ENGINE_SYM known_storage_engines show_engine_param
- { Lex->create_info.db_type= $2; }
- | ENGINE_SYM ALL show_engine_param
- { Lex->create_info.db_type= NULL; }
- | opt_full COLUMNS from_or_in table_ident opt_db wild_and_where
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_FIELDS;
- if ($5.str)
- $4->change_db(&$5);
- if (unlikely(prepare_schema_table(thd, lex, $4, SCH_COLUMNS)))
- MYSQL_YYABORT;
- }
- | master_or_binary LOGS_SYM
- {
- Lex->sql_command = SQLCOM_SHOW_BINLOGS;
- }
- | SLAVE HOSTS_SYM
- {
- Lex->sql_command = SQLCOM_SHOW_SLAVE_HOSTS;
- }
- | BINLOG_SYM EVENTS_SYM binlog_in binlog_from
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS;
- }
- opt_global_limit_clause
- | RELAYLOG_SYM optional_connection_name EVENTS_SYM binlog_in binlog_from
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_RELAYLOG_EVENTS;
- }
- opt_global_limit_clause
- | keys_or_index from_or_in table_ident opt_db opt_where_clause
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_KEYS;
- if ($4.str)
- $3->change_db(&$4);
- if (unlikely(prepare_schema_table(thd, lex, $3, SCH_STATISTICS)))
- MYSQL_YYABORT;
- }
- | opt_storage ENGINES_SYM
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_SHOW_STORAGE_ENGINES;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_ENGINES)))
- MYSQL_YYABORT;
- }
- | AUTHORS_SYM
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_SHOW_AUTHORS;
- }
- | CONTRIBUTORS_SYM
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_SHOW_CONTRIBUTORS;
- }
- | PRIVILEGES
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_SHOW_PRIVILEGES;
- }
- | COUNT_SYM '(' '*' ')' WARNINGS
- {
- LEX_CSTRING var= {STRING_WITH_LEN("warning_count")};
- (void) create_select_for_variable(thd, &var);
- }
- | COUNT_SYM '(' '*' ')' ERRORS
- {
- LEX_CSTRING var= {STRING_WITH_LEN("error_count")};
- (void) create_select_for_variable(thd, &var);
- }
- | WARNINGS opt_global_limit_clause
- { Lex->sql_command = SQLCOM_SHOW_WARNS;}
- | ERRORS opt_global_limit_clause
- { Lex->sql_command = SQLCOM_SHOW_ERRORS;}
- | PROFILES_SYM
- { Lex->sql_command = SQLCOM_SHOW_PROFILES; }
- | PROFILE_SYM opt_profile_defs opt_profile_args opt_global_limit_clause
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_PROFILE;
- if (unlikely(prepare_schema_table(thd, lex, NULL, SCH_PROFILES)))
- MYSQL_YYABORT;
- }
- | opt_var_type STATUS_SYM wild_and_where
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_STATUS;
- lex->option_type= $1;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_SESSION_STATUS)))
- MYSQL_YYABORT;
- }
- | opt_full PROCESSLIST_SYM
- { Lex->sql_command= SQLCOM_SHOW_PROCESSLIST;}
- | opt_var_type VARIABLES wild_and_where
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_VARIABLES;
- lex->option_type= $1;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_SESSION_VARIABLES)))
- MYSQL_YYABORT;
- }
- | charset wild_and_where
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_CHARSETS;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_CHARSETS)))
- MYSQL_YYABORT;
- }
- | COLLATION_SYM wild_and_where
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_COLLATIONS;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_COLLATIONS)))
- MYSQL_YYABORT;
- }
- | GRANTS
- {
- Lex->sql_command= SQLCOM_SHOW_GRANTS;
- if (unlikely(!(Lex->grant_user=
- (LEX_USER*)thd->alloc(sizeof(LEX_USER)))))
- MYSQL_YYABORT;
- Lex->grant_user->user= current_user_and_current_role;
- }
- | GRANTS FOR_SYM user_or_role clear_privileges
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_SHOW_GRANTS;
- lex->grant_user=$3;
- }
- | CREATE DATABASE opt_if_not_exists ident
- {
- Lex->set_command(SQLCOM_SHOW_CREATE_DB, $3);
- Lex->name= $4;
- }
- | CREATE TABLE_SYM table_ident
- {
- LEX *lex= Lex;
- lex->sql_command = SQLCOM_SHOW_CREATE;
- if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL,0))
- MYSQL_YYABORT;
- lex->create_info.storage_media= HA_SM_DEFAULT;
- }
- | CREATE VIEW_SYM table_ident
- {
- LEX *lex= Lex;
- lex->sql_command = SQLCOM_SHOW_CREATE;
- if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL, 0))
- MYSQL_YYABORT;
- lex->table_type= TABLE_TYPE_VIEW;
- }
- | CREATE SEQUENCE_SYM table_ident
- {
- LEX *lex= Lex;
- lex->sql_command = SQLCOM_SHOW_CREATE;
- if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL, 0))
- MYSQL_YYABORT;
- lex->table_type= TABLE_TYPE_SEQUENCE;
- }
- | MASTER_SYM STATUS_SYM
- {
- Lex->sql_command = SQLCOM_SHOW_MASTER_STAT;
- }
- | ALL SLAVES STATUS_SYM
- {
- Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
- Lex->verbose= 1;
- }
- | SLAVE STATUS_SYM
- {
- LEX *lex= thd->lex;
- lex->mi.connection_name= null_clex_str;
- lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
- lex->verbose= 0;
- }
- | SLAVE connection_name STATUS_SYM
- {
- Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
- Lex->verbose= 0;
- }
- | CREATE PROCEDURE_SYM sp_name
- {
- LEX *lex= Lex;
-
- lex->sql_command = SQLCOM_SHOW_CREATE_PROC;
- lex->spname= $3;
- }
- | CREATE FUNCTION_SYM sp_name
- {
- LEX *lex= Lex;
-
- lex->sql_command = SQLCOM_SHOW_CREATE_FUNC;
- lex->spname= $3;
- }
- | CREATE PACKAGE_ORACLE_SYM sp_name
- {
- LEX *lex= Lex;
- lex->sql_command = SQLCOM_SHOW_CREATE_PACKAGE;
- lex->spname= $3;
- }
- | CREATE PACKAGE_ORACLE_SYM BODY_ORACLE_SYM sp_name
- {
- LEX *lex= Lex;
- lex->sql_command = SQLCOM_SHOW_CREATE_PACKAGE_BODY;
- lex->spname= $4;
- }
- | CREATE TRIGGER_SYM sp_name
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_CREATE_TRIGGER;
- lex->spname= $3;
- }
- | CREATE USER_SYM
- {
- Lex->sql_command= SQLCOM_SHOW_CREATE_USER;
- if (unlikely(!(Lex->grant_user=
- (LEX_USER*)thd->alloc(sizeof(LEX_USER)))))
- MYSQL_YYABORT;
- Lex->grant_user->user= current_user;
- }
- | CREATE USER_SYM user
- {
- Lex->sql_command= SQLCOM_SHOW_CREATE_USER;
- Lex->grant_user= $3;
- }
- | PROCEDURE_SYM STATUS_SYM wild_and_where
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_STATUS_PROC;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_PROCEDURES)))
- MYSQL_YYABORT;
- }
- | FUNCTION_SYM STATUS_SYM wild_and_where
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_STATUS_FUNC;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_PROCEDURES)))
- MYSQL_YYABORT;
- }
- | PACKAGE_ORACLE_SYM STATUS_SYM wild_and_where
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_STATUS_PACKAGE;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_PROCEDURES)))
- MYSQL_YYABORT;
- }
- | PACKAGE_ORACLE_SYM BODY_ORACLE_SYM STATUS_SYM wild_and_where
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_STATUS_PACKAGE_BODY;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_PROCEDURES)))
- MYSQL_YYABORT;
- }
- | PROCEDURE_SYM CODE_SYM sp_name
- {
- Lex->sql_command= SQLCOM_SHOW_PROC_CODE;
- Lex->spname= $3;
- }
- | FUNCTION_SYM CODE_SYM sp_name
- {
- Lex->sql_command= SQLCOM_SHOW_FUNC_CODE;
- Lex->spname= $3;
- }
- | PACKAGE_ORACLE_SYM BODY_ORACLE_SYM CODE_SYM sp_name
- {
- Lex->sql_command= SQLCOM_SHOW_PACKAGE_BODY_CODE;
- Lex->spname= $4;
- }
- | CREATE EVENT_SYM sp_name
- {
- Lex->spname= $3;
- Lex->sql_command = SQLCOM_SHOW_CREATE_EVENT;
- }
- | describe_command FOR_SYM expr
- {
- Lex->sql_command= SQLCOM_SHOW_EXPLAIN;
- if (unlikely(prepare_schema_table(thd, Lex, 0, SCH_EXPLAIN)))
- MYSQL_YYABORT;
- add_value_to_list(thd, $3);
- }
- | IDENT_sys remember_tok_start wild_and_where
- {
- LEX *lex= Lex;
- bool in_plugin;
- lex->sql_command= SQLCOM_SHOW_GENERIC;
- ST_SCHEMA_TABLE *table= find_schema_table(thd, &$1, &in_plugin);
- if (unlikely(!table || !table->old_format || !in_plugin))
- {
- thd->parse_error(ER_SYNTAX_ERROR, $2);
- MYSQL_YYABORT;
- }
- if (unlikely(lex->wild && table->idx_field1 < 0))
- {
- thd->parse_error(ER_SYNTAX_ERROR, $3);
- MYSQL_YYABORT;
- }
- if (unlikely(make_schema_select(thd, Lex->current_select, table)))
- MYSQL_YYABORT;
- }
- ;
-
-show_engine_param:
- STATUS_SYM
- { Lex->sql_command= SQLCOM_SHOW_ENGINE_STATUS; }
- | MUTEX_SYM
- { Lex->sql_command= SQLCOM_SHOW_ENGINE_MUTEX; }
- | LOGS_SYM
- { Lex->sql_command= SQLCOM_SHOW_ENGINE_LOGS; }
- ;
-
-master_or_binary:
- MASTER_SYM
- | BINARY
- ;
-
-opt_storage:
- /* empty */
- | STORAGE_SYM
- ;
-
-opt_db:
- /* empty */ { $$= null_clex_str; }
- | from_or_in ident { $$= $2; }
- ;
-
-opt_full:
- /* empty */ { Lex->verbose=0; }
- | FULL { Lex->verbose=1; }
- ;
-
-from_or_in:
- FROM
- | IN_SYM
- ;
-
-binlog_in:
- /* empty */ { Lex->mi.log_file_name = 0; }
- | IN_SYM TEXT_STRING_sys { Lex->mi.log_file_name = $2.str; }
- ;
-
-binlog_from:
- /* empty */ { Lex->mi.pos = 4; /* skip magic number */ }
- | FROM ulonglong_num { Lex->mi.pos = $2; }
- ;
-
-wild_and_where:
- /* empty */ { $$= 0; }
- | LIKE remember_tok_start TEXT_STRING_sys
- {
- Lex->wild= new (thd->mem_root) String($3.str, $3.length,
- system_charset_info);
- if (unlikely(Lex->wild == NULL))
- MYSQL_YYABORT;
- $$= $2;
- }
- | WHERE remember_tok_start expr
- {
- Select->where= normalize_cond(thd, $3);
- if ($3)
- $3->top_level_item();
- $$= $2;
- }
- ;
-
-/* A Oracle compatible synonym for show */
-describe:
- describe_command table_ident
- {
- LEX *lex= Lex;
- if (lex->main_select_push())
- MYSQL_YYABORT;
- mysql_init_select(lex);
- lex->current_select->parsing_place= SELECT_LIST;
- lex->sql_command= SQLCOM_SHOW_FIELDS;
- lex->first_select_lex()->db= null_clex_str;
- lex->verbose= 0;
- if (unlikely(prepare_schema_table(thd, lex, $2, SCH_COLUMNS)))
- MYSQL_YYABORT;
- }
- opt_describe_column
- {
- Select->parsing_place= NO_MATTER;
- Lex->pop_select(); //main select
- }
- | describe_command opt_extended_describe
- { Lex->describe|= DESCRIBE_NORMAL; }
- explainable_command
- {
- LEX *lex=Lex;
- lex->first_select_lex()->options|= SELECT_DESCRIBE;
- }
- ;
-
-explainable_command:
- select
- | select_into
- | insert
- | replace
- | update
- | delete
- ;
-
-describe_command:
- DESC
- | DESCRIBE
- ;
-
-analyze_stmt_command:
- ANALYZE_SYM opt_format_json explainable_command
- {
- Lex->analyze_stmt= true;
- }
- ;
-
-opt_extended_describe:
- EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; }
- | EXTENDED_SYM ALL
- { Lex->describe|= DESCRIBE_EXTENDED | DESCRIBE_EXTENDED2; }
- | PARTITIONS_SYM { Lex->describe|= DESCRIBE_PARTITIONS; }
- | opt_format_json {}
- ;
-
-opt_format_json:
- /* empty */ {}
- | FORMAT_SYM '=' ident_or_text
- {
- if (lex_string_eq(&$3, STRING_WITH_LEN("JSON")))
- Lex->explain_json= true;
- else if (lex_string_eq(&$3, STRING_WITH_LEN("TRADITIONAL")))
- DBUG_ASSERT(Lex->explain_json==false);
- else
- my_yyabort_error((ER_UNKNOWN_EXPLAIN_FORMAT, MYF(0), "EXPLAIN",
- $3.str));
- }
- ;
-
-opt_describe_column:
- /* empty */ {}
- | text_string { Lex->wild= $1; }
- | ident
- {
- Lex->wild= new (thd->mem_root) String((const char*) $1.str,
- $1.length,
- system_charset_info);
- if (unlikely(Lex->wild == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-
-/* flush things */
-
-flush:
- FLUSH_SYM opt_no_write_to_binlog
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_FLUSH;
- lex->type= 0;
- lex->no_write_to_binlog= $2;
- }
- flush_options {}
- ;
-
-flush_options:
- table_or_tables
- {
- Lex->type|= REFRESH_TABLES;
- /*
- Set type of metadata and table locks for
- FLUSH TABLES table_list [WITH READ LOCK].
- */
- YYPS->m_lock_type= TL_READ_NO_INSERT;
- YYPS->m_mdl_type= MDL_SHARED_HIGH_PRIO;
- }
- opt_table_list opt_flush_lock
- {}
- | flush_options_list
- {}
- ;
-
-opt_flush_lock:
- /* empty */ {}
- | flush_lock
- {
- TABLE_LIST *tables= Lex->query_tables;
- for (; tables; tables= tables->next_global)
- {
- tables->mdl_request.set_type(MDL_SHARED_NO_WRITE);
- /* Don't try to flush views. */
- tables->required_type= TABLE_TYPE_NORMAL;
- /* Ignore temporary tables. */
- tables->open_type= OT_BASE_ONLY;
- }
- }
- ;
-
-flush_lock:
- WITH READ_SYM LOCK_SYM optional_flush_tables_arguments
- { Lex->type|= REFRESH_READ_LOCK | $4; }
- | FOR_SYM
- {
- if (unlikely(Lex->query_tables == NULL))
- {
- // Table list can't be empty
- thd->parse_error(ER_NO_TABLES_USED);
- MYSQL_YYABORT;
- }
- Lex->type|= REFRESH_FOR_EXPORT;
- } EXPORT_SYM {}
- ;
-
-flush_options_list:
- flush_options_list ',' flush_option
- | flush_option
- {}
- ;
-
-flush_option:
- ERROR_SYM LOGS_SYM
- { Lex->type|= REFRESH_ERROR_LOG; }
- | ENGINE_SYM LOGS_SYM
- { Lex->type|= REFRESH_ENGINE_LOG; }
- | GENERAL LOGS_SYM
- { Lex->type|= REFRESH_GENERAL_LOG; }
- | SLOW LOGS_SYM
- { Lex->type|= REFRESH_SLOW_LOG; }
- | BINARY LOGS_SYM opt_delete_gtid_domain
- { Lex->type|= REFRESH_BINARY_LOG; }
- | RELAY LOGS_SYM optional_connection_name
- {
- LEX *lex= Lex;
- if (unlikely(lex->type & REFRESH_RELAY_LOG))
- my_yyabort_error((ER_WRONG_USAGE, MYF(0), "FLUSH", "RELAY LOGS"));
- lex->type|= REFRESH_RELAY_LOG;
- lex->relay_log_connection_name= lex->mi.connection_name;
- }
- | QUERY_SYM CACHE_SYM
- { Lex->type|= REFRESH_QUERY_CACHE_FREE; }
- | HOSTS_SYM
- { Lex->type|= REFRESH_HOSTS; }
- | PRIVILEGES
- { Lex->type|= REFRESH_GRANT; }
- | LOGS_SYM
- {
- Lex->type|= REFRESH_LOG;
- Lex->relay_log_connection_name= empty_clex_str;
- }
- | STATUS_SYM
- { Lex->type|= REFRESH_STATUS; }
- | SLAVE optional_connection_name
- {
- LEX *lex= Lex;
- if (unlikely(lex->type & REFRESH_SLAVE))
- my_yyabort_error((ER_WRONG_USAGE, MYF(0), "FLUSH","SLAVE"));
- lex->type|= REFRESH_SLAVE;
- lex->reset_slave_info.all= false;
- }
- | MASTER_SYM
- { Lex->type|= REFRESH_MASTER; }
- | DES_KEY_FILE
- { Lex->type|= REFRESH_DES_KEY_FILE; }
- | RESOURCES
- { Lex->type|= REFRESH_USER_RESOURCES; }
- | SSL_SYM
- { Lex->type|= REFRESH_SSL;}
- | IDENT_sys remember_tok_start
- {
- Lex->type|= REFRESH_GENERIC;
- ST_SCHEMA_TABLE *table= find_schema_table(thd, &$1);
- if (unlikely(!table || !table->reset_table))
- {
- thd->parse_error(ER_SYNTAX_ERROR, $2);
- MYSQL_YYABORT;
- }
- if (unlikely(Lex->view_list.push_back((LEX_CSTRING*)
- thd->memdup(&$1, sizeof(LEX_CSTRING)),
- thd->mem_root)))
- MYSQL_YYABORT;
- }
- ;
-
-opt_table_list:
- /* empty */ {}
- | table_list {}
- ;
-
-backup:
- BACKUP_SYM backup_statements {}
- ;
-
-backup_statements:
- STAGE_SYM ident
- {
- int type;
- if (unlikely(Lex->sphead))
- my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "BACKUP STAGE"));
- if ((type= find_type($2.str, &backup_stage_names,
- FIND_TYPE_NO_PREFIX)) <= 0)
- my_yyabort_error((ER_BACKUP_UNKNOWN_STAGE, MYF(0), $2.str));
- Lex->sql_command= SQLCOM_BACKUP;
- Lex->backup_stage= (backup_stages) (type-1);
- break;
- }
- | LOCK_SYM
- {
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- }
- table_ident
- {
- if (unlikely(!Select->add_table_to_list(thd, $3, NULL, 0,
- TL_READ, MDL_SHARED_HIGH_PRIO)))
- MYSQL_YYABORT;
- Lex->sql_command= SQLCOM_BACKUP_LOCK;
- Lex->pop_select(); //main select
- }
- | UNLOCK_SYM
- {
- /* Table list is empty for unlock */
- Lex->sql_command= SQLCOM_BACKUP_LOCK;
- }
- ;
-
-opt_delete_gtid_domain:
- /* empty */ {}
- | DELETE_DOMAIN_ID_SYM '=' '(' delete_domain_id_list ')'
- {}
- ;
-delete_domain_id_list:
- /* Empty */
- | delete_domain_id
- | delete_domain_id_list ',' delete_domain_id
- ;
-
-delete_domain_id:
- ulonglong_num
- {
- 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);
- }
- ;
-
-optional_flush_tables_arguments:
- /* empty */ {$$= 0;}
- | AND_SYM DISABLE_SYM CHECKPOINT_SYM {$$= REFRESH_CHECKPOINT; }
- ;
-
-reset:
- RESET_SYM
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_RESET; lex->type=0;
- }
- reset_options
- {}
- ;
-
-reset_options:
- reset_options ',' reset_option
- | reset_option
- ;
-
-reset_option:
- SLAVE { Lex->type|= REFRESH_SLAVE; }
- optional_connection_name
- slave_reset_options { }
- | MASTER_SYM
- {
- Lex->type|= REFRESH_MASTER;
- Lex->next_binlog_file_number= 0;
- }
- master_reset_options
- | QUERY_SYM CACHE_SYM { Lex->type|= REFRESH_QUERY_CACHE;}
- ;
-
-slave_reset_options:
- /* empty */ { Lex->reset_slave_info.all= false; }
- | ALL { Lex->reset_slave_info.all= true; }
- ;
-
-master_reset_options:
- /* empty */ {}
- | TO_SYM ulong_num
- {
- Lex->next_binlog_file_number = $2;
- }
- ;
-
-purge:
- PURGE master_or_binary LOGS_SYM TO_SYM TEXT_STRING_sys
- {
- Lex->stmt_purge_to($5);
- }
- | PURGE master_or_binary LOGS_SYM BEFORE_SYM
- { Lex->clause_that_disallows_subselect= "PURGE..BEFORE"; }
- expr
- {
- Lex->clause_that_disallows_subselect= NULL;
- if (Lex->stmt_purge_before($6))
- MYSQL_YYABORT;
- }
- ;
-
-
-/* kill threads */
-
-kill:
- KILL_SYM
- {
- LEX *lex=Lex;
- lex->value_list.empty();
- lex->users_list.empty();
- lex->sql_command= SQLCOM_KILL;
- lex->kill_type= KILL_TYPE_ID;
- }
- kill_type kill_option kill_expr
- {
- Lex->kill_signal= (killed_state) ($3 | $4);
- }
- ;
-
-kill_type:
- /* Empty */ { $$= (int) KILL_HARD_BIT; }
- | HARD_SYM { $$= (int) KILL_HARD_BIT; }
- | SOFT_SYM { $$= 0; }
- ;
-
-kill_option:
- /* empty */ { $$= (int) KILL_CONNECTION; }
- | CONNECTION_SYM { $$= (int) KILL_CONNECTION; }
- | QUERY_SYM { $$= (int) KILL_QUERY; }
- | QUERY_SYM ID_SYM
- {
- $$= (int) KILL_QUERY;
- Lex->kill_type= KILL_TYPE_QUERY;
- }
- ;
-
-kill_expr:
- expr
- {
- Lex->value_list.push_front($$, thd->mem_root);
- }
- | USER_SYM user
- {
- Lex->users_list.push_back($2, thd->mem_root);
- Lex->kill_type= KILL_TYPE_USER;
- }
- ;
-
-
-shutdown:
- SHUTDOWN { Lex->sql_command= SQLCOM_SHUTDOWN; }
- shutdown_option {}
- ;
-
-shutdown_option:
- /* Empty */ { Lex->is_shutdown_wait_for_slaves= false; }
- | WAIT_SYM FOR_SYM ALL SLAVES
- {
- Lex->is_shutdown_wait_for_slaves= true;
- }
- ;
-/* change database */
-
-use:
- USE_SYM ident
- {
- LEX *lex=Lex;
- lex->sql_command=SQLCOM_CHANGE_DB;
- lex->first_select_lex()->db= $2;
- }
- ;
-
-/* import, export of files */
-
-load:
- LOAD data_or_xml
- {
- LEX *lex= thd->lex;
-
- if (unlikely(lex->sphead))
- {
- my_error(ER_SP_BADSTATEMENT, MYF(0),
- $2 == FILETYPE_CSV ? "LOAD DATA" : "LOAD XML");
- MYSQL_YYABORT;
- }
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- mysql_init_select(lex);
- }
- load_data_lock opt_local INFILE TEXT_STRING_filesystem
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_LOAD;
- lex->local_file= $5;
- lex->duplicates= DUP_ERROR;
- lex->ignore= 0;
- if (unlikely(!(lex->exchange= new (thd->mem_root)
- sql_exchange($7.str, 0, $2))))
- MYSQL_YYABORT;
- }
- opt_duplicate INTO TABLE_SYM table_ident opt_use_partition
- {
- LEX *lex=Lex;
- if (unlikely(!Select->add_table_to_list(thd, $12, NULL,
- TL_OPTION_UPDATING,
- $4, MDL_SHARED_WRITE,
- NULL, $13)))
- MYSQL_YYABORT;
- lex->field_list.empty();
- lex->update_list.empty();
- lex->value_list.empty();
- lex->many_values.empty();
- }
- opt_load_data_charset
- { Lex->exchange->cs= $15; }
- opt_xml_rows_identified_by
- opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec
- opt_load_data_set_spec
- {
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- Lex->mark_first_table_as_inserting();
- }
- ;
-
-data_or_xml:
- DATA_SYM { $$= FILETYPE_CSV; }
- | XML_SYM { $$= FILETYPE_XML; }
- ;
-
-opt_local:
- /* empty */ { $$=0;}
- | LOCAL_SYM { $$=1;}
- ;
-
-load_data_lock:
- /* empty */ { $$= TL_WRITE_DEFAULT; }
- | CONCURRENT
- {
- /*
- Ignore this option in SP to avoid problem with query cache and
- triggers with non default priority locks
- */
- $$= (Lex->sphead ? TL_WRITE_DEFAULT : TL_WRITE_CONCURRENT_INSERT);
- }
- | LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; }
- ;
-
-opt_duplicate:
- /* empty */ { Lex->duplicates=DUP_ERROR; }
- | REPLACE { Lex->duplicates=DUP_REPLACE; }
- | IGNORE_SYM { Lex->ignore= 1; }
- ;
-
-opt_field_term:
- /* empty */
- | COLUMNS field_term_list
- ;
-
-field_term_list:
- field_term_list field_term
- | field_term
- ;
-
-field_term:
- TERMINATED BY text_string
- {
- DBUG_ASSERT(Lex->exchange != 0);
- Lex->exchange->field_term= $3;
- }
- | OPTIONALLY ENCLOSED BY text_string
- {
- LEX *lex= Lex;
- DBUG_ASSERT(lex->exchange != 0);
- lex->exchange->enclosed= $4;
- lex->exchange->opt_enclosed= 1;
- }
- | ENCLOSED BY text_string
- {
- DBUG_ASSERT(Lex->exchange != 0);
- Lex->exchange->enclosed= $3;
- }
- | ESCAPED BY text_string
- {
- DBUG_ASSERT(Lex->exchange != 0);
- Lex->exchange->escaped= $3;
- }
- ;
-
-opt_line_term:
- /* empty */
- | LINES line_term_list
- ;
-
-line_term_list:
- line_term_list line_term
- | line_term
- ;
-
-line_term:
- TERMINATED BY text_string
- {
- DBUG_ASSERT(Lex->exchange != 0);
- Lex->exchange->line_term= $3;
- }
- | STARTING BY text_string
- {
- DBUG_ASSERT(Lex->exchange != 0);
- Lex->exchange->line_start= $3;
- }
- ;
-
-opt_xml_rows_identified_by:
- /* empty */ { }
- | ROWS_SYM IDENTIFIED_SYM BY text_string
- { Lex->exchange->line_term = $4; }
- ;
-
-opt_ignore_lines:
- /* empty */
- | IGNORE_SYM NUM lines_or_rows
- {
- DBUG_ASSERT(Lex->exchange != 0);
- Lex->exchange->skip_lines= atol($2.str);
- }
- ;
-
-lines_or_rows:
- LINES { }
- | ROWS_SYM { }
- ;
-
-opt_field_or_var_spec:
- /* empty */ {}
- | '(' fields_or_vars ')' {}
- | '(' ')' {}
- ;
-
-fields_or_vars:
- fields_or_vars ',' field_or_var
- { Lex->field_list.push_back($3, thd->mem_root); }
- | field_or_var
- { Lex->field_list.push_back($1, thd->mem_root); }
- ;
-
-field_or_var:
- simple_ident_nospvar {$$= $1;}
- | '@' ident_or_text
- {
- $$= new (thd->mem_root) Item_user_var_as_out_param(thd, &$2);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-opt_load_data_set_spec:
- /* empty */ {}
- | SET load_data_set_list {}
- ;
-
-load_data_set_list:
- load_data_set_list ',' load_data_set_elem
- | load_data_set_elem
- ;
-
-load_data_set_elem:
- simple_ident_nospvar equal remember_name expr_or_default remember_end
- {
- LEX *lex= Lex;
- if (unlikely(lex->update_list.push_back($1, thd->mem_root)) ||
- unlikely(lex->value_list.push_back($4, thd->mem_root)))
- MYSQL_YYABORT;
- $4->set_name_no_truncate(thd, $3, (uint) ($5 - $3), thd->charset());
- }
- ;
-
-/* Common definitions */
-
-text_literal:
- TEXT_STRING
- {
- if (unlikely(!($$= thd->make_string_literal($1))))
- MYSQL_YYABORT;
- }
- | NCHAR_STRING
- {
- if (unlikely(!($$= thd->make_string_literal_nchar($1))))
- MYSQL_YYABORT;
- }
- | UNDERSCORE_CHARSET TEXT_STRING
- {
- if (unlikely(!($$= thd->make_string_literal_charset($2, $1))))
- MYSQL_YYABORT;
- }
- | text_literal TEXT_STRING_literal
- {
- if (unlikely(!($$= $1->make_string_literal_concat(thd, &$2))))
- MYSQL_YYABORT;
- }
- ;
-
-text_string:
- TEXT_STRING_literal
- {
- $$= new (thd->mem_root) String($1.str,
- $1.length,
- thd->variables.collation_connection);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | hex_or_bin_String { $$= $1; }
- ;
-
-
-hex_or_bin_String:
- HEX_NUM
- {
- Item *tmp= new (thd->mem_root) Item_hex_hybrid(thd, $1.str,
- $1.length);
- if (unlikely(tmp == NULL))
- MYSQL_YYABORT;
- $$= tmp->val_str((String*) 0);
- }
- | HEX_STRING
- {
- Item *tmp= new (thd->mem_root) Item_hex_string(thd, $1.str,
- $1.length);
- if (unlikely(tmp == NULL))
- MYSQL_YYABORT;
- $$= tmp->val_str((String*) 0);
- }
- | BIN_NUM
- {
- Item *tmp= new (thd->mem_root) Item_bin_string(thd, $1.str,
- $1.length);
- if (unlikely(tmp == NULL))
- MYSQL_YYABORT;
- /*
- it is OK only emulate fix_fields, because we need only
- value of constant
- */
- $$= tmp->val_str((String*) 0);
- }
- ;
-
-param_marker:
- PARAM_MARKER
- {
- if (unlikely(!($$= Lex->add_placeholder(thd, &param_clex_str,
- YYLIP->get_tok_start(),
- YYLIP->get_tok_start() + 1))))
- MYSQL_YYABORT;
- }
- | COLON_ORACLE_SYM ident_cli
- {
- if (unlikely(!($$= Lex->add_placeholder(thd, &null_clex_str,
- $1.pos(), $2.end()))))
- MYSQL_YYABORT;
- }
- | COLON_ORACLE_SYM NUM
- {
- if (unlikely(!($$= Lex->add_placeholder(thd, &null_clex_str,
- $1.pos(),
- YYLIP->get_ptr()))))
- MYSQL_YYABORT;
- }
- ;
-
-signed_literal:
- '+' NUM_literal { $$ = $2; }
- | '-' NUM_literal
- {
- $2->max_length++;
- $$= $2->neg(thd);
- }
- ;
-
-literal:
- text_literal { $$ = $1; }
- | NUM_literal { $$ = $1; }
- | temporal_literal { $$= $1; }
- | NULL_SYM
- {
- /*
- For the digest computation, in this context only,
- NULL is considered a literal, hence reduced to '?'
- REDUCE:
- TOK_GENERIC_VALUE := NULL_SYM
- */
- YYLIP->reduce_digest_token(TOK_GENERIC_VALUE, NULL_SYM);
- $$= new (thd->mem_root) Item_null(thd);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- YYLIP->next_state= MY_LEX_OPERATOR_OR_IDENT;
- }
- | FALSE_SYM
- {
- $$= new (thd->mem_root) Item_bool(thd, (char*) "FALSE",0);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | TRUE_SYM
- {
- $$= new (thd->mem_root) Item_bool(thd, (char*) "TRUE",1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | HEX_NUM
- {
- $$= new (thd->mem_root) Item_hex_hybrid(thd, $1.str, $1.length);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | HEX_STRING
- {
- $$= new (thd->mem_root) Item_hex_string(thd, $1.str, $1.length);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | BIN_NUM
- {
- $$= new (thd->mem_root) Item_bin_string(thd, $1.str, $1.length);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | UNDERSCORE_CHARSET hex_or_bin_String
- {
- Item_string_with_introducer *item_str;
- /*
- Pass NULL as name. Name will be set in the "select_item" rule and
- will include the introducer and the original hex/bin notation.
- */
- item_str= new (thd->mem_root)
- Item_string_with_introducer(thd, NULL, $2->ptr(), $2->length(),
- $1);
- if (unlikely(!item_str ||
- !item_str->check_well_formed_result(true)))
- MYSQL_YYABORT;
-
- $$= item_str;
- }
- ;
-
-NUM_literal:
- NUM
- {
- int error;
- $$= new (thd->mem_root)
- Item_int(thd, $1.str,
- (longlong) my_strtoll10($1.str, NULL, &error),
- $1.length);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | LONG_NUM
- {
- int error;
- $$= new (thd->mem_root)
- Item_int(thd, $1.str,
- (longlong) my_strtoll10($1.str, NULL, &error),
- $1.length);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | ULONGLONG_NUM
- {
- $$= new (thd->mem_root) Item_uint(thd, $1.str, $1.length);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | DECIMAL_NUM
- {
- $$= new (thd->mem_root) Item_decimal(thd, $1.str, $1.length,
- thd->charset());
- if (unlikely($$ == NULL) || unlikely(thd->is_error()))
- MYSQL_YYABORT;
- }
- | FLOAT_NUM
- {
- $$= new (thd->mem_root) Item_float(thd, $1.str, $1.length);
- if (unlikely($$ == NULL) || unlikely(thd->is_error()))
- MYSQL_YYABORT;
- }
- ;
-
-
-temporal_literal:
- DATE_SYM TEXT_STRING
- {
- if (unlikely(!($$= type_handler_newdate.create_literal_item(thd,
- $2.str, $2.length,
- YYCSCL, true))))
- MYSQL_YYABORT;
- }
- | TIME_SYM TEXT_STRING
- {
- if (unlikely(!($$= type_handler_time2.create_literal_item(thd,
- $2.str, $2.length,
- YYCSCL, true))))
- MYSQL_YYABORT;
- }
- | TIMESTAMP TEXT_STRING
- {
- if (unlikely(!($$= type_handler_datetime2.create_literal_item(thd,
- $2.str, $2.length,
- YYCSCL, true))))
- MYSQL_YYABORT;
- }
- ;
-
-with_clause:
- WITH opt_recursive
- {
- LEX *lex= Lex;
- With_clause *with_clause=
- new With_clause($2, Lex->curr_with_clause);
- if (unlikely(with_clause == NULL))
- MYSQL_YYABORT;
- lex->derived_tables|= DERIVED_WITH;
- lex->curr_with_clause= with_clause;
- with_clause->add_to_list(Lex->with_clauses_list_last_next);
- if (lex->current_select &&
- lex->current_select->parsing_place == BEFORE_OPT_LIST)
- lex->current_select->parsing_place= NO_MATTER;
- }
- with_list
- {
- $$= Lex->curr_with_clause;
- Lex->curr_with_clause= Lex->curr_with_clause->pop();
- }
- ;
-
-
-opt_recursive:
- /*empty*/ { $$= 0; }
- | RECURSIVE_SYM { $$= 1; }
- ;
-
-
-with_list:
- with_list_element
- | with_list ',' with_list_element
- ;
-
-
-with_list_element:
- query_name
- opt_with_column_list
- {
- $2= new List<LEX_CSTRING> (Lex->with_column_list);
- if (unlikely($2 == NULL))
- MYSQL_YYABORT;
- Lex->with_column_list.empty();
- }
- AS '(' query_expression ')'
- {
- LEX *lex= thd->lex;
- const char *query_start= lex->sphead ? lex->sphead->m_tmp_query
- : thd->query();
- const char *spec_start= $5.pos() + 1;
- With_element *elem= new With_element($1, *$2, $6);
- if (elem == NULL || Lex->curr_with_clause->add_with_element(elem))
- MYSQL_YYABORT;
- if (elem->set_unparsed_spec(thd, spec_start, $7.pos(),
- spec_start - query_start))
- MYSQL_YYABORT;
- }
- ;
-
-
-opt_with_column_list:
- /* empty */
- { $$= NULL; }
- | '(' with_column_list ')'
- { $$= NULL; }
- ;
-
-
-with_column_list:
- ident
- {
- Lex->with_column_list.push_back((LEX_CSTRING*)
- thd->memdup(&$1, sizeof(LEX_CSTRING)));
- }
- | with_column_list ',' ident
- {
- Lex->with_column_list.push_back((LEX_CSTRING*)
- thd->memdup(&$3, sizeof(LEX_CSTRING)));
- }
- ;
-
-
-query_name:
- ident
- {
- $$= (LEX_CSTRING *) thd->memdup(&$1, sizeof(LEX_CSTRING));
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-
-
-/**********************************************************************
-** Creating different items.
-**********************************************************************/
-
-insert_ident:
- simple_ident_nospvar { $$=$1; }
- | table_wild { $$=$1; }
- ;
-
-table_wild:
- ident '.' '*'
- {
- if (unlikely(!($$= Lex->create_item_qualified_asterisk(thd, &$1))))
- MYSQL_YYABORT;
- }
- | ident '.' ident '.' '*'
- {
- if (unlikely(!($$= Lex->create_item_qualified_asterisk(thd, &$1, &$3))))
- MYSQL_YYABORT;
- }
- ;
-
-select_sublist_qualified_asterisk:
- ident_cli '.' '*'
- {
- if (unlikely(!($$= Lex->create_item_qualified_asterisk(thd, &$1))))
- MYSQL_YYABORT;
- }
- | ident_cli '.' ident_cli '.' '*'
- {
- if (unlikely(!($$= Lex->create_item_qualified_asterisk(thd, &$1, &$3))))
- MYSQL_YYABORT;
- }
- ;
-
-order_ident:
- expr { $$=$1; }
- ;
-
-
-simple_ident:
- ident_cli
- {
- if (unlikely(!($$= Lex->create_item_ident(thd, &$1))))
- MYSQL_YYABORT;
- }
- | ident_cli '.' ident_cli
- {
- if (unlikely(!($$= Lex->create_item_ident(thd, &$1, &$3))))
- MYSQL_YYABORT;
- }
- | '.' ident_cli '.' ident_cli
- {
- Lex_ident_cli empty($2.pos(), 0);
- if (unlikely(!($$= Lex->create_item_ident(thd, &empty, &$2, &$4))))
- MYSQL_YYABORT;
- }
- | ident_cli '.' ident_cli '.' ident_cli
- {
- if (unlikely(!($$= Lex->create_item_ident(thd, &$1, &$3, &$5))))
- MYSQL_YYABORT;
- }
- | COLON_ORACLE_SYM ident_cli '.' ident_cli
- {
- if (unlikely(!($$= Lex->make_item_colon_ident_ident(thd, &$2, &$4))))
- MYSQL_YYABORT;
- }
- ;
-
-simple_ident_nospvar:
- ident
- {
- if (unlikely(!($$= Lex->create_item_ident_nosp(thd, &$1))))
- MYSQL_YYABORT;
- }
- | ident '.' ident
- {
- if (unlikely(!($$= Lex->create_item_ident_nospvar(thd, &$1, &$3))))
- MYSQL_YYABORT;
- }
- | COLON_ORACLE_SYM ident_cli '.' ident_cli
- {
- if (unlikely(!($$= Lex->make_item_colon_ident_ident(thd, &$2, &$4))))
- MYSQL_YYABORT;
- }
- | '.' ident '.' ident
- {
- Lex_ident_sys none;
- if (unlikely(!($$= Lex->create_item_ident(thd, &none, &$2, &$4))))
- MYSQL_YYABORT;
- }
- | ident '.' ident '.' ident
- {
- if (unlikely(!($$= Lex->create_item_ident(thd, &$1, &$3, &$5))))
- MYSQL_YYABORT;
- }
- ;
-
-field_ident:
- ident { $$=$1;}
- | ident '.' ident '.' ident
- {
- TABLE_LIST *table= Select->table_list.first;
- if (unlikely(my_strcasecmp(table_alias_charset, $1.str,
- table->db.str)))
- my_yyabort_error((ER_WRONG_DB_NAME, MYF(0), $1.str));
- if (unlikely(my_strcasecmp(table_alias_charset, $3.str,
- table->table_name.str)))
- my_yyabort_error((ER_WRONG_TABLE_NAME, MYF(0), $3.str));
- $$=$5;
- }
- | ident '.' ident
- {
- TABLE_LIST *table= Select->table_list.first;
- if (unlikely(my_strcasecmp(table_alias_charset, $1.str,
- table->alias.str)))
- my_yyabort_error((ER_WRONG_TABLE_NAME, MYF(0), $1.str));
- $$=$3;
- }
- | '.' ident { $$=$2;} /* For Delphi */
- ;
-
-table_ident:
- ident
- {
- $$= new (thd->mem_root) Table_ident(&$1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | ident '.' ident
- {
- $$= new (thd->mem_root) Table_ident(thd, &$1, &$3, 0);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | '.' ident
- {
- /* For Delphi */
- $$= new (thd->mem_root) Table_ident(&$2);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-table_ident_opt_wild:
- ident opt_wild
- {
- $$= new (thd->mem_root) Table_ident(&$1);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | ident '.' ident opt_wild
- {
- $$= new (thd->mem_root) Table_ident(thd, &$1, &$3, 0);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-table_ident_nodb:
- ident
- {
- LEX_CSTRING db={(char*) any_db,3};
- $$= new (thd->mem_root) Table_ident(thd, &db, &$1, 0);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-IDENT_cli:
- IDENT
- | IDENT_QUOTED
- ;
-
-ident_cli:
- IDENT
- | IDENT_QUOTED
- | keyword_ident { $$= $1; }
- ;
-
-IDENT_sys:
- IDENT_cli
- {
- if (unlikely(thd->to_ident_sys_alloc(&$$, &$1)))
- MYSQL_YYABORT;
- }
- ;
-
-TEXT_STRING_sys:
- TEXT_STRING
- {
- if (thd->make_text_string_sys(&$$, &$1))
- MYSQL_YYABORT;
- }
- ;
-
-TEXT_STRING_literal:
- TEXT_STRING
- {
- if (thd->make_text_string_connection(&$$, &$1))
- MYSQL_YYABORT;
- }
- ;
-
-TEXT_STRING_filesystem:
- TEXT_STRING
- {
- if (thd->make_text_string_filesystem(&$$, &$1))
- MYSQL_YYABORT;
- }
- ;
-
-ident_table_alias:
- IDENT_sys
- | keyword_table_alias
- {
- if (unlikely($$.copy_keyword(thd, &$1)))
- MYSQL_YYABORT;
- }
- ;
-
-ident_set_usual_case:
- IDENT_sys
- | keyword_set_usual_case
- {
- if (unlikely($$.copy_keyword(thd, &$1)))
- MYSQL_YYABORT;
- }
- ;
-
-ident_sysvar_name:
- IDENT_sys
- | keyword_sysvar_name
- {
- if (unlikely($$.copy_keyword(thd, &$1)))
- MYSQL_YYABORT;
- }
- | TEXT_STRING_sys
- {
- if (unlikely($$.copy_sys(thd, &$1)))
- MYSQL_YYABORT;
- }
- ;
-
-
-ident:
- IDENT_sys
- | keyword_ident
- {
- if (unlikely($$.copy_keyword(thd, &$1)))
- MYSQL_YYABORT;
- }
- ;
-
-ident_directly_assignable:
- IDENT_sys
- | keyword_directly_assignable
- {
- if (unlikely($$.copy_keyword(thd, &$1)))
- MYSQL_YYABORT;
- }
- ;
-
-
-label_ident:
- IDENT_sys
- | keyword_label
- {
- if (unlikely($$.copy_keyword(thd, &$1)))
- MYSQL_YYABORT;
- }
- ;
-
-labels_declaration_oracle:
- label_declaration_oracle { $$= $1; }
- | labels_declaration_oracle label_declaration_oracle { $$= $2; }
- ;
-
-label_declaration_oracle:
- SHIFT_LEFT label_ident SHIFT_RIGHT
- {
- if (unlikely(Lex->sp_push_goto_label(thd, &$2)))
- MYSQL_YYABORT;
- $$= $2;
- }
- ;
-
-ident_or_text:
- ident { $$=$1;}
- | TEXT_STRING_sys { $$=$1;}
- | LEX_HOSTNAME { $$=$1;}
- ;
-
-user_maybe_role:
- ident_or_text
- {
- if (unlikely(!($$=(LEX_USER*) thd->calloc(sizeof(LEX_USER)))))
- MYSQL_YYABORT;
- $$->user = $1;
-
- if (unlikely(check_string_char_length(&$$->user, ER_USERNAME,
- username_char_length,
- system_charset_info, 0)))
- MYSQL_YYABORT;
- }
- | ident_or_text '@' ident_or_text
- {
- if (unlikely(!($$=(LEX_USER*) thd->calloc(sizeof(LEX_USER)))))
- MYSQL_YYABORT;
- $$->user = $1; $$->host=$3;
-
- if (unlikely(check_string_char_length(&$$->user, ER_USERNAME,
- username_char_length,
- system_charset_info, 0)) ||
- unlikely(check_host_name(&$$->host)))
- MYSQL_YYABORT;
- if ($$->host.str[0])
- {
- /*
- Convert hostname part of username to lowercase.
- It's OK to use in-place lowercase as long as
- the character set is utf8.
- */
- my_casedn_str(system_charset_info, (char*) $$->host.str);
- }
- else
- {
- /*
- fix historical undocumented convention that empty host is the
- same as '%'
- */
- $$->host= host_not_specified;
- }
- }
- | CURRENT_USER optional_braces
- {
- if (unlikely(!($$=(LEX_USER*)thd->calloc(sizeof(LEX_USER)))))
- MYSQL_YYABORT;
- $$->user= current_user;
- $$->auth= new (thd->mem_root) USER_AUTH();
- }
- ;
-
-user_or_role: user_maybe_role | current_role;
-
-user: user_maybe_role
- {
- if ($1->user.str != current_user.str && $1->host.str == 0)
- $1->host= host_not_specified;
- $$= $1;
- }
- ;
-
-/* Keywords which we allow as table aliases. */
-keyword_table_alias:
- keyword_data_type
- | keyword_set_special_case
- | keyword_sp_block_section
- | keyword_sp_head
- | keyword_sp_var_and_label
- | keyword_sp_var_not_label
- | keyword_sysvar_type
- | keyword_verb_clause
- | FUNCTION_SYM
- ;
-
-/* Keyword that we allow for identifiers (except SP labels) */
-keyword_ident:
- keyword_data_type
- | keyword_set_special_case
- | keyword_sp_block_section
- | keyword_sp_head
- | keyword_sp_var_and_label
- | keyword_sp_var_not_label
- | keyword_sysvar_type
- | keyword_verb_clause
- | FUNCTION_SYM
- | WINDOW_SYM
- ;
-
-/*
- Keywords that we allow for labels in SPs.
- Should not include keywords that start a statement or SP characteristics.
-*/
-keyword_label:
- keyword_data_type
- | keyword_set_special_case
- | keyword_sp_var_and_label
- | keyword_sysvar_type
- | FUNCTION_SYM
- | COMPRESSED_SYM
- ;
-
-keyword_sysvar_name:
- keyword_data_type
- | keyword_set_special_case
- | keyword_sp_block_section
- | keyword_sp_head
- | keyword_sp_var_and_label
- | keyword_sp_var_not_label
- | keyword_verb_clause
- | FUNCTION_SYM
- | WINDOW_SYM
- ;
-
-keyword_sp_decl:
- keyword_sp_head
- | keyword_set_special_case
- | keyword_sp_var_and_label
- | keyword_sp_var_not_label
- | keyword_sysvar_type
- | keyword_verb_clause
- | WINDOW_SYM
- ;
-
-keyword_set_usual_case:
- keyword_data_type
- | keyword_sp_block_section
- | keyword_sp_head
- | keyword_sp_var_and_label
- | keyword_sp_var_not_label
- | keyword_sysvar_type
- | keyword_verb_clause
- | FUNCTION_SYM
- | WINDOW_SYM
- ;
-
-keyword_directly_assignable:
- keyword_data_type
- | keyword_set_special_case
- | keyword_sp_var_and_label
- | keyword_sp_var_not_label
- | keyword_sysvar_type
- | FUNCTION_SYM
- | WINDOW_SYM
- ;
-
-/*
- Keywords that we allow in Oracle-style direct assignments:
- xxx := 10;
- but do not allow in labels in the default sql_mode:
- label:
- stmt1;
- stmt2;
- TODO: check if some of them can migrate to keyword_sp_var_and_label.
-*/
-keyword_sp_var_not_label:
- ASCII_SYM
- | BACKUP_SYM
- | BINLOG_SYM
- | BYTE_SYM
- | CACHE_SYM
- | CHECKSUM_SYM
- | CHECKPOINT_SYM
- | COLUMN_ADD_SYM
- | COLUMN_CHECK_SYM
- | COLUMN_CREATE_SYM
- | COLUMN_DELETE_SYM
- | COLUMN_GET_SYM
- | COMMENT_SYM
- | COMPRESSED_SYM
- | DEALLOCATE_SYM
- | EXAMINED_SYM
- | EXCLUDE_SYM
- | EXECUTE_SYM
- | FLUSH_SYM
- | FOLLOWING_SYM
- | FORMAT_SYM
- | GET_SYM
- | HELP_SYM
- | HOST_SYM
- | INSTALL_SYM
- | OPTION
- | OPTIONS_SYM
- | OTHERS_MARIADB_SYM
- | OWNER_SYM
- | PARSER_SYM
- | PERIOD_SYM
- | PORT_SYM
- | PRECEDING_SYM
- | PREPARE_SYM
- | REMOVE_SYM
- | RESET_SYM
- | RESTORE_SYM
- | SECURITY_SYM
- | SERVER_SYM
- | SIGNED_SYM
- | SOCKET_SYM
- | SLAVE
- | SLAVES
- | SONAME_SYM
- | START_SYM
- | STOP_SYM
- | STORED_SYM
- | TIES_SYM
- | UNICODE_SYM
- | UNINSTALL_SYM
- | UNBOUNDED_SYM
- | WITHIN
- | WRAPPER_SYM
- | XA_SYM
- | UPGRADE_SYM
- ;
-
-/*
- Keywords that can start optional clauses in SP or trigger declarations
- Allowed as identifiers (e.g. table, column names),
- but:
- - not allowed as SP label names
- - not allowed as variable names in Oracle-style assignments:
- xxx := 10;
-
- If we allowed these variables in assignments, there would be conflicts
- with SP characteristics, or verb clauses, or compound statements, e.g.:
- CREATE PROCEDURE p1 LANGUAGE ...
- would be either:
- CREATE PROCEDURE p1 LANGUAGE SQL BEGIN END;
- or
- CREATE PROCEDURE p1 LANGUAGE:=10;
-
- Note, these variables can still be assigned using quoted identifiers:
- `do`:= 10;
- "do":= 10; (when ANSI_QUOTES)
- or using a SET statement:
- SET do= 10;
-
- Note, some of these keywords are reserved keywords in Oracle.
- In case if heavy grammar conflicts are found in the future,
- we'll possibly need to make them reserved for sql_mode=ORACLE.
-
- TODO: Allow these variables as SP lables when sql_mode=ORACLE.
- TODO: Allow assigning of "SP characteristics" marked variables
- inside compound blocks.
- TODO: Allow "follows" and "precedes" as variables in compound blocks:
- BEGIN
- follows := 10;
- END;
- as they conflict only with non-block FOR EACH ROW statement:
- CREATE TRIGGER .. FOR EACH ROW follows:= 10;
- CREATE TRIGGER .. FOR EACH ROW FOLLOWS tr1 a:= 10;
-*/
-keyword_sp_head:
- CONTAINS_SYM /* SP characteristic */
- | LANGUAGE_SYM /* SP characteristic */
- | NO_SYM /* SP characteristic */
- | CHARSET /* SET CHARSET utf8; */
- | FOLLOWS_SYM /* Conflicts with assignment in FOR EACH */
- | PRECEDES_SYM /* Conflicts with assignment in FOR EACH */
- ;
-
-/*
- Keywords that start a statement.
- Generally allowed as identifiers (e.g. table, column names)
- - not allowed as SP label names
- - not allowed as variable names in Oracle-style assignments:
- xxx:=10
-*/
-keyword_verb_clause:
- CLOSE_SYM /* Verb clause. Reserved in Oracle */
- | COMMIT_SYM /* Verb clause. Reserved in Oracle */
- | DO_SYM /* Verb clause */
- | HANDLER_SYM /* Verb clause */
- | OPEN_SYM /* Verb clause. Reserved in Oracle */
- | REPAIR /* Verb clause */
- | ROLLBACK_SYM /* Verb clause. Reserved in Oracle */
- | SAVEPOINT_SYM /* Verb clause. Reserved in Oracle */
- | SHUTDOWN /* Verb clause */
- | TRUNCATE_SYM /* Verb clause. Reserved in Oracle */
- ;
-
-keyword_set_special_case:
- NAMES_SYM
- | ROLE_SYM
- | PASSWORD_SYM
- ;
-
-/*
- Keywords that start an SP block section.
-*/
-keyword_sp_block_section:
- BEGIN_ORACLE_SYM
- | EXCEPTION_ORACLE_SYM
- | END
- ;
-
-keyword_sysvar_type:
- GLOBAL_SYM
- | LOCAL_SYM
- | SESSION_SYM
- ;
-
-
-/*
- These keywords are generally allowed as identifiers,
- but not allowed as non-delimited SP variable names in sql_mode=ORACLE.
-*/
-keyword_data_type:
- BIT_SYM
- | BOOLEAN_SYM
- | BOOL_SYM
- | CLOB_MARIADB_SYM
- | CLOB_ORACLE_SYM
- | DATE_SYM %prec PREC_BELOW_CONTRACTION_TOKEN2
- | DATETIME
- | ENUM
- | FIXED_SYM
- | GEOMETRYCOLLECTION
- | GEOMETRY_SYM
- | JSON_SYM
- | LINESTRING
- | MEDIUM_SYM
- | MULTILINESTRING
- | MULTIPOINT
- | MULTIPOLYGON
- | NATIONAL_SYM
- | NCHAR_SYM
- | NUMBER_MARIADB_SYM
- | NUMBER_ORACLE_SYM
- | NVARCHAR_SYM
- | POINT_SYM
- | POLYGON
- | RAW_MARIADB_SYM
- | RAW_ORACLE_SYM
- | ROW_SYM
- | SERIAL_SYM
- | TEXT_SYM
- | TIMESTAMP %prec PREC_BELOW_CONTRACTION_TOKEN2
- | TIME_SYM %prec PREC_BELOW_CONTRACTION_TOKEN2
- | VARCHAR2_MARIADB_SYM
- | VARCHAR2_ORACLE_SYM
- | YEAR_SYM
- ;
-
-
-/*
- These keywords are fine for both SP variable names and SP labels.
-*/
-keyword_sp_var_and_label:
- ACTION
- | ACCOUNT_SYM
- | ADDDATE_SYM
- | ADMIN_SYM
- | AFTER_SYM
- | AGAINST
- | AGGREGATE_SYM
- | ALGORITHM_SYM
- | ALWAYS_SYM
- | ANY_SYM
- | AT_SYM
- | ATOMIC_SYM
- | AUTHORS_SYM
- | AUTO_INC
- | AUTOEXTEND_SIZE_SYM
- | AUTO_SYM
- | AVG_ROW_LENGTH
- | AVG_SYM
- | BLOCK_SYM
- | BODY_MARIADB_SYM
- | BTREE_SYM
- | CASCADED
- | CATALOG_NAME_SYM
- | CHAIN_SYM
- | CHANGED
- | CIPHER_SYM
- | CLIENT_SYM
- | CLASS_ORIGIN_SYM
- | COALESCE
- | CODE_SYM
- | COLLATION_SYM
- | COLUMN_NAME_SYM
- | COLUMNS
- | COMMITTED_SYM
- | COMPACT_SYM
- | COMPLETION_SYM
- | CONCURRENT
- | CONNECTION_SYM
- | CONSISTENT_SYM
- | CONSTRAINT_CATALOG_SYM
- | CONSTRAINT_SCHEMA_SYM
- | CONSTRAINT_NAME_SYM
- | CONTEXT_SYM
- | CONTRIBUTORS_SYM
- | CURRENT_POS_SYM
- | CPU_SYM
- | CUBE_SYM
- /*
- Although a reserved keyword in SQL:2003 (and :2008),
- not reserved in MySQL per WL#2111 specification.
- */
- | CURRENT_SYM
- | CURSOR_NAME_SYM
- | CYCLE_SYM
- | DATA_SYM
- | DATAFILE_SYM
- | DATE_FORMAT_SYM
- | DAY_SYM
- | DECODE_MARIADB_SYM
- | DECODE_ORACLE_SYM
- | DEFINER_SYM
- | DELAY_KEY_WRITE_SYM
- | DES_KEY_FILE
- | DIAGNOSTICS_SYM
- | DIRECTORY_SYM
- | DISABLE_SYM
- | DISCARD
- | DISK_SYM
- | DUMPFILE
- | DUPLICATE_SYM
- | DYNAMIC_SYM
- | ELSEIF_ORACLE_SYM
- | ELSIF_MARIADB_SYM
- | ENDS_SYM
- | ENGINE_SYM
- | ENGINES_SYM
- | ERROR_SYM
- | ERRORS
- | ESCAPE_SYM
- | EVENT_SYM
- | EVENTS_SYM
- | EVERY_SYM
- | EXCEPTION_MARIADB_SYM
- | EXCHANGE_SYM
- | EXPANSION_SYM
- | EXPIRE_SYM
- | EXPORT_SYM
- | EXTENDED_SYM
- | EXTENT_SIZE_SYM
- | FAULTS_SYM
- | FAST_SYM
- | FOUND_SYM
- | ENABLE_SYM
- | FULL
- | FILE_SYM
- | FIRST_SYM
- | GENERAL
- | GENERATED_SYM
- | GET_FORMAT
- | GRANTS
- | GOTO_MARIADB_SYM
- | HASH_SYM
- | HARD_SYM
- | HISTORY_SYM
- | HOSTS_SYM
- | HOUR_SYM
- | ID_SYM
- | IDENTIFIED_SYM
- | IGNORE_SERVER_IDS_SYM
- | INCREMENT_SYM
- | IMMEDIATE_SYM
- | INVOKER_SYM
- | IMPORT
- | INDEXES
- | INITIAL_SIZE_SYM
- | IO_SYM
- | IPC_SYM
- | ISOLATION
- | ISOPEN_SYM
- | ISSUER_SYM
- | INSERT_METHOD
- | INVISIBLE_SYM
- | KEY_BLOCK_SIZE
- | LAST_VALUE
- | LAST_SYM
- | LASTVAL_SYM
- | LEAVES
- | LESS_SYM
- | LEVEL_SYM
- | LIST_SYM
- | LOCKS_SYM
- | LOGFILE_SYM
- | LOGS_SYM
- | MAX_ROWS
- | MASTER_SYM
- | MASTER_HEARTBEAT_PERIOD_SYM
- | MASTER_GTID_POS_SYM
- | MASTER_HOST_SYM
- | MASTER_PORT_SYM
- | MASTER_LOG_FILE_SYM
- | MASTER_LOG_POS_SYM
- | MASTER_USER_SYM
- | MASTER_USE_GTID_SYM
- | MASTER_PASSWORD_SYM
- | MASTER_SERVER_ID_SYM
- | MASTER_CONNECT_RETRY_SYM
- | MASTER_DELAY_SYM
- | MASTER_SSL_SYM
- | MASTER_SSL_CA_SYM
- | MASTER_SSL_CAPATH_SYM
- | MASTER_SSL_CERT_SYM
- | MASTER_SSL_CIPHER_SYM
- | MASTER_SSL_CRL_SYM
- | MASTER_SSL_CRLPATH_SYM
- | MASTER_SSL_KEY_SYM
- | MAX_CONNECTIONS_PER_HOUR
- | MAX_QUERIES_PER_HOUR
- | MAX_SIZE_SYM
- | MAX_STATEMENT_TIME_SYM
- | MAX_UPDATES_PER_HOUR
- | MAX_USER_CONNECTIONS_SYM
- | MEMORY_SYM
- | MERGE_SYM
- | MESSAGE_TEXT_SYM
- | MICROSECOND_SYM
- | MIGRATE_SYM
- | MINUTE_SYM
- | MINVALUE_SYM
- | MIN_ROWS
- | MODIFY_SYM
- | MODE_SYM
- | MONTH_SYM
- | MUTEX_SYM
- | MYSQL_SYM
- | MYSQL_ERRNO_SYM
- | NAME_SYM
- | NEXT_SYM %prec PREC_BELOW_CONTRACTION_TOKEN2
- | NEXTVAL_SYM
- | NEVER_SYM
- | NEW_SYM
- | NOCACHE_SYM
- | NOCYCLE_SYM
- | NOMINVALUE_SYM
- | NOMAXVALUE_SYM
- | NO_WAIT_SYM
- | NOWAIT_SYM
- | NODEGROUP_SYM
- | NONE_SYM
- | NOTFOUND_SYM
- | OF_SYM
- | OFFSET_SYM
- | OLD_PASSWORD_SYM
- | ONE_SYM
- | ONLINE_SYM
- | ONLY_SYM
- | PACKAGE_MARIADB_SYM
- | PACK_KEYS_SYM
- | PAGE_SYM
- | PARTIAL
- | PARTITIONING_SYM
- | PARTITIONS_SYM
- | PERSISTENT_SYM
- | PHASE_SYM
- | PLUGIN_SYM
- | PLUGINS_SYM
- | PRESERVE_SYM
- | PREV_SYM
- | PREVIOUS_SYM %prec PREC_BELOW_CONTRACTION_TOKEN2
- | PRIVILEGES
- | PROCESS
- | PROCESSLIST_SYM
- | PROFILE_SYM
- | PROFILES_SYM
- | PROXY_SYM
- | QUARTER_SYM
- | QUERY_SYM
- | QUICK
- | RAISE_MARIADB_SYM
- | READ_ONLY_SYM
- | REBUILD_SYM
- | RECOVER_SYM
- | REDO_BUFFER_SIZE_SYM
- | REDOFILE_SYM
- | REDUNDANT_SYM
- | RELAY
- | RELAYLOG_SYM
- | RELAY_LOG_FILE_SYM
- | RELAY_LOG_POS_SYM
- | RELAY_THREAD
- | RELOAD
- | REORGANIZE_SYM
- | REPEATABLE_SYM
- | REPLICATION
- | RESOURCES
- | RESTART_SYM
- | RESUME_SYM
- | RETURNED_SQLSTATE_SYM
- | RETURNS_SYM
- | REUSE_SYM
- | REVERSE_SYM
- | ROLLUP_SYM
- | ROUTINE_SYM
- | ROWCOUNT_SYM
- | ROWTYPE_MARIADB_SYM
- | ROW_COUNT_SYM
- | ROW_FORMAT_SYM
- | RTREE_SYM
- | SCHEDULE_SYM
- | SCHEMA_NAME_SYM
- | SECOND_SYM
- | SEQUENCE_SYM
- | SERIALIZABLE_SYM
- | SETVAL_SYM
- | SIMPLE_SYM
- | SHARE_SYM
- | SLAVE_POS_SYM
- | SLOW
- | SNAPSHOT_SYM
- | SOFT_SYM
- | SOUNDS_SYM
- | SOURCE_SYM
- | SQL_CACHE_SYM
- | SQL_BUFFER_RESULT
- | SQL_NO_CACHE_SYM
- | SQL_THREAD
- | STAGE_SYM
- | STARTS_SYM
- | STATEMENT_SYM
- | STATUS_SYM
- | STORAGE_SYM
- | STRING_SYM
- | SUBCLASS_ORIGIN_SYM
- | SUBDATE_SYM
- | SUBJECT_SYM
- | SUBPARTITION_SYM
- | SUBPARTITIONS_SYM
- | SUPER_SYM
- | SUSPEND_SYM
- | SWAPS_SYM
- | SWITCHES_SYM
- | SYSTEM
- | SYSTEM_TIME_SYM
- | TABLE_NAME_SYM
- | TABLES
- | TABLE_CHECKSUM_SYM
- | TABLESPACE
- | TEMPORARY
- | TEMPTABLE_SYM
- | THAN_SYM
- | TRANSACTION_SYM %prec PREC_BELOW_CONTRACTION_TOKEN2
- | TRANSACTIONAL_SYM
- | TRIGGERS_SYM
- | TRIM_ORACLE
- | TIMESTAMP_ADD
- | TIMESTAMP_DIFF
- | TYPES_SYM
- | TYPE_SYM
- | UDF_RETURNS_SYM
- | UNCOMMITTED_SYM
- | UNDEFINED_SYM
- | UNDO_BUFFER_SIZE_SYM
- | UNDOFILE_SYM
- | UNKNOWN_SYM
- | UNTIL_SYM
- | USER_SYM %prec PREC_BELOW_CONTRACTION_TOKEN2
- | USE_FRM
- | VARIABLES
- | VERSIONING_SYM
- | VIEW_SYM
- | VIRTUAL_SYM
- | VALUE_SYM
- | WARNINGS
- | WAIT_SYM
- | WEEK_SYM
- | WEIGHT_STRING_SYM
- | WITHOUT
- | WORK_SYM
- | X509_SYM
- | XML_SYM
- | VIA_SYM
- ;
-
-/*
- SQLCOM_SET_OPTION statement.
-
- Note that to avoid shift/reduce conflicts, we have separate rules for the
- first option listed in the statement.
-*/
-
-set:
- SET
- {
- LEX *lex=Lex;
- if (lex->main_select_push())
- MYSQL_YYABORT;
- lex->set_stmt_init();
- lex->var_list.empty();
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
- }
- start_option_value_list
- {
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
- | SET STATEMENT_SYM
- {
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- Lex->set_stmt_init();
- }
- set_stmt_option_value_following_option_type_list
- {
- LEX *lex= Lex;
- if (unlikely(lex->table_or_sp_used()))
- my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "SET STATEMENT"));
- lex->stmt_var_list= lex->var_list;
- lex->var_list.empty();
- Lex->pop_select(); //main select
- if (Lex->check_main_unit_semantics())
- MYSQL_YYABORT;
- }
- FOR_SYM verb_clause
- {}
- ;
-
-set_assign:
- ident_directly_assignable SET_VAR
- {
- LEX *lex=Lex;
- lex->set_stmt_init();
- lex->var_list.empty();
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
- }
- set_expr_or_default
- {
- if (unlikely(Lex->set_variable(&$1, $4)) ||
- unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
- | ident_directly_assignable '.' ident SET_VAR
- {
- LEX *lex=Lex;
- lex->set_stmt_init();
- lex->var_list.empty();
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
- }
- set_expr_or_default
- {
- LEX *lex= Lex;
- DBUG_ASSERT(lex->var_list.is_empty());
- if (unlikely(lex->set_variable(&$1, &$3, $6)) ||
- unlikely(lex->sphead->restore_lex(thd)))
- MYSQL_YYABORT;
- }
- | COLON_ORACLE_SYM ident '.' ident SET_VAR
- {
- LEX *lex= Lex;
- if (unlikely(!lex->is_trigger_new_or_old_reference(&$2)))
- {
- thd->parse_error(ER_SYNTAX_ERROR, $1.pos());
- MYSQL_YYABORT;
- }
- lex->set_stmt_init();
- lex->var_list.empty();
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
- }
- set_expr_or_default
- {
- LEX_CSTRING tmp= { $2.str, $2.length };
- if (unlikely(Lex->set_trigger_field(&tmp, &$4, $7)) ||
- unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
- ;
-
-set_stmt_option_value_following_option_type_list:
- /*
- Only system variables can be used here. If this condition is changed
- please check careful code under lex->option_type == OPT_STATEMENT
- condition on wrong type casts.
- */
- option_value_following_option_type
- | set_stmt_option_value_following_option_type_list ',' option_value_following_option_type
- ;
-
-/* Start of option value list */
-start_option_value_list:
- option_value_no_option_type
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
- option_value_list_continued
- | TRANSACTION_SYM
- {
- Lex->option_type= OPT_DEFAULT;
- }
- transaction_characteristics
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
- | option_type
- {
- Lex->option_type= $1;
- }
- start_option_value_list_following_option_type
- ;
-
-
-/* Start of option value list, option_type was given */
-start_option_value_list_following_option_type:
- option_value_following_option_type
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
- option_value_list_continued
- | TRANSACTION_SYM transaction_characteristics
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
- ;
-
-/* Remainder of the option value list after first option value. */
-option_value_list_continued:
- /* empty */
- | ',' option_value_list
- ;
-
-/* Repeating list of option values after first option value. */
-option_value_list:
- {
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
- }
- option_value
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
- | option_value_list ','
- {
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
- }
- option_value
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
- ;
-
-/* Wrapper around option values following the first option value in the stmt. */
-option_value:
- option_type
- {
- Lex->option_type= $1;
- }
- option_value_following_option_type
- | option_value_no_option_type
- ;
-
-option_type:
- GLOBAL_SYM { $$=OPT_GLOBAL; }
- | LOCAL_SYM { $$=OPT_SESSION; }
- | SESSION_SYM { $$=OPT_SESSION; }
- ;
-
-opt_var_type:
- /* empty */ { $$=OPT_SESSION; }
- | GLOBAL_SYM { $$=OPT_GLOBAL; }
- | LOCAL_SYM { $$=OPT_SESSION; }
- | SESSION_SYM { $$=OPT_SESSION; }
- ;
-
-opt_var_ident_type:
- /* empty */ { $$=OPT_DEFAULT; }
- | GLOBAL_SYM '.' { $$=OPT_GLOBAL; }
- | LOCAL_SYM '.' { $$=OPT_SESSION; }
- | SESSION_SYM '.' { $$=OPT_SESSION; }
- ;
-
-/* Option values with preceding option_type. */
-option_value_following_option_type:
- ident equal set_expr_or_default
- {
- if (unlikely(Lex->set_system_variable(Lex->option_type, &$1, $3)))
- MYSQL_YYABORT;
- }
- | ident '.' ident equal set_expr_or_default
- {
- if (unlikely(Lex->set_system_variable(thd, Lex->option_type, &$1, &$3, $5)))
- MYSQL_YYABORT;
- }
- | DEFAULT '.' ident equal set_expr_or_default
- {
- if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $5)))
- MYSQL_YYABORT;
- }
- ;
-
-/* Option values without preceding option_type. */
-option_value_no_option_type:
- ident_set_usual_case equal set_expr_or_default
- {
- if (unlikely(Lex->set_variable(&$1, $3)))
- MYSQL_YYABORT;
- }
- | ident '.' ident equal set_expr_or_default
- {
- if (unlikely(Lex->set_variable(&$1, &$3, $5)))
- MYSQL_YYABORT;
- }
- | DEFAULT '.' ident equal set_expr_or_default
- {
- if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $5)))
- MYSQL_YYABORT;
- }
- | '@' ident_or_text equal expr
- {
- if (unlikely(Lex->set_user_variable(thd, &$2, $4)))
- MYSQL_YYABORT;
- }
- | '@' '@' opt_var_ident_type ident_sysvar_name equal set_expr_or_default
- {
- if (unlikely(Lex->set_system_variable($3, &$4, $6)))
- MYSQL_YYABORT;
- }
- | '@' '@' opt_var_ident_type ident_sysvar_name '.' ident equal set_expr_or_default
- {
- if (unlikely(Lex->set_system_variable(thd, $3, &$4, &$6, $8)))
- MYSQL_YYABORT;
- }
- | '@' '@' opt_var_ident_type DEFAULT '.' ident equal set_expr_or_default
- {
- if (unlikely(Lex->set_default_system_variable($3, &$6, $8)))
- MYSQL_YYABORT;
- }
- | charset old_or_new_charset_name_or_default
- {
- LEX *lex= thd->lex;
- CHARSET_INFO *cs2;
- cs2= $2 ? $2: global_system_variables.character_set_client;
- set_var_collation_client *var;
- var= (new (thd->mem_root)
- set_var_collation_client(cs2,
- thd->variables.collation_database,
- cs2));
- if (unlikely(var == NULL))
- MYSQL_YYABORT;
- lex->var_list.push_back(var, thd->mem_root);
- }
- | NAMES_SYM equal expr
- {
- LEX *lex= Lex;
- sp_pcontext *spc= lex->spcont;
- LEX_CSTRING names= { STRING_WITH_LEN("names") };
- if (unlikely(spc && spc->find_variable(&names, false)))
- my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), names.str);
- else
- thd->parse_error();
- MYSQL_YYABORT;
- }
- | NAMES_SYM charset_name_or_default opt_collate
- {
- LEX *lex= Lex;
- CHARSET_INFO *cs2;
- CHARSET_INFO *cs3;
- cs2= $2 ? $2 : global_system_variables.character_set_client;
- cs3= $3 ? $3 : cs2;
- if (unlikely(!my_charset_same(cs2, cs3)))
- {
- my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
- cs3->name, cs2->csname);
- MYSQL_YYABORT;
- }
- set_var_collation_client *var;
- var= new (thd->mem_root) set_var_collation_client(cs3, cs3, cs3);
- if (unlikely(var == NULL) ||
- unlikely(lex->var_list.push_back(var, thd->mem_root)))
- MYSQL_YYABORT;
- }
- | DEFAULT ROLE_SYM grant_role
- {
- LEX *lex = Lex;
- LEX_USER *user;
- if (unlikely(!(user=(LEX_USER *) thd->calloc(sizeof(LEX_USER)))))
- MYSQL_YYABORT;
- user->user= current_user;
- set_var_default_role *var= (new (thd->mem_root)
- set_var_default_role(user,
- $3->user));
- if (unlikely(var == NULL) ||
- unlikely(lex->var_list.push_back(var, thd->mem_root)))
- MYSQL_YYABORT;
-
- thd->lex->autocommit= TRUE;
- if (lex->sphead)
- lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
- }
- | DEFAULT ROLE_SYM grant_role FOR_SYM user
- {
- LEX *lex = Lex;
- set_var_default_role *var= (new (thd->mem_root)
- set_var_default_role($5, $3->user));
- if (unlikely(var == NULL) ||
- unlikely(lex->var_list.push_back(var, thd->mem_root)))
- MYSQL_YYABORT;
- thd->lex->autocommit= TRUE;
- if (lex->sphead)
- lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
- }
- | ROLE_SYM ident_or_text
- {
- LEX *lex = Lex;
- set_var_role *var= new (thd->mem_root) set_var_role($2);
- if (unlikely(var == NULL) ||
- unlikely(lex->var_list.push_back(var, thd->mem_root)))
- MYSQL_YYABORT;
- }
- | ROLE_SYM equal set_expr_or_default
- {
- if (unlikely(Lex->set_variable(&$1, $3)))
- MYSQL_YYABORT;
- }
- | PASSWORD_SYM opt_for_user text_or_password
- {
- LEX *lex = Lex;
- set_var_password *var= (new (thd->mem_root)
- set_var_password(lex->definer));
- if (unlikely(var == NULL) ||
- unlikely(lex->var_list.push_back(var, thd->mem_root)))
- MYSQL_YYABORT;
- lex->autocommit= TRUE;
- if (lex->sphead)
- lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
- }
- ;
-
-
-transaction_characteristics:
- transaction_access_mode
- | isolation_level
- | transaction_access_mode ',' isolation_level
- | isolation_level ',' transaction_access_mode
- ;
-
-transaction_access_mode:
- transaction_access_mode_types
- {
- LEX *lex=Lex;
- Item *item= new (thd->mem_root) Item_int(thd, (int32) $1);
- if (unlikely(item == NULL))
- MYSQL_YYABORT;
- set_var *var= (new (thd->mem_root)
- set_var(thd, lex->option_type,
- find_sys_var(thd, "tx_read_only"),
- &null_clex_str,
- item));
- if (unlikely(var == NULL))
- MYSQL_YYABORT;
- if (unlikely(lex->var_list.push_back(var, thd->mem_root)))
- MYSQL_YYABORT;
- }
- ;
-
-isolation_level:
- ISOLATION LEVEL_SYM isolation_types
- {
- LEX *lex=Lex;
- Item *item= new (thd->mem_root) Item_int(thd, (int32) $3);
- if (unlikely(item == NULL))
- MYSQL_YYABORT;
- set_var *var= (new (thd->mem_root)
- set_var(thd, lex->option_type,
- find_sys_var(thd, "tx_isolation"),
- &null_clex_str,
- item));
- if (unlikely(var == NULL) ||
- unlikely(lex->var_list.push_back(var, thd->mem_root)))
- MYSQL_YYABORT;
- }
- ;
-
-transaction_access_mode_types:
- READ_SYM ONLY_SYM { $$= true; }
- | READ_SYM WRITE_SYM { $$= false; }
- ;
-
-isolation_types:
- READ_SYM UNCOMMITTED_SYM { $$= ISO_READ_UNCOMMITTED; }
- | READ_SYM COMMITTED_SYM { $$= ISO_READ_COMMITTED; }
- | REPEATABLE_SYM READ_SYM { $$= ISO_REPEATABLE_READ; }
- | SERIALIZABLE_SYM { $$= ISO_SERIALIZABLE; }
- ;
-
-opt_for_user:
- equal
- {
- LEX *lex= thd->lex;
- sp_pcontext *spc= lex->spcont;
- LEX_CSTRING pw= { STRING_WITH_LEN("password") };
-
- if (unlikely(spc && spc->find_variable(&pw, false)))
- my_yyabort_error((ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str));
- if (unlikely(!(lex->definer= (LEX_USER*)
- thd->calloc(sizeof(LEX_USER)))))
- MYSQL_YYABORT;
- lex->definer->user= current_user;
- lex->definer->auth= new (thd->mem_root) USER_AUTH();
- }
- | FOR_SYM user equal { Lex->definer= $2; }
- ;
-
-text_or_password:
- TEXT_STRING
- {
- Lex->definer->auth= new (thd->mem_root) USER_AUTH();
- Lex->definer->auth->auth_str= $1;
- }
- | PASSWORD_SYM '(' TEXT_STRING ')'
- {
- Lex->definer->auth= new (thd->mem_root) USER_AUTH();
- Lex->definer->auth->pwtext= $3;
- }
- | OLD_PASSWORD_SYM '(' TEXT_STRING ')'
- {
- Lex->definer->auth= new (thd->mem_root) USER_AUTH();
- Lex->definer->auth->pwtext= $3;
- Lex->definer->auth->auth_str.str= Item_func_password::alloc(thd,
- $3.str, $3.length, Item_func_password::OLD);
- Lex->definer->auth->auth_str.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
- }
- ;
-
-set_expr_or_default:
- expr { $$=$1; }
- | DEFAULT { $$=0; }
- | ON
- {
- $$=new (thd->mem_root) Item_string_sys(thd, "ON", 2);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | ALL
- {
- $$=new (thd->mem_root) Item_string_sys(thd, "ALL", 3);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- | BINARY
- {
- $$=new (thd->mem_root) Item_string_sys(thd, "binary", 6);
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
- }
- ;
-
-/* Lock function */
-
-lock:
- LOCK_SYM table_or_tables
- {
- LEX *lex= Lex;
-
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "LOCK"));
- lex->sql_command= SQLCOM_LOCK_TABLES;
- }
- table_lock_list opt_lock_wait_timeout
- {}
- ;
-
-opt_lock_wait_timeout:
- /* empty */
- {}
- | WAIT_SYM ulong_num
- {
- if (unlikely(set_statement_var_if_exists(thd, STRING_WITH_LEN("lock_wait_timeout"), $2)) ||
- unlikely(set_statement_var_if_exists(thd, STRING_WITH_LEN("innodb_lock_wait_timeout"), $2)))
- MYSQL_YYABORT;
- }
- | NOWAIT_SYM
- {
- if (unlikely(set_statement_var_if_exists(thd, STRING_WITH_LEN("lock_wait_timeout"), 0)) ||
- unlikely(set_statement_var_if_exists(thd, STRING_WITH_LEN("innodb_lock_wait_timeout"), 0)))
- MYSQL_YYABORT;
- }
- ;
-
-table_or_tables:
- TABLE_SYM { }
- | TABLES { }
- ;
-
-table_lock_list:
- table_lock
- | table_lock_list ',' table_lock
- ;
-
-table_lock:
- table_ident opt_table_alias_clause lock_option
- {
- thr_lock_type lock_type= (thr_lock_type) $3;
- bool lock_for_write= (lock_type >= TL_WRITE_ALLOW_WRITE);
- ulong table_options= lock_for_write ? TL_OPTION_UPDATING : 0;
- enum_mdl_type mdl_type= !lock_for_write
- ? MDL_SHARED_READ
- : lock_type == TL_WRITE_CONCURRENT_INSERT
- ? MDL_SHARED_WRITE
- : MDL_SHARED_NO_READ_WRITE;
-
- if (unlikely(!Lex->current_select_or_default()->
- add_table_to_list(thd, $1, $2, table_options,
- lock_type, mdl_type)))
- MYSQL_YYABORT;
- }
- ;
-
-lock_option:
- READ_SYM { $$= TL_READ_NO_INSERT; }
- | WRITE_SYM { $$= TL_WRITE_DEFAULT; }
- | WRITE_SYM CONCURRENT
- {
- $$= (Lex->sphead ? TL_WRITE_DEFAULT : TL_WRITE_CONCURRENT_INSERT);
- }
-
- | LOW_PRIORITY WRITE_SYM { $$= TL_WRITE_LOW_PRIORITY; }
- | READ_SYM LOCAL_SYM { $$= TL_READ; }
- ;
-
-unlock:
- UNLOCK_SYM
- {
- LEX *lex= Lex;
-
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "UNLOCK"));
- lex->sql_command= SQLCOM_UNLOCK_TABLES;
- }
- table_or_tables
- {}
- ;
-
-/*
-** Handler: direct access to ISAM functions
-*/
-
-handler:
- HANDLER_SYM
- {
- if (Lex->main_select_push())
- MYSQL_YYABORT;
- }
- handler_tail
- {
- Lex->pop_select(); //main select
- }
- ;
-
-handler_tail:
- table_ident OPEN_SYM opt_table_alias_clause
- {
- LEX *lex= Lex;
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER"));
- lex->sql_command = SQLCOM_HA_OPEN;
- if (!lex->current_select->add_table_to_list(thd, $1, $3, 0))
- MYSQL_YYABORT;
- }
- | table_ident_nodb CLOSE_SYM
- {
- LEX *lex= Lex;
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER"));
- lex->sql_command = SQLCOM_HA_CLOSE;
- if (!lex->current_select->add_table_to_list(thd, $1, 0, 0))
- MYSQL_YYABORT;
- }
- | table_ident_nodb READ_SYM
- {
- LEX *lex=Lex;
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER"));
- lex->clause_that_disallows_subselect= "HANDLER..READ";
- lex->sql_command = SQLCOM_HA_READ;
- lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */
- Item *one= new (thd->mem_root) Item_int(thd, (int32) 1);
- if (unlikely(one == NULL))
- MYSQL_YYABORT;
- lex->current_select->select_limit= one;
- lex->current_select->offset_limit= 0;
- lex->limit_rows_examined= 0;
- if (!lex->current_select->add_table_to_list(thd, $1, 0, 0))
- MYSQL_YYABORT;
- }
- handler_read_or_scan opt_where_clause opt_global_limit_clause
- {
- LEX *lex=Lex;
- lex->clause_that_disallows_subselect= NULL;
- if (!lex->current_select->explicit_limit)
- {
- Item *one= new (thd->mem_root) Item_int(thd, (int32) 1);
- if (one == NULL)
- MYSQL_YYABORT;
- lex->current_select->select_limit= one;
- lex->current_select->offset_limit= 0;
- lex->limit_rows_examined= 0;
- }
- /* Stored functions are not supported for HANDLER READ. */
- if (lex->uses_stored_routines())
- {
- my_error(ER_NOT_SUPPORTED_YET, MYF(0),
- "stored functions in HANDLER ... READ");
- MYSQL_YYABORT;
- }
- }
- ;
-
-handler_read_or_scan:
- handler_scan_function { Lex->ident= null_clex_str; }
- | ident handler_rkey_function { Lex->ident= $1; }
- ;
-
-handler_scan_function:
- FIRST_SYM { Lex->ha_read_mode = RFIRST; }
- | NEXT_SYM { Lex->ha_read_mode = RNEXT; }
- ;
-
-handler_rkey_function:
- FIRST_SYM { Lex->ha_read_mode = RFIRST; }
- | NEXT_SYM { Lex->ha_read_mode = RNEXT; }
- | PREV_SYM { Lex->ha_read_mode = RPREV; }
- | LAST_SYM { Lex->ha_read_mode = RLAST; }
- | handler_rkey_mode
- {
- LEX *lex=Lex;
- lex->ha_read_mode = RKEY;
- lex->ha_rkey_mode=$1;
- if (unlikely(!(lex->insert_list= new (thd->mem_root) List_item)))
- MYSQL_YYABORT;
- }
- '(' values ')'
- {}
- ;
-
-handler_rkey_mode:
- '=' { $$=HA_READ_KEY_EXACT; }
- | GE { $$=HA_READ_KEY_OR_NEXT; }
- | LE { $$=HA_READ_KEY_OR_PREV; }
- | '>' { $$=HA_READ_AFTER_KEY; }
- | '<' { $$=HA_READ_BEFORE_KEY; }
- ;
-
-/* GRANT / REVOKE */
-
-revoke:
- REVOKE clear_privileges revoke_command
- {}
- ;
-
-revoke_command:
- grant_privileges ON opt_table grant_ident FROM user_and_role_list
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_REVOKE;
- lex->type= 0;
- }
- | grant_privileges ON FUNCTION_SYM grant_ident FROM user_and_role_list
- {
- if (unlikely(Lex->add_grant_command(thd, SQLCOM_REVOKE,
- TYPE_ENUM_FUNCTION)))
- MYSQL_YYABORT;
- }
- | grant_privileges ON PROCEDURE_SYM grant_ident FROM user_and_role_list
- {
- if (unlikely(Lex->add_grant_command(thd, SQLCOM_REVOKE,
- TYPE_ENUM_PROCEDURE)))
- MYSQL_YYABORT;
- }
- | grant_privileges ON PACKAGE_ORACLE_SYM grant_ident
- FROM user_and_role_list
- {
- if (unlikely(Lex->add_grant_command(thd, SQLCOM_REVOKE,
- TYPE_ENUM_PACKAGE)))
- MYSQL_YYABORT;
- }
- | grant_privileges ON PACKAGE_ORACLE_SYM BODY_ORACLE_SYM grant_ident
- FROM user_and_role_list
- {
- if (unlikely(Lex->add_grant_command(thd, SQLCOM_REVOKE,
- TYPE_ENUM_PACKAGE_BODY)))
- MYSQL_YYABORT;
- }
- | ALL opt_privileges ',' GRANT OPTION FROM user_and_role_list
- {
- Lex->sql_command = SQLCOM_REVOKE_ALL;
- }
- | PROXY_SYM ON user FROM user_list
- {
- LEX *lex= Lex;
- lex->users_list.push_front ($3);
- lex->sql_command= SQLCOM_REVOKE;
- lex->type= TYPE_ENUM_PROXY;
- }
- | admin_option_for_role FROM user_and_role_list
- {
- Lex->sql_command= SQLCOM_REVOKE_ROLE;
- if (unlikely(Lex->users_list.push_front($1, thd->mem_root)))
- MYSQL_YYABORT;
- }
- ;
-
-admin_option_for_role:
- ADMIN_SYM OPTION FOR_SYM grant_role
- { Lex->with_admin_option= true; $$= $4; }
- | grant_role
- { Lex->with_admin_option= false; $$= $1; }
- ;
-
-grant:
- GRANT clear_privileges grant_command
- {}
- ;
-
-grant_command:
- grant_privileges ON opt_table grant_ident TO_SYM grant_list
- opt_require_clause opt_grant_options
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_GRANT;
- lex->type= 0;
- }
- | grant_privileges ON FUNCTION_SYM grant_ident TO_SYM grant_list
- opt_require_clause opt_grant_options
- {
- if (unlikely(Lex->add_grant_command(thd, SQLCOM_GRANT,
- TYPE_ENUM_FUNCTION)))
- MYSQL_YYABORT;
- }
- | grant_privileges ON PROCEDURE_SYM grant_ident TO_SYM grant_list
- opt_require_clause opt_grant_options
- {
- if (unlikely(Lex->add_grant_command(thd, SQLCOM_GRANT,
- TYPE_ENUM_PROCEDURE)))
- MYSQL_YYABORT;
- }
- | grant_privileges ON PACKAGE_ORACLE_SYM grant_ident TO_SYM grant_list
- opt_require_clause opt_grant_options
- {
- if (unlikely(Lex->add_grant_command(thd, SQLCOM_GRANT,
- TYPE_ENUM_PACKAGE)))
- MYSQL_YYABORT;
- }
- | grant_privileges ON PACKAGE_ORACLE_SYM BODY_ORACLE_SYM grant_ident TO_SYM grant_list
- opt_require_clause opt_grant_options
- {
- if (unlikely(Lex->add_grant_command(thd, SQLCOM_GRANT,
- TYPE_ENUM_PACKAGE_BODY)))
- MYSQL_YYABORT;
- }
- | PROXY_SYM ON user TO_SYM grant_list opt_grant_option
- {
- LEX *lex= Lex;
- lex->users_list.push_front ($3);
- lex->sql_command= SQLCOM_GRANT;
- lex->type= TYPE_ENUM_PROXY;
- }
- | grant_role TO_SYM grant_list opt_with_admin_option
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_GRANT_ROLE;
- /* The first role is the one that is granted */
- if (unlikely(Lex->users_list.push_front($1, thd->mem_root)))
- MYSQL_YYABORT;
- }
-
- ;
-
-opt_with_admin:
- /* nothing */ { Lex->definer = 0; }
- | WITH ADMIN_SYM user_or_role { Lex->definer = $3; }
- ;
-
-opt_with_admin_option:
- /* nothing */ { Lex->with_admin_option= false; }
- | WITH ADMIN_SYM OPTION { Lex->with_admin_option= true; }
- ;
-
-role_list:
- grant_role
- {
- if (unlikely(Lex->users_list.push_back($1, thd->mem_root)))
- MYSQL_YYABORT;
- }
- | role_list ',' grant_role
- {
- if (unlikely(Lex->users_list.push_back($3, thd->mem_root)))
- MYSQL_YYABORT;
- }
- ;
-
-current_role:
- CURRENT_ROLE optional_braces
- {
- if (unlikely(!($$=(LEX_USER*) thd->calloc(sizeof(LEX_USER)))))
- MYSQL_YYABORT;
- $$->user= current_role;
- $$->auth= NULL;
- }
- ;
-
-grant_role:
- ident_or_text
- {
- CHARSET_INFO *cs= system_charset_info;
- /* trim end spaces (as they'll be lost in mysql.user anyway) */
- $1.length= cs->cset->lengthsp(cs, $1.str, $1.length);
- ((char*) $1.str)[$1.length] = '\0';
- if (unlikely($1.length == 0))
- my_yyabort_error((ER_INVALID_ROLE, MYF(0), ""));
- if (unlikely(!($$=(LEX_USER*) thd->alloc(sizeof(LEX_USER)))))
- MYSQL_YYABORT;
- $$->user= $1;
- $$->host= empty_clex_str;
- $$->auth= NULL;
-
- if (unlikely(check_string_char_length(&$$->user, ER_USERNAME,
- username_char_length,
- cs, 0)))
- MYSQL_YYABORT;
- }
- | current_role
- ;
-
-opt_table:
- /* Empty */
- | TABLE_SYM
- ;
-
-grant_privileges:
- object_privilege_list {}
- | ALL opt_privileges
- {
- Lex->all_privileges= 1;
- Lex->grant= GLOBAL_ACLS;
- }
- ;
-
-opt_privileges:
- /* empty */
- | PRIVILEGES
- ;
-
-object_privilege_list:
- object_privilege
- | object_privilege_list ',' object_privilege
- ;
-
-object_privilege:
- SELECT_SYM
- { Lex->which_columns = SELECT_ACL;}
- opt_column_list {}
- | INSERT
- { Lex->which_columns = INSERT_ACL;}
- opt_column_list {}
- | UPDATE_SYM
- { Lex->which_columns = UPDATE_ACL; }
- opt_column_list {}
- | REFERENCES
- { Lex->which_columns = REFERENCES_ACL;}
- opt_column_list {}
- | DELETE_SYM { Lex->grant |= DELETE_ACL;}
- | USAGE {}
- | INDEX_SYM { Lex->grant |= INDEX_ACL;}
- | ALTER { Lex->grant |= ALTER_ACL;}
- | CREATE { Lex->grant |= CREATE_ACL;}
- | DROP { Lex->grant |= DROP_ACL;}
- | EXECUTE_SYM { Lex->grant |= EXECUTE_ACL;}
- | RELOAD { Lex->grant |= RELOAD_ACL;}
- | SHUTDOWN { Lex->grant |= SHUTDOWN_ACL;}
- | PROCESS { Lex->grant |= PROCESS_ACL;}
- | FILE_SYM { Lex->grant |= FILE_ACL;}
- | GRANT OPTION { Lex->grant |= GRANT_ACL;}
- | SHOW DATABASES { Lex->grant |= SHOW_DB_ACL;}
- | SUPER_SYM { Lex->grant |= SUPER_ACL;}
- | CREATE TEMPORARY TABLES { Lex->grant |= CREATE_TMP_ACL;}
- | LOCK_SYM TABLES { Lex->grant |= LOCK_TABLES_ACL; }
- | REPLICATION SLAVE { Lex->grant |= REPL_SLAVE_ACL; }
- | REPLICATION CLIENT_SYM { Lex->grant |= REPL_CLIENT_ACL; }
- | CREATE VIEW_SYM { Lex->grant |= CREATE_VIEW_ACL; }
- | SHOW VIEW_SYM { Lex->grant |= SHOW_VIEW_ACL; }
- | CREATE ROUTINE_SYM { Lex->grant |= CREATE_PROC_ACL; }
- | ALTER ROUTINE_SYM { Lex->grant |= ALTER_PROC_ACL; }
- | CREATE USER_SYM { Lex->grant |= CREATE_USER_ACL; }
- | EVENT_SYM { Lex->grant |= EVENT_ACL;}
- | TRIGGER_SYM { Lex->grant |= TRIGGER_ACL; }
- | CREATE TABLESPACE { Lex->grant |= CREATE_TABLESPACE_ACL; }
- | DELETE_SYM HISTORY_SYM { Lex->grant |= DELETE_HISTORY_ACL; }
- ;
-
-opt_and:
- /* empty */ {}
- | AND_SYM {}
- ;
-
-require_list:
- require_list_element opt_and require_list
- | require_list_element
- ;
-
-require_list_element:
- SUBJECT_SYM TEXT_STRING
- {
- LEX *lex=Lex;
- if (lex->account_options.x509_subject.str)
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SUBJECT"));
- lex->account_options.x509_subject= $2;
- }
- | ISSUER_SYM TEXT_STRING
- {
- LEX *lex=Lex;
- if (lex->account_options.x509_issuer.str)
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "ISSUER"));
- lex->account_options.x509_issuer= $2;
- }
- | CIPHER_SYM TEXT_STRING
- {
- LEX *lex=Lex;
- if (lex->account_options.ssl_cipher.str)
- my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "CIPHER"));
- lex->account_options.ssl_cipher= $2;
- }
- ;
-
-grant_ident:
- '*'
- {
- LEX *lex= Lex;
- if (unlikely(lex->copy_db_to(&lex->current_select->db)))
- MYSQL_YYABORT;
- if (lex->grant == GLOBAL_ACLS)
- lex->grant = DB_ACLS & ~GRANT_ACL;
- else if (unlikely(lex->columns.elements))
- my_yyabort_error((ER_ILLEGAL_GRANT_FOR_TABLE, MYF(0)));
- }
- | ident '.' '*'
- {
- LEX *lex= Lex;
- lex->current_select->db= $1;
- if (lex->grant == GLOBAL_ACLS)
- lex->grant = DB_ACLS & ~GRANT_ACL;
- else if (unlikely(lex->columns.elements))
- my_yyabort_error((ER_ILLEGAL_GRANT_FOR_TABLE, MYF(0)));
- }
- | '*' '.' '*'
- {
- LEX *lex= Lex;
- lex->current_select->db= null_clex_str;
- if (lex->grant == GLOBAL_ACLS)
- lex->grant= GLOBAL_ACLS & ~GRANT_ACL;
- else if (unlikely(lex->columns.elements))
- my_yyabort_error((ER_ILLEGAL_GRANT_FOR_TABLE, MYF(0)));
- }
- | table_ident
- {
- LEX *lex=Lex;
- if (unlikely(!lex->current_select->
- add_table_to_list(thd, $1,NULL,
- TL_OPTION_UPDATING)))
- MYSQL_YYABORT;
- if (lex->grant == GLOBAL_ACLS)
- lex->grant = TABLE_ACLS & ~GRANT_ACL;
- }
- ;
-
-user_list:
- user
- {
- if (unlikely(Lex->users_list.push_back($1, thd->mem_root)))
- MYSQL_YYABORT;
- }
- | user_list ',' user
- {
- if (unlikely(Lex->users_list.push_back($3, thd->mem_root)))
- MYSQL_YYABORT;
- }
- ;
-
-grant_list:
- grant_user
- {
- if (unlikely(Lex->users_list.push_back($1, thd->mem_root)))
- MYSQL_YYABORT;
- }
- | grant_list ',' grant_user
- {
- if (unlikely(Lex->users_list.push_back($3, thd->mem_root)))
- MYSQL_YYABORT;
- }
- ;
-
-user_and_role_list:
- user_or_role
- {
- if (unlikely(Lex->users_list.push_back($1, thd->mem_root)))
- MYSQL_YYABORT;
- }
- | user_and_role_list ',' user_or_role
- {
- if (unlikely(Lex->users_list.push_back($3, thd->mem_root)))
- MYSQL_YYABORT;
- }
- ;
-
-via_or_with: VIA_SYM | WITH ;
-using_or_as: USING | AS ;
-
-grant_user:
- user IDENTIFIED_SYM BY TEXT_STRING
- {
- $$= $1;
- $1->auth= new (thd->mem_root) USER_AUTH();
- $1->auth->pwtext= $4;
- }
- | user IDENTIFIED_SYM BY PASSWORD_SYM TEXT_STRING
- {
- $$= $1;
- $1->auth= new (thd->mem_root) USER_AUTH();
- $1->auth->auth_str= $5;
- }
- | user IDENTIFIED_SYM via_or_with auth_expression
- {
- $$= $1;
- $1->auth= $4;
- }
- | user_or_role
- {
- $$= $1;
- }
- ;
-
-auth_expression:
- auth_token OR_SYM auth_expression
- {
- $$= $1;
- DBUG_ASSERT($$->next == NULL);
- $$->next= $3;
- }
- | auth_token
- {
- $$= $1;
- }
- ;
-
-auth_token:
- ident_or_text opt_auth_str
- {
- $$= $2;
- $$->plugin= $1;
- }
- ;
-
-opt_auth_str:
- /* empty */
- {
- if (!($$=(USER_AUTH*) thd->calloc(sizeof(USER_AUTH))))
- MYSQL_YYABORT;
- }
- | using_or_as TEXT_STRING_sys
- {
- if (!($$=(USER_AUTH*) thd->calloc(sizeof(USER_AUTH))))
- MYSQL_YYABORT;
- $$->auth_str= $2;
- }
- | using_or_as PASSWORD_SYM '(' TEXT_STRING ')'
- {
- if (!($$=(USER_AUTH*) thd->calloc(sizeof(USER_AUTH))))
- MYSQL_YYABORT;
- $$->pwtext= $4;
- }
- ;
-
-opt_column_list:
- /* empty */
- {
- LEX *lex=Lex;
- lex->grant |= lex->which_columns;
- }
- | '(' column_list ')' { }
- ;
-
-column_list:
- column_list ',' column_list_id
- | column_list_id
- ;
-
-column_list_id:
- ident
- {
- String *new_str= new (thd->mem_root) String((const char*) $1.str,$1.length,system_charset_info);
- if (unlikely(new_str == NULL))
- MYSQL_YYABORT;
- List_iterator <LEX_COLUMN> iter(Lex->columns);
- class LEX_COLUMN *point;
- LEX *lex=Lex;
- while ((point=iter++))
- {
- if (!my_strcasecmp(system_charset_info,
- point->column.c_ptr(), new_str->c_ptr()))
- break;
- }
- lex->grant_tot_col|= lex->which_columns;
- if (point)
- point->rights |= lex->which_columns;
- else
- {
- LEX_COLUMN *col= (new (thd->mem_root)
- LEX_COLUMN(*new_str,lex->which_columns));
- if (unlikely(col == NULL))
- MYSQL_YYABORT;
- lex->columns.push_back(col, thd->mem_root);
- }
- }
- ;
-
-opt_require_clause:
- /* empty */
- | REQUIRE_SYM require_list
- {
- Lex->account_options.ssl_type= SSL_TYPE_SPECIFIED;
- }
- | REQUIRE_SYM SSL_SYM
- {
- Lex->account_options.ssl_type= SSL_TYPE_ANY;
- }
- | REQUIRE_SYM X509_SYM
- {
- Lex->account_options.ssl_type= SSL_TYPE_X509;
- }
- | REQUIRE_SYM NONE_SYM
- {
- Lex->account_options.ssl_type= SSL_TYPE_NONE;
- }
- ;
-
-resource_option:
- MAX_QUERIES_PER_HOUR ulong_num
- {
- Lex->account_options.questions=$2;
- Lex->account_options.specified_limits|= USER_RESOURCES::QUERIES_PER_HOUR;
- }
- | MAX_UPDATES_PER_HOUR ulong_num
- {
- Lex->account_options.updates=$2;
- Lex->account_options.specified_limits|= USER_RESOURCES::UPDATES_PER_HOUR;
- }
- | MAX_CONNECTIONS_PER_HOUR ulong_num
- {
- Lex->account_options.conn_per_hour= $2;
- Lex->account_options.specified_limits|= USER_RESOURCES::CONNECTIONS_PER_HOUR;
- }
- | MAX_USER_CONNECTIONS_SYM int_num
- {
- Lex->account_options.user_conn= $2;
- Lex->account_options.specified_limits|= USER_RESOURCES::USER_CONNECTIONS;
- }
- | MAX_STATEMENT_TIME_SYM NUM_literal
- {
- Lex->account_options.max_statement_time= $2->val_real();
- Lex->account_options.specified_limits|= USER_RESOURCES::MAX_STATEMENT_TIME;
- }
- ;
-
-resource_option_list:
- resource_option_list resource_option {}
- | resource_option {}
- ;
-
-opt_resource_options:
- /* empty */ {}
- | WITH resource_option_list
- ;
-
-
-opt_grant_options:
- /* empty */ {}
- | WITH grant_option_list {}
- ;
-
-opt_grant_option:
- /* empty */ {}
- | WITH GRANT OPTION { Lex->grant |= GRANT_ACL;}
- ;
-
-grant_option_list:
- grant_option_list grant_option {}
- | grant_option {}
- ;
-
-grant_option:
- GRANT OPTION { Lex->grant |= GRANT_ACL;}
- | resource_option {}
- ;
-
-begin_stmt_mariadb:
- BEGIN_MARIADB_SYM
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_BEGIN;
- lex->start_transaction_opt= 0;
- }
- opt_work {}
- ;
-
-compound_statement:
- sp_proc_stmt_compound_ok
- {
- Lex->sql_command= SQLCOM_COMPOUND;
- if (Lex->sp_body_finalize_procedure(thd))
- MYSQL_YYABORT;
- }
- ;
-
-opt_not:
- /* nothing */ { $$= 0; }
- | not { $$= 1; }
- ;
-
-opt_work:
- /* empty */ {}
- | WORK_SYM {}
- ;
-
-opt_chain:
- /* empty */
- { $$= TVL_UNKNOWN; }
- | AND_SYM NO_SYM CHAIN_SYM { $$= TVL_NO; }
- | AND_SYM CHAIN_SYM { $$= TVL_YES; }
- ;
-
-opt_release:
- /* empty */
- { $$= TVL_UNKNOWN; }
- | RELEASE_SYM { $$= TVL_YES; }
- | NO_SYM RELEASE_SYM { $$= TVL_NO; }
- ;
-
-commit:
- COMMIT_SYM opt_work opt_chain opt_release
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_COMMIT;
- /* Don't allow AND CHAIN RELEASE. */
- MYSQL_YYABORT_UNLESS($3 != TVL_YES || $4 != TVL_YES);
- lex->tx_chain= $3;
- lex->tx_release= $4;
- }
- ;
-
-rollback:
- ROLLBACK_SYM opt_work opt_chain opt_release
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_ROLLBACK;
- /* Don't allow AND CHAIN RELEASE. */
- MYSQL_YYABORT_UNLESS($3 != TVL_YES || $4 != TVL_YES);
- lex->tx_chain= $3;
- lex->tx_release= $4;
- }
- | ROLLBACK_SYM opt_work TO_SYM SAVEPOINT_SYM ident
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_ROLLBACK_TO_SAVEPOINT;
- lex->ident= $5;
- }
- | ROLLBACK_SYM opt_work TO_SYM ident
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_ROLLBACK_TO_SAVEPOINT;
- lex->ident= $4;
- }
- ;
-
-savepoint:
- SAVEPOINT_SYM ident
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_SAVEPOINT;
- lex->ident= $2;
- }
- ;
-
-release:
- RELEASE_SYM SAVEPOINT_SYM ident
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_RELEASE_SAVEPOINT;
- lex->ident= $3;
- }
- ;
-
-/*
- UNIONS : glue selects together
-*/
-
-unit_type_decl:
- UNION_SYM union_option
- { $$.unit_type= UNION_TYPE; $$.distinct= $2; }
- | INTERSECT_SYM
- { $$.unit_type= INTERSECT_TYPE; $$.distinct= 1; }
- | EXCEPT_SYM
- { $$.unit_type= EXCEPT_TYPE; $$.distinct= 1; }
- ;
-
-/*
- Start a UNION, for non-top level query expressions.
-*/
-union_option:
- /* empty */ { $$=1; }
- | DISTINCT { $$=1; }
- | ALL { $$=0; }
- ;
-
-query_expression_option:
- STRAIGHT_JOIN { Select->options|= SELECT_STRAIGHT_JOIN; }
- | HIGH_PRIORITY
- {
- YYPS->m_lock_type= TL_READ_HIGH_PRIORITY;
- YYPS->m_mdl_type= MDL_SHARED_READ;
- Select->options|= SELECT_HIGH_PRIORITY;
- }
- | DISTINCT { Select->options|= SELECT_DISTINCT; }
- | UNIQUE_SYM { Select->options|= SELECT_DISTINCT; }
- | SQL_SMALL_RESULT { Select->options|= SELECT_SMALL_RESULT; }
- | SQL_BIG_RESULT { Select->options|= SELECT_BIG_RESULT; }
- | SQL_BUFFER_RESULT { Select->options|= OPTION_BUFFER_RESULT; }
- | SQL_CALC_FOUND_ROWS { Select->options|= OPTION_FOUND_ROWS; }
- | ALL { Select->options|= SELECT_ALL; }
- ;
-
-/**************************************************************************
-
- DEFINER clause support.
-
-**************************************************************************/
-
-definer_opt:
- no_definer
- | definer
- ;
-
-no_definer:
- /* empty */
- {
- /*
- We have to distinguish missing DEFINER-clause from case when
- CURRENT_USER specified as definer explicitly in order to properly
- handle CREATE TRIGGER statements which come to replication thread
- from older master servers (i.e. to create non-suid trigger in this
- case).
- */
- thd->lex->definer= 0;
- }
- ;
-
-definer:
- DEFINER_SYM '=' user_or_role
- {
- Lex->definer= $3;
- Lex->account_options.reset();
- }
- ;
-
-/**************************************************************************
-
- CREATE VIEW statement parts.
-
-**************************************************************************/
-
-view_algorithm:
- ALGORITHM_SYM '=' UNDEFINED_SYM { $$= DTYPE_ALGORITHM_UNDEFINED; }
- | ALGORITHM_SYM '=' MERGE_SYM { $$= VIEW_ALGORITHM_MERGE; }
- | ALGORITHM_SYM '=' TEMPTABLE_SYM { $$= VIEW_ALGORITHM_TMPTABLE; }
- ;
-
-opt_view_suid:
- /* empty */ { $$= VIEW_SUID_DEFAULT; }
- | view_suid { $$= $1; }
- ;
-
-view_suid:
- SQL_SYM SECURITY_SYM DEFINER_SYM { $$= VIEW_SUID_DEFINER; }
- | SQL_SYM SECURITY_SYM INVOKER_SYM { $$= VIEW_SUID_INVOKER; }
- ;
-
-view_list_opt:
- /* empty */
- {}
- | '(' view_list ')' { }
- ;
-
-view_list:
- ident
- {
- Lex->view_list.push_back((LEX_CSTRING*)
- thd->memdup(&$1, sizeof(LEX_CSTRING)),
- thd->mem_root);
- }
- | view_list ',' ident
- {
- Lex->view_list.push_back((LEX_CSTRING*)
- thd->memdup(&$3, sizeof(LEX_CSTRING)),
- thd->mem_root);
- }
- ;
-
-view_select:
- {
- LEX *lex= Lex;
- lex->parsing_options.allows_variable= FALSE;
- lex->create_view->select.str= (char *) YYLIP->get_cpp_ptr();
- }
- query_expression
- view_check_option
- {
- if (Lex->parsed_create_view($2, $3))
- MYSQL_YYABORT;
- }
- ;
-
-view_check_option:
- /* empty */ { $$= VIEW_CHECK_NONE; }
- | WITH CHECK_SYM OPTION { $$= VIEW_CHECK_CASCADED; }
- | WITH CASCADED CHECK_SYM OPTION { $$= VIEW_CHECK_CASCADED; }
- | WITH LOCAL_SYM CHECK_SYM OPTION { $$= VIEW_CHECK_LOCAL; }
- ;
-
-/**************************************************************************
-
- CREATE TRIGGER statement parts.
-
-**************************************************************************/
-
-trigger_action_order:
- FOLLOWS_SYM
- { $$= TRG_ORDER_FOLLOWS; }
- | PRECEDES_SYM
- { $$= TRG_ORDER_PRECEDES; }
- ;
-
-trigger_follows_precedes_clause:
- /* empty */
- {
- $$.ordering_clause= TRG_ORDER_NONE;
- $$.anchor_trigger_name.str= NULL;
- $$.anchor_trigger_name.length= 0;
- }
- |
- trigger_action_order ident_or_text
- {
- $$.ordering_clause= $1;
- $$.anchor_trigger_name= $2;
- }
- ;
-
-trigger_tail:
- remember_name
- opt_if_not_exists
- {
- if (unlikely(Lex->add_create_options_with_check($2)))
- MYSQL_YYABORT;
- }
- sp_name
- trg_action_time
- trg_event
- ON
- remember_name /* $8 */
- { /* $9 */
- Lex->raw_trg_on_table_name_begin= YYLIP->get_tok_start();
- }
- table_ident /* $10 */
- FOR_SYM
- remember_name /* $12 */
- { /* $13 */
- Lex->raw_trg_on_table_name_end= YYLIP->get_tok_start();
- }
- EACH_SYM
- ROW_SYM
- {
- Lex->trg_chistics.ordering_clause_begin= YYLIP->get_cpp_ptr();
- }
- trigger_follows_precedes_clause /* $17 */
- { /* $18 */
- LEX *lex= thd->lex;
- Lex_input_stream *lip= YYLIP;
-
- if (unlikely(lex->sphead))
- my_yyabort_error((ER_SP_NO_RECURSIVE_CREATE, MYF(0), "TRIGGER"));
-
- lex->stmt_definition_begin= $1;
- lex->ident.str= $8;
- lex->ident.length= $12 - $8;
- lex->spname= $4;
- (*static_cast<st_trg_execution_order*>(&lex->trg_chistics))= ($17);
- lex->trg_chistics.ordering_clause_end= lip->get_cpp_ptr();
-
- if (unlikely(!lex->make_sp_head(thd, $4, &sp_handler_trigger,
- DEFAULT_AGGREGATE)))
- MYSQL_YYABORT;
-
- lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
- }
- sp_proc_stmt /* $19 */
- { /* $20 */
- LEX *lex= Lex;
-
- lex->sql_command= SQLCOM_CREATE_TRIGGER;
- if (lex->sp_body_finalize_trigger(thd))
- MYSQL_YYABORT;
-
- /*
- We have to do it after parsing trigger body, because some of
- sp_proc_stmt alternatives are not saving/restoring LEX, so
- lex->query_tables can be wiped out.
- */
- if (!lex->first_select_lex()->
- add_table_to_list(thd, $10, (LEX_CSTRING*) 0,
- TL_OPTION_UPDATING, TL_READ_NO_INSERT,
- MDL_SHARED_NO_WRITE))
- MYSQL_YYABORT;
- }
- ;
-
-/**************************************************************************
-
- CREATE FUNCTION | PROCEDURE statements parts.
-
-**************************************************************************/
-
-sf_return_type:
- {
- LEX *lex= Lex;
- lex->init_last_field(&lex->sphead->m_return_field_def,
- &empty_clex_str,
- thd->variables.collation_database);
- }
- sp_param_type_with_opt_collate
- {
- if (unlikely(Lex->sphead->fill_field_definition(thd,
- Lex->last_field)))
- MYSQL_YYABORT;
- }
- ;
-
-sf_c_chistics_and_body_standalone:
- sp_c_chistics
- {
- LEX *lex= thd->lex;
- lex->sphead->set_c_chistics(lex->sp_chistics);
- lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start());
- }
- sp_tail_is
- sp_body
- {
- if (unlikely(Lex->sp_body_finalize_function(thd)))
- MYSQL_YYABORT;
- }
- ;
-
-sp_tail_standalone:
- sp_name
- {
- if (unlikely(!Lex->make_sp_head_no_recursive(thd, $1,
- &sp_handler_procedure,
- DEFAULT_AGGREGATE)))
- MYSQL_YYABORT;
- }
- opt_sp_parenthesized_pdparam_list
- sp_c_chistics
- {
- Lex->sphead->set_c_chistics(Lex->sp_chistics);
- Lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start());
- }
- sp_tail_is
- sp_body
- opt_sp_name
- {
- if (unlikely(Lex->sp_body_finalize_procedure_standalone(thd, $8)))
- MYSQL_YYABORT;
- }
- ;
-
-
-opt_package_routine_end_name:
- /* Empty */ { $$= null_clex_str; }
- | ident { $$= $1; }
- ;
-
-sp_tail_is:
- IS
- | AS
- ;
-
-/*************************************************************************/
-
-xa:
- XA_SYM begin_or_start xid opt_join_or_resume
- {
- Lex->sql_command = SQLCOM_XA_START;
- }
- | XA_SYM END xid opt_suspend
- {
- Lex->sql_command = SQLCOM_XA_END;
- }
- | XA_SYM PREPARE_SYM xid
- {
- Lex->sql_command = SQLCOM_XA_PREPARE;
- }
- | XA_SYM COMMIT_SYM xid opt_one_phase
- {
- Lex->sql_command = SQLCOM_XA_COMMIT;
- }
- | XA_SYM ROLLBACK_SYM xid
- {
- Lex->sql_command = SQLCOM_XA_ROLLBACK;
- }
- | XA_SYM RECOVER_SYM opt_format_xid
- {
- Lex->sql_command = SQLCOM_XA_RECOVER;
- Lex->verbose= $3;
- }
- ;
-
-opt_format_xid:
- /* empty */ { $$= false; }
- | FORMAT_SYM '=' ident_or_text
- {
- if (lex_string_eq(&$3, STRING_WITH_LEN("SQL")))
- $$= true;
- else if (lex_string_eq(&$3, STRING_WITH_LEN("RAW")))
- $$= false;
- else
- {
- my_yyabort_error((ER_UNKNOWN_EXPLAIN_FORMAT, MYF(0),
- "XA RECOVER", $3.str));
- $$= false;
- }
- }
- ;
-
-xid:
- text_string
- {
- MYSQL_YYABORT_UNLESS($1->length() <= MAXGTRIDSIZE);
- if (unlikely(!(Lex->xid=(XID *)thd->alloc(sizeof(XID)))))
- MYSQL_YYABORT;
- Lex->xid->set(1L, $1->ptr(), $1->length(), 0, 0);
- }
- | text_string ',' text_string
- {
- MYSQL_YYABORT_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
- if (unlikely(!(Lex->xid=(XID *)thd->alloc(sizeof(XID)))))
- MYSQL_YYABORT;
- Lex->xid->set(1L, $1->ptr(), $1->length(), $3->ptr(), $3->length());
- }
- | text_string ',' text_string ',' ulong_num
- {
- MYSQL_YYABORT_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
- if (unlikely(!(Lex->xid=(XID *)thd->alloc(sizeof(XID)))))
- MYSQL_YYABORT;
- Lex->xid->set($5, $1->ptr(), $1->length(), $3->ptr(), $3->length());
- }
- ;
-
-begin_or_start:
- BEGIN_MARIADB_SYM {}
- | BEGIN_ORACLE_SYM {}
- | START_SYM {}
- ;
-
-opt_join_or_resume:
- /* nothing */ { Lex->xa_opt=XA_NONE; }
- | JOIN_SYM { Lex->xa_opt=XA_JOIN; }
- | RESUME_SYM { Lex->xa_opt=XA_RESUME; }
- ;
-
-opt_one_phase:
- /* nothing */ { Lex->xa_opt=XA_NONE; }
- | ONE_SYM PHASE_SYM { Lex->xa_opt=XA_ONE_PHASE; }
- ;
-
-opt_suspend:
- /* nothing */
- { Lex->xa_opt=XA_NONE; }
- | SUSPEND_SYM
- { Lex->xa_opt=XA_SUSPEND; }
- opt_migrate
- ;
-
-opt_migrate:
- /* nothing */ {}
- | FOR_SYM MIGRATE_SYM { Lex->xa_opt=XA_FOR_MIGRATE; }
- ;
-
-install:
- INSTALL_SYM PLUGIN_SYM opt_if_not_exists ident SONAME_SYM TEXT_STRING_sys
- {
- if (Lex->stmt_install_plugin($3, $4, $6))
- MYSQL_YYABORT;
- }
- | INSTALL_SYM SONAME_SYM TEXT_STRING_sys
- {
- Lex->stmt_install_plugin($3);
- }
- ;
-
-uninstall:
- UNINSTALL_SYM PLUGIN_SYM opt_if_exists ident
- {
- if (Lex->stmt_uninstall_plugin_by_name($3, $4))
- MYSQL_YYABORT;
- }
- | UNINSTALL_SYM SONAME_SYM opt_if_exists TEXT_STRING_sys
- {
- if (Lex->stmt_uninstall_plugin_by_soname($3, $4))
- MYSQL_YYABORT;
- }
- ;
-
-/* Avoid compiler warning from sql_yacc.cc where yyerrlab1 is not used */
-keep_gcc_happy:
- IMPOSSIBLE_ACTION
- {
- YYERROR;
- }
- ;
-
-/**
- @} (end of group Parser)
-*/
diff --git a/sql/strfunc.cc b/sql/strfunc.cc
index 99ff9c50588..c488ab1afbb 100644
--- a/sql/strfunc.cc
+++ b/sql/strfunc.cc
@@ -1,4 +1,5 @@
/* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2009, 2020, 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
@@ -45,11 +46,12 @@
static const char field_separator=',';
-ulonglong find_set(TYPELIB *lib, const char *str, size_t length, CHARSET_INFO *cs,
+ulonglong find_set(const TYPELIB *lib,
+ const char *str, size_t length, CHARSET_INFO *cs,
char **err_pos, uint *err_len, bool *set_warning)
{
CHARSET_INFO *strip= cs ? cs : &my_charset_latin1;
- const char *end= str + strip->cset->lengthsp(strip, str, length);
+ const char *end= str + strip->lengthsp(str, length);
ulonglong found= 0;
*err_pos= 0; // No error yet
*err_len= 0;
@@ -67,8 +69,8 @@ ulonglong find_set(TYPELIB *lib, const char *str, size_t length, CHARSET_INFO *c
for ( ; pos < end; pos+= mblen)
{
my_wc_t wc;
- if ((mblen= cs->cset->mb_wc(cs, &wc, (const uchar *) pos,
- (const uchar *) end)) < 1)
+ if ((mblen= cs->mb_wc(&wc, (const uchar *) pos,
+ (const uchar *) end)) < 1)
mblen= 1; // Not to hang on a wrong multibyte sequence
if (wc == (my_wc_t) field_separator)
break;
@@ -169,8 +171,8 @@ uint find_type2(const TYPELIB *typelib, const char *x, size_t length,
for (pos=0 ; (j=typelib->type_names[pos]) ; pos++)
{
- if (!my_strnncoll(cs, (const uchar*) x, length,
- (const uchar*) j, typelib->type_lengths[pos]))
+ if (!cs->strnncoll(x, length,
+ j, typelib->type_lengths[pos]))
DBUG_RETURN(pos+1);
}
DBUG_PRINT("exit",("Couldn't find type"));
@@ -337,8 +339,8 @@ int find_string_in_array(LEX_CSTRING * const haystack, LEX_CSTRING * const needl
{
const LEX_CSTRING *pos;
for (pos= haystack; pos->str; pos++)
- if (!cs->coll->strnncollsp(cs, (uchar *) pos->str, pos->length,
- (uchar *) needle->str, needle->length))
+ if (!cs->strnncollsp(pos->str, pos->length,
+ needle->str, needle->length))
{
return (int)(pos - haystack);
}
diff --git a/sql/strfunc.h b/sql/strfunc.h
index d66d4c63444..b2b293e153f 100644
--- a/sql/strfunc.h
+++ b/sql/strfunc.h
@@ -18,7 +18,8 @@
typedef struct st_typelib TYPELIB;
-ulonglong find_set(TYPELIB *lib, const char *x, size_t length, CHARSET_INFO *cs,
+ulonglong find_set(const TYPELIB *lib,
+ const char *x, size_t length, CHARSET_INFO *cs,
char **err_pos, uint *err_len, bool *set_warning);
ulonglong find_set_from_flags(TYPELIB *lib, uint default_name,
ulonglong cur_set, ulonglong default_set,
diff --git a/sql/structs.h b/sql/structs.h
index 0c00aeec33a..f6d63051dfe 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -618,6 +618,8 @@ public:
m_handler= handler;
Lex_length_and_dec_st::operator=(length_and_dec);
}
+ void set_handler_length_flags(const Type_handler *handler, const char *length,
+ uint32 flags);
void set(const Type_handler *handler, const char *length)
{
set(handler, length, 0);
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 1c47f652f4c..e7082d067d7 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -45,8 +45,7 @@
#include "mysqld.h"
#include "lock.h"
#include "sql_time.h" // known_date_time_formats
-#include "sql_acl.h" // SUPER_ACL,
- // mysql_user_table_is_in_short_password_format
+#include "sql_acl.h" // mysql_user_table_is_in_short_password_format
#include "derror.h" // read_texts
#include "sql_base.h" // close_cached_tables
#include "hostname.h" // host_cache_size
@@ -67,6 +66,9 @@
#include "semisync_slave.h"
#include <ssl_compat.h>
+#define PCRE2_STATIC 1 /* Important on Windows */
+#include "pcre2.h" /* pcre2 header file */
+
/*
The rule for this file: everything should be 'static'. When a sys_var
variable or a function from this file is - in very rare cases - needed
@@ -78,8 +80,7 @@
#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
static Sys_var_mybool Sys_pfs_enabled(
- "performance_schema",
- "Enable the performance schema.",
+ "performance_schema", "Enable the performance schema.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_enabled),
CMD_LINE(OPT_ARG), DEFAULT(FALSE));
@@ -87,10 +88,9 @@ static Sys_var_long Sys_pfs_events_waits_history_long_size(
"performance_schema_events_waits_history_long_size",
"Number of rows in EVENTS_WAITS_HISTORY_LONG."
" Use 0 to disable, -1 for automated sizing.",
- PARSED_EARLY READ_ONLY
- GLOBAL_VAR(pfs_param.m_events_waits_history_long_sizing),
+ PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_waits_history_long_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
- DEFAULT(-1), BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
static Sys_var_long Sys_pfs_events_waits_history_size(
"performance_schema_events_waits_history_size",
@@ -98,7 +98,7 @@ static Sys_var_long Sys_pfs_events_waits_history_size(
" Use 0 to disable, -1 for automated sizing.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_waits_history_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024),
- DEFAULT(-1), BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
static Sys_var_ulong Sys_pfs_max_cond_classes(
"performance_schema_max_cond_classes",
@@ -113,7 +113,23 @@ static Sys_var_long Sys_pfs_max_cond_instances(
" Use 0 to disable, -1 for automated sizing.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_cond_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
- DEFAULT(-1), BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
+
+static Sys_var_long Sys_pfs_max_program_instances(
+ "performance_schema_max_program_instances",
+ "Maximum number of instrumented programs."
+ " Use 0 to disable, -1 for automated scaling.",
+ PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_program_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
+
+static Sys_var_long Sys_pfs_max_prepared_stmt_instances(
+ "performance_schema_max_prepared_statements_instances",
+ "Maximum number of instrumented prepared statements."
+ " Use 0 to disable, -1 for automated scaling.",
+ PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_prepared_stmt_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
static Sys_var_ulong Sys_pfs_max_file_classes(
"performance_schema_max_file_classes",
@@ -135,7 +151,7 @@ static Sys_var_long Sys_pfs_max_file_instances(
" Use 0 to disable, -1 for automated sizing.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_file_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
- DEFAULT(-1), BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
static Sys_var_long Sys_pfs_max_sockets(
"performance_schema_max_socket_instances",
@@ -143,16 +159,14 @@ static Sys_var_long Sys_pfs_max_sockets(
" Use 0 to disable, -1 for automated sizing.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_socket_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
- DEFAULT(-1),
- BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
static Sys_var_ulong Sys_pfs_max_socket_classes(
"performance_schema_max_socket_classes",
"Maximum number of socket instruments.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_socket_class_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 256),
- DEFAULT(PFS_MAX_SOCKET_CLASS),
- BLOCK_SIZE(1));
+ DEFAULT(PFS_MAX_SOCKET_CLASS), BLOCK_SIZE(1));
static Sys_var_ulong Sys_pfs_max_mutex_classes(
"performance_schema_max_mutex_classes",
@@ -167,7 +181,7 @@ static Sys_var_long Sys_pfs_max_mutex_instances(
" Use 0 to disable, -1 for automated sizing.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_mutex_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 100*1024*1024),
- DEFAULT(-1), BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
static Sys_var_ulong Sys_pfs_max_rwlock_classes(
"performance_schema_max_rwlock_classes",
@@ -182,7 +196,7 @@ static Sys_var_long Sys_pfs_max_rwlock_instances(
" Use 0 to disable, -1 for automated sizing.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_rwlock_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 100*1024*1024),
- DEFAULT(-1), BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
static Sys_var_long Sys_pfs_max_table_handles(
"performance_schema_max_table_handles",
@@ -190,7 +204,7 @@ static Sys_var_long Sys_pfs_max_table_handles(
" Use 0 to disable, -1 for automated sizing.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_table_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
- DEFAULT(-1), BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
static Sys_var_long Sys_pfs_max_table_instances(
"performance_schema_max_table_instances",
@@ -198,7 +212,23 @@ static Sys_var_long Sys_pfs_max_table_instances(
" Use 0 to disable, -1 for automated sizing.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_table_share_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
- DEFAULT(-1), BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
+
+static Sys_var_long Sys_pfs_max_table_lock_stat(
+ "performance_schema_max_table_lock_stat",
+ "Maximum number of lock statistics for instrumented tables."
+ " Use 0 to disable, -1 for automated scaling.",
+ PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_table_lock_stat_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
+
+static Sys_var_long Sys_pfs_max_index_stat(
+ "performance_schema_max_index_stat",
+ "Maximum number of index statistics for instrumented tables."
+ " Use 0 to disable, -1 for automated scaling.",
+ PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_index_stat_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
static Sys_var_ulong Sys_pfs_max_thread_classes(
"performance_schema_max_thread_classes",
@@ -213,23 +243,21 @@ static Sys_var_long Sys_pfs_max_thread_instances(
" Use 0 to disable, -1 for automated sizing.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_thread_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
- DEFAULT(-1), BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
-static Sys_var_ulong Sys_pfs_setup_actors_size(
+static Sys_var_long Sys_pfs_setup_actors_size(
"performance_schema_setup_actors_size",
"Maximum number of rows in SETUP_ACTORS.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_setup_actor_sizing),
- CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024),
- DEFAULT(PFS_MAX_SETUP_ACTOR),
- BLOCK_SIZE(1));
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024),
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
-static Sys_var_ulong Sys_pfs_setup_objects_size(
+static Sys_var_long Sys_pfs_setup_objects_size(
"performance_schema_setup_objects_size",
"Maximum number of rows in SETUP_OBJECTS.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_setup_object_sizing),
- CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024),
- DEFAULT(PFS_MAX_SETUP_OBJECT),
- BLOCK_SIZE(1));
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
static Sys_var_long Sys_pfs_accounts_size(
"performance_schema_accounts_size",
@@ -237,8 +265,7 @@ static Sys_var_long Sys_pfs_accounts_size(
" Use 0 to disable, -1 for automated sizing.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_account_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
- DEFAULT(-1),
- BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
static Sys_var_long Sys_pfs_hosts_size(
"performance_schema_hosts_size",
@@ -246,8 +273,7 @@ static Sys_var_long Sys_pfs_hosts_size(
" Use 0 to disable, -1 for automated sizing.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_host_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
- DEFAULT(-1),
- BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
static Sys_var_long Sys_pfs_users_size(
"performance_schema_users_size",
@@ -255,16 +281,14 @@ static Sys_var_long Sys_pfs_users_size(
" Use 0 to disable, -1 for automated sizing.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_user_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
- DEFAULT(-1),
- BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
static Sys_var_ulong Sys_pfs_max_stage_classes(
"performance_schema_max_stage_classes",
"Maximum number of stage instruments.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_stage_class_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 256),
- DEFAULT(PFS_MAX_STAGE_CLASS),
- BLOCK_SIZE(1));
+ DEFAULT(PFS_MAX_STAGE_CLASS), BLOCK_SIZE(1));
static Sys_var_long Sys_pfs_events_stages_history_long_size(
"performance_schema_events_stages_history_long_size",
@@ -272,8 +296,7 @@ static Sys_var_long Sys_pfs_events_stages_history_long_size(
" Use 0 to disable, -1 for automated sizing.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_stages_history_long_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
- DEFAULT(-1),
- BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
static Sys_var_long Sys_pfs_events_stages_history_size(
"performance_schema_events_stages_history_size",
@@ -281,26 +304,27 @@ static Sys_var_long Sys_pfs_events_stages_history_size(
" Use 0 to disable, -1 for automated sizing.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_stages_history_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024),
- DEFAULT(-1),
- BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
/**
Variable performance_schema_max_statement_classes.
The default number of statement classes is the sum of:
+ - SQLCOM_END for all regular "statement/sql/...",
+ - SP_PSI_STATEMENT_INFO_COUNT for "statement/sp/...".
- (COM_END - mariadb gap) for all regular "statement/com/...",
- 1 for "statement/com/new_packet", for unknown enum_server_command
- 1 for "statement/com/Error", for invalid enum_server_command
- - SQLCOM_END for all regular "statement/sql/...",
- 1 for "statement/sql/error", for invalid enum_sql_command
- 1 for "statement/rpl/relay_log", for replicated statements.
+ - 1 for "statement/scheduler/event", for scheduled events.
*/
static Sys_var_ulong Sys_pfs_max_statement_classes(
"performance_schema_max_statement_classes",
"Maximum number of statement instruments.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_statement_class_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 256),
- DEFAULT((ulong) SQLCOM_END +
- (ulong) (COM_END -(COM_MDB_GAP_END - COM_MDB_GAP_BEG + 1)) + 4),
+ DEFAULT((ulong) SQLCOM_END + SP_PSI_STATEMENT_INFO_COUNT +
+ (ulong) (COM_END -(COM_MDB_GAP_END - COM_MDB_GAP_BEG + 1)) + 5),
BLOCK_SIZE(1));
static Sys_var_long Sys_pfs_events_statements_history_long_size(
@@ -309,8 +333,7 @@ static Sys_var_long Sys_pfs_events_statements_history_long_size(
" Use 0 to disable, -1 for automated sizing.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_statements_history_long_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
- DEFAULT(-1),
- BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
static Sys_var_long Sys_pfs_events_statements_history_size(
"performance_schema_events_statements_history_size",
@@ -318,8 +341,21 @@ static Sys_var_long Sys_pfs_events_statements_history_size(
" Use 0 to disable, -1 for automated sizing.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_statements_history_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024),
- DEFAULT(-1),
- BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_pfs_statement_stack_size(
+ "performance_schema_max_statement_stack",
+ "Number of rows per thread in EVENTS_STATEMENTS_CURRENT.",
+ PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_statement_stack_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(1, 256),
+ DEFAULT(PFS_STATEMENTS_STACK_SIZE), BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_pfs_max_memory_classes(
+ "performance_schema_max_memory_classes",
+ "Maximum number of memory pool instruments.",
+ PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_memory_class_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024),
+ DEFAULT(PFS_MAX_MEMORY_CLASS), BLOCK_SIZE(1));
static Sys_var_long Sys_pfs_digest_size(
"performance_schema_digests_size",
@@ -327,16 +363,30 @@ static Sys_var_long Sys_pfs_digest_size(
" Use 0 to disable, -1 for automated sizing.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_digest_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 200),
- DEFAULT(-1),
- BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
+
+static Sys_var_long Sys_pfs_events_transactions_history_long_size(
+ "performance_schema_events_transactions_history_long_size",
+ "Number of rows in EVENTS_TRANSACTIONS_HISTORY_LONG."
+ " Use 0 to disable, -1 for automated sizing.",
+ PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_transactions_history_long_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024),
+ DEFAULT(PFS_AUTOSIZE_VALUE), BLOCK_SIZE(1));
+
+static Sys_var_long Sys_pfs_events_transactions_history_size(
+ "performance_schema_events_transactions_history_size",
+ "Number of rows per thread in EVENTS_TRANSACTIONS_HISTORY."
+ " Use 0 to disable, -1 for automated sizing.",
+ PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_events_transactions_history_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024),
+ DEFAULT(PFS_AUTOSIZE_VALUE), BLOCK_SIZE(1));
static Sys_var_long Sys_pfs_max_digest_length(
"performance_schema_max_digest_length",
"Maximum length considered for digest text, when stored in performance_schema tables.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_max_digest_length),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024 * 1024),
- DEFAULT(1024),
- BLOCK_SIZE(1));
+ DEFAULT(1024), BLOCK_SIZE(1));
static Sys_var_long Sys_pfs_connect_attrs_size(
"performance_schema_session_connect_attrs_size",
@@ -345,8 +395,22 @@ static Sys_var_long Sys_pfs_connect_attrs_size(
PARSED_EARLY READ_ONLY
GLOBAL_VAR(pfs_param.m_session_connect_attrs_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024 * 1024),
- DEFAULT(-1),
- BLOCK_SIZE(1));
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
+
+static Sys_var_long Sys_pfs_max_metadata_locks(
+ "performance_schema_max_metadata_locks",
+ "Maximum number of metadata locks."
+ " Use 0 to disable, -1 for automated scaling.",
+ PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_metadata_lock_sizing),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 100*1024*1024),
+ DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1));
+
+static Sys_var_long Sys_pfs_max_sql_text_length(
+ "performance_schema_max_sql_text_length",
+ "Maximum length of displayed sql text.",
+ PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_max_sql_text_length),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024 * 1024),
+ DEFAULT(1024), BLOCK_SIZE(1));
#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
@@ -437,16 +501,16 @@ static Sys_var_ulong Sys_back_log(
AUTO_SET READ_ONLY GLOBAL_VAR(back_log), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, 65535), DEFAULT(150), BLOCK_SIZE(1));
-static Sys_var_charptr Sys_basedir(
+static Sys_var_charptr_fscs Sys_basedir(
"basedir", "Path to installation directory. All paths are "
"usually resolved relative to this",
READ_ONLY GLOBAL_VAR(mysql_home_ptr), CMD_LINE(REQUIRED_ARG, 'b'),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
-static Sys_var_charptr Sys_my_bind_addr(
+static Sys_var_charptr_fscs Sys_my_bind_addr(
"bind_address", "IP address to bind to.",
READ_ONLY GLOBAL_VAR(my_bind_addr_str), CMD_LINE(REQUIRED_ARG),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
const char *Sys_var_vers_asof::asof_keywords[]= {"DEFAULT", NULL};
static Sys_var_vers_asof Sys_vers_asof_timestamp(
@@ -462,7 +526,9 @@ static Sys_var_enum Sys_vers_alter_history(
SESSION_VAR(vers_alter_history), CMD_LINE(REQUIRED_ARG),
vers_alter_history_keywords, DEFAULT(VERS_ALTER_HISTORY_ERROR));
-static Sys_var_ulonglong Sys_binlog_cache_size(
+static Sys_var_on_access_global<Sys_var_ulonglong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_CACHE_SIZE>
+Sys_binlog_cache_size(
"binlog_cache_size", "The size of the transactional cache for "
"updates to transactional engines for the binary log. "
"If you often use transactions containing many statements, "
@@ -471,14 +537,18 @@ static Sys_var_ulonglong Sys_binlog_cache_size(
CMD_LINE(REQUIRED_ARG),
VALID_RANGE(IO_SIZE, SIZE_T_MAX), DEFAULT(32768), BLOCK_SIZE(IO_SIZE));
-static Sys_var_ulonglong Sys_binlog_file_cache_size(
+static Sys_var_on_access_global<Sys_var_ulonglong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_FILE_CACHE_SIZE>
+Sys_binlog_file_cache_size(
"binlog_file_cache_size",
"The size of file cache for the binary log",
GLOBAL_VAR(binlog_file_cache_size),
CMD_LINE(REQUIRED_ARG),
VALID_RANGE(IO_SIZE*2, SIZE_T_MAX), DEFAULT(IO_SIZE*4), BLOCK_SIZE(IO_SIZE));
-static Sys_var_ulonglong Sys_binlog_stmt_cache_size(
+static Sys_var_on_access_global<Sys_var_ulonglong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_STMT_CACHE_SIZE>
+Sys_binlog_stmt_cache_size(
"binlog_stmt_cache_size", "The size of the statement cache for "
"updates to non-transactional engines for the binary log. "
"If you often use statements updating a great number of rows, "
@@ -520,7 +590,8 @@ bool check_has_super(sys_var *self, THD *thd, set_var *var)
{
DBUG_ASSERT(self->scope() != sys_var::GLOBAL);// don't abuse check_has_super()
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (!(thd->security_ctx->master_access & SUPER_ACL))
+ if (!(thd->security_ctx->master_access &
+ PRIV_SET_RESTRICTED_SESSION_SYSTEM_VARIABLE))
{
my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
return true;
@@ -536,9 +607,6 @@ static Sys_var_bit Sys_core_file("core_file", "write a core-file on crashes",
static bool binlog_format_check(sys_var *self, THD *thd, set_var *var)
{
- if (check_has_super(self, thd, var))
- return true;
-
/*
MariaDB Galera does not support STATEMENT or MIXED binlog format currently.
*/
@@ -609,7 +677,10 @@ static bool fix_binlog_format_after_update(sys_var *self, THD *thd,
return false;
}
-static Sys_var_enum Sys_binlog_format(
+static Sys_var_on_access<Sys_var_enum,
+ PRIV_SET_SYSTEM_VAR_BINLOG_FORMAT,
+ PRIV_SET_SYSTEM_VAR_BINLOG_FORMAT>
+Sys_binlog_format(
"binlog_format", "What form of binary logging the master will "
"use: either ROW for row-based binary logging, STATEMENT "
"for statement-based binary logging, or MIXED. MIXED is statement-"
@@ -624,9 +695,6 @@ static Sys_var_enum Sys_binlog_format(
static bool binlog_direct_check(sys_var *self, THD *thd, set_var *var)
{
- if (check_has_super(self, thd, var))
- return true;
-
if (var->type == OPT_GLOBAL)
return false;
@@ -638,7 +706,10 @@ static bool binlog_direct_check(sys_var *self, THD *thd, set_var *var)
return false;
}
-static Sys_var_mybool Sys_binlog_direct(
+static Sys_var_on_access<Sys_var_mybool,
+ PRIV_SET_SYSTEM_VAR_BINLOG_DIRECT_NON_TRANSACTIONAL_UPDATES,
+ PRIV_SET_SYSTEM_VAR_BINLOG_DIRECT_NON_TRANSACTIONAL_UPDATES>
+Sys_binlog_direct(
"binlog_direct_non_transactional_updates",
"Causes updates to non-transactional engines using statement format to "
"be written directly to binary log. Before using this option make sure "
@@ -665,10 +736,10 @@ static Sys_var_ulonglong Sys_bulk_insert_buff_size(
SESSION_VAR(bulk_insert_buff_size), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, SIZE_T_MAX), DEFAULT(8192*1024), BLOCK_SIZE(1));
-static Sys_var_charptr Sys_character_sets_dir(
+static Sys_var_charptr_fscs Sys_character_sets_dir(
"character_sets_dir", "Directory where character sets are",
READ_ONLY GLOBAL_VAR(charsets_dir), CMD_LINE(REQUIRED_ARG),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
static bool check_not_null(sys_var *self, THD *thd, set_var *var)
{
@@ -914,24 +985,26 @@ static Sys_var_enum Sys_concurrent_insert(
GLOBAL_VAR(myisam_concurrent_insert), CMD_LINE(OPT_ARG),
concurrent_insert_names, DEFAULT(1));
-static Sys_var_ulong Sys_connect_timeout(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_CONNECT_TIMEOUT>
+Sys_connect_timeout(
"connect_timeout",
"The number of seconds the mysqld server is waiting for a connect "
"packet before responding with 'Bad handshake'",
GLOBAL_VAR(connect_timeout), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(2, LONG_TIMEOUT), DEFAULT(CONNECT_TIMEOUT), BLOCK_SIZE(1));
-static Sys_var_charptr Sys_datadir(
+static Sys_var_charptr_fscs Sys_datadir(
"datadir", "Path to the database root directory",
READ_ONLY GLOBAL_VAR(mysql_real_data_home_ptr),
- CMD_LINE(REQUIRED_ARG, 'h'), IN_FS_CHARSET, DEFAULT(mysql_real_data_home));
+ CMD_LINE(REQUIRED_ARG, 'h'), DEFAULT(mysql_real_data_home));
#ifndef DBUG_OFF
static Sys_var_dbug Sys_dbug(
"debug", "Built-in DBUG debugger", sys_var::SESSION,
CMD_LINE(OPT_ARG, '#'), DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(check_has_super), ON_UPDATE(0),
- DEPRECATED("'@@debug_dbug'"));
+ DEPRECATED("'@@debug_dbug'")); // since 5.5.37
static Sys_var_dbug Sys_debug_dbug(
"debug_dbug", "Built-in DBUG debugger", sys_var::SESSION,
@@ -1083,7 +1156,9 @@ static Sys_var_enum Sys_event_scheduler(
ON_CHECK(event_scheduler_check), ON_UPDATE(event_scheduler_update));
#endif
-static Sys_var_ulong Sys_expire_logs_days(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_EXPIRE_LOGS_DAYS>
+Sys_expire_logs_days(
"expire_logs_days",
"If non-zero, binary logs will be purged after expire_logs_days "
"days; possible purges happen at startup and at binary log rotation",
@@ -1120,7 +1195,7 @@ static Sys_var_charptr Sys_ft_boolean_syntax(
"ft_boolean_syntax", "List of operators for "
"MATCH ... AGAINST ( ... IN BOOLEAN MODE)",
GLOBAL_VAR(ft_boolean_syntax),
- CMD_LINE(REQUIRED_ARG), IN_SYSTEM_CHARSET,
+ CMD_LINE(REQUIRED_ARG),
DEFAULT(DEFAULT_FTB_SYNTAX), NO_MUTEX_GUARD,
NOT_IN_BINLOG, ON_CHECK(check_ftb_syntax), ON_UPDATE(query_cache_flush));
@@ -1147,11 +1222,11 @@ static Sys_var_ulong Sys_ft_query_expansion_limit(
CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, 1000), DEFAULT(20), BLOCK_SIZE(1));
-static Sys_var_charptr Sys_ft_stopword_file(
+static Sys_var_charptr_fscs Sys_ft_stopword_file(
"ft_stopword_file",
"Use stopwords from this file instead of built-in list",
READ_ONLY GLOBAL_VAR(ft_stopword_file), CMD_LINE(REQUIRED_ARG),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
static Sys_var_mybool Sys_ignore_builtin_innodb(
"ignore_builtin_innodb",
@@ -1169,10 +1244,13 @@ static bool check_init_string(sys_var *self, THD *thd, set_var *var)
return false;
}
static PolyLock_rwlock PLock_sys_init_connect(&LOCK_sys_init_connect);
-static Sys_var_lexstring Sys_init_connect(
+
+static Sys_var_on_access_global<Sys_var_lexstring,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_INIT_CONNECT>
+Sys_init_connect(
"init_connect", "Command(s) that are executed for each "
"new connection (unless the user has SUPER privilege)",
- GLOBAL_VAR(opt_init_connect), CMD_LINE(REQUIRED_ARG), IN_SYSTEM_CHARSET,
+ GLOBAL_VAR(opt_init_connect), CMD_LINE(REQUIRED_ARG),
DEFAULT(""), &PLock_sys_init_connect, NOT_IN_BINLOG,
ON_CHECK(check_init_string));
@@ -1192,11 +1270,11 @@ static Sys_var_session_lexstring Sys_default_master_connection(
"default_master_connection",
"Master connection to use for all slave variables and slave commands",
SESSION_ONLY(default_master_connection),
- NO_CMD_LINE, IN_SYSTEM_CHARSET,
+ NO_CMD_LINE,
DEFAULT(""), MAX_CONNECTION_NAME, ON_CHECK(check_master_connection));
#endif
-static Sys_var_charptr Sys_init_file(
+static Sys_var_charptr_fscs Sys_init_file(
"init_file", "Read SQL commands from this file at startup",
READ_ONLY GLOBAL_VAR(opt_init_file),
#ifdef DISABLE_GRANT_OPTIONS
@@ -1204,13 +1282,15 @@ static Sys_var_charptr Sys_init_file(
#else
CMD_LINE(REQUIRED_ARG),
#endif
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
static PolyLock_rwlock PLock_sys_init_slave(&LOCK_sys_init_slave);
-static Sys_var_lexstring Sys_init_slave(
+static Sys_var_on_access_global<Sys_var_lexstring,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_INIT_SLAVE>
+Sys_init_slave(
"init_slave", "Command(s) that are executed by a slave server "
"each time the SQL thread starts", GLOBAL_VAR(opt_init_slave),
- CMD_LINE(REQUIRED_ARG), IN_SYSTEM_CHARSET,
+ CMD_LINE(REQUIRED_ARG),
DEFAULT(""), &PLock_sys_init_slave,
NOT_IN_BINLOG, ON_CHECK(check_init_string));
@@ -1296,10 +1376,10 @@ static Sys_var_mybool Sys_large_pages(
READ_ONLY GLOBAL_VAR(opt_large_pages),
IF_WIN(NO_CMD_LINE, CMD_LINE(OPT_ARG)), DEFAULT(FALSE));
-static Sys_var_charptr Sys_language(
+static Sys_var_charptr_fscs Sys_language(
"lc_messages_dir", "Directory where error messages are",
READ_ONLY GLOBAL_VAR(lc_messages_dir_ptr), CMD_LINE(REQUIRED_ARG, 'L'),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
static Sys_var_mybool Sys_local_infile(
"local_infile", "Enable LOAD DATA LOCAL INFILE",
@@ -1323,19 +1403,25 @@ static Sys_var_mybool Sys_log_bin(
"log_bin", "Whether the binary log is enabled",
READ_ONLY GLOBAL_VAR(opt_bin_log), NO_CMD_LINE, DEFAULT(FALSE));
-static Sys_var_mybool Sys_log_bin_compress(
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_LOG_BIN_COMPRESS>
+Sys_log_bin_compress(
"log_bin_compress", "Whether the binary log can be compressed",
GLOBAL_VAR(opt_bin_log_compress), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
/* the min length is 10, means that Begin/Commit/Rollback would never be compressed! */
-static Sys_var_uint Sys_log_bin_compress_min_len(
+static Sys_var_on_access_global<Sys_var_uint,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_LOG_BIN_COMPRESS_MIN_LEN>
+Sys_log_bin_compress_min_len(
"log_bin_compress_min_len",
"Minimum length of sql statement(in statement mode) or record(in row mode)"
"that can be compressed.",
GLOBAL_VAR(opt_bin_log_compress_min_len),
CMD_LINE(OPT_ARG), VALID_RANGE(10, 1024), DEFAULT(256), BLOCK_SIZE(1));
-static Sys_var_mybool Sys_trust_function_creators(
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_LOG_BIN_TRUST_FUNCTION_CREATORS>
+Sys_trust_function_creators(
"log_bin_trust_function_creators",
"If set to FALSE (the default), then when --log-bin is used, creation "
"of a stored function (or trigger) is allowed only to users having the "
@@ -1347,14 +1433,14 @@ static Sys_var_mybool Sys_trust_function_creators(
GLOBAL_VAR(trust_function_creators),
CMD_LINE(OPT_ARG), DEFAULT(FALSE));
-static Sys_var_charptr Sys_log_error(
+static Sys_var_charptr_fscs Sys_log_error(
"log_error",
"Log errors to file (instead of stdout). If file name is not specified "
"then 'datadir'/'log-basename'.err or the 'pid-file' path with extension "
".err is used",
READ_ONLY GLOBAL_VAR(log_error_file_ptr),
CMD_LINE(OPT_ARG, OPT_LOG_ERROR),
- IN_FS_CHARSET, DEFAULT(disabled_my_option));
+ DEFAULT(disabled_my_option));
static Sys_var_bit Sys_log_queries_not_using_indexes(
"log_queries_not_using_indexes",
@@ -1509,36 +1595,41 @@ static Sys_var_ulong Sys_max_allowed_packet(
BLOCK_SIZE(1024), NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(check_max_allowed_packet));
-static Sys_var_ulong Sys_slave_max_allowed_packet(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_MAX_ALLOWED_PACKET>
+Sys_slave_max_allowed_packet(
"slave_max_allowed_packet",
"The maximum packet length to sent successfully from the master to slave.",
GLOBAL_VAR(slave_max_allowed_packet), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(1024, MAX_MAX_ALLOWED_PACKET),
- DEFAULT(MAX_MAX_ALLOWED_PACKET),
- BLOCK_SIZE(1024));
+ DEFAULT(MAX_MAX_ALLOWED_PACKET), BLOCK_SIZE(1024));
-static Sys_var_ulonglong Sys_max_binlog_cache_size(
+static Sys_var_on_access_global<Sys_var_ulonglong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_BINLOG_CACHE_SIZE>
+Sys_max_binlog_cache_size(
"max_binlog_cache_size",
"Sets the total size of the transactional cache",
GLOBAL_VAR(max_binlog_cache_size), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(IO_SIZE, SIZE_T_MAX),
- DEFAULT((SIZE_T_MAX/IO_SIZE)*IO_SIZE),
- BLOCK_SIZE(IO_SIZE));
+ DEFAULT((SIZE_T_MAX/IO_SIZE)*IO_SIZE), BLOCK_SIZE(IO_SIZE));
-static Sys_var_ulonglong Sys_max_binlog_stmt_cache_size(
+static Sys_var_on_access_global<Sys_var_ulonglong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_BINLOG_STMT_CACHE_SIZE>
+Sys_max_binlog_stmt_cache_size(
"max_binlog_stmt_cache_size",
"Sets the total size of the statement cache",
GLOBAL_VAR(max_binlog_stmt_cache_size), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(IO_SIZE, SIZE_T_MAX),
- DEFAULT((SIZE_T_MAX/IO_SIZE)*IO_SIZE),
- BLOCK_SIZE(IO_SIZE));
+ DEFAULT((SIZE_T_MAX/IO_SIZE)*IO_SIZE), BLOCK_SIZE(IO_SIZE));
static bool fix_max_binlog_size(sys_var *self, THD *thd, enum_var_type type)
{
mysql_bin_log.set_max_size(max_binlog_size);
return false;
}
-static Sys_var_ulong Sys_max_binlog_size(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_BINLOG_SIZE>
+Sys_max_binlog_size(
"max_binlog_size",
"Binary log will be rotated automatically when the size exceeds this "
"value.",
@@ -1558,7 +1649,9 @@ static bool fix_max_connections(sys_var *self, THD *thd, enum_var_type type)
// Default max_connections of 151 is larger than Apache's default max
// children, to avoid "too many connections" error in a common setup
-static Sys_var_ulong Sys_max_connections(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_CONNECTIONS>
+Sys_max_connections(
"max_connections", "The number of simultaneous clients allowed",
PARSED_EARLY GLOBAL_VAR(max_connections), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(10, 100000),
@@ -1575,7 +1668,9 @@ static Sys_var_uint Sys_default_password_lifetime(
GLOBAL_VAR(default_password_lifetime), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, UINT_MAX), DEFAULT(0), BLOCK_SIZE(1));
-static Sys_var_mybool Sys_disconnect_on_expired_password(
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_DISCONNECT_ON_EXPIRED_PASSWORD>
+Sys_disconnect_on_expired_password(
"disconnect_on_expired_password",
"This variable controls how the server handles clients that are not "
"aware of the sandbox mode. If enabled, the server disconnects the "
@@ -1583,7 +1678,9 @@ static Sys_var_mybool Sys_disconnect_on_expired_password(
GLOBAL_VAR(disconnect_on_expired_password), CMD_LINE(OPT_ARG),
DEFAULT(FALSE));
-static Sys_var_ulong Sys_max_connect_errors(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_CONNECT_ERRORS>
+Sys_max_connect_errors(
"max_connect_errors",
"If there is more than this number of interrupted connections from "
"a host this host will be blocked from further connections",
@@ -1591,7 +1688,9 @@ static Sys_var_ulong Sys_max_connect_errors(
VALID_RANGE(1, UINT_MAX), DEFAULT(MAX_CONNECT_ERRORS),
BLOCK_SIZE(1));
-static Sys_var_uint Sys_max_password_errors(
+static Sys_var_on_access_global<Sys_var_uint,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_PASSWORD_ERRORS>
+Sys_max_password_errors(
"max_password_errors",
"If there is more than this number of failed connect attempts "
"due to invalid password, user will be blocked from further connections until FLUSH_PRIVILEGES.",
@@ -1659,19 +1758,18 @@ static Sys_var_ulong Sys_metadata_locks_hash_instances(
VALID_RANGE(1, 1024), DEFAULT(8),
BLOCK_SIZE(1));
-static Sys_var_ulonglong Sys_pseudo_thread_id(
+static Sys_var_on_access_session<Sys_var_ulonglong,
+ PRIV_SET_SYSTEM_SESSION_VAR_PSEUDO_THREAD_ID>
+Sys_pseudo_thread_id(
"pseudo_thread_id",
"This variable is for internal server use",
SESSION_ONLY(pseudo_thread_id),
NO_CMD_LINE, VALID_RANGE(0, ULONGLONG_MAX), DEFAULT(0),
- BLOCK_SIZE(1), NO_MUTEX_GUARD, IN_BINLOG,
- ON_CHECK(check_has_super));
+ BLOCK_SIZE(1), NO_MUTEX_GUARD, IN_BINLOG);
static bool
check_gtid_domain_id(sys_var *self, THD *thd, set_var *var)
{
- if (check_has_super(self, thd, var))
- return true;
if (var->type != OPT_GLOBAL &&
error_if_in_trans_or_substatement(thd,
ER_STORED_FUNCTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO,
@@ -1682,7 +1780,10 @@ check_gtid_domain_id(sys_var *self, THD *thd, set_var *var)
}
-static Sys_var_uint Sys_gtid_domain_id(
+static Sys_var_on_access<Sys_var_uint,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_DOMAIN_ID,
+ PRIV_SET_SYSTEM_SESSION_VAR_GTID_DOMAIN_ID>
+Sys_gtid_domain_id(
"gtid_domain_id",
"Used with global transaction ID to identify logically independent "
"replication streams. When events can propagate through multiple "
@@ -1700,8 +1801,6 @@ static bool check_gtid_seq_no(sys_var *self, THD *thd, set_var *var)
uint32 domain_id, server_id;
uint64 seq_no;
- if (check_has_super(self, thd, var))
- return true;
if (unlikely(error_if_in_trans_or_substatement(thd,
ER_STORED_FUNCTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO,
ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO)))
@@ -1719,7 +1818,9 @@ static bool check_gtid_seq_no(sys_var *self, THD *thd, set_var *var)
}
-static Sys_var_ulonglong Sys_gtid_seq_no(
+static Sys_var_on_access_session<Sys_var_ulonglong,
+ PRIV_SET_SYSTEM_SESSION_VAR_GTID_SEQ_NO>
+Sys_gtid_seq_no(
"gtid_seq_no",
"Internal server usage, for replication with global transaction id. "
"When set, next event group logged to the binary log will use this "
@@ -1883,7 +1984,9 @@ static Sys_var_gtid_slave_pos Sys_gtid_slave_pos(
GLOBAL_VAR(opt_gtid_slave_pos_dummy), NO_CMD_LINE);
-static Sys_var_mybool Sys_gtid_strict_mode(
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_STRICT_MODE>
+Sys_gtid_strict_mode(
"gtid_strict_mode",
"Enforce strict seq_no ordering of events in the binary log. Slave "
"stops with an error if it encounters an event that would cause it to "
@@ -1932,7 +2035,8 @@ Sys_var_gtid_binlog_state::do_check(THD *thd, set_var *var)
my_error(ER_INCORRECT_GTID_STATE, MYF(0));
return true;
}
- if (!(data= (gtid_binlog_state_data *)my_malloc(sizeof(*data), MYF(0))))
+ if (!(data= (gtid_binlog_state_data *)my_malloc(PSI_INSTRUMENT_ME,
+ sizeof(*data), MYF(0))))
{
my_free(list);
my_error(ER_OUT_OF_RESOURCES, MYF(0));
@@ -2026,7 +2130,9 @@ Sys_var_last_gtid::session_value_ptr(THD *thd, const LEX_CSTRING *base)
}
-static Sys_var_uint Sys_gtid_cleanup_batch_size(
+static Sys_var_on_access_global<Sys_var_uint,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_CLEANUP_BATCH_SIZE>
+Sys_gtid_cleanup_batch_size(
"gtid_cleanup_batch_size",
"Normally does not need tuning. How many old rows must accumulate in "
"the mysql.gtid_slave_pos table before a background job will be run to "
@@ -2058,7 +2164,9 @@ fix_slave_parallel_threads(sys_var *self, THD *thd, enum_var_type type)
}
-static Sys_var_ulong Sys_slave_parallel_threads(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_PARALLEL_THREADS>
+Sys_slave_parallel_threads(
"slave_parallel_threads",
"If non-zero, number of threads to spawn to apply in parallel events "
"on the slave that were group-committed on the master or were logged "
@@ -2071,7 +2179,9 @@ static Sys_var_ulong Sys_slave_parallel_threads(
ON_UPDATE(fix_slave_parallel_threads));
/* Alias for @@slave_parallel_threads to match what MySQL 5.7 uses. */
-static Sys_var_ulong Sys_slave_parallel_workers(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_PARALLEL_WORKERS>
+Sys_slave_parallel_workers(
"slave_parallel_workers",
"Alias for slave_parallel_threads",
GLOBAL_VAR(opt_slave_parallel_threads), CMD_LINE(REQUIRED_ARG),
@@ -2099,7 +2209,9 @@ fix_slave_domain_parallel_threads(sys_var *self, THD *thd, enum_var_type type)
}
-static Sys_var_ulong Sys_slave_domain_parallel_threads(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_DOMAIN_PARALLEL_THREADS>
+Sys_slave_domain_parallel_threads(
"slave_domain_parallel_threads",
"Maximum number of parallel threads to use on slave for events in a "
"single replication domain. When using multiple domains, this can be "
@@ -2113,7 +2225,9 @@ static Sys_var_ulong Sys_slave_domain_parallel_threads(
ON_UPDATE(fix_slave_domain_parallel_threads));
-static Sys_var_ulong Sys_slave_parallel_max_queued(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_PARALLEL_MAX_QUEUED>
+Sys_slave_parallel_max_queued(
"slave_parallel_max_queued",
"Limit on how much memory SQL threads should use per parallel "
"replication thread when reading ahead in the relay log looking for "
@@ -2210,7 +2324,9 @@ export TYPELIB slave_parallel_mode_typelib = {
NULL
};
-static Sys_var_slave_parallel_mode Sys_slave_parallel_mode(
+static Sys_var_on_access_global<Sys_var_slave_parallel_mode,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_PARALLEL_MODE>
+Sys_slave_parallel_mode(
"slave_parallel_mode",
"Controls what transactions are applied in parallel when using "
"--slave-parallel-threads. Possible values: \"optimistic\" tries to "
@@ -2221,7 +2337,7 @@ static Sys_var_slave_parallel_mode Sys_slave_parallel_mode(
"\"minimal\" only parallelizes the commit steps of transactions. "
"\"none\" disables parallel apply completely.",
GLOBAL_VAR(opt_slave_parallel_mode), NO_CMD_LINE,
- slave_parallel_mode_names, DEFAULT(SLAVE_PARALLEL_CONSERVATIVE));
+ slave_parallel_mode_names, DEFAULT(SLAVE_PARALLEL_OPTIMISTIC));
static Sys_var_bit Sys_skip_parallel_replication(
@@ -2254,7 +2370,9 @@ fix_gtid_ignore_duplicates(sys_var *self, THD *thd, enum_var_type type)
}
-static Sys_var_mybool Sys_gtid_ignore_duplicates(
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_IGNORE_DUPLICATES>
+Sys_gtid_ignore_duplicates(
"gtid_ignore_duplicates",
"When set, different master connections in multi-source replication are "
"allowed to receive and process event groups with the same GTID (when "
@@ -2270,7 +2388,9 @@ static Sys_var_mybool Sys_gtid_ignore_duplicates(
#endif
-static Sys_var_ulong Sys_binlog_commit_wait_count(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_COMMIT_WAIT_COUNT>
+Sys_binlog_commit_wait_count(
"binlog_commit_wait_count",
"If non-zero, binlog write will wait at most binlog_commit_wait_usec "
"microseconds for at least this many commits to queue up for group "
@@ -2281,7 +2401,9 @@ static Sys_var_ulong Sys_binlog_commit_wait_count(
VALID_RANGE(0, ULONG_MAX), DEFAULT(0), BLOCK_SIZE(1));
-static Sys_var_ulong Sys_binlog_commit_wait_usec(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_COMMIT_WAIT_USEC>
+Sys_binlog_commit_wait_usec(
"binlog_commit_wait_usec",
"Maximum time, in microseconds, to wait for more commits to queue up "
"for binlog group commit. Only takes effect if the value of "
@@ -2320,18 +2442,6 @@ static Sys_var_ulong Sys_max_length_for_sort_data(
SESSION_VAR(max_length_for_sort_data), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(4, 8192*1024L), DEFAULT(1024), BLOCK_SIZE(1));
-static Sys_var_ulong Sys_max_long_data_size(
- "max_long_data_size",
- "The maximum BLOB length to send to server from "
- "mysql_send_long_data API. Deprecated option; "
- "use max_allowed_packet instead.",
- READ_ONLY GLOBAL_VAR(max_long_data_size),
- CMD_LINE(REQUIRED_ARG, OPT_MAX_LONG_DATA_SIZE),
- VALID_RANGE(1024, UINT_MAX32), DEFAULT(1024*1024),
- BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG,
- ON_CHECK(0), ON_UPDATE(0),
- DEPRECATED("'@@max_allowed_packet'"));
-
static PolyLock_mutex PLock_prepared_stmt_count(&LOCK_prepared_stmt_count);
static Sys_var_uint Sys_max_prepared_stmt_count(
"max_prepared_stmt_count",
@@ -2388,7 +2498,7 @@ static Sys_var_ulong Sys_max_tmp_tables(
SESSION_VAR(max_tmp_tables), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(1, UINT_MAX), DEFAULT(32), BLOCK_SIZE(1),
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(0),
- DEPRECATED(""));
+ DEPRECATED("")); // since 10.1.2
static Sys_var_ulong Sys_max_write_lock_count(
"max_write_lock_count",
@@ -2495,7 +2605,9 @@ static Sys_var_enum Sys_old_alter_table(
"old_alter_table", "Alias for alter_algorithm. "
"Deprecated. Use --alter-algorithm instead.",
SESSION_VAR(alter_algorithm), CMD_LINE(OPT_ARG),
- alter_algorithm_modes, DEFAULT(0));
+ alter_algorithm_modes, DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(0), ON_UPDATE(0),
+ DEPRECATED("'@@alter_algorithm'")); // Since 10.5.1
static bool check_old_passwords(sys_var *self, THD *thd, set_var *var)
{
@@ -2598,6 +2710,7 @@ export const char *optimizer_switch_names[]=
"condition_pushdown_for_subquery",
"rowid_filter",
"condition_pushdown_from_having",
+ "not_null_range_scan",
"default",
NullS
};
@@ -2609,7 +2722,7 @@ static bool fix_optimizer_switch(sys_var *self, THD *thd,
push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT,
ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT),
- "engine_condition_pushdown=on");
+ "engine_condition_pushdown=on"); // since 10.1.1
return false;
}
static Sys_var_flagset Sys_optimizer_switch(
@@ -2637,15 +2750,15 @@ static Sys_var_ulong Sys_optimizer_trace_max_mem_size(
SESSION_VAR(optimizer_trace_max_mem_size), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, ULONG_MAX), DEFAULT(1024 * 1024), BLOCK_SIZE(1));
-static Sys_var_charptr Sys_pid_file(
+static Sys_var_charptr_fscs Sys_pid_file(
"pid_file", "Pid file used by safe_mysqld",
READ_ONLY GLOBAL_VAR(pidfile_name_ptr), CMD_LINE(REQUIRED_ARG),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
-static Sys_var_charptr Sys_plugin_dir(
+static Sys_var_charptr_fscs Sys_plugin_dir(
"plugin_dir", "Directory for plugins",
READ_ONLY GLOBAL_VAR(opt_plugin_dir_ptr), CMD_LINE(REQUIRED_ARG),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
static Sys_var_uint Sys_port(
"port",
@@ -2671,12 +2784,10 @@ static Sys_var_uint Sys_protocol_version(
VALID_RANGE(0, ~0U), DEFAULT(PROTOCOL_VERSION), BLOCK_SIZE(1));
static Sys_var_proxy_user Sys_proxy_user(
- "proxy_user", "The proxy user account name used when logging in",
- IN_SYSTEM_CHARSET);
+ "proxy_user", "The proxy user account name used when logging in");
static Sys_var_external_user Sys_exterenal_user(
- "external_user", "The external user account used when logging in",
- IN_SYSTEM_CHARSET);
+ "external_user", "The external user account used when logging in");
static Sys_var_ulong Sys_read_buff_size(
"read_buffer_size",
@@ -2770,7 +2881,9 @@ static bool fix_read_only(sys_var *self, THD *thd, enum_var_type type)
transition (especially when transitioning from false to true) and
synchronizes both booleans in the end.
*/
-static Sys_var_mybool Sys_readonly(
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_READ_ONLY>
+Sys_readonly(
"read_only",
"Make all non-temporary tables read-only, with the exception for "
"replication (slave) threads and users with the SUPER privilege",
@@ -2809,13 +2922,6 @@ static Sys_var_ulong Sys_range_alloc_block_size(
VALID_RANGE(RANGE_ALLOC_BLOCK_SIZE, UINT_MAX),
DEFAULT(RANGE_ALLOC_BLOCK_SIZE), BLOCK_SIZE(1024));
-static Sys_var_ulong Sys_multi_range_count(
- "multi_range_count", "Ignored. Use mrr_buffer_size instead",
- SESSION_VAR(multi_range_count), CMD_LINE(REQUIRED_ARG),
- VALID_RANGE(1, ULONG_MAX), DEFAULT(256), BLOCK_SIZE(1),
- NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(0),
- DEPRECATED("'@@mrr_buffer_size'"));
-
static bool fix_thd_mem_root(sys_var *self, THD *thd, enum_var_type type)
{
if (type != OPT_GLOBAL)
@@ -2864,27 +2970,10 @@ static Sys_var_mybool Sys_skip_show_database(
READ_ONLY GLOBAL_VAR(opt_skip_show_db), CMD_LINE(OPT_ARG),
DEFAULT(FALSE));
-static Sys_var_charptr Sys_socket(
+static Sys_var_charptr_fscs Sys_socket(
"socket", "Socket file to use for connection",
READ_ONLY GLOBAL_VAR(mysqld_unix_port), CMD_LINE(REQUIRED_ARG),
- IN_FS_CHARSET, DEFAULT(0));
-
-/*
- thread_concurrency is a no-op on all platforms since
- MySQL 5.1. It will be removed in the context of
- WL#5265
-*/
-static Sys_var_ulong Sys_thread_concurrency(
- "thread_concurrency",
- "Permits the application to give the threads system a hint for "
- "the desired number of threads that should be run at the same time."
- "This variable has no effect, and is deprecated. "
- "It will be removed in a future release.",
- READ_ONLY GLOBAL_VAR(concurrency),
- CMD_LINE(REQUIRED_ARG, OPT_THREAD_CONCURRENCY),
- VALID_RANGE(1, 512), DEFAULT(DEFAULT_CONCURRENCY), BLOCK_SIZE(1),
- NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(0),
- DEPRECATED(""));
+ DEFAULT(0));
static Sys_var_ulonglong Sys_thread_stack(
"thread_stack", "The stack size for each thread",
@@ -2892,7 +2981,7 @@ static Sys_var_ulonglong Sys_thread_stack(
VALID_RANGE(128*1024, ULONGLONG_MAX), DEFAULT(DEFAULT_THREAD_STACK),
BLOCK_SIZE(1024));
-static Sys_var_charptr Sys_tmpdir(
+static Sys_var_charptr_fscs Sys_tmpdir(
"tmpdir", "Path for temporary files. Several paths may "
"be specified, separated by a "
#if defined(__WIN__)
@@ -2902,7 +2991,7 @@ static Sys_var_charptr Sys_tmpdir(
#endif
", in this case they are used in a round-robin fashion",
READ_ONLY GLOBAL_VAR(opt_mysql_tmpdir), CMD_LINE(REQUIRED_ARG, 't'),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
static bool fix_trans_mem_root(sys_var *self, THD *thd, enum_var_type type)
{
@@ -3064,19 +3153,55 @@ static Sys_var_mybool Sys_query_cache_wlock_invalidate(
DEFAULT(FALSE));
#endif /* HAVE_QUERY_CACHE */
-static Sys_var_mybool Sys_secure_auth(
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SECURE_AUTH>
+Sys_secure_auth(
"secure_auth",
"Disallow authentication for accounts that have old (pre-4.1) "
"passwords",
GLOBAL_VAR(opt_secure_auth), CMD_LINE(OPT_ARG),
DEFAULT(TRUE));
-static Sys_var_charptr Sys_secure_file_priv(
+static bool check_require_secure_transport(sys_var *self, THD *thd, set_var *var)
+{
+#ifndef _WIN32
+ /*
+ Always allow require_secure_transport to be enabled on
+ Linux, because it always has Unix domain sockets that are secure:
+ */
+ return false;
+#else
+ /*
+ Check SSL is enabled before turning require_secure_transport ON,
+ otherwise no connections will be allowed on Windows:
+ */
+ if (!var->save_result.ulonglong_value)
+ return false;
+ if (opt_use_ssl || opt_enable_named_pipe)
+ return false;
+ /* reject if SSL is disabled: */
+ my_error(ER_NO_SECURE_TRANSPORTS_CONFIGURED, MYF(0));
+ return true;
+#endif
+}
+
+static Sys_var_mybool Sys_require_secure_transport(
+ "require_secure_transport",
+ "When this option is enabled, connections attempted using insecure "
+ "transport will be rejected. Secure transports are SSL/TLS, "
+ "Unix sockets or named pipes.",
+ GLOBAL_VAR(opt_require_secure_transport),
+ CMD_LINE(OPT_ARG),
+ DEFAULT(FALSE),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(check_require_secure_transport), ON_UPDATE(0));
+
+static Sys_var_charptr_fscs Sys_secure_file_priv(
"secure_file_priv",
"Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to files "
"within specified directory",
PREALLOCATED READ_ONLY GLOBAL_VAR(opt_secure_file_priv),
- CMD_LINE(REQUIRED_ARG), IN_FS_CHARSET, DEFAULT(0));
+ CMD_LINE(REQUIRED_ARG), DEFAULT(0));
static bool fix_server_id(sys_var *self, THD *thd, enum_var_type type)
{
@@ -3093,15 +3218,20 @@ static bool fix_server_id(sys_var *self, THD *thd, enum_var_type type)
}
return false;
}
-static Sys_var_ulong Sys_server_id(
+static Sys_var_on_access<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SERVER_ID,
+ PRIV_SET_SYSTEM_SESSION_VAR_SERVER_ID>
+Sys_server_id(
"server_id",
"Uniquely identifies the server instance in the community of "
"replication partners",
SESSION_VAR(server_id), CMD_LINE(REQUIRED_ARG, OPT_SERVER_ID),
VALID_RANGE(1, UINT_MAX32), DEFAULT(1), BLOCK_SIZE(1), NO_MUTEX_GUARD,
- NOT_IN_BINLOG, ON_CHECK(check_has_super), ON_UPDATE(fix_server_id));
+ NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(fix_server_id));
-static Sys_var_mybool Sys_slave_compressed_protocol(
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_COMPRESSED_PROTOCOL>
+Sys_slave_compressed_protocol(
"slave_compressed_protocol",
"Use compression on master/slave protocol",
GLOBAL_VAR(opt_slave_compressed_protocol), CMD_LINE(OPT_ARG),
@@ -3109,7 +3239,9 @@ static Sys_var_mybool Sys_slave_compressed_protocol(
#ifdef HAVE_REPLICATION
static const char *slave_exec_mode_names[]= {"STRICT", "IDEMPOTENT", 0};
-static Sys_var_enum Slave_exec_mode(
+static Sys_var_on_access_global<Sys_var_enum,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_EXEC_MODE>
+Slave_exec_mode(
"slave_exec_mode",
"How replication events should be executed. Legal values "
"are STRICT (default) and IDEMPOTENT. In IDEMPOTENT mode, "
@@ -3121,7 +3253,9 @@ static Sys_var_enum Slave_exec_mode(
GLOBAL_VAR(slave_exec_mode_options), CMD_LINE(REQUIRED_ARG),
slave_exec_mode_names, DEFAULT(SLAVE_EXEC_MODE_STRICT));
-static Sys_var_enum Slave_ddl_exec_mode(
+static Sys_var_on_access_global<Sys_var_enum,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_DDL_EXEC_MODE>
+Slave_ddl_exec_mode(
"slave_ddl_exec_mode",
"How replication events should be executed. Legal values "
"are STRICT and IDEMPOTENT (default). In IDEMPOTENT mode, "
@@ -3132,22 +3266,27 @@ static Sys_var_enum Slave_ddl_exec_mode(
slave_exec_mode_names, DEFAULT(SLAVE_EXEC_MODE_IDEMPOTENT));
static const char *slave_run_triggers_for_rbr_names[]=
- {"NO", "YES", "LOGGING", 0};
-static Sys_var_enum Slave_run_triggers_for_rbr(
+ {"NO", "YES", "LOGGING", "ENFORCE", 0};
+static Sys_var_on_access_global<Sys_var_enum,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_RUN_TRIGGERS_FOR_RBR>
+Slave_run_triggers_for_rbr(
"slave_run_triggers_for_rbr",
"Modes for how triggers in row-base replication on slave side will be "
- "executed. Legal values are NO (default), YES and LOGGING. NO means "
+ "executed. Legal values are NO (default), YES, LOGGING and ENFORCE. NO means "
"that trigger for RBR will not be running on slave. YES and LOGGING "
"means that triggers will be running on slave, if there was not "
"triggers running on the master for the statement. LOGGING also means "
"results of that the executed triggers work will be written to "
- "the binlog.",
+ "the binlog. ENFORCE means that triggers will always be run on the slave, "
+ "even if there are triggers on the master. ENFORCE implies LOGGING.",
GLOBAL_VAR(slave_run_triggers_for_rbr), CMD_LINE(REQUIRED_ARG),
slave_run_triggers_for_rbr_names,
DEFAULT(SLAVE_RUN_TRIGGERS_FOR_RBR_NO));
static const char *slave_type_conversions_name[]= {"ALL_LOSSY", "ALL_NON_LOSSY", 0};
-static Sys_var_set Slave_type_conversions(
+static Sys_var_on_access_global<Sys_var_set,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_TYPE_CONVERSIONS>
+Slave_type_conversions(
"slave_type_conversions",
"Set of slave type conversions that are enabled."
" If the variable is empty, no conversions are"
@@ -3156,7 +3295,9 @@ static Sys_var_set Slave_type_conversions(
slave_type_conversions_name,
DEFAULT(0));
-static Sys_var_mybool Sys_slave_sql_verify_checksum(
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_SQL_VERIFY_CHECKSUM>
+Sys_slave_sql_verify_checksum(
"slave_sql_verify_checksum",
"Force checksum verification of replication events after reading them "
"from relay log. Note: Events are always checksum-verified by slave on "
@@ -3164,7 +3305,9 @@ static Sys_var_mybool Sys_slave_sql_verify_checksum(
GLOBAL_VAR(opt_slave_sql_verify_checksum), CMD_LINE(OPT_ARG),
DEFAULT(TRUE));
-static Sys_var_mybool Sys_master_verify_checksum(
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_MASTER_VERIFY_CHECKSUM>
+Sys_master_verify_checksum(
"master_verify_checksum",
"Force checksum verification of logged events in the binary log before "
"sending them to slaves or printing them in the output of "
@@ -3190,7 +3333,9 @@ Sys_var_replicate_events_marked_for_skip::global_update(THD *thd, set_var *var)
DBUG_RETURN(result);
}
-static Sys_var_replicate_events_marked_for_skip Replicate_events_marked_for_skip
+static Sys_var_on_access_global<Sys_var_replicate_events_marked_for_skip,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_EVENTS_MARKED_FOR_SKIP>
+Replicate_events_marked_for_skip
("replicate_events_marked_for_skip",
"Whether the slave should replicate events that were created with "
"@@skip_replication=1 on the master. Default REPLICATE (no events are "
@@ -3257,7 +3402,9 @@ static bool fix_rpl_semi_sync_master_wait_no_slave(sys_var *self, THD *thd,
return false;
}
-static Sys_var_mybool Sys_semisync_master_enabled(
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_MASTER_ENABLED>
+Sys_semisync_master_enabled(
"rpl_semi_sync_master_enabled",
"Enable semi-synchronous replication master (disabled by default).",
GLOBAL_VAR(rpl_semi_sync_master_enabled),
@@ -3265,7 +3412,9 @@ static Sys_var_mybool Sys_semisync_master_enabled(
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(fix_rpl_semi_sync_master_enabled));
-static Sys_var_ulong Sys_semisync_master_timeout(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_MASTER_TIMEOUT>
+Sys_semisync_master_timeout(
"rpl_semi_sync_master_timeout",
"The timeout value (in ms) for semi-synchronous replication in the "
"master",
@@ -3275,7 +3424,9 @@ static Sys_var_ulong Sys_semisync_master_timeout(
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(fix_rpl_semi_sync_master_timeout));
-static Sys_var_mybool Sys_semisync_master_wait_no_slave(
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_MASTER_WAIT_NO_SLAVE>
+Sys_semisync_master_wait_no_slave(
"rpl_semi_sync_master_wait_no_slave",
"Wait until timeout when no semi-synchronous replication slave "
"available (enabled by default).",
@@ -3284,7 +3435,9 @@ static Sys_var_mybool Sys_semisync_master_wait_no_slave(
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(fix_rpl_semi_sync_master_wait_no_slave));
-static Sys_var_ulong Sys_semisync_master_trace_level(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_MASTER_TRACE_LEVEL>
+Sys_semisync_master_trace_level(
"rpl_semi_sync_master_trace_level",
"The tracing level for semi-sync replication.",
GLOBAL_VAR(rpl_semi_sync_master_trace_level),
@@ -3296,7 +3449,9 @@ static Sys_var_ulong Sys_semisync_master_trace_level(
static const char *repl_semisync_wait_point[]=
{"AFTER_SYNC", "AFTER_COMMIT", NullS};
-static Sys_var_enum Sys_semisync_master_wait_point(
+static Sys_var_on_access_global<Sys_var_enum,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_MASTER_WAIT_POINT>
+Sys_semisync_master_wait_point(
"rpl_semi_sync_master_wait_point",
"Should transaction wait for semi-sync ack after having synced binlog, "
"or after having committed in storage engine.",
@@ -3334,7 +3489,9 @@ static bool fix_rpl_semi_sync_slave_kill_conn_timeout(sys_var *self, THD *thd,
return false;
}
-static Sys_var_mybool Sys_semisync_slave_enabled(
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_SLAVE_ENABLED>
+Sys_semisync_slave_enabled(
"rpl_semi_sync_slave_enabled",
"Enable semi-synchronous replication slave (disabled by default).",
GLOBAL_VAR(rpl_semi_sync_slave_enabled),
@@ -3342,7 +3499,9 @@ static Sys_var_mybool Sys_semisync_slave_enabled(
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(fix_rpl_semi_sync_slave_enabled));
-static Sys_var_ulong Sys_semisync_slave_trace_level(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_SLAVE_TRACE_LEVEL>
+Sys_semisync_slave_trace_level(
"rpl_semi_sync_slave_trace_level",
"The tracing level for semi-sync replication.",
GLOBAL_VAR(rpl_semi_sync_slave_trace_level),
@@ -3351,7 +3510,9 @@ static Sys_var_ulong Sys_semisync_slave_trace_level(
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(fix_rpl_semi_sync_slave_trace_level));
-static Sys_var_mybool Sys_semisync_slave_delay_master(
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_SLAVE_DELAY_MASTER>
+Sys_semisync_slave_delay_master(
"rpl_semi_sync_slave_delay_master",
"Only write master info file when ack is needed.",
GLOBAL_VAR(rpl_semi_sync_slave_delay_master),
@@ -3359,7 +3520,9 @@ static Sys_var_mybool Sys_semisync_slave_delay_master(
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(fix_rpl_semi_sync_slave_delay_master));
-static Sys_var_uint Sys_semisync_slave_kill_conn_timeout(
+static Sys_var_on_access_global<Sys_var_uint,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_SLAVE_KILL_CONN_TIMEOUT>
+Sys_semisync_slave_kill_conn_timeout(
"rpl_semi_sync_slave_kill_conn_timeout",
"Timeout for the mysql connection used to kill the slave io_thread's "
"connection on master. This timeout comes into play when stop slave "
@@ -3371,7 +3534,9 @@ static Sys_var_uint Sys_semisync_slave_kill_conn_timeout(
ON_UPDATE(fix_rpl_semi_sync_slave_kill_conn_timeout));
#endif /* HAVE_REPLICATION */
-static Sys_var_ulong Sys_slow_launch_time(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SLOW_LAUNCH_TIME>
+Sys_slow_launch_time(
"slow_launch_time",
"If creating the thread takes longer than this value (in seconds), "
"the Slow_launch_threads counter will be incremented",
@@ -3390,7 +3555,7 @@ export sql_mode_t expand_sql_mode(sql_mode_t sql_mode)
if (sql_mode & MODE_ANSI)
{
/*
- Note that we dont set
+ Note that we don't set
MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | MODE_NO_FIELD_OPTIONS
to allow one to get full use of MySQL in this mode.
@@ -3534,44 +3699,44 @@ static Sys_var_set Sys_old_behavior(
#define SSL_OPT(X) NO_CMD_LINE
#endif
-static Sys_var_charptr Sys_ssl_ca(
+static Sys_var_charptr_fscs Sys_ssl_ca(
"ssl_ca",
"CA file in PEM format (check OpenSSL docs, implies --ssl)",
READ_ONLY GLOBAL_VAR(opt_ssl_ca), SSL_OPT(OPT_SSL_CA),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
-static Sys_var_charptr Sys_ssl_capath(
+static Sys_var_charptr_fscs Sys_ssl_capath(
"ssl_capath",
"CA directory (check OpenSSL docs, implies --ssl)",
READ_ONLY GLOBAL_VAR(opt_ssl_capath), SSL_OPT(OPT_SSL_CAPATH),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
-static Sys_var_charptr Sys_ssl_cert(
+static Sys_var_charptr_fscs Sys_ssl_cert(
"ssl_cert", "X509 cert in PEM format (implies --ssl)",
READ_ONLY GLOBAL_VAR(opt_ssl_cert), SSL_OPT(OPT_SSL_CERT),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
-static Sys_var_charptr Sys_ssl_cipher(
+static Sys_var_charptr_fscs Sys_ssl_cipher(
"ssl_cipher", "SSL cipher to use (implies --ssl)",
READ_ONLY GLOBAL_VAR(opt_ssl_cipher), SSL_OPT(OPT_SSL_CIPHER),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
-static Sys_var_charptr Sys_ssl_key(
+static Sys_var_charptr_fscs Sys_ssl_key(
"ssl_key", "X509 key in PEM format (implies --ssl)",
READ_ONLY GLOBAL_VAR(opt_ssl_key), SSL_OPT(OPT_SSL_KEY),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
-static Sys_var_charptr Sys_ssl_crl(
+static Sys_var_charptr_fscs Sys_ssl_crl(
"ssl_crl",
"CRL file in PEM format (check OpenSSL docs, implies --ssl)",
READ_ONLY GLOBAL_VAR(opt_ssl_crl), SSL_OPT(OPT_SSL_CRL),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
-static Sys_var_charptr Sys_ssl_crlpath(
+static Sys_var_charptr_fscs Sys_ssl_crlpath(
"ssl_crlpath",
"CRL directory (check OpenSSL docs, implies --ssl)",
READ_ONLY GLOBAL_VAR(opt_ssl_crlpath), SSL_OPT(OPT_SSL_CRLPATH),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
static const char *tls_version_names[]=
{
@@ -3625,7 +3790,7 @@ static Sys_var_charptr Sys_system_time_zone(
"system_time_zone", "The server system time zone",
READ_ONLY GLOBAL_VAR(system_time_zone_ptr),
CMD_LINE_HELP_ONLY,
- IN_SYSTEM_CHARSET, DEFAULT(system_time_zone));
+ DEFAULT(system_time_zone));
/*
If One use views with prepared statements this should be bigger than
@@ -3708,7 +3873,9 @@ static bool fix_threadpool_stall_limit(sys_var*, THD*, enum_var_type)
}
#ifdef _WIN32
-static Sys_var_uint Sys_threadpool_min_threads(
+static Sys_var_on_access_global<Sys_var_uint,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_THREAD_POOL>
+Sys_threadpool_min_threads(
"thread_pool_min_threads",
"Minimum number of threads in the thread pool.",
GLOBAL_VAR(threadpool_min_threads), CMD_LINE(REQUIRED_ARG),
@@ -3718,7 +3885,9 @@ static Sys_var_uint Sys_threadpool_min_threads(
);
static const char *threadpool_mode_names[]={ "windows", "generic", 0 };
-static Sys_var_enum Sys_threadpool_mode(
+static Sys_var_on_access_global<Sys_var_enum,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_THREAD_POOL>
+Sys_threadpool_mode(
"thread_pool_mode",
"Chose implementation of the threadpool",
READ_ONLY GLOBAL_VAR(threadpool_mode), CMD_LINE(REQUIRED_ARG),
@@ -3727,27 +3896,35 @@ static Sys_var_enum Sys_threadpool_mode(
#endif
static const char *threadpool_priority_names[]={ "high", "low", "auto", 0 };
-static Sys_var_enum Sys_thread_pool_priority(
+static Sys_var_on_access_global<Sys_var_enum,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_THREAD_POOL>
+Sys_thread_pool_priority(
"thread_pool_priority",
"Threadpool priority. High priority connections usually start executing earlier than low priority."
"If priority set to 'auto', the the actual priority(low or high) is determined based on whether or not connection is inside transaction.",
SESSION_VAR(threadpool_priority), CMD_LINE(REQUIRED_ARG),
threadpool_priority_names, DEFAULT(TP_PRIORITY_AUTO));
-static Sys_var_uint Sys_threadpool_idle_thread_timeout(
+static Sys_var_on_access_global<Sys_var_uint,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_THREAD_POOL>
+Sys_threadpool_idle_thread_timeout(
"thread_pool_idle_timeout",
"Timeout in seconds for an idle thread in the thread pool."
"Worker thread will be shut down after timeout",
GLOBAL_VAR(threadpool_idle_timeout), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(1, UINT_MAX), DEFAULT(60), BLOCK_SIZE(1)
);
-static Sys_var_uint Sys_threadpool_oversubscribe(
+static Sys_var_on_access_global<Sys_var_uint,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_THREAD_POOL>
+Sys_threadpool_oversubscribe(
"thread_pool_oversubscribe",
"How many additional active worker threads in a group are allowed.",
GLOBAL_VAR(threadpool_oversubscribe), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(1, 1000), DEFAULT(3), BLOCK_SIZE(1)
);
-static Sys_var_uint Sys_threadpool_size(
+static Sys_var_on_access_global<Sys_var_uint,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_THREAD_POOL>
+Sys_threadpool_size(
"thread_pool_size",
"Number of thread groups in the pool. "
"This parameter is roughly equivalent to maximum number of concurrently "
@@ -3757,19 +3934,23 @@ static Sys_var_uint Sys_threadpool_size(
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_threadpool_size),
ON_UPDATE(fix_threadpool_size)
);
-static Sys_var_uint Sys_threadpool_stall_limit(
+static Sys_var_on_access_global<Sys_var_uint,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_THREAD_POOL>
+Sys_threadpool_stall_limit(
"thread_pool_stall_limit",
"Maximum query execution time in milliseconds,"
"before an executing non-yielding thread is considered stalled."
"If a worker thread is stalled, additional worker thread "
"may be created to handle remaining clients.",
GLOBAL_VAR(threadpool_stall_limit), CMD_LINE(REQUIRED_ARG),
- VALID_RANGE(10, UINT_MAX), DEFAULT(500), BLOCK_SIZE(1),
+ VALID_RANGE(1, UINT_MAX), DEFAULT(DEFAULT_THREADPOOL_STALL_LIMIT), BLOCK_SIZE(1),
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(fix_threadpool_stall_limit)
);
-static Sys_var_uint Sys_threadpool_max_threads(
+static Sys_var_on_access_global<Sys_var_uint,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_THREAD_POOL>
+Sys_threadpool_max_threads(
"thread_pool_max_threads",
"Maximum allowed number of worker threads in the thread pool",
GLOBAL_VAR(threadpool_max_threads), CMD_LINE(REQUIRED_ARG),
@@ -3778,12 +3959,32 @@ static Sys_var_uint Sys_threadpool_max_threads(
ON_UPDATE(fix_tp_max_threads)
);
-static Sys_var_uint Sys_threadpool_threadpool_prio_kickup_timer(
+static Sys_var_on_access_global<Sys_var_uint,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_THREAD_POOL>
+Sys_threadpool_threadpool_prio_kickup_timer(
"thread_pool_prio_kickup_timer",
"The number of milliseconds before a dequeued low-priority statement is moved to the high-priority queue",
GLOBAL_VAR(threadpool_prio_kickup_timer), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, UINT_MAX), DEFAULT(1000), BLOCK_SIZE(1)
);
+
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_THREAD_POOL>
+Sys_threadpool_exact_stats(
+ "thread_pool_exact_stats",
+ "If set to 1, provides better statistics in information_schema threadpool tables",
+ GLOBAL_VAR(threadpool_exact_stats), CMD_LINE(OPT_ARG), DEFAULT(FALSE),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG
+);
+
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_THREAD_POOL>
+Sys_threadpool_dedicated_listener(
+ "thread_pool_dedicated_listener",
+ "If set to 1,listener thread will not pick up queries",
+ GLOBAL_VAR(threadpool_dedicated_listener), CMD_LINE(OPT_ARG), DEFAULT(FALSE),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG
+);
#endif /* HAVE_POOL_OF_THREADS */
/**
@@ -3866,7 +4067,7 @@ static Sys_var_ulonglong Sys_tmp_table_size(
"If an internal in-memory temporary table exceeds this size, MariaDB "
"will automatically convert it to an on-disk MyISAM or Aria table.",
SESSION_VAR(tmp_memory_table_size), CMD_LINE(REQUIRED_ARG),
- VALID_RANGE(1024, (ulonglong)~(intptr)0), DEFAULT(16*1024*1024),
+ VALID_RANGE(0, (ulonglong)~(intptr)0), DEFAULT(16*1024*1024),
BLOCK_SIZE(1));
static Sys_var_ulonglong Sys_tmp_memory_table_size(
@@ -3875,7 +4076,7 @@ static Sys_var_ulonglong Sys_tmp_memory_table_size(
"will automatically convert it to an on-disk MyISAM or Aria table. "
"Same as tmp_table_size.",
SESSION_VAR(tmp_memory_table_size), CMD_LINE(REQUIRED_ARG),
- VALID_RANGE(1024, (ulonglong)~(intptr)0), DEFAULT(16*1024*1024),
+ VALID_RANGE(0, (ulonglong)~(intptr)0), DEFAULT(16*1024*1024),
BLOCK_SIZE(1));
static Sys_var_ulonglong Sys_tmp_disk_table_size(
@@ -3883,15 +4084,7 @@ static Sys_var_ulonglong Sys_tmp_disk_table_size(
"Max size for data for an internal temporary on-disk MyISAM or Aria table.",
SESSION_VAR(tmp_disk_table_size), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(1024, (ulonglong)~(intptr)0),
- DEFAULT((ulonglong)~(intptr)0),
- BLOCK_SIZE(1));
-
-static Sys_var_mybool Sys_timed_mutexes(
- "timed_mutexes",
- "Specify whether to time mutexes. Deprecated, has no effect.",
- GLOBAL_VAR(timed_mutexes), CMD_LINE(OPT_ARG), DEFAULT(0),
- NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(0),
- DEPRECATED(""));
+ DEFAULT((ulonglong)~(intptr)0), BLOCK_SIZE(1));
static Sys_var_charptr Sys_version(
"version", "Server version number. It may also include a suffix "
@@ -3901,7 +4094,7 @@ static Sys_var_charptr Sys_version(
"enabled, for example 10.1.1-MariaDB-mariadb1precise-log.",
READ_ONLY GLOBAL_VAR(server_version_ptr),
CMD_LINE_HELP_ONLY,
- IN_SYSTEM_CHARSET, DEFAULT(server_version));
+ DEFAULT(server_version));
static char *server_version_comment_ptr;
static Sys_var_charptr Sys_version_comment(
@@ -3910,14 +4103,14 @@ static Sys_var_charptr Sys_version_comment(
"mariadb.org binary distribution.",
READ_ONLY GLOBAL_VAR(server_version_comment_ptr),
CMD_LINE_HELP_ONLY,
- IN_SYSTEM_CHARSET, DEFAULT(MYSQL_COMPILATION_COMMENT));
+ DEFAULT(MYSQL_COMPILATION_COMMENT));
static char *server_version_compile_machine_ptr;
static Sys_var_charptr Sys_version_compile_machine(
"version_compile_machine", "The machine type or architecture "
"MariaDB was built on, for example i686.",
READ_ONLY GLOBAL_VAR(server_version_compile_machine_ptr),
- CMD_LINE_HELP_ONLY, IN_SYSTEM_CHARSET, DEFAULT(DEFAULT_MACHINE));
+ CMD_LINE_HELP_ONLY, DEFAULT(DEFAULT_MACHINE));
static char *server_version_compile_os_ptr;
static Sys_var_charptr Sys_version_compile_os(
@@ -3925,7 +4118,7 @@ static Sys_var_charptr Sys_version_compile_os(
"on, for example debian-linux-gnu.",
READ_ONLY GLOBAL_VAR(server_version_compile_os_ptr),
CMD_LINE_HELP_ONLY,
- IN_SYSTEM_CHARSET, DEFAULT(SYSTEM_TYPE));
+ DEFAULT(SYSTEM_TYPE));
#include <source_revision.h>
static char *server_version_source_revision;
@@ -3933,19 +4126,19 @@ static Sys_var_charptr Sys_version_source_revision(
"version_source_revision", "Source control revision id for MariaDB source code",
READ_ONLY GLOBAL_VAR(server_version_source_revision),
CMD_LINE_HELP_ONLY,
- IN_SYSTEM_CHARSET, DEFAULT(SOURCE_REVISION));
+ DEFAULT(SOURCE_REVISION));
static char *malloc_library;
static Sys_var_charptr Sys_malloc_library(
"version_malloc_library", "Version of the used malloc library",
READ_ONLY GLOBAL_VAR(malloc_library), CMD_LINE_HELP_ONLY,
- IN_SYSTEM_CHARSET, DEFAULT(guess_malloc_library()));
+ DEFAULT(guess_malloc_library()));
static char *ssl_library;
static Sys_var_charptr Sys_ssl_library(
"version_ssl_library", "Version of the used SSL library",
READ_ONLY GLOBAL_VAR(ssl_library), CMD_LINE_HELP_ONLY,
- IN_SYSTEM_CHARSET, DEFAULT(SSL_LIBRARY));
+ DEFAULT(SSL_LIBRARY));
static Sys_var_ulong Sys_net_wait_timeout(
"wait_timeout",
@@ -3982,12 +4175,12 @@ static Sys_var_plugin Sys_default_storage_engine(
MYSQL_STORAGE_ENGINE_PLUGIN, DEFAULT(&default_storage_engine),
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_not_null));
-// Alias for @@default_storage_engine
static Sys_var_plugin Sys_storage_engine(
"storage_engine", "Alias for @@default_storage_engine. Deprecated",
SESSION_VAR(table_plugin), NO_CMD_LINE,
MYSQL_STORAGE_ENGINE_PLUGIN, DEFAULT(&default_storage_engine),
- NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_not_null));
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_not_null), ON_UPDATE(0),
+ DEPRECATED("'@@default_storage_engine'")); // since 10.5.1
static Sys_var_plugin Sys_default_tmp_storage_engine(
"default_tmp_storage_engine", "The default storage engine for user-created temporary tables",
@@ -3998,7 +4191,8 @@ static Sys_var_plugin Sys_enforce_storage_engine(
"enforce_storage_engine", "Force the use of a storage engine for new tables",
SESSION_VAR(enforced_table_plugin),
NO_CMD_LINE, MYSQL_STORAGE_ENGINE_PLUGIN,
- DEFAULT(&enforced_storage_engine), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_has_super));
+ DEFAULT(&enforced_storage_engine), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(check_has_super));
#ifdef HAVE_REPLICATION
@@ -4026,7 +4220,9 @@ check_gtid_pos_auto_engines(sys_var *self, THD *thd, set_var *var)
}
-static Sys_var_pluginlist Sys_gtid_pos_auto_engines(
+static Sys_var_on_access_global<Sys_var_pluginlist,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_POS_AUTO_ENGINES>
+Sys_gtid_pos_auto_engines(
"gtid_pos_auto_engines",
"List of engines for which to automatically create a "
"mysql.gtid_slave_pos_ENGINE table, if a transaction using that engine "
@@ -4070,23 +4266,26 @@ static Sys_var_debug_sync Sys_debug_sync(
static Sys_var_charptr Sys_date_format(
"date_format", "The DATE format (ignored)",
READ_ONLY GLOBAL_VAR(global_date_format.format.str),
- CMD_LINE(REQUIRED_ARG), IN_SYSTEM_CHARSET,
+ CMD_LINE(REQUIRED_ARG),
DEFAULT(known_date_time_formats[ISO_FORMAT].date_format),
- NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(0), DEPRECATED(""));
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(0),
+ DEPRECATED("")); // since 10.1.2
static Sys_var_charptr Sys_datetime_format(
"datetime_format", "The DATETIME format (ignored)",
READ_ONLY GLOBAL_VAR(global_datetime_format.format.str),
- CMD_LINE(REQUIRED_ARG), IN_SYSTEM_CHARSET,
+ CMD_LINE(REQUIRED_ARG),
DEFAULT(known_date_time_formats[ISO_FORMAT].datetime_format),
- NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(0), DEPRECATED(""));
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(0),
+ DEPRECATED("")); // since 10.1.2
static Sys_var_charptr Sys_time_format(
"time_format", "The TIME format (ignored)",
READ_ONLY GLOBAL_VAR(global_time_format.format.str),
- CMD_LINE(REQUIRED_ARG), IN_SYSTEM_CHARSET,
+ CMD_LINE(REQUIRED_ARG),
DEFAULT(known_date_time_formats[ISO_FORMAT].time_format),
- NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(0), DEPRECATED(""));
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(0),
+ DEPRECATED("")); // since 10.1.2
static bool fix_autocommit(sys_var *self, THD *thd, enum_var_type type)
{
@@ -4157,9 +4356,10 @@ export sys_var *Sys_autocommit_ptr= &Sys_autocommit; // for sql_yacc.yy
static Sys_var_mybool Sys_big_tables(
"big_tables", "Old variable, which if set to 1, allows large result sets "
"by saving all temporary sets to disk, avoiding 'table full' errors. No "
- "longer needed, as the server now handles this automatically. "
- "sql_big_tables is a synonym.",
- SESSION_VAR(big_tables), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+ "longer needed, as the server now handles this automatically.",
+ SESSION_VAR(big_tables), CMD_LINE(OPT_ARG), DEFAULT(FALSE),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(0),
+ DEPRECATED("")); // since 10.5.0
static Sys_var_bit Sys_big_selects(
"sql_big_selects", "If set to 0, MariaDB will not perform large SELECTs."
@@ -4174,7 +4374,8 @@ static Sys_var_bit Sys_log_off(
"query log is done for the client. Only clients with the SUPER privilege "
"can update this variable.",
NO_SET_STMT SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_LOG_OFF,
- DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_has_super));
+ DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(check_has_super));
/**
This function sets the session variable thd->variables.sql_log_bin
@@ -4222,9 +4423,6 @@ static bool check_session_only_variable(sys_var *self, THD *,set_var *var)
*/
static bool check_sql_log_bin(sys_var *self, THD *thd, set_var *var)
{
- if (check_has_super(self, thd, var))
- return true;
-
if (check_session_only_variable(self, thd, var))
return true;
@@ -4236,7 +4434,10 @@ static bool check_sql_log_bin(sys_var *self, THD *thd, set_var *var)
return false;
}
-static Sys_var_mybool Sys_log_binlog(
+static Sys_var_on_access<Sys_var_mybool,
+ PRIV_SET_SYSTEM_VAR_SQL_LOG_BIN,
+ PRIV_SET_SYSTEM_VAR_SQL_LOG_BIN>
+Sys_sql_log_bin(
"sql_log_bin", "If set to 0 (1 is the default), no logging to the binary "
"log is done for the client. Only clients with the SUPER privilege can "
"update this variable. Can have unintended consequences if set globally, "
@@ -4389,12 +4590,21 @@ static Sys_var_harows Sys_select_limit(
VALID_RANGE(0, HA_POS_ERROR), DEFAULT(HA_POS_ERROR), BLOCK_SIZE(1));
static const char *secure_timestamp_levels[]= {"NO", "SUPER", "REPLICATION", "YES", 0};
-static bool check_timestamp(sys_var *self, THD *thd, set_var *var)
+bool Sys_var_timestamp::on_check_access_session(THD *thd) const
{
- if (opt_secure_timestamp == SECTIME_NO)
+ switch (opt_secure_timestamp) {
+ case SECTIME_NO:
return false;
- if (opt_secure_timestamp == SECTIME_SUPER)
- return check_has_super(self, thd, var);
+ case SECTIME_SUPER:
+ return check_global_access(thd, SUPER_ACL | BINLOG_REPLAY_ACL);
+ case SECTIME_REPL:
+ /*
+ Perhaps we eventually should do this here:
+ return check_global_access(thd, BINLOG_REPLAY_ACL);
+ */
+ case SECTIME_YES:
+ break;
+ }
char buf[1024];
strxnmov(buf, sizeof(buf), "--secure-timestamp=",
secure_timestamp_levels[opt_secure_timestamp], NULL);
@@ -4405,7 +4615,7 @@ static Sys_var_timestamp Sys_timestamp(
"timestamp", "Set the time for this client",
sys_var::ONLY_SESSION, NO_CMD_LINE,
VALID_RANGE(0, TIMESTAMP_MAX_VALUE),
- NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(check_timestamp));
+ NO_MUTEX_GUARD, IN_BINLOG);
static bool update_last_insert_id(THD *thd, set_var *var)
{
@@ -4563,7 +4773,7 @@ static char *glob_hostname_ptr;
static Sys_var_charptr Sys_hostname(
"hostname", "Server host name",
READ_ONLY GLOBAL_VAR(glob_hostname_ptr), NO_CMD_LINE,
- IN_SYSTEM_CHARSET, DEFAULT(glob_hostname));
+ DEFAULT(glob_hostname));
#ifndef EMBEDDED_LIBRARY
static Sys_var_charptr Sys_repl_report_host(
@@ -4576,21 +4786,21 @@ static Sys_var_charptr Sys_repl_report_host(
"NAT and other routing issues, that IP may not be valid for connecting "
"to the slave from the master or other hosts",
READ_ONLY GLOBAL_VAR(report_host), CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(0));
+ DEFAULT(0));
static Sys_var_charptr Sys_repl_report_user(
"report_user",
"The account user name of the slave to be reported to the master "
"during slave registration",
READ_ONLY GLOBAL_VAR(report_user), CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(0));
+ DEFAULT(0));
static Sys_var_charptr Sys_repl_report_password(
"report_password",
"The account password of the slave to be reported to the master "
"during slave registration",
READ_ONLY GLOBAL_VAR(report_password), CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(0));
+ DEFAULT(0));
static Sys_var_uint Sys_repl_report_port(
"report_port",
@@ -4611,7 +4821,7 @@ static Sys_var_mybool Sys_keep_files_on_create(
static char *license;
static Sys_var_charptr Sys_license(
"license", "The type of license the server has",
- READ_ONLY GLOBAL_VAR(license), NO_CMD_LINE, IN_SYSTEM_CHARSET,
+ READ_ONLY GLOBAL_VAR(license), NO_CMD_LINE,
DEFAULT(STRINGIFY_ARG(LICENSE)));
#include <proxy_protocol.h>
@@ -4630,7 +4840,9 @@ static bool fix_proxy_protocol_networks(sys_var *, THD *, enum_var_type)
}
-static Sys_var_charptr Sys_proxy_protocol_networks(
+static Sys_var_on_access_global<Sys_var_charptr_fscs,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_PROXY_PROTOCOL_NETWORKS>
+Sys_proxy_protocol_networks(
"proxy_protocol_networks", "Enable proxy protocol for these source "
"networks. The syntax is a comma separated list of IPv4 and IPv6 "
"networks. If the network doesn't contain mask, it is considered to be "
@@ -4638,7 +4850,7 @@ static Sys_var_charptr Sys_proxy_protocol_networks(
"directive on the line. String \"localhost\" represents non-TCP "
"local connections (Unix domain socket, Windows named pipe or shared memory).",
GLOBAL_VAR(my_proxy_protocol_networks), CMD_LINE(REQUIRED_ARG),
- IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(check_proxy_protocol_networks), ON_UPDATE(fix_proxy_protocol_networks));
@@ -4735,10 +4947,10 @@ static bool fix_general_log_file(sys_var *self, THD *thd, enum_var_type type)
return fix_log(&opt_logname, opt_log_basename, ".log", opt_log,
reopen_general_log);
}
-static Sys_var_charptr Sys_general_log_path(
+static Sys_var_charptr_fscs Sys_general_log_path(
"general_log_file", "Log connections and queries to given file",
PREALLOCATED GLOBAL_VAR(opt_logname), CMD_LINE(REQUIRED_ARG),
- IN_FS_CHARSET, DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(check_log_path), ON_UPDATE(fix_general_log_file));
static void reopen_slow_log(char* name)
@@ -4751,12 +4963,12 @@ static bool fix_slow_log_file(sys_var *self, THD *thd, enum_var_type type)
return fix_log(&opt_slow_logname, opt_log_basename, "-slow.log",
global_system_variables.sql_log_slow, reopen_slow_log);
}
-static Sys_var_charptr Sys_slow_log_path(
+static Sys_var_charptr_fscs Sys_slow_log_path(
"slow_query_log_file", "Log slow queries to given log file. "
"Defaults logging to 'hostname'-slow.log. Must be enabled to activate "
"other slow log options",
PREALLOCATED GLOBAL_VAR(opt_slow_logname), CMD_LINE(REQUIRED_ARG),
- IN_FS_CHARSET, DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(check_log_path), ON_UPDATE(fix_slow_log_file));
static Sys_var_have Sys_have_compress(
@@ -4817,6 +5029,16 @@ static Sys_var_have Sys_have_symlink(
"--skip-symbolic-links option.",
READ_ONLY GLOBAL_VAR(have_symlink), NO_CMD_LINE);
+#ifdef __SANITIZE_ADDRESS__
+static char *have_sanitizer;
+static Sys_var_charptr_fscs Sys_have_santitizer(
+ "have_sanitizer",
+ "If the server is compiled with ASan (Address sanitizer) this will be "
+ "set to ASAN",
+ READ_ONLY GLOBAL_VAR(have_sanitizer), NO_CMD_LINE,
+ DEFAULT("ASAN"));
+#endif
+
static bool fix_log_state(sys_var *self, THD *thd, enum_var_type type);
static Sys_var_mybool Sys_general_log(
@@ -4907,56 +5129,60 @@ static Sys_var_mybool Sys_log_slave_updates(
READ_ONLY GLOBAL_VAR(opt_log_slave_updates), CMD_LINE(OPT_ARG),
DEFAULT(0));
-static Sys_var_charptr Sys_relay_log(
+static Sys_var_charptr_fscs Sys_relay_log(
"relay_log", "The location and name to use for relay logs.",
READ_ONLY GLOBAL_VAR(opt_relay_logname), CMD_LINE(REQUIRED_ARG),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
/*
Uses NO_CMD_LINE since the --relay-log-index option set
opt_relaylog_index_name variable and computes a value for the
relay_log_index variable.
*/
-static Sys_var_charptr Sys_relay_log_index(
+static Sys_var_charptr_fscs Sys_relay_log_index(
"relay_log_index", "The location and name to use for the file "
"that keeps a list of the last relay logs.",
READ_ONLY GLOBAL_VAR(relay_log_index), NO_CMD_LINE,
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
/*
Uses NO_CMD_LINE since the --log-bin-index option set
opt_binlog_index_name variable and computes a value for the
log_bin_index variable.
*/
-static Sys_var_charptr Sys_binlog_index(
+static Sys_var_charptr_fscs Sys_binlog_index(
"log_bin_index", "File that holds the names for last binary log files.",
READ_ONLY GLOBAL_VAR(log_bin_index), NO_CMD_LINE,
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
-static Sys_var_charptr Sys_relay_log_basename(
+static Sys_var_charptr_fscs Sys_relay_log_basename(
"relay_log_basename",
"The full path of the relay log file names, excluding the extension.",
READ_ONLY GLOBAL_VAR(relay_log_basename), NO_CMD_LINE,
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
-static Sys_var_charptr Sys_log_bin_basename(
+static Sys_var_charptr_fscs Sys_log_bin_basename(
"log_bin_basename",
"The full path of the binary log file names, excluding the extension.",
READ_ONLY GLOBAL_VAR(log_bin_basename), NO_CMD_LINE,
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
-static Sys_var_charptr Sys_relay_log_info_file(
+static Sys_var_charptr_fscs Sys_relay_log_info_file(
"relay_log_info_file", "The location and name of the file that "
"remembers where the SQL replication thread is in the relay logs.",
READ_ONLY GLOBAL_VAR(relay_log_info_file), CMD_LINE(REQUIRED_ARG),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
-static Sys_var_mybool Sys_relay_log_purge(
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_RELAY_LOG_PURGE>
+Sys_relay_log_purge(
"relay_log_purge", "if disabled - do not purge relay logs. "
"if enabled - purge them as soon as they are no more needed.",
GLOBAL_VAR(relay_log_purge), CMD_LINE(OPT_ARG), DEFAULT(TRUE));
-static Sys_var_mybool Sys_relay_log_recovery(
+static Sys_var_on_access_global<Sys_var_mybool,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_RELAY_LOG_RECOVERY>
+Sys_relay_log_recovery(
"relay_log_recovery", "Enables automatic relay log recovery "
"right after the database startup, which means that the IO Thread "
"starts re-fetching from the master right after the last transaction "
@@ -5088,12 +5314,14 @@ static Sys_var_rpl_filter Sys_replicate_do_db(
"statement-based replication, only the default database (that "
"is, the one selected by USE) is considered, not any explicitly "
"mentioned tables in the query. For row-based replication, the "
- "actual names of table(s) being updated are checked.");
+ "actual names of table(s) being updated are checked.",
+ PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_DO_DB);
static Sys_var_rpl_filter Sys_replicate_do_table(
"replicate_do_table", OPT_REPLICATE_DO_TABLE,
"Tells the slave to restrict replication to tables in the "
- "comma-separated list.");
+ "comma-separated list.",
+ PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_DO_TABLE);
static Sys_var_rpl_filter Sys_replicate_ignore_db(
"replicate_ignore_db", OPT_REPLICATE_IGNORE_DB,
@@ -5102,32 +5330,38 @@ static Sys_var_rpl_filter Sys_replicate_ignore_db(
"statement-based replication, only the default database (that "
"is, the one selected by USE) is considered, not any explicitly "
"mentioned tables in the query. For row-based replication, the "
- "actual names of table(s) being updated are checked.");
+ "actual names of table(s) being updated are checked.",
+ PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_IGNORE_DB);
static Sys_var_rpl_filter Sys_replicate_ignore_table(
"replicate_ignore_table", OPT_REPLICATE_IGNORE_TABLE,
"Tells the slave thread not to replicate any statement that "
"updates the specified table, even if any other tables might be "
- "updated by the same statement.");
+ "updated by the same statement.",
+ PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_IGNORE_TABLE);
static Sys_var_rpl_filter Sys_replicate_wild_do_table(
"replicate_wild_do_table", OPT_REPLICATE_WILD_DO_TABLE,
"Tells the slave thread to restrict replication to statements "
"where any of the updated tables match the specified database "
- "and table name patterns.");
+ "and table name patterns.",
+ PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_WILD_DO_TABLE);
static Sys_var_rpl_filter Sys_replicate_wild_ignore_table(
"replicate_wild_ignore_table", OPT_REPLICATE_WILD_IGNORE_TABLE,
"Tells the slave thread to not replicate to the tables that "
- "match the given wildcard pattern.");
+ "match the given wildcard pattern.",
+ PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_WILD_IGNORE_TABLE);
-static Sys_var_charptr Sys_slave_load_tmpdir(
+static Sys_var_charptr_fscs Sys_slave_load_tmpdir(
"slave_load_tmpdir", "The location where the slave should put "
"its temporary files when replicating a LOAD DATA INFILE command",
READ_ONLY GLOBAL_VAR(slave_load_tmpdir), CMD_LINE(REQUIRED_ARG),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
-static Sys_var_uint Sys_slave_net_timeout(
+static Sys_var_on_access_global<Sys_var_uint,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_NET_TIMEOUT>
+Sys_slave_net_timeout(
"slave_net_timeout", "Number of seconds to wait for more data "
"from any master/slave connection before aborting the read",
GLOBAL_VAR(slave_net_timeout), CMD_LINE(REQUIRED_ARG),
@@ -5243,9 +5477,11 @@ static Sys_var_charptr Sys_slave_skip_errors(
"replication when a query event returns an error from the "
"provided list",
READ_ONLY GLOBAL_VAR(opt_slave_skip_errors), CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(0));
+ DEFAULT(0));
-static Sys_var_ulonglong Sys_read_binlog_speed_limit(
+static Sys_var_on_access_global<Sys_var_ulonglong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_READ_BINLOG_SPEED_LIMIT>
+Sys_read_binlog_speed_limit(
"read_binlog_speed_limit", "Maximum speed(KB/s) to read binlog from"
" master (0 = no limit)",
GLOBAL_VAR(opt_read_binlog_speed_limit), CMD_LINE(REQUIRED_ARG),
@@ -5259,20 +5495,24 @@ static Sys_var_charptr Sys_slave_transaction_retry_errors(
"connect error and 2 types of lost connection error are automatically "
"added to this list",
READ_ONLY GLOBAL_VAR(opt_slave_transaction_retry_errors), CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(0));
+ DEFAULT(0));
static Sys_var_ulonglong Sys_relay_log_space_limit(
"relay_log_space_limit", "Maximum space to use for all relay logs",
READ_ONLY GLOBAL_VAR(relay_log_space_limit), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, ULONGLONG_MAX), DEFAULT(0), BLOCK_SIZE(1));
-static Sys_var_uint Sys_sync_relaylog_period(
+static Sys_var_on_access_global<Sys_var_uint,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SYNC_RELAY_LOG>
+Sys_sync_relaylog_period(
"sync_relay_log", "Synchronously flush relay log to disk after "
"every #th event. Use 0 to disable synchronous flushing",
GLOBAL_VAR(sync_relaylog_period), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, UINT_MAX), DEFAULT(10000), BLOCK_SIZE(1));
-static Sys_var_uint Sys_sync_relayloginfo_period(
+static Sys_var_on_access_global<Sys_var_uint,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SYNC_RELAY_LOG_INFO>
+Sys_sync_relayloginfo_period(
"sync_relay_log_info", "Synchronously flush relay log info "
"to disk after every #th transaction. Use 0 to disable "
"synchronous flushing",
@@ -5280,13 +5520,17 @@ static Sys_var_uint Sys_sync_relayloginfo_period(
VALID_RANGE(0, UINT_MAX), DEFAULT(10000), BLOCK_SIZE(1));
#endif
-static Sys_var_uint Sys_sync_binlog_period(
+static Sys_var_on_access_global<Sys_var_uint,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SYNC_BINLOG>
+Sys_sync_binlog_period(
"sync_binlog", "Synchronously flush binary log to disk after "
"every #th event. Use 0 (default) to disable synchronous flushing",
GLOBAL_VAR(sync_binlog_period), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, UINT_MAX), DEFAULT(0), BLOCK_SIZE(1));
-static Sys_var_uint Sys_sync_masterinfo_period(
+static Sys_var_on_access_global<Sys_var_uint,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SYNC_MASTER_INFO>
+Sys_sync_masterinfo_period(
"sync_master_info", "Synchronously flush master info to disk "
"after every #th event. Use 0 to disable synchronous flushing",
GLOBAL_VAR(sync_masterinfo_period), CMD_LINE(REQUIRED_ARG),
@@ -5301,7 +5545,9 @@ static Sys_var_ulong Sys_slave_trans_retries(
GLOBAL_VAR(slave_trans_retries), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, UINT_MAX), DEFAULT(10), BLOCK_SIZE(1));
-static Sys_var_ulong Sys_slave_trans_retry_interval(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_TRANSACTION_RETRY_INTERVAL>
+Sys_slave_trans_retry_interval(
"slave_transaction_retry_interval", "Interval of the slave SQL "
"thread will retry a transaction in case it failed with a deadlock "
"or elapsed lock wait timeout or listed in "
@@ -5399,10 +5645,10 @@ static Sys_var_tz Sys_time_zone(
#include "wsrep_sst.h"
#include "wsrep_binlog.h"
-static Sys_var_charptr Sys_wsrep_provider(
+static Sys_var_charptr_fscs Sys_wsrep_provider(
"wsrep_provider", "Path to replication provider library",
PREALLOCATED GLOBAL_VAR(wsrep_provider), CMD_LINE(REQUIRED_ARG),
- IN_FS_CHARSET, DEFAULT(WSREP_NONE),
+ DEFAULT(WSREP_NONE),
NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(wsrep_provider_check), ON_UPDATE(wsrep_provider_update));
@@ -5411,19 +5657,19 @@ static Sys_var_charptr Sys_wsrep_provider_options(
"options (see wsrep_provider_options documentation).",
PREALLOCATED GLOBAL_VAR(wsrep_provider_options),
CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(wsrep_provider_options_check),
ON_UPDATE(wsrep_provider_options_update));
-static Sys_var_charptr Sys_wsrep_data_home_dir(
+static Sys_var_charptr_fscs Sys_wsrep_data_home_dir(
"wsrep_data_home_dir", "home directory for wsrep provider",
READ_ONLY GLOBAL_VAR(wsrep_data_home_dir), CMD_LINE(REQUIRED_ARG),
- IN_FS_CHARSET, DEFAULT(mysql_real_data_home));
+ DEFAULT(mysql_real_data_home));
static Sys_var_charptr Sys_wsrep_cluster_name(
"wsrep_cluster_name", "Name for the cluster",
PREALLOCATED GLOBAL_VAR(wsrep_cluster_name), CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(WSREP_CLUSTER_NAME),
+ DEFAULT(WSREP_CLUSTER_NAME),
NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(wsrep_cluster_name_check),
ON_UPDATE(wsrep_cluster_name_update));
@@ -5433,7 +5679,7 @@ static Sys_var_charptr Sys_wsrep_cluster_address (
"wsrep_cluster_address", "Address to initially connect to cluster",
PREALLOCATED GLOBAL_VAR(wsrep_cluster_address),
CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(""),
+ DEFAULT(""),
&PLock_wsrep_cluster_config, NOT_IN_BINLOG,
ON_CHECK(wsrep_cluster_address_check),
ON_UPDATE(wsrep_cluster_address_update));
@@ -5443,7 +5689,7 @@ static Sys_var_charptr Sys_wsrep_node_name (
"wsrep_sst_donor as a preferred donor. Note that multiple nodes "
"in a cluster can have the same name.",
PREALLOCATED GLOBAL_VAR(wsrep_node_name), CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(glob_hostname), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ DEFAULT(glob_hostname), NO_MUTEX_GUARD, NOT_IN_BINLOG,
wsrep_node_name_check, wsrep_node_name_update);
static Sys_var_charptr Sys_wsrep_node_address (
@@ -5451,7 +5697,7 @@ static Sys_var_charptr Sys_wsrep_node_address (
"the format ip address[:port]. Used in situations where autoguessing "
"is not reliable. As of MariaDB 10.1.8, supports IPv6.",
PREALLOCATED GLOBAL_VAR(wsrep_node_address), CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(""),
+ DEFAULT(""),
NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(wsrep_node_address_check),
ON_UPDATE(wsrep_node_address_update));
@@ -5459,7 +5705,7 @@ static Sys_var_charptr Sys_wsrep_node_address (
static Sys_var_charptr Sys_wsrep_node_incoming_address(
"wsrep_node_incoming_address", "Client connection address",
PREALLOCATED GLOBAL_VAR(wsrep_node_incoming_address),CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(WSREP_NODE_INCOMING_AUTO));
+ DEFAULT(WSREP_NODE_INCOMING_AUTO));
static Sys_var_ulong Sys_wsrep_slave_threads(
"wsrep_slave_threads", "Number of slave appliers to launch",
@@ -5472,7 +5718,7 @@ static Sys_var_ulong Sys_wsrep_slave_threads(
static Sys_var_charptr Sys_wsrep_dbug_option(
"wsrep_dbug_option", "DBUG options to provider library",
GLOBAL_VAR(wsrep_dbug_option),CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(""));
+ DEFAULT(""));
static const char *wsrep_debug_names[]=
{ "NONE", "SERVER", "TRANSACTION", "STREAMING", "CLIENT", NullS };
@@ -5554,14 +5800,14 @@ static Sys_var_mybool Sys_wsrep_drupal_282555_workaround(
static Sys_var_charptr sys_wsrep_sst_method(
"wsrep_sst_method", "State snapshot transfer method",
GLOBAL_VAR(wsrep_sst_method),CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(WSREP_SST_DEFAULT), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ DEFAULT(WSREP_SST_DEFAULT), NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(wsrep_sst_method_check));
static Sys_var_charptr Sys_wsrep_sst_receive_address(
"wsrep_sst_receive_address", "Address where node is waiting for "
"SST contact",
GLOBAL_VAR(wsrep_sst_receive_address),CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(WSREP_SST_ADDRESS_AUTO), NO_MUTEX_GUARD,
+ DEFAULT(WSREP_SST_ADDRESS_AUTO), NO_MUTEX_GUARD,
NOT_IN_BINLOG,
ON_CHECK(wsrep_sst_receive_address_check),
ON_UPDATE(wsrep_sst_receive_address_update));
@@ -5569,7 +5815,7 @@ static Sys_var_charptr Sys_wsrep_sst_receive_address(
static Sys_var_charptr Sys_wsrep_sst_auth(
"wsrep_sst_auth", "Authentication for SST connection",
PREALLOCATED GLOBAL_VAR(wsrep_sst_auth), CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(NULL), NO_MUTEX_GUARD,
+ DEFAULT(NULL), NO_MUTEX_GUARD,
NOT_IN_BINLOG,
ON_CHECK(wsrep_sst_auth_check),
ON_UPDATE(wsrep_sst_auth_update));
@@ -5577,7 +5823,7 @@ static Sys_var_charptr Sys_wsrep_sst_auth(
static Sys_var_charptr Sys_wsrep_sst_donor(
"wsrep_sst_donor", "preferred donor node for the SST",
GLOBAL_VAR(wsrep_sst_donor),CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(wsrep_sst_donor_check),
ON_UPDATE(wsrep_sst_donor_update));
@@ -5599,7 +5845,7 @@ static Sys_var_charptr Sys_wsrep_start_position (
"wsrep_start_position", "global transaction position to start from ",
PREALLOCATED GLOBAL_VAR(wsrep_start_position),
CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(WSREP_START_POSITION_ZERO),
+ DEFAULT(WSREP_START_POSITION_ZERO),
NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(wsrep_start_position_check),
ON_UPDATE(wsrep_start_position_update));
@@ -5619,7 +5865,7 @@ static Sys_var_ulong Sys_wsrep_max_ws_rows (
static Sys_var_charptr Sys_wsrep_notify_cmd(
"wsrep_notify_cmd", "",
GLOBAL_VAR(wsrep_notify_cmd),CMD_LINE(REQUIRED_ARG),
- IN_SYSTEM_CHARSET, DEFAULT(""));
+ DEFAULT(""));
static Sys_var_mybool Sys_wsrep_certify_nonPK(
"wsrep_certify_nonPK", "Certify tables with no primary key",
@@ -5646,7 +5892,7 @@ static Sys_var_mybool Sys_wsrep_causal_reads(
CMD_LINE(OPT_ARG, OPT_WSREP_CAUSAL_READS), DEFAULT(FALSE),
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(wsrep_causal_reads_update),
- DEPRECATED("'@@wsrep_sync_wait=1'"));
+ DEPRECATED("'@@wsrep_sync_wait=1'")); // since 10.1.3
static Sys_var_uint Sys_wsrep_sync_wait(
"wsrep_sync_wait", "Ensure \"synchronous\" read view before executing "
@@ -5668,12 +5914,20 @@ static Sys_var_enum Sys_wsrep_OSU_method(
static PolyLock_mutex PLock_wsrep_desync(&LOCK_wsrep_desync);
static Sys_var_mybool Sys_wsrep_desync (
"wsrep_desync", "To desynchronize the node from the cluster",
- GLOBAL_VAR(wsrep_desync),
+ GLOBAL_VAR(wsrep_desync),
CMD_LINE(OPT_ARG), DEFAULT(FALSE),
&PLock_wsrep_desync, NOT_IN_BINLOG,
ON_CHECK(wsrep_desync_check),
ON_UPDATE(wsrep_desync_update));
+static Sys_var_mybool Sys_wsrep_strict_ddl (
+ "wsrep_strict_ddl", "If set, reject DDL on affected tables not supporting Galera replication",
+ GLOBAL_VAR(wsrep_strict_ddl),
+ CMD_LINE(OPT_ARG), DEFAULT(FALSE),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(0),
+ ON_UPDATE(0));
+
static const char *wsrep_reject_queries_names[]= { "NONE", "ALL", "ALL_KILL", NullS };
static Sys_var_enum Sys_wsrep_reject_queries(
"wsrep_reject_queries", "Variable to set to reject queries",
@@ -5712,7 +5966,7 @@ static Sys_var_mybool Sys_wsrep_load_data_splitting(
"transaction after every 10K rows inserted (deprecated)",
GLOBAL_VAR(wsrep_load_data_splitting),
CMD_LINE(OPT_ARG), DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG,
- ON_CHECK(0), ON_UPDATE(0), DEPRECATED(""));
+ ON_CHECK(0), ON_UPDATE(0), DEPRECATED("")); // since 10.4.3
static Sys_var_mybool Sys_wsrep_slave_FK_checks(
"wsrep_slave_FK_checks", "Should slave thread do "
@@ -5775,9 +6029,17 @@ static Sys_var_uint Sys_wsrep_gtid_domain_id(
"wsrep_gtid_domain_id", "When wsrep_gtid_mode is set, this value is "
"used as gtid_domain_id for galera transactions and also copied to the "
"joiner nodes during state transfer. It is ignored, otherwise.",
- GLOBAL_VAR(wsrep_gtid_domain_id), CMD_LINE(REQUIRED_ARG),
+ GLOBAL_VAR(wsrep_gtid_server.domain_id), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, UINT_MAX32), DEFAULT(0), BLOCK_SIZE(1));
+static Sys_var_ulonglong Sys_wsrep_gtid_seq_no(
+ "wsrep_gtid_seq_no",
+ "Internal server usage, manually set WSREP GTID seqno.",
+ SESSION_ONLY(wsrep_gtid_seq_no),
+ NO_CMD_LINE, VALID_RANGE(0, ULONGLONG_MAX), DEFAULT(0),
+ BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(wsrep_gtid_seq_no_check));
+
static Sys_var_mybool Sys_wsrep_gtid_mode(
"wsrep_gtid_mode", "Automatically update the (joiner) node's "
"wsrep_gtid_domain_id value with that of donor's (received during "
@@ -5790,7 +6052,7 @@ static char *wsrep_patch_version_ptr;
static Sys_var_charptr Sys_wsrep_patch_version(
"wsrep_patch_version", "Wsrep patch version, for example wsrep_25.10.",
READ_ONLY GLOBAL_VAR(wsrep_patch_version_ptr), CMD_LINE_HELP_ONLY,
- IN_SYSTEM_CHARSET, DEFAULT(WSREP_PATCH_VERSION));
+ DEFAULT(WSREP_PATCH_VERSION));
#endif /* WITH_WSREP */
@@ -5805,8 +6067,7 @@ static Sys_var_ulong Sys_host_cache_size(
"How many host names should be cached to avoid resolving.",
AUTO_SET GLOBAL_VAR(host_cache_size),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 65536),
- DEFAULT(HOST_CACHE_SIZE),
- BLOCK_SIZE(1),
+ DEFAULT(HOST_CACHE_SIZE), BLOCK_SIZE(1),
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(fix_host_cache_size));
@@ -5857,14 +6118,14 @@ static Sys_var_mybool Sys_tcp_nodelay(
ON_CHECK(check_session_only_variable),
ON_UPDATE(update_tcp_nodelay));
-static Sys_var_charptr Sys_ignore_db_dirs(
+static Sys_var_charptr_fscs Sys_ignore_db_dirs(
"ignore_db_dirs",
"Specifies a directory to add to the ignore list when collecting "
"database names from the datadir. Put a blank argument to reset "
"the list accumulated so far.",
READ_ONLY GLOBAL_VAR(opt_ignore_db_dirs),
CMD_LINE(REQUIRED_ARG, OPT_IGNORE_DB_DIRECTORY),
- IN_FS_CHARSET, DEFAULT(0));
+ DEFAULT(0));
static Sys_var_ulong Sys_sp_cache_size(
"stored_program_cache",
@@ -5915,7 +6176,9 @@ static Sys_var_uint Sys_extra_port(
READ_ONLY GLOBAL_VAR(mysqld_extra_port), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, UINT_MAX32), DEFAULT(0), BLOCK_SIZE(1));
-static Sys_var_ulong Sys_extra_max_connections(
+static Sys_var_on_access_global<Sys_var_ulong,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_EXTRA_MAX_CONNECTIONS>
+Sys_extra_max_connections(
"extra_max_connections", "The number of connections on extra-port",
GLOBAL_VAR(extra_max_connections), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(1, 100000), DEFAULT(1), BLOCK_SIZE(1), NO_MUTEX_GUARD,
@@ -5975,34 +6238,52 @@ static Sys_var_set Sys_log_disabled_statements(
DEFAULT(LOG_DISABLE_SP),
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_has_super));
+#define NOT_SUPPORTED_YET -2
+#ifndef PCRE2_EXTENDED_MORE
+#define PCRE2_EXTENDED_MORE NOT_SUPPORTED_YET
+#endif
+
static const char *default_regex_flags_names[]=
{
"DOTALL", // (?s) . matches anything including NL
"DUPNAMES", // (?J) Allow duplicate names for subpatterns
"EXTENDED", // (?x) Ignore white space and # comments
- "EXTRA", // (?X) extra features (e.g. error on unknown escape character)
+ "EXTENDED_MORE",//(?xx) Ignore white space and # comments inside cheracter
+ "EXTRA", // means nothing since PCRE2
"MULTILINE", // (?m) ^ and $ match newlines within data
"UNGREEDY", // (?U) Invert greediness of quantifiers
0
};
static const int default_regex_flags_to_pcre[]=
{
- PCRE_DOTALL,
- PCRE_DUPNAMES,
- PCRE_EXTENDED,
- PCRE_EXTRA,
- PCRE_MULTILINE,
- PCRE_UNGREEDY,
+ PCRE2_DOTALL,
+ PCRE2_DUPNAMES,
+ PCRE2_EXTENDED,
+ PCRE2_EXTENDED_MORE,
+ -1, /* EXTRA flag not available since PCRE2 */
+ PCRE2_MULTILINE,
+ PCRE2_UNGREEDY,
0
};
-int default_regex_flags_pcre(const THD *thd)
+int default_regex_flags_pcre(THD *thd)
{
ulonglong src= thd->variables.default_regex_flags;
int i, res;
for (i= res= 0; default_regex_flags_to_pcre[i]; i++)
{
if (src & (1ULL << i))
+ {
+ if (default_regex_flags_to_pcre[i] < 0)
+ {
+ const char *msg= default_regex_flags_to_pcre[i] == NOT_SUPPORTED_YET
+ ? "Your version of PCRE2 does not support the %s flag. Ignored."
+ : "PCRE2 doesn't support the %s flag. Ignored.";
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_UNKNOWN_ERROR, msg, default_regex_flags_names[i]);
+ continue;
+ }
res|= default_regex_flags_to_pcre[i];
+ }
}
return res;
}
@@ -6057,7 +6338,10 @@ static Sys_var_mybool Sys_userstat(
GLOBAL_VAR(opt_userstat_running),
CMD_LINE(OPT_ARG), DEFAULT(FALSE));
-static Sys_var_mybool Sys_binlog_annotate_row_events(
+static Sys_var_on_access<Sys_var_mybool,
+ PRIV_SET_SYSTEM_VAR_BINLOG_ANNOTATE_ROW_EVENTS,
+ PRIV_SET_SYSTEM_VAR_BINLOG_ANNOTATE_ROW_EVENTS>
+Sys_binlog_annotate_row_events(
"binlog_annotate_row_events",
"Tells the master to annotate RBR events with the statement that "
"caused these events",
@@ -6171,7 +6455,10 @@ static Sys_var_mybool Sys_binlog_encryption(
DEFAULT(FALSE));
static const char *binlog_row_image_names[]= {"MINIMAL", "NOBLOB", "FULL", NullS};
-static Sys_var_enum Sys_binlog_row_image(
+static Sys_var_on_access<Sys_var_enum,
+ PRIV_SET_SYSTEM_VAR_BINLOG_ROW_IMAGE,
+ PRIV_SET_SYSTEM_VAR_BINLOG_ROW_IMAGE>
+Sys_binlog_row_image(
"binlog_row_image",
"Controls whether rows should be logged in 'FULL', 'NOBLOB' or "
"'MINIMAL' formats. 'FULL', means that all columns in the before "
@@ -6184,6 +6471,21 @@ static Sys_var_enum Sys_binlog_row_image(
SESSION_VAR(binlog_row_image), CMD_LINE(REQUIRED_ARG),
binlog_row_image_names, DEFAULT(BINLOG_ROW_IMAGE_FULL));
+static const char *binlog_row_metadata_names[]= {"NO_LOG", "MINIMAL", "FULL", NullS};
+static Sys_var_on_access_global<Sys_var_enum,
+ PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_ROW_METADATA>
+Sys_binlog_row_metadata(
+ "binlog_row_metadata",
+ "Controls whether metadata is logged using FULL , MINIMAL format and NO_LOG."
+ "FULL causes all metadata to be logged; MINIMAL means that only "
+ "metadata actually required by slave is logged; NO_LOG NO metadata will be logged."
+ "Default: NO_LOG.",
+ GLOBAL_VAR(binlog_row_metadata), CMD_LINE(REQUIRED_ARG),
+ binlog_row_metadata_names, DEFAULT(Table_map_log_event::BINLOG_ROW_METADATA_NO_LOG),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(NULL),
+ ON_UPDATE(NULL));
+
+
static bool check_pseudo_slave_mode(sys_var *self, THD *thd, set_var *var)
{
longlong previous_val= thd->variables.pseudo_slave_mode;
@@ -6262,8 +6564,7 @@ static Sys_var_ulong Sys_log_tc_size(
READ_ONLY GLOBAL_VAR(opt_tc_log_size),
CMD_LINE(REQUIRED_ARG),
VALID_RANGE(my_getpagesize() * 3, ULONG_MAX),
- DEFAULT(my_getpagesize() * 6),
- BLOCK_SIZE(my_getpagesize()));
+ DEFAULT(my_getpagesize() * 6), BLOCK_SIZE(my_getpagesize()));
#endif
static Sys_var_ulonglong Sys_max_thread_mem(
@@ -6278,7 +6579,7 @@ static Sys_var_ulonglong Sys_max_thread_mem(
static Sys_var_sesvartrack Sys_track_session_sys_vars(
"session_track_system_variables",
"Track changes in registered system variables. ",
- CMD_LINE(REQUIRED_ARG), IN_SYSTEM_CHARSET,
+ CMD_LINE(REQUIRED_ARG),
DEFAULT("autocommit,character_set_client,character_set_connection,"
"character_set_results,time_zone"));
@@ -6340,6 +6641,22 @@ static Sys_var_mybool Sys_session_track_state_change(
ON_CHECK(0),
ON_UPDATE(update_session_track_state_change));
+
+static bool update_session_track_user_variables(sys_var *self, THD *thd,
+ enum_var_type type)
+{
+ return thd->session_tracker.user_variables.update(thd, 0);
+}
+
+static Sys_var_mybool Sys_session_track_user_variables(
+ "session_track_user_variables",
+ "Track changes to user variables.",
+ SESSION_VAR(session_track_user_variables),
+ CMD_LINE(OPT_ARG), DEFAULT(FALSE),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(0),
+ ON_UPDATE(update_session_track_user_variables));
+
#endif //EMBEDDED_LIBRARY
static Sys_var_uint Sys_in_subquery_conversion_threshold(
diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic
index f33f469b160..ed2aaf49b9f 100644
--- a/sql/sys_vars.ic
+++ b/sql/sys_vars.ic
@@ -1,5 +1,5 @@
/* Copyright (c) 2002, 2011, Oracle and/or its affiliates.
- Copyright (c) 2010, 2019, MariaDB Corporation.
+ Copyright (c) 2010, 2020, 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
@@ -31,6 +31,7 @@
#include "tztime.h" // my_tz_find, my_tz_SYSTEM, struct Time_zone
#include "rpl_mi.h" // For Multi-Source Replication
#include "debug_sync.h"
+#include "sql_acl.h" // check_global_access()
/*
a set of mostly trivial (as in f(X)=X) defines below to make system variable
@@ -97,11 +98,48 @@
exit(255); \
}
-enum charset_enum {IN_SYSTEM_CHARSET, IN_FS_CHARSET};
static const char *bool_values[3]= {"OFF", "ON", 0};
TYPELIB bool_typelib={ array_elements(bool_values)-1, "", bool_values, 0 };
+
+template<class BASE, privilege_t GLOBAL_PRIV, privilege_t SESSION_PRIV>
+class Sys_var_on_access: public BASE
+{
+ using BASE::BASE;
+ bool on_check_access_global(THD *thd) const override
+ {
+ return check_global_access(thd, GLOBAL_PRIV);
+ }
+ bool on_check_access_session(THD *thd) const override
+ {
+ return check_global_access(thd, SESSION_PRIV);
+ }
+};
+
+
+template<class BASE, privilege_t GLOBAL_PRIV>
+class Sys_var_on_access_global: public BASE
+{
+ using BASE::BASE;
+ bool on_check_access_global(THD *thd) const override
+ {
+ return check_global_access(thd, GLOBAL_PRIV);
+ }
+};
+
+
+template<class BASE, privilege_t SESSION_PRIV>
+class Sys_var_on_access_session: public BASE
+{
+ using BASE::BASE;
+ bool on_check_access_session(THD *thd) const override
+ {
+ return check_global_access(thd, SESSION_PRIV);
+ }
+};
+
+
/**
A small wrapper class to pass getopt arguments as a pair
to the Sys_var_* constructors. It improves type safety and helps
@@ -449,9 +487,6 @@ public:
or not. The state of the initial value is specified in the constructor,
after that it's managed automatically. The value of NULL is supported.
- Class specific constructor arguments:
- enum charset_enum is_os_charset_arg
-
Backing store: char*
@note
@@ -465,7 +500,6 @@ public:
Sys_var_charptr_base(const char *name_arg,
const char *comment, int flag_args, ptrdiff_t off, size_t size,
CMD_LINE getopt,
- enum charset_enum is_os_charset_arg,
const char *def_val, PolyLock *lock=0,
enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
on_check_function on_check_func=0,
@@ -476,7 +510,6 @@ public:
lock, binlog_status_arg, on_check_func, on_update_func,
substitute)
{
- is_os_charset= is_os_charset_arg == IN_FS_CHARSET;
/*
use GET_STR_ALLOC - if ALLOCATED it must be *always* allocated,
otherwise (GET_STR) you'll never know whether to free it or not.
@@ -529,7 +562,8 @@ public:
size_t len=var->save_result.string_value.length;
if (ptr)
{
- new_val= (char*)my_memdup(ptr, len+1, MYF(MY_WME));
+ new_val= (char*)my_memdup(key_memory_Sys_var_charptr_value,
+ ptr, len+1, MYF(MY_WME));
if (!new_val) return 0;
new_val[len]=0;
}
@@ -565,14 +599,13 @@ public:
Sys_var_charptr(const char *name_arg,
const char *comment, int flag_args, ptrdiff_t off, size_t size,
CMD_LINE getopt,
- enum charset_enum is_os_charset_arg,
const char *def_val, PolyLock *lock=0,
enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
on_check_function on_check_func=0,
on_update_function on_update_func=0,
const char *substitute=0) :
Sys_var_charptr_base(name_arg, comment, flag_args, off, size, getopt,
- is_os_charset_arg, def_val, lock, binlog_status_arg,
+ def_val, lock, binlog_status_arg,
on_check_func, on_update_func, substitute)
{
SYSVAR_ASSERT(scope() == GLOBAL);
@@ -588,6 +621,18 @@ public:
{ DBUG_ASSERT(FALSE); }
};
+
+class Sys_var_charptr_fscs: public Sys_var_charptr
+{
+ using Sys_var_charptr::Sys_var_charptr;
+public:
+ CHARSET_INFO *charset(THD *thd) const override
+ {
+ return thd->variables.character_set_filesystem;
+ }
+};
+
+
#ifndef EMBEDDED_LIBRARY
class Sys_var_sesvartrack: public Sys_var_charptr_base
{
@@ -595,11 +640,10 @@ public:
Sys_var_sesvartrack(const char *name_arg,
const char *comment,
CMD_LINE getopt,
- enum charset_enum is_os_charset_arg,
const char *def_val, PolyLock *lock= 0) :
Sys_var_charptr_base(name_arg, comment,
SESSION_VAR(session_track_system_variables),
- getopt, is_os_charset_arg, def_val, lock,
+ getopt, def_val, lock,
VARIABLE_NOT_IN_BINLOG, 0, 0, 0)
{}
bool do_check(THD *thd, set_var *var)
@@ -648,14 +692,12 @@ public:
class Sys_var_proxy_user: public sys_var
{
public:
- Sys_var_proxy_user(const char *name_arg,
- const char *comment, enum charset_enum is_os_charset_arg)
+ Sys_var_proxy_user(const char *name_arg, const char *comment)
: sys_var(&all_sys_vars, name_arg, comment,
sys_var::READONLY+sys_var::ONLY_SESSION, 0, NO_GETOPT,
NO_ARG, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
NULL, NULL, NULL)
{
- is_os_charset= is_os_charset_arg == IN_FS_CHARSET;
option.var_type|= GET_STR;
}
bool do_check(THD *thd, set_var *var)
@@ -688,9 +730,8 @@ protected:
class Sys_var_external_user : public Sys_var_proxy_user
{
public:
- Sys_var_external_user(const char *name_arg, const char *comment_arg,
- enum charset_enum is_os_charset_arg)
- : Sys_var_proxy_user (name_arg, comment_arg, is_os_charset_arg)
+ Sys_var_external_user(const char *name_arg, const char *comment_arg)
+ : Sys_var_proxy_user (name_arg, comment_arg)
{}
protected:
@@ -705,36 +746,44 @@ class Sys_var_rpl_filter: public sys_var
{
private:
int opt_id;
+ privilege_t m_access_global;
public:
- Sys_var_rpl_filter(const char *name, int getopt_id, const char *comment)
+ Sys_var_rpl_filter(const char *name, int getopt_id, const char *comment,
+ privilege_t access_global)
: sys_var(&all_sys_vars, name, comment, sys_var::GLOBAL, 0, NO_GETOPT,
NO_ARG, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
- NULL, NULL, NULL), opt_id(getopt_id)
+ NULL, NULL, NULL), opt_id(getopt_id),
+ m_access_global(access_global)
{
option.var_type|= GET_STR | GET_ASK_ADDR;
}
- bool do_check(THD *thd, set_var *var)
+ bool do_check(THD *thd, set_var *var) override
{
return Sys_var_charptr::do_string_check(thd, var, charset(thd));
}
- void session_save_default(THD *thd, set_var *var)
+ void session_save_default(THD *, set_var *) override
{ DBUG_ASSERT(FALSE); }
- void global_save_default(THD *thd, set_var *var)
+ void global_save_default(THD *, set_var *) override
{ DBUG_ASSERT(FALSE); }
- bool session_update(THD *thd, set_var *var)
+ bool session_update(THD *, set_var *) override
{
DBUG_ASSERT(FALSE);
return true;
}
- bool global_update(THD *thd, set_var *var);
+ bool global_update(THD *thd, set_var *var) override;
+
+ bool on_check_access_global(THD *thd) const override
+ {
+ return check_global_access(thd, m_access_global);
+ }
protected:
- uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base);
+ uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) override;
bool set_filter_value(const char *value, Master_info *mi);
};
@@ -742,9 +791,6 @@ protected:
The class for string variables. Useful for strings that aren't necessarily
\0-terminated. Otherwise the same as Sys_var_charptr.
- Class specific constructor arguments:
- enum charset_enum is_os_charset_arg
-
Backing store: LEX_CSTRING
@note
@@ -756,14 +802,13 @@ public:
Sys_var_lexstring(const char *name_arg,
const char *comment, int flag_args, ptrdiff_t off, size_t size,
CMD_LINE getopt,
- enum charset_enum is_os_charset_arg,
const char *def_val, PolyLock *lock=0,
enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
on_check_function on_check_func=0,
on_update_function on_update_func=0,
const char *substitute=0)
: Sys_var_charptr(name_arg, comment, flag_args, off, sizeof(char*),
- getopt, is_os_charset_arg, def_val, lock, binlog_status_arg,
+ getopt, def_val, lock, binlog_status_arg,
on_check_func, on_update_func, substitute)
{
global_var(LEX_CSTRING).length= strlen(def_val);
@@ -792,7 +837,6 @@ public:
Sys_var_session_lexstring(const char *name_arg,
const char *comment, int flag_args,
ptrdiff_t off, size_t size, CMD_LINE getopt,
- enum charset_enum is_os_charset_arg,
const char *def_val, size_t max_length_arg,
on_check_function on_check_func=0,
on_update_function on_update_func=0)
@@ -1960,6 +2004,7 @@ public:
thd->sys_var_tmp.double_value= 0;
return (uchar*) &thd->sys_var_tmp.double_value;
}
+ bool on_check_access_session(THD *thd) const;
};
@@ -2498,6 +2543,10 @@ public:
uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base);
uchar *default_value_ptr(THD *thd)
{ return 0; }
+ bool on_check_access_global(THD *thd) const
+ {
+ return check_global_access(thd, PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_SLAVE_POS);
+ }
};
@@ -2540,6 +2589,11 @@ public:
uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base);
uchar *default_value_ptr(THD *thd)
{ return 0; }
+ bool on_check_access_global(THD *thd) const
+ {
+ return
+ check_global_access(thd, PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_BINLOG_STATE);
+ }
};
diff --git a/sql/table.cc b/sql/table.cc
index 4962a002cb9..2b31cbef083 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
- Copyright (c) 2008, 2019, MariaDB
+ Copyright (c) 2008, 2020, 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
@@ -27,7 +27,6 @@
#include "strfunc.h" // unhex_type2
#include "sql_partition.h" // mysql_unpack_partition,
// fix_partition_func, partition_info
-#include "sql_acl.h" // *_ACL, acl_getroot_no_password
#include "sql_base.h"
#include "create_options.h"
#include "sql_trigger.h"
@@ -59,6 +58,7 @@ struct extra2_fields
LEX_CUSTRING field_flags;
LEX_CUSTRING system_period;
LEX_CUSTRING application_period;
+ LEX_CUSTRING field_data_type_info;
void reset()
{ bzero((void*)this, sizeof(*this)); }
};
@@ -272,7 +272,7 @@ TABLE_CATEGORY get_table_category(const LEX_CSTRING *db,
if (is_infoschema_db(db))
return TABLE_CATEGORY_INFORMATION;
- if (lex_string_eq(&PERFORMANCE_SCHEMA_DB_NAME, db))
+ if (is_perfschema_db(db))
return TABLE_CATEGORY_PERFORMANCE;
if (lex_string_eq(&MYSQL_SCHEMA_NAME, db))
@@ -322,7 +322,8 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name,
path_length= build_table_filename(path, sizeof(path) - 1,
db, table_name, "", 0);
- init_sql_alloc(&mem_root, "table_share", TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0));
+ init_sql_alloc(key_memory_table_share, &mem_root, TABLE_ALLOC_BLOCK_SIZE, 0,
+ MYF(0));
if (multi_alloc_root(&mem_root,
&share, sizeof(*share),
&key_buff, key_length,
@@ -345,11 +346,10 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name,
if (share->table_category == TABLE_CATEGORY_LOG)
share->no_replicate= 1;
if (key_length > 6 &&
- my_strnncoll(table_alias_charset, (const uchar*) key, 6,
- (const uchar*) "mysql", 6) == 0)
+ table_alias_charset->strnncoll(key, 6, "mysql", 6) == 0)
share->not_usable_by_query_cache= 1;
- init_sql_alloc(&share->stats_cb.mem_root, "share_stats",
+ init_sql_alloc(PSI_INSTRUMENT_ME, &share->stats_cb.mem_root,
TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0));
memcpy((char*) &share->mem_root, (char*) &mem_root, sizeof(mem_root));
@@ -411,8 +411,9 @@ void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key,
This can't be MY_THREAD_SPECIFIC for slaves as they are freed
during cleanup() from Relay_log_info::close_temporary_tables()
*/
- init_sql_alloc(&share->mem_root, "tmp_table_share", TABLE_ALLOC_BLOCK_SIZE,
- 0, MYF(thd->slave_thread ? 0 : MY_THREAD_SPECIFIC));
+ init_sql_alloc(key_memory_table_share, &share->mem_root,
+ TABLE_ALLOC_BLOCK_SIZE, 0,
+ MYF(thd->slave_thread ? 0 : MY_THREAD_SPECIFIC));
share->table_category= TABLE_CATEGORY_TEMPORARY;
share->tmp_table= INTERNAL_TMP_TABLE;
share->db.str= (char*) key;
@@ -676,7 +677,8 @@ enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags)
frmlen= uint4korr(head+10);
set_if_smaller(frmlen, FRM_MAX_SIZE); // safety
- if (!(buf= (uchar*)my_malloc(frmlen, MYF(MY_THREAD_SPECIFIC|MY_WME))))
+ if (!(buf= (uchar*)my_malloc(PSI_INSTRUMENT_ME, frmlen,
+ MYF(MY_THREAD_SPECIFIC|MY_WME))))
goto err;
memcpy(buf, head, sizeof(head));
@@ -973,6 +975,38 @@ void Column_definition_attributes::frm_unpack_basic(const uchar *buff)
}
+void Column_definition_attributes::frm_pack_numeric_with_dec(uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(pack_flag) == 0);
+ uint tmp_pack_flag= pack_flag | (decimals << FIELDFLAG_DEC_SHIFT);
+ int2store(buff + 3, length);
+ int2store(buff + 8, tmp_pack_flag);
+ buff[10]= (uchar) unireg_check;
+}
+
+
+bool
+Column_definition_attributes::frm_unpack_numeric_with_dec(TABLE_SHARE *share,
+ const uchar *buff)
+{
+ frm_unpack_basic(buff);
+ decimals= f_decimals(pack_flag);
+ pack_flag&= ~FIELDFLAG_DEC_MASK;
+ return frm_unpack_charset(share, buff);
+}
+
+
+bool
+Column_definition_attributes::frm_unpack_temporal_with_dec(TABLE_SHARE *share,
+ uint intlen,
+ const uchar *buff)
+{
+ frm_unpack_basic(buff);
+ decimals= temporal_dec(intlen);
+ return frm_unpack_charset(share, buff);
+}
+
+
void Column_definition_attributes::frm_pack_charset(uchar *buff) const
{
buff[11]= (uchar) (charset->number >> 8);
@@ -1086,7 +1120,6 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
Field **vfield_ptr= table->vfield;
Field **dfield_ptr= table->default_field;
Virtual_column_info **check_constraint_ptr= table->check_constraints;
- sql_mode_t saved_mode= thd->variables.sql_mode;
Query_arena backup_arena;
Virtual_column_info *vcol= 0;
StringBuffer<MAX_FIELD_WIDTH> expr_str;
@@ -1112,7 +1145,7 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
thd->stmt_arena= table->expr_arena;
thd->update_charset(&my_charset_utf8mb4_general_ci, table->s->table_charset);
expr_str.append(&parse_vcol_keyword);
- thd->variables.sql_mode &= ~MODE_NO_BACKSLASH_ESCAPES;
+ Sql_mode_instant_remove sms(thd, MODE_NO_BACKSLASH_ESCAPES);
while (pos < end)
{
@@ -1295,7 +1328,6 @@ end:
thd->stmt_arena= backup_stmt_arena_ptr;
if (save_character_set_client)
thd->update_charset(save_character_set_client, save_collation);
- thd->variables.sql_mode= saved_mode;
DBUG_RETURN(res);
}
@@ -1534,6 +1566,12 @@ bool read_extra2(const uchar *frm_image, size_t len, extra2_fields *fields)
fields->application_period.str= extra2;
fields->application_period.length= length;
break;
+ case EXTRA2_FIELD_DATA_TYPE_INFO:
+ if (fields->field_data_type_info.str)
+ DBUG_RETURN(true);
+ fields->field_data_type_info.str= extra2;
+ fields->field_data_type_info.length= length;
+ break;
default:
/* abort frm parsing if it's an unknown but important extra2 value */
if (type >= EXTRA2_ENGINE_IMPORTANT)
@@ -1548,6 +1586,86 @@ bool read_extra2(const uchar *frm_image, size_t len, extra2_fields *fields)
}
+class Field_data_type_info_array
+{
+public:
+ class Elem
+ {
+ LEX_CSTRING m_type_info;
+ public:
+ void set(const LEX_CSTRING &type_info)
+ {
+ m_type_info= type_info;
+ }
+ const LEX_CSTRING &type_info() const
+ {
+ return m_type_info;
+ }
+ };
+private:
+ Elem *m_array;
+ uint m_count;
+ bool alloc(MEM_ROOT *root, uint count)
+ {
+ DBUG_ASSERT(!m_array);
+ DBUG_ASSERT(!m_count);
+ size_t nbytes= sizeof(Elem) * count;
+ if (!(m_array= (Elem*) alloc_root(root, nbytes)))
+ return true;
+ m_count= count;
+ bzero((void*) m_array, nbytes);
+ return false;
+ }
+ static uint32 read_length(uchar **pos, const uchar *end)
+ {
+ ulonglong num= safe_net_field_length_ll(pos, end - *pos);
+ if (num > UINT_MAX32)
+ return 0;
+ return (uint32) num;
+ }
+ static bool read_string(LEX_CSTRING *to, uchar **pos, const uchar *end)
+ {
+ to->length= read_length(pos, end);
+ if (*pos + to->length > end)
+ return true; // Not enough data
+ to->str= (const char *) *pos;
+ *pos+= to->length;
+ return false;
+ }
+public:
+ Field_data_type_info_array()
+ :m_array(NULL), m_count(0)
+ { }
+ uint count() const
+ {
+ return m_count;
+ }
+ const Elem& element(uint i) const
+ {
+ DBUG_ASSERT(i < m_count);
+ return m_array[i];
+ }
+ bool parse(MEM_ROOT *root, uint count, LEX_CUSTRING &image)
+ {
+ const uchar *pos= image.str;
+ const uchar *end= pos + image.length;
+ if (alloc(root, count))
+ return true;
+ for (uint i= 0; i < count && pos < end; i++)
+ {
+ LEX_CSTRING type_info;
+ uint fieldnr= read_length((uchar**) &pos, end);
+ if ((fieldnr == 0 && i > 0) || fieldnr >= count)
+ return true; // Bad data
+ if (read_string(&type_info, (uchar**) &pos, end) || type_info.length == 0)
+ return true; // Bad data
+ m_array[fieldnr].set(type_info);
+ }
+ return pos < end; // Error if some data is still left
+ }
+};
+
+
/**
Read data from a binary .frm file image into a TABLE_SHARE
@@ -1598,6 +1716,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
uint ext_key_parts= 0;
plugin_ref se_plugin= 0;
bool vers_can_native= false;
+ Field_data_type_info_array field_data_type_info_array;
MEM_ROOT *old_root= thd->mem_root;
Virtual_column_info **table_check_constraints;
@@ -1716,7 +1835,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
{
const CHARSET_INFO *cs= thd->variables.collation_database;
/* unknown charset in frm_image[38] or pre-3.23 frm */
- if (use_mb(cs))
+ if (cs->use_mb())
{
/* Warn that we may be changing the size of character columns */
sql_print_warning("'%s' had no or invalid character set, "
@@ -1793,7 +1912,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
name.length= str_db_type_length;
plugin_ref tmp_plugin= ha_resolve_by_name(thd, &name, false);
- if (tmp_plugin != NULL && !plugin_equals(tmp_plugin, se_plugin))
+ if (tmp_plugin != NULL && !plugin_equals(tmp_plugin, se_plugin) &&
+ legacy_db_type != DB_TYPE_S3)
{
if (se_plugin)
{
@@ -2077,10 +2197,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
use_hash= share->fields >= MAX_FIELDS_BEFORE_HASH;
if (use_hash)
- use_hash= !my_hash_init(&share->name_hash,
- system_charset_info,
- share->fields,0,0,
- (my_hash_get_key) get_field_name,0,0);
+ use_hash= !my_hash_init(PSI_INSTRUMENT_ME, &share->name_hash,
+ system_charset_info, share->fields, 0, 0,
+ (my_hash_get_key) get_field_name, 0, 0);
if (share->mysql_version >= 50700 && share->mysql_version < 100000 &&
vcol_screen_length)
@@ -2136,6 +2255,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
status_var_increment(thd->status_var.feature_application_time_periods);
}
+ if (extra2.field_data_type_info.length &&
+ field_data_type_info_array.parse(old_root, share->fields,
+ extra2.field_data_type_info))
+ goto err;
+
for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++)
{
uint interval_nr= 0, recpos;
@@ -2215,10 +2339,41 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
enum_field_types field_type= (enum_field_types) strpos[13];
if (!(handler= Type_handler::get_handler_by_real_type(field_type)))
goto err; // Not supported field type
+ handler= handler->type_handler_frm_unpack(strpos);
if (handler->Column_definition_attributes_frm_unpack(&attr, share,
strpos,
&extra2.gis))
goto err;
+
+ if (field_data_type_info_array.count())
+ {
+ const LEX_CSTRING &info= field_data_type_info_array.
+ element(i).type_info();
+ DBUG_EXECUTE_IF("frm_data_type_info",
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_UNKNOWN_ERROR, "DBUG: [%u] name='%s' type_info='%.*s'",
+ i, share->fieldnames.type_names[i],
+ (uint) info.length, info.str););
+
+ if (info.length)
+ {
+ const Type_handler *h= Type_handler::handler_by_name_or_error(thd,
+ info);
+ /*
+ This code will eventually be extended here:
+ - If the handler was not found by name, we could
+ still open the table using the fallback type handler "handler",
+ at least for a limited set of commands.
+ - If the handler was found by name, we could check
+ that "h" and "handler" have the same type code
+ (and maybe some other properties) to make sure
+ that the FRM data is consistent.
+ */
+ if (!h)
+ goto err;
+ handler= h;
+ }
+ }
}
if (((uint) strpos[10]) & MYSQL57_GENERATED_FIELD)
@@ -2250,6 +2405,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
attr.length= (uint) strpos[3];
recpos= uint2korr(strpos+4),
attr.pack_flag= uint2korr(strpos+6);
+ if (f_is_num(attr.pack_flag))
+ {
+ attr.decimals= f_decimals(attr.pack_flag);
+ attr.pack_flag&= ~FIELDFLAG_DEC_MASK;
+ }
attr.pack_flag&= ~FIELDFLAG_NO_DEFAULT; // Safety for old files
attr.unireg_check= (Field::utype) MTYP_TYPENR((uint) strpos[8]);
interval_nr= (uint) strpos[10];
@@ -2578,7 +2738,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
KEY_PART_INFO *new_key_part= (keyinfo-1)->key_part +
(keyinfo-1)->ext_key_parts;
uint add_keyparts_for_this_key= add_first_key_parts;
- uint length_bytes= 0, len_null_byte= 0, ext_key_length= 0;
+ uint len_null_byte= 0, ext_key_length= 0;
Field *field;
if ((keyinfo-1)->algorithm == HA_KEY_ALG_LONG_HASH)
@@ -2590,19 +2750,15 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
*/
for (i= 0; i < keyinfo->user_defined_key_parts; i++)
{
+ uint length_bytes= 0;
uint fieldnr= keyinfo->key_part[i].fieldnr;
field= share->field[fieldnr-1];
if (field->null_ptr)
len_null_byte= HA_KEY_NULL_LENGTH;
- if ((field->type() == MYSQL_TYPE_BLOB ||
- field->real_type() == MYSQL_TYPE_VARCHAR ||
- field->type() == MYSQL_TYPE_GEOMETRY) &&
- keyinfo->algorithm != HA_KEY_ALG_LONG_HASH )
- {
- length_bytes= HA_KEY_BLOB_LENGTH;
- }
+ if (keyinfo->algorithm != HA_KEY_ALG_LONG_HASH)
+ length_bytes= field->key_part_length_bytes();
ext_key_length+= keyinfo->key_part[i].length + len_null_byte
+ length_bytes;
@@ -2691,20 +2847,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
keyinfo->flags|=HA_NULL_PART_KEY;
keyinfo->key_length+= HA_KEY_NULL_LENGTH;
}
- if (field->type() == MYSQL_TYPE_BLOB ||
- field->real_type() == MYSQL_TYPE_VARCHAR ||
- field->type() == MYSQL_TYPE_GEOMETRY)
- {
- if (field->type() == MYSQL_TYPE_BLOB ||
- field->type() == MYSQL_TYPE_GEOMETRY)
- key_part->key_part_flag|= HA_BLOB_PART;
- else
- key_part->key_part_flag|= HA_VAR_LENGTH_PART;
- key_part->store_length+=HA_KEY_BLOB_LENGTH;
- keyinfo->key_length+= HA_KEY_BLOB_LENGTH;
- }
- if (field->type() == MYSQL_TYPE_BIT)
- key_part->key_part_flag|= HA_BIT_PART;
+
+ key_part->key_part_flag|= field->key_part_flag();
+ uint16 key_part_length_bytes= field->key_part_length_bytes();
+ key_part->store_length+= key_part_length_bytes;
+ keyinfo->key_length+= key_part_length_bytes;
if (i == 0 && key != primary_key)
field->flags |= (((keyinfo->flags & HA_NOSAME ||
@@ -3099,7 +3246,6 @@ static bool sql_unusable_for_discovery(THD *thd, handlerton *engine,
int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write,
const char *sql, size_t sql_length)
{
- sql_mode_t saved_mode= thd->variables.sql_mode;
CHARSET_INFO *old_cs= thd->variables.character_set_client;
Parser_state parser_state;
bool error;
@@ -3127,7 +3273,7 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write,
if (parser_state.init(thd, sql_copy, sql_length))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
- thd->variables.sql_mode= MODE_NO_ENGINE_SUBSTITUTION | MODE_NO_DIR_IN_CREATE;
+ Sql_mode_instant_set sms(thd, MODE_NO_ENGINE_SUBSTITUTION | MODE_NO_DIR_IN_CREATE);
thd->variables.character_set_client= system_charset_info;
tmp_disable_binlog(thd);
old_lex= thd->lex;
@@ -3176,7 +3322,6 @@ ret:
if (arena)
thd->restore_active_arena(arena, &backup);
reenable_binlog(thd);
- thd->variables.sql_mode= saved_mode;
thd->variables.character_set_client= old_cs;
if (unlikely(thd->is_error() || error))
{
@@ -3612,8 +3757,8 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
error= OPEN_FRM_NEEDS_REBUILD;
goto err;
}
- init_sql_alloc(&outparam->mem_root, "table", TABLE_ALLOC_BLOCK_SIZE, 0,
- MYF(0));
+ init_sql_alloc(key_memory_TABLE, &outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE,
+ 0, MYF(0));
/*
We have to store the original alias in mem_root as constraints and virtual
@@ -3796,7 +3941,6 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
outparam->check_constraints= check_constraint_ptr;
vcol_init_mode mode= VCOL_INIT_DEPENDENCY_FAILURE_IS_WARNING;
-#if MYSQL_VERSION_ID > 100500
switch (thd->lex->sql_command)
{
case SQLCOM_CREATE_TABLE:
@@ -3811,7 +3955,6 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
default:
break;
}
-#endif
if (parse_vcol_defs(thd, &outparam->mem_root, outparam,
&error_reported, mode))
@@ -4446,21 +4589,17 @@ bool get_field(MEM_ROOT *mem, Field *field, String *res)
StringBuffer<MAX_FIELD_WIDTH> str;
bool rc;
THD *thd= field->get_thd();
- sql_mode_t sql_mode_backup= thd->variables.sql_mode;
- thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
+ Sql_mode_instant_remove sms(thd, MODE_PAD_CHAR_TO_FULL_LENGTH);
field->val_str(&str);
if ((rc= !str.length() ||
!(to= strmake_root(mem, str.ptr(), str.length()))))
{
res->length(0);
- goto ex;
+ return rc;
}
res->set(to, str.length(), field->charset());
-
-ex:
- thd->variables.sql_mode= sql_mode_backup;
- return rc;
+ return false;
}
@@ -4604,7 +4743,7 @@ bool check_table_name(const char *name, size_t length, bool check_for_path_chars
{
#if defined(USE_MB) && defined(USE_MB_IDENT)
last_char_is_space= my_isspace(system_charset_info, *name);
- if (use_mb(system_charset_info))
+ if (system_charset_info->use_mb())
{
int len=my_ismbchar(system_charset_info, name, end);
if (len)
@@ -4639,7 +4778,7 @@ bool check_column_name(const char *name)
{
#if defined(USE_MB) && defined(USE_MB_IDENT)
last_char_is_space= my_isspace(system_charset_info, *name);
- if (use_mb(system_charset_info))
+ if (system_charset_info->use_mb())
{
int len=my_ismbchar(system_charset_info, name,
name+system_charset_info->mbmaxlen);
@@ -5129,6 +5268,8 @@ void TABLE::init(THD *thd, TABLE_LIST *tl)
(*f_ptr)->cond_selectivity= 1.0;
}
+ notnull_cond= 0;
+
DBUG_ASSERT(!file->keyread_enabled());
restore_record(this, s->default_values);
@@ -6012,7 +6153,7 @@ TABLE_LIST *TABLE_LIST::last_leaf_for_name_resolution()
want_access Acess which we require
*/
-void TABLE_LIST::register_want_access(ulong want_access)
+void TABLE_LIST::register_want_access(privilege_t want_access)
{
/* Remove SHOW_VIEW_ACL, because it will be checked during making view */
want_access&= ~SHOW_VIEW_ACL;
@@ -6067,7 +6208,7 @@ bool TABLE_LIST::prepare_view_security_context(THD *thd)
}
else
{
- if (thd->security_ctx->master_access & SUPER_ACL)
+ if (thd->security_ctx->master_access & PRIV_REVEAL_MISSING_DEFINER)
{
my_error(ER_NO_SUCH_USER, MYF(0), definer.user.str, definer.host.str);
@@ -6181,7 +6322,7 @@ bool TABLE_LIST::prepare_security(THD *thd)
thd->security_ctx= save_security_ctx;
#else
while ((tbl= tb++))
- tbl->grant.privilege= ~NO_ACCESS;
+ tbl->grant.privilege= ALL_KNOWN_ACL;
#endif
DBUG_RETURN(FALSE);
}
@@ -6447,8 +6588,8 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
&view->view->first_select_lex()->context:
&thd->lex->first_select_lex()->context);
Item *item= (new (thd->mem_root)
- Item_direct_view_ref(thd, context, field_ref, view->alias.str,
- name, view));
+ Item_direct_view_ref(thd, context, field_ref, view->alias,
+ *name, view));
if (!item)
return NULL;
/*
@@ -7557,14 +7698,9 @@ void TABLE::create_key_part_by_field(KEY_PART_INFO *key_part_info,
{
key_part_info->store_length+= HA_KEY_NULL_LENGTH;
}
- if (field->type() == MYSQL_TYPE_BLOB ||
- field->type() == MYSQL_TYPE_GEOMETRY ||
- field->real_type() == MYSQL_TYPE_VARCHAR)
- {
- key_part_info->store_length+= HA_KEY_BLOB_LENGTH;
- key_part_info->key_part_flag|=
- field->type() == MYSQL_TYPE_BLOB ? HA_BLOB_PART: HA_VAR_LENGTH_PART;
- }
+
+ key_part_info->key_part_flag|= field->key_part_flag();
+ key_part_info->store_length+= field->key_part_length_bytes();
key_part_info->type= (uint8) field->key_type();
key_part_info->key_type =
@@ -8084,11 +8220,10 @@ size_t max_row_length(TABLE *table, MY_BITMAP const *cols, const uchar *data)
void init_mdl_requests(TABLE_LIST *table_list)
{
for ( ; table_list ; table_list= table_list->next_global)
- table_list->mdl_request.init(MDL_key::TABLE,
- table_list->db.str, table_list->table_name.str,
- table_list->lock_type >= TL_WRITE_ALLOW_WRITE ?
- MDL_SHARED_WRITE : MDL_SHARED_READ,
- MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&table_list->mdl_request, MDL_key::TABLE,
+ table_list->db.str, table_list->table_name.str,
+ table_list->lock_type >= TL_WRITE_ALLOW_WRITE
+ ? MDL_SHARED_WRITE : MDL_SHARED_READ, MDL_TRANSACTION);
}
@@ -9471,7 +9606,7 @@ bool TR_table::check(bool error)
}
Field_enum *iso_level= static_cast<Field_enum *>(table->field[FLD_ISO_LEVEL]);
- st_typelib *typelib= iso_level->typelib;
+ const st_typelib *typelib= iso_level->typelib;
if (typelib->count != 4)
goto wrong_enum;
@@ -9497,12 +9632,12 @@ bool TR_table::check(bool error)
return false;
}
-bool vers_select_conds_t::resolve_units(THD *thd)
+bool vers_select_conds_t::check_units(THD *thd)
{
DBUG_ASSERT(type != SYSTEM_TIME_UNSPECIFIED);
DBUG_ASSERT(start.item);
- return start.resolve_unit(thd) ||
- end.resolve_unit(thd);
+ return start.check_unit(thd) ||
+ end.check_unit(thd);
}
bool vers_select_conds_t::eq(const vers_select_conds_t &conds) const
@@ -9528,22 +9663,21 @@ bool vers_select_conds_t::eq(const vers_select_conds_t &conds) const
}
-bool Vers_history_point::resolve_unit(THD *thd)
+bool Vers_history_point::check_unit(THD *thd)
{
if (!item)
return false;
if (item->fix_fields_if_needed(thd, &item))
return true;
- return item->this_item()->real_type_handler()->
- type_handler_for_system_time()->
- Vers_history_point_resolve_unit(thd, this);
-}
-
-
-void Vers_history_point::bad_expression_data_type_error(const char *type) const
-{
- my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
- type, "FOR SYSTEM_TIME");
+ const Type_handler *t= item->this_item()->real_type_handler();
+ DBUG_ASSERT(t);
+ if (!t->vers())
+ {
+ my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
+ t->name().ptr(), "FOR SYSTEM_TIME");
+ return true;
+ }
+ return false;
}
diff --git a/sql/table.h b/sql/table.h
index cd9eaaf1e76..9430ceb5fe3 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1,7 +1,7 @@
#ifndef TABLE_INCLUDED
#define TABLE_INCLUDED
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
- Copyright (c) 2009, 2019, MariaDB
+ Copyright (c) 2009, 2020, 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
@@ -31,6 +31,9 @@
#include "thr_lock.h" /* thr_lock_type */
#include "filesort_utils.h"
#include "parse_file.h"
+#include "sql_i_s.h"
+#include "sql_type.h" /* vers_kind_t */
+#include "privilege.h" /* privilege_t */
/* Structs that defines the TABLE */
@@ -307,19 +310,25 @@ typedef struct st_grant_info
The set is implemented as a bitmap, with the bits defined in sql_acl.h.
*/
- ulong privilege;
+ privilege_t privilege;
/**
@brief the set of privileges that the current user needs to fulfil in
order to carry out the requested operation.
*/
- ulong want_privilege;
+ privilege_t want_privilege;
/**
Stores the requested access acl of top level tables list. Is used to
check access rights to the underlying tables of a view.
*/
- ulong orig_want_privilege;
+ privilege_t orig_want_privilege;
/** The grant state for internal tables. */
GRANT_INTERNAL_INFO m_internal;
+
+ st_grant_info()
+ :privilege(NO_ACL),
+ want_privilege(NO_ACL),
+ orig_want_privilege(NO_ACL)
+ { }
} GRANT_INFO;
enum tmp_table_type
@@ -812,7 +821,7 @@ struct TABLE_SHARE
}
};
- vers_sys_type_t versioned;
+ vers_kind_t versioned;
period_info_t vers;
period_info_t period;
@@ -1066,8 +1075,8 @@ private:
public:
Blob_mem_storage() :truncated_value(false)
{
- init_alloc_root(&storage, "Blob_mem_storage", MAX_FIELD_VARCHARLENGTH, 0,
- MYF(0));
+ init_alloc_root(key_memory_blob_mem_storage,
+ &storage, MAX_FIELD_VARCHARLENGTH, 0, MYF(0));
}
~ Blob_mem_storage()
{
@@ -1113,9 +1122,6 @@ struct st_cond_statistic;
#define CHECK_ROW_FOR_NULLS_TO_REJECT (1 << 0)
#define REJECT_ROW_DUE_TO_NULL_FIELDS (1 << 1)
-/* Bitmap of table's fields */
-typedef Bitmap<MAX_FIELDS> Field_map;
-
class SplM_opt_info;
struct vers_select_conds_t;
@@ -1416,6 +1422,13 @@ public:
SplM_opt_info *spl_opt_info;
key_map keys_usable_for_splitting;
+ /*
+ Conjunction of the predicates of the form IS NOT NULL(f) where f refers to
+ a column of this TABLE such that they can be inferred from the condition
+ of the WHERE clause or from some ON expression of the processed select
+ and can be useful for range optimizer.
+ */
+ Item *notnull_cond;
inline void reset() { bzero((void*)this, sizeof(*this)); }
void init(THD *thd, TABLE_LIST *tl);
@@ -1582,7 +1595,7 @@ public:
return s->versioned;
}
- bool versioned(vers_sys_type_t type) const
+ bool versioned(vers_kind_t type) const
{
DBUG_ASSERT(s);
DBUG_ASSERT(type);
@@ -1595,7 +1608,7 @@ public:
return versioned() ? vers_write : false;
}
- bool versioned_write(vers_sys_type_t type) const
+ bool versioned_write(vers_kind_t type) const
{
DBUG_ASSERT(type);
DBUG_ASSERT(versioned() || !vers_write);
@@ -1693,71 +1706,6 @@ typedef struct st_foreign_key_info
LEX_CSTRING *fk_option_name(enum_fk_option opt);
bool fk_modifies_child(enum_fk_option opt);
-#define MY_I_S_MAYBE_NULL 1U
-#define MY_I_S_UNSIGNED 2U
-
-
-#define SKIP_OPEN_TABLE 0U // do not open table
-#define OPEN_FRM_ONLY 1U // open FRM file only
-#define OPEN_FULL_TABLE 2U // open FRM,MYD, MYI files
-
-typedef struct st_field_info
-{
- /**
- This is used as column name.
- */
- const char* field_name;
- /**
- For string-type columns, this is the maximum number of
- characters. Otherwise, it is the 'display-length' for the column.
- */
- uint field_length;
- /**
- This denotes data type for the column. For the most part, there seems to
- be one entry in the enum for each SQL data type, although there seem to
- be a number of additional entries in the enum.
- */
- enum enum_field_types field_type;
- int value;
- /**
- This is used to set column attributes. By default, columns are @c NOT
- @c NULL and @c SIGNED, and you can deviate from the default
- by setting the appopriate flags. You can use either one of the flags
- @c MY_I_S_MAYBE_NULL and @cMY_I_S_UNSIGNED or
- combine them using the bitwise or operator @c |. Both flags are
- defined in table.h.
- */
- uint field_flags; // Field atributes(maybe_null, signed, unsigned etc.)
- const char* old_name;
- /**
- This should be one of @c SKIP_OPEN_TABLE,
- @c OPEN_FRM_ONLY or @c OPEN_FULL_TABLE.
- */
- uint open_method;
-} ST_FIELD_INFO;
-
-
-struct TABLE_LIST;
-typedef class Item COND;
-
-typedef struct st_schema_table
-{
- const char *table_name;
- ST_FIELD_INFO *fields_info;
- /* for FLUSH table_name */
- int (*reset_table) ();
- /* Fill table with data */
- int (*fill_table) (THD *thd, TABLE_LIST *tables, COND *cond);
- /* Handle fileds for old SHOW */
- int (*old_format) (THD *thd, struct st_schema_table *schema_table);
- int (*process_table) (THD *thd, TABLE_LIST *tables, TABLE *table,
- bool res, const LEX_CSTRING *db_name,
- const LEX_CSTRING *table_name);
- int idx_field1, idx_field2;
- bool hidden;
- uint i_s_requested_object; /* the object we need to open(TABLE | VIEW) */
-} ST_SCHEMA_TABLE;
-
class IS_table_read_plan;
/*
@@ -1894,7 +1842,7 @@ class Item_in_subselect;
/* trivial class, for %union in sql_yacc.yy */
struct vers_history_point_t
{
- vers_sys_type_t unit;
+ vers_kind_t unit;
Item *item;
};
@@ -1904,7 +1852,7 @@ class Vers_history_point : public vers_history_point_t
public:
Vers_history_point() { empty(); }
- Vers_history_point(vers_sys_type_t unit_arg, Item *item_arg)
+ Vers_history_point(vers_kind_t unit_arg, Item *item_arg)
{
unit= unit_arg;
item= item_arg;
@@ -1916,21 +1864,9 @@ public:
item= p.item;
fix_item();
}
- void empty() { unit= VERS_UNDEFINED; item= NULL; }
+ void empty() { unit= VERS_TIMESTAMP; item= NULL; }
void print(String *str, enum_query_type, const char *prefix, size_t plen) const;
- bool resolve_unit(THD *thd);
- bool resolve_unit_trx_id(THD *thd)
- {
- if (unit == VERS_UNDEFINED)
- unit= VERS_TRX_ID;
- return false;
- }
- bool resolve_unit_timestamp(THD *thd)
- {
- if (unit == VERS_UNDEFINED)
- unit= VERS_TIMESTAMP;
- return false;
- }
+ bool check_unit(THD *thd);
void bad_expression_data_type_error(const char *type) const;
bool eq(const vers_history_point_t &point) const;
};
@@ -1989,6 +1925,7 @@ struct vers_select_conds_t
{
return type != SYSTEM_TIME_UNSPECIFIED;
}
+ bool check_units(THD *thd);
bool was_set() const
{
return orig_type != SYSTEM_TIME_UNSPECIFIED;
@@ -1997,7 +1934,6 @@ struct vers_select_conds_t
{
return type != SYSTEM_TIME_UNSPECIFIED && type != SYSTEM_TIME_ALL;
}
- bool resolve_units(THD *thd);
bool eq(const vers_select_conds_t &conds) const;
};
@@ -2076,8 +2012,8 @@ struct TABLE_LIST
alias= (alias_arg ? *alias_arg : *table_name_arg);
lock_type= lock_type_arg;
updating= lock_type >= TL_WRITE_ALLOW_WRITE;
- mdl_request.init(MDL_key::TABLE, db.str, table_name.str, mdl_type,
- MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&mdl_request, MDL_key::TABLE, db.str, table_name.str,
+ mdl_type, MDL_TRANSACTION);
}
TABLE_LIST(TABLE *table_arg, thr_lock_type lock_type)
@@ -2578,7 +2514,7 @@ struct TABLE_LIST
return FALSE;
}
- void register_want_access(ulong want_access);
+ void register_want_access(privilege_t want_access);
bool prepare_security(THD *thd);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *find_view_security_context(THD *thd);
@@ -2628,22 +2564,10 @@ struct TABLE_LIST
}
/* Set of functions returning/setting state of a derived table/view. */
- inline bool is_non_derived()
- {
- return (!derived_type);
- }
- inline bool is_view_or_derived()
- {
- return (derived_type);
- }
- inline bool is_view()
- {
- return (derived_type & DTYPE_VIEW);
- }
- inline bool is_derived()
- {
- return (derived_type & DTYPE_TABLE);
- }
+ bool is_non_derived() const { return (!derived_type); }
+ bool is_view_or_derived() const { return derived_type; }
+ bool is_view() const { return (derived_type & DTYPE_VIEW); }
+ bool is_derived() const { return (derived_type & DTYPE_TABLE); }
bool is_with_table();
bool is_recursive_with_table();
bool is_with_table_recursive_reference();
@@ -2659,22 +2583,19 @@ struct TABLE_LIST
{
derived_type= DTYPE_TABLE;
}
- inline bool is_merged_derived()
- {
- return (derived_type & DTYPE_MERGE);
- }
+ bool is_merged_derived() const { return (derived_type & DTYPE_MERGE); }
inline void set_merged_derived()
{
DBUG_ENTER("set_merged_derived");
DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
(alias.str ? alias.str : "<NULL>"),
get_unit()));
- derived_type= ((derived_type & DTYPE_MASK) |
- DTYPE_TABLE | DTYPE_MERGE);
+ derived_type= static_cast<uint8>((derived_type & DTYPE_MASK) |
+ DTYPE_TABLE | DTYPE_MERGE);
set_check_merged();
DBUG_VOID_RETURN;
}
- inline bool is_materialized_derived()
+ bool is_materialized_derived() const
{
return (derived_type & DTYPE_MATERIALIZE);
}
@@ -2685,15 +2606,13 @@ struct TABLE_LIST
(alias.str ? alias.str : "<NULL>"),
get_unit()));
derived= get_unit();
- derived_type= ((derived_type & (derived ? DTYPE_MASK : DTYPE_VIEW)) |
- DTYPE_TABLE | DTYPE_MATERIALIZE);
+ derived_type= static_cast<uint8>((derived_type &
+ (derived ? DTYPE_MASK : DTYPE_VIEW)) |
+ DTYPE_TABLE | DTYPE_MATERIALIZE);
set_check_materialized();
DBUG_VOID_RETURN;
}
- inline bool is_multitable()
- {
- return (derived_type & DTYPE_MULTITABLE);
- }
+ bool is_multitable() const { return (derived_type & DTYPE_MULTITABLE); }
inline void set_multitable()
{
derived_type|= DTYPE_MULTITABLE;
@@ -3124,9 +3043,12 @@ extern LEX_CSTRING MYSQL_PROC_NAME;
inline bool is_infoschema_db(const LEX_CSTRING *name)
{
- return (INFORMATION_SCHEMA_NAME.length == name->length &&
- !my_strcasecmp(system_charset_info,
- INFORMATION_SCHEMA_NAME.str, name->str));
+ return lex_string_eq(&INFORMATION_SCHEMA_NAME, name);
+}
+
+inline bool is_perfschema_db(const LEX_CSTRING *name)
+{
+ return lex_string_eq(&PERFORMANCE_SCHEMA_DB_NAME, name);
}
inline void mark_as_null_row(TABLE *table)
diff --git a/sql/table_cache.cc b/sql/table_cache.cc
index 0743525b944..d8786f72244 100644
--- a/sql/table_cache.cc
+++ b/sql/table_cache.cc
@@ -68,7 +68,6 @@ I_P_List <TDC_element,
I_P_List_null_counter,
I_P_List_fast_push_back<TDC_element> > unused_shares;
-static tdc_version_t tdc_version; /* Increments on each reload */
static bool tdc_inited;
@@ -324,12 +323,12 @@ static my_bool tc_purge_callback(TDC_element *element, tc_purge_arg *arg)
}
-void tc_purge(bool mark_flushed)
+void tc_purge()
{
tc_purge_arg argument;
TABLE *table;
- argument.mark_flushed= mark_flushed;
+ argument.mark_flushed= false;
tdc_iterate(0, (my_hash_walk_action) tc_purge_callback, &argument);
while ((table= argument.purge_tables.pop_front()))
intern_close_table(table);
@@ -624,7 +623,6 @@ bool tdc_init(void)
tdc_inited= true;
mysql_mutex_init(key_LOCK_unused_shares, &LOCK_unused_shares,
MY_MUTEX_INIT_FAST);
- tdc_version= 1L; /* Increments on each reload */
lf_hash_init(&tdc_hash, sizeof(TDC_element) +
sizeof(Share_free_tables) * (tc_instances - 1),
LF_HASH_UNIQUE, 0, 0,
@@ -657,7 +655,7 @@ void tdc_start_shutdown(void)
tdc_size= 0;
tc_size= 0;
/* Free all cached but unused TABLEs and TABLE_SHAREs. */
- purge_tables(true);
+ purge_tables();
}
DBUG_VOID_RETURN;
}
@@ -850,7 +848,6 @@ retry:
element->share= share;
share->tdc= element;
element->ref_count++;
- element->version= tdc_refresh_version();
element->flushed= false;
mysql_mutex_unlock(&element->LOCK_table_share);
@@ -965,9 +962,9 @@ void tdc_release_share(TABLE_SHARE *share)
mysql_mutex_lock(&share->tdc->LOCK_table_share);
DBUG_PRINT("enter",
- ("share: %p table: %s.%s ref_count: %u version: %lld",
+ ("share: %p table: %s.%s ref_count: %u",
share, share->db.str, share->table_name.str,
- share->tdc->ref_count, share->tdc->version));
+ share->tdc->ref_count));
DBUG_ASSERT(share->tdc->ref_count);
if (share->tdc->ref_count > 1)
@@ -1007,47 +1004,6 @@ void tdc_release_share(TABLE_SHARE *share)
/**
- Auxiliary function which allows to kill delayed threads for
- particular table identified by its share.
-
- @param share Table share.
-
- @pre Caller should have TABLE_SHARE::tdc.LOCK_table_share mutex.
-*/
-
-static void kill_delayed_threads_for_table(TDC_element *element)
-{
- All_share_tables_list::Iterator it(element->all_tables);
- TABLE *tab;
-
- mysql_mutex_assert_owner(&element->LOCK_table_share);
-
- if (!delayed_insert_threads)
- return;
-
- while ((tab= it++))
- {
- THD *in_use= tab->in_use;
-
- DBUG_ASSERT(in_use && tab->s->tdc->flushed);
- if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
- ! in_use->killed)
- {
- in_use->killed= KILL_SYSTEM_THREAD;
- mysql_mutex_lock(&in_use->mysys_var->mutex);
- if (in_use->mysys_var->current_cond)
- {
- mysql_mutex_lock(in_use->mysys_var->current_mutex);
- mysql_cond_broadcast(in_use->mysys_var->current_cond);
- mysql_mutex_unlock(in_use->mysys_var->current_mutex);
- }
- mysql_mutex_unlock(&in_use->mysys_var->mutex);
- }
- }
-}
-
-
-/**
Remove all or some (depending on parameter) instances of TABLE and
TABLE_SHARE from the table definition cache.
@@ -1080,15 +1036,13 @@ static void kill_delayed_threads_for_table(TDC_element *element)
metadata lock on the table.
@param db Name of database
@param table_name Name of table
- @param kill_delayed_threads If TRUE, kill INSERT DELAYED threads
@note It assumes that table instances are already not used by any
(other) thread (this should be achieved by using meta-data locks).
*/
bool tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
- const char *db, const char *table_name,
- bool kill_delayed_threads)
+ const char *db, const char *table_name)
{
Share_free_tables::List purge_tables;
TABLE *table;
@@ -1132,9 +1086,6 @@ bool tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
tc_remove_all_unused_tables(element, &purge_tables,
remove_type != TDC_RT_REMOVE_NOT_OWN_KEEP_SHARE);
- if (kill_delayed_threads)
- kill_delayed_threads_for_table(element);
-
if (remove_type == TDC_RT_REMOVE_NOT_OWN ||
remove_type == TDC_RT_REMOVE_NOT_OWN_KEEP_SHARE)
{
@@ -1217,7 +1168,7 @@ bool tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
*/
int tdc_wait_for_old_version(THD *thd, const char *db, const char *table_name,
- ulong wait_timeout, uint deadlock_weight, tdc_version_t refresh_version)
+ ulong wait_timeout, uint deadlock_weight)
{
TDC_element *element;
@@ -1225,7 +1176,7 @@ int tdc_wait_for_old_version(THD *thd, const char *db, const char *table_name,
return FALSE;
else if (element == MY_ERRPTR)
return TRUE;
- else if (element->flushed && refresh_version > element->version)
+ else if (element->flushed)
{
struct timespec abstime;
set_timespec(abstime, wait_timeout);
@@ -1236,20 +1187,6 @@ int tdc_wait_for_old_version(THD *thd, const char *db, const char *table_name,
}
-tdc_version_t tdc_refresh_version(void)
-{
- return (tdc_version_t)my_atomic_load64_explicit(&tdc_version, MY_MEMORY_ORDER_RELAXED);
-}
-
-
-tdc_version_t tdc_increment_refresh_version(void)
-{
- tdc_version_t v= (tdc_version_t)my_atomic_add64_explicit(&tdc_version, 1, MY_MEMORY_ORDER_RELAXED);
- DBUG_PRINT("tcache", ("incremented global refresh_version to: %lld", v));
- return v + 1;
-}
-
-
/**
Iterate table definition cache.
@@ -1320,10 +1257,10 @@ int tdc_iterate(THD *thd, my_hash_walk_action action, void *argument,
if (no_dups)
{
- init_alloc_root(&no_dups_argument.root, "no_dups", 4096, 4096,
- MYF(alloc_flags));
- my_hash_init(&no_dups_argument.hash, &my_charset_bin, tdc_records(), 0, 0,
- eliminate_duplicates_get_key, 0, hash_flags);
+ init_alloc_root(PSI_INSTRUMENT_ME, &no_dups_argument.root, 4096, 4096, MYF(alloc_flags));
+ my_hash_init(PSI_INSTRUMENT_ME, &no_dups_argument.hash, &my_charset_bin,
+ tdc_records(), 0, 0, eliminate_duplicates_get_key, 0,
+ hash_flags);
no_dups_argument.action= action;
no_dups_argument.argument= argument;
action= (my_hash_walk_action) eliminate_duplicates;
diff --git a/sql/table_cache.h b/sql/table_cache.h
index 611980c615f..f971c377992 100644
--- a/sql/table_cache.h
+++ b/sql/table_cache.h
@@ -26,14 +26,11 @@ struct Share_free_tables
char pad[CPU_LEVEL1_DCACHE_LINESIZE];
};
-typedef int64 tdc_version_t;
-#define TDC_VERSION_MAX INT_MAX64
struct TDC_element
{
uchar m_key[NAME_LEN + 1 + NAME_LEN + 1];
uint m_key_length;
- tdc_version_t version;
bool flushed;
TABLE_SHARE *share;
@@ -85,20 +82,16 @@ extern TABLE_SHARE *tdc_acquire_share(THD *thd, TABLE_LIST *tl, uint flags,
TABLE **out_table= 0);
extern void tdc_release_share(TABLE_SHARE *share);
extern bool tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
- const char *db, const char *table_name,
- bool kill_delayed_threads);
+ const char *db, const char *table_name);
extern int tdc_wait_for_old_version(THD *thd, const char *db,
const char *table_name,
- ulong wait_timeout, uint deadlock_weight,
- tdc_version_t refresh_version= TDC_VERSION_MAX);
-extern tdc_version_t tdc_refresh_version(void);
-extern tdc_version_t tdc_increment_refresh_version(void);
+ ulong wait_timeout, uint deadlock_weight);
extern int tdc_iterate(THD *thd, my_hash_walk_action action, void *argument,
bool no_dups= false);
extern uint tc_records(void);
-extern void tc_purge(bool mark_flushed= false);
+extern void tc_purge();
extern void tc_add_table(THD *thd, TABLE *table);
extern void tc_release_table(TABLE *table);
extern TABLE *tc_acquire_table(THD *thd, TDC_element *element);
diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc
index 2e0f0a4918e..c675b11741a 100644
--- a/sql/temporary_tables.cc
+++ b/sql/temporary_tables.cc
@@ -955,7 +955,8 @@ TMP_TABLE_SHARE *THD::create_temporary_table(LEX_CUSTRING *frm,
/* Create the table definition key for the temporary table. */
key_length= create_tmp_table_def_key(key_cache, db, table_name);
- if (!(share= (TMP_TABLE_SHARE *) my_malloc(sizeof(TMP_TABLE_SHARE) +
+ if (!(share= (TMP_TABLE_SHARE *) my_malloc(key_memory_table_share,
+ sizeof(TMP_TABLE_SHARE) +
strlen(path) + 1 + key_length,
MYF(MY_WME))))
{
@@ -1002,7 +1003,8 @@ TMP_TABLE_SHARE *THD::create_temporary_table(LEX_CUSTRING *frm,
if (!temporary_tables)
{
if ((temporary_tables=
- (All_tmp_tables_list *) my_malloc(sizeof(All_tmp_tables_list),
+ (All_tmp_tables_list *) my_malloc(key_memory_table_share,
+ sizeof(All_tmp_tables_list),
MYF(MY_WME))))
{
temporary_tables->empty();
@@ -1107,7 +1109,8 @@ TABLE *THD::open_temporary_table(TMP_TABLE_SHARE *share,
DBUG_ENTER("THD::open_temporary_table");
- if (!(table= (TABLE *) my_malloc(sizeof(TABLE), MYF(MY_WME))))
+ if (!(table= (TABLE *) my_malloc(key_memory_TABLE, sizeof(TABLE),
+ MYF(MY_WME))))
{
DBUG_RETURN(NULL); /* Out of memory */
}
diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc
index d43e7c4c9b5..89ad359befa 100644
--- a/sql/thr_malloc.cc
+++ b/sql/thr_malloc.cc
@@ -58,11 +58,10 @@ extern "C" {
}
}
-void init_sql_alloc(MEM_ROOT *mem_root,
- const char *area_name __attribute__((unused)),
- uint block_size, uint pre_alloc, myf my_flags)
+void init_sql_alloc(PSI_memory_key key, MEM_ROOT *mem_root, uint block_size,
+ uint pre_alloc, myf my_flags)
{
- init_alloc_root(mem_root, area_name, block_size, pre_alloc, my_flags);
+ init_alloc_root(key, mem_root, block_size, pre_alloc, my_flags);
mem_root->error_handler=sql_alloc_error_handler;
}
diff --git a/sql/thr_malloc.h b/sql/thr_malloc.h
index a6ab5477d41..cc56666bcc9 100644
--- a/sql/thr_malloc.h
+++ b/sql/thr_malloc.h
@@ -18,8 +18,8 @@
typedef struct st_mem_root MEM_ROOT;
-void init_sql_alloc(MEM_ROOT *root, const char *area_name, uint block_size,
- uint pre_alloc_size, myf my_flags);
+void init_sql_alloc(PSI_memory_key key, MEM_ROOT *root, uint block_size, uint
+ pre_alloc_size, myf my_flags);
char *sql_strmake_with_convert(THD *thd, const char *str, size_t arg_length,
CHARSET_INFO *from_cs,
size_t max_res_length,
diff --git a/sql/thread_pool_info.cc b/sql/thread_pool_info.cc
new file mode 100644
index 00000000000..99ac3cd148c
--- /dev/null
+++ b/sql/thread_pool_info.cc
@@ -0,0 +1,357 @@
+/* Copyright(C) 2019 MariaDB
+
+This program is free software; you can redistribute itand /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 02111 - 1301 USA*/
+
+#include <mysql_version.h>
+#include <mysql/plugin.h>
+
+#include <my_global.h>
+#include <sql_class.h>
+#include <sql_i_s.h>
+#include <mysql/plugin.h>
+#include <sql_show.h>
+#include <threadpool_generic.h>
+
+namespace Show {
+
+static ST_FIELD_INFO groups_fields_info[] =
+{
+ Column("GROUP_ID", SLong(6), NOT_NULL),
+ Column("CONNECTIONS", SLong(6), NOT_NULL),
+ Column("THREADS", SLong(6), NOT_NULL),
+ Column("ACTIVE_THREADS", SLong(6), NOT_NULL),
+ Column("STANDBY_THREADS", SLong(6), NOT_NULL),
+ Column("QUEUE_LENGTH", SLong(6), NOT_NULL),
+ Column("HAS_LISTENER", STiny(1), NOT_NULL),
+ Column("IS_STALLED", STiny(1), NOT_NULL),
+ CEnd()
+};
+
+} // namespace Show
+
+
+static int groups_fill_table(THD* thd, TABLE_LIST* tables, COND*)
+{
+ if (!all_groups)
+ return 0;
+
+ TABLE* table = tables->table;
+ for (uint i = 0; i < threadpool_max_size && all_groups[i].pollfd != INVALID_HANDLE_VALUE; i++)
+ {
+ thread_group_t* group = &all_groups[i];
+ /* ID */
+ table->field[0]->store(i, true);
+ /* CONNECTION_COUNT */
+ table->field[1]->store(group->connection_count, true);
+ /* THREAD_COUNT */
+ table->field[2]->store(group->thread_count, true);
+ /* ACTIVE_THREAD_COUNT */
+ table->field[3]->store(group->active_thread_count, true);
+ /* STANDBY_THREAD_COUNT */
+ table->field[4]->store(group->waiting_threads.elements(), true);
+ /* QUEUE LENGTH */
+ uint queue_len = group->queues[TP_PRIORITY_LOW].elements()
+ + group->queues[TP_PRIORITY_HIGH].elements();
+ table->field[5]->store(queue_len, true);
+ /* HAS_LISTENER */
+ table->field[6]->store((longlong)(group->listener != 0), true);
+ /* IS_STALLED */
+ table->field[7]->store(group->stalled, true);
+
+ if (schema_table_store_record(thd, table))
+ return 1;
+ }
+ return 0;
+}
+
+
+static int groups_init(void* p)
+{
+ ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*)p;
+ schema->fields_info = Show::groups_fields_info;
+ schema->fill_table = groups_fill_table;
+ return 0;
+}
+
+
+namespace Show {
+
+static ST_FIELD_INFO queues_field_info[] =
+{
+ Column("GROUP_ID", SLong(6), NOT_NULL),
+ Column("POSITION", SLong(6), NOT_NULL),
+ Column("PRIORITY", SLong(1), NOT_NULL),
+ Column("CONNECTION_ID", ULonglong(19), NOT_NULL),
+ Column("QUEUEING_TIME_MICROSECONDS", SLonglong(19), NOT_NULL),
+ CEnd()
+};
+
+} // namespace Show
+
+typedef connection_queue_t::Iterator connection_queue_iterator;
+
+static int queues_fill_table(THD* thd, TABLE_LIST* tables, COND*)
+{
+ if (!all_groups)
+ return 0;
+
+ TABLE* table = tables->table;
+ for (uint group_id = 0;
+ group_id < threadpool_max_size && all_groups[group_id].pollfd != INVALID_HANDLE_VALUE;
+ group_id++)
+ {
+ thread_group_t* group = &all_groups[group_id];
+
+ mysql_mutex_lock(&group->mutex);
+ bool err = false;
+ int pos = 0;
+ ulonglong now = microsecond_interval_timer();
+ for (uint prio = 0; prio < NQUEUES && !err; prio++)
+ {
+ connection_queue_iterator it(group->queues[prio]);
+ TP_connection_generic* c;
+ while ((c = it++) != 0)
+ {
+ /* GROUP_ID */
+ table->field[0]->store(group_id, true);
+ /* POSITION */
+ table->field[1]->store(pos++, true);
+ /* PRIORITY */
+ table->field[2]->store(prio, true);
+ /* CONNECTION_ID */
+ table->field[3]->store(c->thd->thread_id, true);
+ /* QUEUEING_TIME */
+ table->field[4]->store(now - c->enqueue_time, true);
+
+ err = schema_table_store_record(thd, table);
+ if (err)
+ break;
+ }
+ }
+ mysql_mutex_unlock(&group->mutex);
+ if (err)
+ return 1;
+ }
+ return 0;
+}
+
+static int queues_init(void* p)
+{
+ ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*)p;
+ schema->fields_info = Show::queues_field_info;
+ schema->fill_table = queues_fill_table;
+ return 0;
+}
+
+namespace Show {
+
+static ST_FIELD_INFO stats_fields_info[] =
+{
+ Column("GROUP_ID", SLong(6), NOT_NULL),
+ Column("THREAD_CREATIONS", SLonglong(19), NOT_NULL),
+ Column("THREAD_CREATIONS_DUE_TO_STALL", SLonglong(19), NOT_NULL),
+ Column("WAKES", SLonglong(19), NOT_NULL),
+ Column("WAKES_DUE_TO_STALL", SLonglong(19), NOT_NULL),
+ Column("THROTTLES", SLonglong(19), NOT_NULL),
+ Column("STALLS", SLonglong(19), NOT_NULL),
+ Column("POLLS_BY_LISTENER", SLonglong(19), NOT_NULL),
+ Column("POLLS_BY_WORKER", SLonglong(19), NOT_NULL),
+ Column("DEQUEUES_BY_LISTENER", SLonglong(19), NOT_NULL),
+ Column("DEQUEUES_BY_WORKER", SLonglong(19), NOT_NULL),
+ CEnd()
+};
+
+} // namespace Show
+
+
+static int stats_fill_table(THD* thd, TABLE_LIST* tables, COND*)
+{
+ if (!all_groups)
+ return 0;
+
+ TABLE* table = tables->table;
+ for (uint i = 0; i < threadpool_max_size && all_groups[i].pollfd != INVALID_HANDLE_VALUE; i++)
+ {
+ table->field[0]->store(i, true);
+ thread_group_t* group = &all_groups[i];
+
+ mysql_mutex_lock(&group->mutex);
+ thread_group_counters_t* counters = &group->counters;
+ table->field[1]->store(counters->thread_creations, true);
+ table->field[2]->store(counters->thread_creations_due_to_stall, true);
+ table->field[3]->store(counters->wakes, true);
+ table->field[4]->store(counters->wakes_due_to_stall, true);
+ table->field[5]->store(counters->throttles, true);
+ table->field[6]->store(counters->stalls, true);
+ table->field[7]->store(counters->polls_by_listener, true);
+ table->field[8]->store(counters->polls_by_worker, true);
+ table->field[9]->store(counters->dequeues_by_listener, true);
+ table->field[10]->store(counters->dequeues_by_worker, true);
+ mysql_mutex_unlock(&group->mutex);
+ if (schema_table_store_record(thd, table))
+ return 1;
+ }
+ return 0;
+}
+
+static int stats_reset_table()
+{
+ for (uint i = 0; i < threadpool_max_size && all_groups[i].pollfd != INVALID_HANDLE_VALUE; i++)
+ {
+ thread_group_t* group = &all_groups[i];
+ mysql_mutex_lock(&group->mutex);
+ memset(&group->counters, 0, sizeof(group->counters));
+ mysql_mutex_unlock(&group->mutex);
+ }
+ return 0;
+}
+
+static int stats_init(void* p)
+{
+ ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*)p;
+ schema->fields_info = Show::stats_fields_info;
+ schema->fill_table = stats_fill_table;
+ schema->reset_table = stats_reset_table;
+ return 0;
+}
+
+
+namespace Show {
+
+static ST_FIELD_INFO waits_fields_info[] =
+{
+ Column("REASON", Varchar(16), NOT_NULL),
+ Column("COUNT", SLonglong(19), NOT_NULL),
+ CEnd()
+};
+
+} // namespace Show
+
+/* See thd_wait_type enum for explanation*/
+static const LEX_CSTRING wait_reasons[THD_WAIT_LAST] =
+{
+ {STRING_WITH_LEN("UNKNOWN")},
+ {STRING_WITH_LEN("SLEEP")},
+ {STRING_WITH_LEN("DISKIO")},
+ {STRING_WITH_LEN("ROW_LOCK")},
+ {STRING_WITH_LEN("GLOBAL_LOCK")},
+ {STRING_WITH_LEN("META_DATA_LOCK")},
+ {STRING_WITH_LEN("TABLE_LOCK")},
+ {STRING_WITH_LEN("USER_LOCK")},
+ {STRING_WITH_LEN("BINLOG")},
+ {STRING_WITH_LEN("GROUP_COMMIT")},
+ {STRING_WITH_LEN("SYNC")},
+ {STRING_WITH_LEN("NET")}
+};
+
+extern Atomic_counter<unsigned long long> tp_waits[THD_WAIT_LAST];
+
+static int waits_fill_table(THD* thd, TABLE_LIST* tables, COND*)
+{
+ if (!all_groups)
+ return 0;
+
+ TABLE* table = tables->table;
+ for (auto i = 0; i < THD_WAIT_LAST; i++)
+ {
+ table->field[0]->store(wait_reasons[i].str, wait_reasons[i].length, system_charset_info);
+ table->field[1]->store(tp_waits[i], true);
+ if (schema_table_store_record(thd, table))
+ return 1;
+ }
+ return 0;
+}
+
+static int waits_reset_table()
+{
+ for (auto i = 0; i < THD_WAIT_LAST; i++)
+ tp_waits[i] = 0;
+
+ return 0;
+}
+
+static int waits_init(void* p)
+{
+ ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*)p;
+ schema->fields_info = Show::waits_fields_info;
+ schema->fill_table = waits_fill_table;
+ schema->reset_table = waits_reset_table;
+ return 0;
+}
+
+static struct st_mysql_information_schema plugin_descriptor =
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+maria_declare_plugin(thread_pool_info)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &plugin_descriptor,
+ "THREAD_POOL_GROUPS",
+ "Vladislav Vaintroub",
+ "Provides information about threadpool groups.",
+ PLUGIN_LICENSE_GPL,
+ groups_init,
+ 0,
+ 0x0100,
+ NULL,
+ NULL,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &plugin_descriptor,
+ "THREAD_POOL_QUEUES",
+ "Vladislav Vaintroub",
+ "Provides information about threadpool queues.",
+ PLUGIN_LICENSE_GPL,
+ queues_init,
+ 0,
+ 0x0100,
+ NULL,
+ NULL,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &plugin_descriptor,
+ "THREAD_POOL_STATS",
+ "Vladislav Vaintroub",
+ "Provides performance counter information for threadpool.",
+ PLUGIN_LICENSE_GPL,
+ stats_init,
+ 0,
+ 0x0100,
+ NULL,
+ NULL,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &plugin_descriptor,
+ "THREAD_POOL_WAITS",
+ "Vladislav Vaintroub",
+ "Provides wait counters for threadpool.",
+ PLUGIN_LICENSE_GPL,
+ waits_init,
+ 0,
+ 0x0100,
+ NULL,
+ NULL,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/sql/threadpool.h b/sql/threadpool.h
index 6299510d002..fe77100a82a 100644
--- a/sql/threadpool.h
+++ b/sql/threadpool.h
@@ -24,16 +24,19 @@ extern uint threadpool_min_threads; /* Minimum threads in pool */
extern uint threadpool_idle_timeout; /* Shutdown idle worker threads after this timeout */
extern uint threadpool_size; /* Number of parallel executing threads */
extern uint threadpool_max_size;
-extern uint threadpool_stall_limit; /* time interval in 10 ms units for stall checks*/
+extern uint threadpool_stall_limit; /* time interval in milliseconds for stall checks*/
extern uint threadpool_max_threads; /* Maximum threads in pool */
extern uint threadpool_oversubscribe; /* Maximum active threads in group */
extern uint threadpool_prio_kickup_timer; /* Time before low prio item gets prio boost */
+extern my_bool threadpool_exact_stats; /* Better queueing time stats for information_schema, at small performance cost */
+extern my_bool threadpool_dedicated_listener; /* Listener thread does not pick up work items. */
#ifdef _WIN32
extern uint threadpool_mode; /* Thread pool implementation , windows or generic */
#define TP_MODE_WINDOWS 0
#define TP_MODE_GENERIC 1
#endif
+#define DEFAULT_THREADPOOL_STALL_LIMIT 500U
struct TP_connection;
extern void tp_callback(TP_connection *c);
@@ -64,8 +67,6 @@ extern int tp_get_thread_count();
/* Activate threadpool scheduler */
extern void tp_scheduler(void);
-extern int show_threadpool_idle_threads(THD *thd, SHOW_VAR *var, char *buff,
- enum enum_var_type scope);
enum TP_PRIORITY {
TP_PRIORITY_HIGH,
@@ -88,6 +89,8 @@ enum TP_STATE
inside threadpool_win.cc and threadpool_unix.cc
*/
+class CONNECT;
+
struct TP_connection
{
THD* thd;
diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc
index efcc56d67be..40b230e5392 100644
--- a/sql/threadpool_common.cc
+++ b/sql/threadpool_common.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2012 Monty Program Ab
+/* Copyright (C) 2012, 2019, 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
@@ -23,6 +23,8 @@
#include <sql_audit.h>
#include <debug_sync.h>
#include <threadpool.h>
+#include <my_counter.h>
+
#ifdef WITH_WSREP
#include "wsrep_trans_observer.h"
#endif /* WITH_WSREP */
@@ -38,6 +40,8 @@ uint threadpool_max_threads;
uint threadpool_oversubscribe;
uint threadpool_mode;
uint threadpool_prio_kickup_timer;
+my_bool threadpool_exact_stats;
+my_bool threadpool_dedicated_listener;
/* Stats */
TP_STATISTICS tp_stats;
@@ -147,7 +151,7 @@ static void thread_attach(THD* thd)
pthread_setspecific(THR_KEY_mysys,thd->mysys_var);
thd->thread_stack=(char*)&thd;
thd->store_globals();
- PSI_CALL_set_thread(thd->event_scheduler.m_psi);
+ PSI_CALL_set_thread(thd->get_psi());
mysql_socket_set_thread_owner(thd->net.vio->mysql_socket);
}
@@ -160,9 +164,8 @@ static TP_PRIORITY get_priority(TP_connection *c)
DBUG_ASSERT(c->thd == current_thd);
TP_PRIORITY prio= (TP_PRIORITY)c->thd->variables.threadpool_priority;
if (prio == TP_PRIORITY_AUTO)
- {
- return c->thd->transaction.is_active() ? TP_PRIORITY_HIGH : TP_PRIORITY_LOW;
- }
+ prio= c->thd->transaction.is_active() ? TP_PRIORITY_HIGH : TP_PRIORITY_LOW;
+
return prio;
}
@@ -232,21 +235,13 @@ static THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data)
pthread_setspecific(THR_KEY_mysys, 0);
my_thread_init();
st_my_thread_var* mysys_var= (st_my_thread_var *)pthread_getspecific(THR_KEY_mysys);
+ PSI_CALL_set_thread(PSI_CALL_new_thread(key_thread_one_connection, connect, 0));
if (!mysys_var ||!(thd= connect->create_thd(NULL)))
{
/* Out of memory? */
connect->close_and_delete();
if (mysys_var)
- {
-#ifdef HAVE_PSI_INTERFACE
- /*
- current PSI is still from worker thread.
- Set to 0, to avoid premature cleanup by my_thread_end
- */
- if (PSI_server) PSI_server->set_thread(0);
-#endif
my_thread_end();
- }
return NULL;
}
delete connect;
@@ -254,11 +249,6 @@ static THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data)
thd->set_mysys_var(mysys_var);
thd->event_scheduler.data= scheduler_data;
- /* Create new PSI thread for use with the THD. */
- thd->event_scheduler.m_psi=
- PSI_CALL_new_thread(key_thread_one_connection, thd, thd->thread_id);
-
-
/* Login. */
thread_attach(thd);
re_init_net_server_extension(thd);
@@ -298,6 +288,7 @@ static void threadpool_remove_connection(THD *thd)
end_connection(thd);
close_connection(thd, 0);
unlink_thd(thd);
+ PSI_CALL_delete_current_thread(); // before THD is destroyed
delete thd;
/*
@@ -388,19 +379,6 @@ end:
}
-
-/* Dummy functions, do nothing */
-
-static bool tp_init_new_connection_thread()
-{
- return 0;
-}
-
-static bool tp_end_thread(THD *, bool)
-{
- return 0;
-}
-
static TP_pool *pool;
static bool tp_init()
@@ -484,12 +462,17 @@ void tp_timeout_handler(TP_connection *c)
mysql_mutex_unlock(&thd->LOCK_thd_kill);
}
+MY_ALIGNED(CPU_LEVEL1_DCACHE_LINESIZE) Atomic_counter<unsigned long long> tp_waits[THD_WAIT_LAST];
static void tp_wait_begin(THD *thd, int type)
{
TP_connection *c = get_TP_connection(thd);
if (c)
+ {
+ DBUG_ASSERT(type > 0 && type < THD_WAIT_LAST);
+ tp_waits[type]++;
c->wait_begin(type);
+ }
}
@@ -520,18 +503,16 @@ static scheduler_functions tp_scheduler_functions=
NULL,
NULL,
tp_init, // init
- tp_init_new_connection_thread, // init_new_connection_thread
tp_add_connection, // add_connection
tp_wait_begin, // thd_wait_begin
tp_wait_end, // thd_wait_end
tp_post_kill_notification, // post kill notification
- tp_end_thread, // Dummy function
tp_end // end
};
void pool_of_threads_scheduler(struct scheduler_functions *func,
ulong *arg_max_connections,
- uint *arg_connection_count)
+ Atomic_counter<uint> *arg_connection_count)
{
*func = tp_scheduler_functions;
func->max_threads= threadpool_max_threads;
diff --git a/sql/threadpool_generic.cc b/sql/threadpool_generic.cc
index 6f8e1982836..e8e3497eae4 100644
--- a/sql/threadpool_generic.cc
+++ b/sql/threadpool_generic.cc
@@ -13,56 +13,28 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+#if (defined HAVE_POOL_OF_THREADS) && !defined(EMBEDDED_LIBRARY)
+
+#include "threadpool_generic.h"
#include "mariadb.h"
#include <violite.h>
#include <sql_priv.h>
#include <sql_class.h>
#include <my_pthread.h>
#include <scheduler.h>
-
-#ifdef HAVE_POOL_OF_THREADS
-
-#ifdef _WIN32
-/* AIX may define this, too ?*/
-#define HAVE_IOCP
-#endif
-
-#ifdef HAVE_IOCP
-#define OPTIONAL_IO_POLL_READ_PARAM this
-#else
-#define OPTIONAL_IO_POLL_READ_PARAM 0
-#endif
-
-#ifdef _WIN32
-typedef HANDLE TP_file_handle;
-#else
-typedef int TP_file_handle;
-#define INVALID_HANDLE_VALUE -1
-#endif
-
-
#include <sql_connect.h>
#include <mysqld.h>
#include <debug_sync.h>
#include <time.h>
#include <sql_plist.h>
#include <threadpool.h>
-#include <time.h>
-#ifdef __linux__
-#include <sys/epoll.h>
-typedef struct epoll_event native_event;
-#elif defined(HAVE_KQUEUE)
-#include <sys/event.h>
-typedef struct kevent native_event;
-#elif defined (__sun)
-#include <port.h>
-typedef port_event_t native_event;
-#elif defined (HAVE_IOCP)
-typedef OVERLAPPED_ENTRY native_event;
-#else
-#error threadpool is not available on this platform
-#endif
+#include <algorithm>
+#ifdef HAVE_IOCP
+#define OPTIONAL_IO_POLL_READ_PARAM this
+#else
+#define OPTIONAL_IO_POLL_READ_PARAM 0
+#endif
static void io_poll_close(TP_file_handle fd)
{
@@ -119,86 +91,7 @@ static PSI_thread_info thread_list[] =
#define PSI_register(X) /* no-op */
#endif
-
-struct thread_group_t;
-
-/* Per-thread structure for workers */
-struct worker_thread_t
-{
- ulonglong event_count; /* number of request handled by this thread */
- thread_group_t* thread_group;
- worker_thread_t *next_in_list;
- worker_thread_t **prev_in_list;
-
- mysql_cond_t cond;
- bool woken;
-};
-
-typedef I_P_List<worker_thread_t, I_P_List_adapter<worker_thread_t,
- &worker_thread_t::next_in_list,
- &worker_thread_t::prev_in_list>
- >
-worker_list_t;
-
-struct TP_connection_generic:public TP_connection
-{
- TP_connection_generic(CONNECT *c);
- ~TP_connection_generic();
-
- virtual int init(){ return 0; };
- virtual void set_io_timeout(int sec);
- virtual int start_io();
- virtual void wait_begin(int type);
- virtual void wait_end();
-
- thread_group_t *thread_group;
- TP_connection_generic *next_in_queue;
- TP_connection_generic **prev_in_queue;
- ulonglong abs_wait_timeout;
- ulonglong dequeue_time;
- TP_file_handle fd;
- bool bound_to_poll_descriptor;
- int waiting;
-#ifdef HAVE_IOCP
- OVERLAPPED overlapped;
-#endif
-#ifdef _WIN32
- enum_vio_type vio_type;
-#endif
-};
-
-
-typedef I_P_List<TP_connection_generic,
- I_P_List_adapter<TP_connection_generic,
- &TP_connection_generic::next_in_queue,
- &TP_connection_generic::prev_in_queue>,
- I_P_List_null_counter,
- I_P_List_fast_push_back<TP_connection_generic> >
-connection_queue_t;
-
-const int NQUEUES=2; /* We have high and low priority queues*/
-
-struct MY_ALIGNED(CPU_LEVEL1_DCACHE_LINESIZE) thread_group_t
-{
- mysql_mutex_t mutex;
- connection_queue_t queues[NQUEUES];
- worker_list_t waiting_threads;
- worker_thread_t *listener;
- pthread_attr_t *pthread_attr;
- TP_file_handle pollfd;
- int thread_count;
- int active_thread_count;
- int connection_count;
- /* Stats for the deadlock detection timer routine.*/
- int io_event_count;
- int queue_event_count;
- ulonglong last_thread_creation_time;
- int shutdown_pipe[2];
- bool shutdown;
- bool stalled;
-};
-
-static thread_group_t *all_groups;
+thread_group_t *all_groups;
static uint group_count;
static int32 shutdown_group_count;
@@ -224,9 +117,9 @@ static pool_timer_t pool_timer;
static void queue_put(thread_group_t *thread_group, TP_connection_generic *connection);
static void queue_put(thread_group_t *thread_group, native_event *ev, int cnt);
-static int wake_thread(thread_group_t *thread_group);
-static int wake_or_create_thread(thread_group_t *thread_group);
-static int create_worker(thread_group_t *thread_group);
+static int wake_thread(thread_group_t *thread_group,bool due_to_stall);
+static int wake_or_create_thread(thread_group_t *thread_group, bool due_to_stall=false);
+static int create_worker(thread_group_t *thread_group, bool due_to_stall);
static void *worker_main(void *param);
static void check_stall(thread_group_t *thread_group);
static void set_next_timeout_check(ulonglong abstime);
@@ -563,11 +456,11 @@ static void queue_init(thread_group_t *thread_group)
static void queue_put(thread_group_t *thread_group, native_event *ev, int cnt)
{
- ulonglong now= pool_timer.current_microtime;
+ ulonglong now= threadpool_exact_stats?microsecond_interval_timer():pool_timer.current_microtime;
for(int i=0; i < cnt; i++)
{
TP_connection_generic *c = (TP_connection_generic *)native_event_get_userdata(&ev[i]);
- c->dequeue_time= now;
+ c->enqueue_time= now;
thread_group->queues[c->priority].push_back(c);
}
}
@@ -681,7 +574,7 @@ void check_stall(thread_group_t *thread_group)
for (;;)
{
c= thread_group->queues[TP_PRIORITY_LOW].front();
- if (c && pool_timer.current_microtime - c->dequeue_time > 1000ULL * threadpool_prio_kickup_timer)
+ if (c && pool_timer.current_microtime - c->enqueue_time > 1000ULL * threadpool_prio_kickup_timer)
{
thread_group->queues[TP_PRIORITY_LOW].remove(c);
thread_group->queues[TP_PRIORITY_HIGH].push_back(c);
@@ -698,7 +591,7 @@ void check_stall(thread_group_t *thread_group)
*/
if (!thread_group->listener && !thread_group->io_event_count)
{
- wake_or_create_thread(thread_group);
+ wake_or_create_thread(thread_group, true);
mysql_mutex_unlock(&thread_group->mutex);
return;
}
@@ -735,7 +628,8 @@ void check_stall(thread_group_t *thread_group)
if (!is_queue_empty(thread_group) && !thread_group->queue_event_count)
{
thread_group->stalled= true;
- wake_or_create_thread(thread_group);
+ TP_INCREMENT_GROUP_COUNTER(thread_group,stalls);
+ wake_or_create_thread(thread_group,true);
}
/* Reset queue event count */
@@ -790,13 +684,13 @@ static TP_connection_generic * listener(worker_thread_t *current_thread,
break;
cnt = io_poll_wait(thread_group->pollfd, ev, MAX_EVENTS, -1);
-
+ TP_INCREMENT_GROUP_COUNTER(thread_group, polls_by_listener);
if (cnt <=0)
{
DBUG_ASSERT(thread_group->shutdown);
break;
}
-
+
mysql_mutex_lock(&thread_group->mutex);
if (thread_group->shutdown)
@@ -851,7 +745,7 @@ static TP_connection_generic * listener(worker_thread_t *current_thread,
more workers.
*/
- bool listener_picks_event=is_queue_empty(thread_group);
+ bool listener_picks_event=is_queue_empty(thread_group) && !threadpool_dedicated_listener;
queue_put(thread_group, ev, cnt);
if (listener_picks_event)
{
@@ -864,7 +758,7 @@ static TP_connection_generic * listener(worker_thread_t *current_thread,
if(thread_group->active_thread_count==0)
{
/* We added some work items to queue, now wake a worker. */
- if(wake_thread(thread_group))
+ if(wake_thread(thread_group, false))
{
/*
Wake failed, hence groups has no idle threads. Now check if there are
@@ -882,7 +776,7 @@ static TP_connection_generic * listener(worker_thread_t *current_thread,
create thread, but waiting for timer would be an inefficient and
pointless delay.
*/
- create_worker(thread_group);
+ create_worker(thread_group, false);
}
}
}
@@ -919,7 +813,7 @@ static void add_thread_count(thread_group_t *thread_group, int32 count)
per group to prevent deadlocks (one listener + one worker)
*/
-static int create_worker(thread_group_t *thread_group)
+static int create_worker(thread_group_t *thread_group, bool due_to_stall)
{
pthread_t thread_id;
bool max_threads_reached= false;
@@ -942,6 +836,11 @@ static int create_worker(thread_group_t *thread_group)
thread_group->last_thread_creation_time=microsecond_interval_timer();
statistic_increment(thread_created,&LOCK_status);
add_thread_count(thread_group, 1);
+ TP_INCREMENT_GROUP_COUNTER(thread_group,thread_creations);
+ if(due_to_stall)
+ {
+ TP_INCREMENT_GROUP_COUNTER(thread_group, thread_creations_due_to_stall);
+ }
}
else
{
@@ -967,23 +866,24 @@ end:
The actual values were not calculated using any scientific methods.
They just look right, and behave well in practice.
-
- TODO: Should throttling depend on thread_pool_stall_limit?
*/
+
+#define THROTTLING_FACTOR (threadpool_stall_limit/std::max(DEFAULT_THREADPOOL_STALL_LIMIT,threadpool_stall_limit))
+
static ulonglong microsecond_throttling_interval(thread_group_t *thread_group)
{
int count= thread_group->thread_count;
- if (count < 4)
+ if (count < 1+ (int)threadpool_oversubscribe)
return 0;
-
+
if (count < 8)
- return 50*1000;
-
+ return 50*1000*THROTTLING_FACTOR;
+
if(count < 16)
- return 100*1000;
-
- return 200*1000;
+ return 100*1000*THROTTLING_FACTOR;
+
+ return 200*100*THROTTLING_FACTOR;
}
@@ -993,15 +893,17 @@ static ulonglong microsecond_throttling_interval(thread_group_t *thread_group)
Worker creation is throttled, so we avoid too many threads
to be created during the short time.
*/
-static int wake_or_create_thread(thread_group_t *thread_group)
+static int wake_or_create_thread(thread_group_t *thread_group, bool due_to_stall)
{
DBUG_ENTER("wake_or_create_thread");
if (thread_group->shutdown)
DBUG_RETURN(0);
- if (wake_thread(thread_group) == 0)
+ if (wake_thread(thread_group, due_to_stall) == 0)
+ {
DBUG_RETURN(0);
+ }
if (thread_group->thread_count > thread_group->connection_count)
DBUG_RETURN(-1);
@@ -1015,7 +917,7 @@ static int wake_or_create_thread(thread_group_t *thread_group)
idle thread to wakeup. Smells like a potential deadlock or very slowly
executing requests, e.g sleeps or user locks.
*/
- DBUG_RETURN(create_worker(thread_group));
+ DBUG_RETURN(create_worker(thread_group, due_to_stall));
}
ulonglong now = microsecond_interval_timer();
@@ -1026,9 +928,10 @@ static int wake_or_create_thread(thread_group_t *thread_group)
if (time_since_last_thread_created >
microsecond_throttling_interval(thread_group))
{
- DBUG_RETURN(create_worker(thread_group));
+ DBUG_RETURN(create_worker(thread_group, due_to_stall));
}
-
+
+ TP_INCREMENT_GROUP_COUNTER(thread_group,throttles);
DBUG_RETURN(-1);
}
@@ -1074,7 +977,7 @@ void thread_group_destroy(thread_group_t *thread_group)
Wake sleeping thread from waiting list
*/
-static int wake_thread(thread_group_t *thread_group)
+static int wake_thread(thread_group_t *thread_group,bool due_to_stall)
{
DBUG_ENTER("wake_thread");
worker_thread_t *thread = thread_group->waiting_threads.front();
@@ -1083,6 +986,11 @@ static int wake_thread(thread_group_t *thread_group)
thread->woken= true;
thread_group->waiting_threads.remove(thread);
mysql_cond_signal(&thread->cond);
+ TP_INCREMENT_GROUP_COUNTER(thread_group, wakes);
+ if (due_to_stall)
+ {
+ TP_INCREMENT_GROUP_COUNTER(thread_group, wakes_due_to_stall);
+ }
DBUG_RETURN(0);
}
DBUG_RETURN(1); /* no thread in waiter list => missed wakeup */
@@ -1140,7 +1048,7 @@ static void thread_group_close(thread_group_t *thread_group)
wake_listener(thread_group);
/* Wake all workers. */
- while(wake_thread(thread_group) == 0)
+ while(wake_thread(thread_group, false) == 0)
{
}
@@ -1162,7 +1070,7 @@ static void queue_put(thread_group_t *thread_group, TP_connection_generic *conne
{
DBUG_ENTER("queue_put");
- connection->dequeue_time= pool_timer.current_microtime;
+ connection->enqueue_time= threadpool_exact_stats?microsecond_interval_timer():pool_timer.current_microtime;
thread_group->queues[connection->priority].push_back(connection);
if (thread_group->active_thread_count == 0)
@@ -1224,7 +1132,10 @@ TP_connection_generic *get_event(worker_thread_t *current_thread,
{
connection = queue_get(thread_group);
if(connection)
+ {
+ TP_INCREMENT_GROUP_COUNTER(thread_group,dequeues_by_worker);
break;
+ }
}
/* If there is currently no listener in the group, become one. */
@@ -1235,7 +1146,10 @@ TP_connection_generic *get_event(worker_thread_t *current_thread,
mysql_mutex_unlock(&thread_group->mutex);
connection = listener(current_thread, thread_group);
-
+ if (connection)
+ {
+ TP_INCREMENT_GROUP_COUNTER(thread_group, dequeues_by_listener);
+ }
mysql_mutex_lock(&thread_group->mutex);
thread_group->active_thread_count++;
/* There is no listener anymore, it just returned. */
@@ -1251,9 +1165,9 @@ TP_connection_generic *get_event(worker_thread_t *current_thread,
*/
if (!oversubscribed)
{
-
native_event ev[MAX_EVENTS];
int cnt = io_poll_wait(thread_group->pollfd, ev, MAX_EVENTS, 0);
+ TP_INCREMENT_GROUP_COUNTER(thread_group, polls_by_worker);
if (cnt > 0)
{
queue_put(thread_group, ev, cnt);
@@ -1300,6 +1214,7 @@ TP_connection_generic *get_event(worker_thread_t *current_thread,
}
thread_group->stalled= false;
+
mysql_mutex_unlock(&thread_group->mutex);
DBUG_RETURN(connection);
@@ -1433,14 +1348,13 @@ TP_connection_generic::TP_connection_generic(CONNECT *c):
, overlapped()
#endif
{
- DBUG_ASSERT(c->vio);
+ DBUG_ASSERT(c->vio_type != VIO_CLOSED);
#ifdef _WIN32
- vio_type= c->vio->type;
- fd= (vio_type == VIO_TYPE_NAMEDPIPE) ?
- c->vio->hPipe: (TP_file_handle)mysql_socket_getfd(c->vio->mysql_socket);
+ fd= (c->vio_type == VIO_TYPE_NAMEDPIPE) ?
+ c->pipe: (TP_file_handle) mysql_socket_getfd(c->sock);
#else
- fd= mysql_socket_getfd(c->vio->mysql_socket);
+ fd= mysql_socket_getfd(c->sock);
#endif
/* Assign connection to a group. */
@@ -1516,7 +1430,7 @@ static int change_group(TP_connection_generic *c,
new_group->connection_count++;
/* Ensure that there is a listener in the new group. */
if (!new_group->thread_count)
- ret= create_worker(new_group);
+ ret= create_worker(new_group, false);
mysql_mutex_unlock(&new_group->mutex);
return ret;
}
@@ -1618,7 +1532,8 @@ int TP_pool_generic::init()
DBUG_ENTER("TP_pool_generic::TP_pool_generic");
threadpool_max_size= MY_MAX(threadpool_size, 128);
all_groups= (thread_group_t *)
- my_malloc(sizeof(thread_group_t) * threadpool_max_size, MYF(MY_WME|MY_ZEROFILL));
+ my_malloc(PSI_INSTRUMENT_ME,
+ sizeof(thread_group_t) * threadpool_max_size, MYF(MY_WME|MY_ZEROFILL));
if (!all_groups)
{
threadpool_max_size= 0;
@@ -1776,4 +1691,6 @@ static void print_pool_blocked_message(bool max_threads_reached)
}
}
+
+
#endif /* HAVE_POOL_OF_THREADS */
diff --git a/sql/threadpool_generic.h b/sql/threadpool_generic.h
new file mode 100644
index 00000000000..4b83e1d796f
--- /dev/null
+++ b/sql/threadpool_generic.h
@@ -0,0 +1,150 @@
+/* Copyright(C) 2019 MariaDB
+ *
+ * This program is free software; you can redistribute itand /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 02111 - 1301 USA*/
+
+#if defined (HAVE_POOL_OF_THREADS)
+#include <my_global.h>
+#include <sql_plist.h>
+#include <my_pthread.h>
+#include <threadpool.h>
+#include <mysqld.h>
+#include <violite.h>
+
+#ifdef _WIN32
+#include <windows.h>
+/* AIX may define this, too ?*/
+#define HAVE_IOCP
+#endif
+
+
+#ifdef _WIN32
+typedef HANDLE TP_file_handle;
+#else
+typedef int TP_file_handle;
+#define INVALID_HANDLE_VALUE -1
+#endif
+
+#ifdef __linux__
+#include <sys/epoll.h>
+typedef struct epoll_event native_event;
+#elif defined(HAVE_KQUEUE)
+#include <sys/event.h>
+typedef struct kevent native_event;
+#elif defined (__sun)
+#include <port.h>
+typedef port_event_t native_event;
+#elif defined (HAVE_IOCP)
+typedef OVERLAPPED_ENTRY native_event;
+#else
+#error threadpool is not available on this platform
+#endif
+
+struct thread_group_t;
+
+/* Per-thread structure for workers */
+struct worker_thread_t
+{
+ ulonglong event_count; /* number of request handled by this thread */
+ thread_group_t* thread_group;
+ worker_thread_t* next_in_list;
+ worker_thread_t** prev_in_list;
+ mysql_cond_t cond;
+ bool woken;
+};
+
+typedef I_P_List<worker_thread_t, I_P_List_adapter<worker_thread_t,
+ & worker_thread_t::next_in_list,
+ & worker_thread_t::prev_in_list>,
+ I_P_List_counter
+>
+worker_list_t;
+
+struct TP_connection_generic :public TP_connection
+{
+ TP_connection_generic(CONNECT* c);
+ ~TP_connection_generic();
+
+ virtual int init() { return 0; };
+ virtual void set_io_timeout(int sec);
+ virtual int start_io();
+ virtual void wait_begin(int type);
+ virtual void wait_end();
+
+ thread_group_t* thread_group;
+ TP_connection_generic* next_in_queue;
+ TP_connection_generic** prev_in_queue;
+ ulonglong abs_wait_timeout;
+ ulonglong enqueue_time;
+ TP_file_handle fd;
+ bool bound_to_poll_descriptor;
+ int waiting;
+#ifdef HAVE_IOCP
+ OVERLAPPED overlapped;
+#endif
+#ifdef _WIN32
+ enum_vio_type vio_type;
+#endif
+};
+
+
+typedef I_P_List<TP_connection_generic,
+ I_P_List_adapter<TP_connection_generic,
+ & TP_connection_generic::next_in_queue,
+ & TP_connection_generic::prev_in_queue>,
+ I_P_List_counter,
+ I_P_List_fast_push_back<TP_connection_generic> >
+ connection_queue_t;
+
+const int NQUEUES = 2; /* We have high and low priority queues*/
+
+struct thread_group_counters_t
+{
+ ulonglong thread_creations;
+ ulonglong thread_creations_due_to_stall;
+ ulonglong wakes;
+ ulonglong wakes_due_to_stall;
+ ulonglong throttles;
+ ulonglong stalls;
+ ulonglong dequeues_by_worker;
+ ulonglong dequeues_by_listener;
+ ulonglong polls_by_listener;
+ ulonglong polls_by_worker;
+};
+
+struct MY_ALIGNED(CPU_LEVEL1_DCACHE_LINESIZE) thread_group_t
+{
+ mysql_mutex_t mutex;
+ connection_queue_t queues[NQUEUES];
+ worker_list_t waiting_threads;
+ worker_thread_t* listener;
+ pthread_attr_t* pthread_attr;
+ TP_file_handle pollfd;
+ int thread_count;
+ int active_thread_count;
+ int connection_count;
+ /* Stats for the deadlock detection timer routine.*/
+ int io_event_count;
+ int queue_event_count;
+ ulonglong last_thread_creation_time;
+ int shutdown_pipe[2];
+ bool shutdown;
+ bool stalled;
+ thread_group_counters_t counters;
+};
+
+#define TP_INCREMENT_GROUP_COUNTER(group,var) group->counters.var++;
+
+extern thread_group_t* all_groups;
+#endif
+
diff --git a/sql/threadpool_win.cc b/sql/threadpool_win.cc
index 6e96fa8e11c..c9968d48c06 100644
--- a/sql/threadpool_win.cc
+++ b/sql/threadpool_win.cc
@@ -31,31 +31,6 @@
#include <threadpool.h>
#include <windows.h>
-
-
-/*
- WEAK_SYMBOL(return_type, function_name, argument_type1,..,argument_typeN)
-
- Declare and load function pointer from kernel32. The name of the static
- variable that holds the function pointer is my_<original function name>
- This should be combined with
- #define <original function name> my_<original function name>
- so that one could use Widows APIs transparently, without worrying whether
- they are present in a particular version or not.
-
- Of course, prior to use of any function there should be a check for correct
- Windows version, or check whether function pointer is not NULL.
-*/
-#define WEAK_SYMBOL(return_type, function, ...) \
- typedef return_type (WINAPI *pFN_##function)(__VA_ARGS__); \
- static pFN_##function my_##function = (pFN_##function) \
- (GetProcAddress(GetModuleHandle("kernel32"),#function))
-
-
-WEAK_SYMBOL(BOOL, SetThreadpoolStackInformation, PTP_POOL,
- PTP_POOL_STACK_INFORMATION);
-#define SetThreadpoolStackInformation my_SetThreadpoolStackInformation
-
/* Log a warning */
static void tp_log_warning(const char *msg, const char *fct)
{
@@ -167,15 +142,14 @@ int TP_connection_win::init()
{
memset(&overlapped, 0, sizeof(OVERLAPPED));
- Vio *vio = connect->vio;
- switch ((vio_type = vio->type))
+ switch ((vio_type = connect->vio_type))
{
case VIO_TYPE_SSL:
case VIO_TYPE_TCPIP:
- handle= (HANDLE)mysql_socket_getfd(vio->mysql_socket);
+ handle= (HANDLE) mysql_socket_getfd(connect->sock);
break;
case VIO_TYPE_NAMEDPIPE:
- handle= (HANDLE)vio->hPipe;
+ handle= connect->pipe;
break;
default:
abort();
@@ -452,19 +426,13 @@ int TP_pool_win::init()
}
}
- /*
- Control stack size (OS must be Win7 or later)
- */
- if (SetThreadpoolStackInformation)
+ TP_POOL_STACK_INFORMATION stackinfo;
+ stackinfo.StackCommit = 0;
+ stackinfo.StackReserve = (SIZE_T)my_thread_stack_size;
+ if (!SetThreadpoolStackInformation(pool, &stackinfo))
{
- TP_POOL_STACK_INFORMATION stackinfo;
- stackinfo.StackCommit = 0;
- stackinfo.StackReserve = (SIZE_T)my_thread_stack_size;
- if (!SetThreadpoolStackInformation(pool, &stackinfo))
- {
- tp_log_warning("Can't set threadpool stack size",
- "SetThreadpoolStackInformation");
- }
+ tp_log_warning("Can't set threadpool stack size",
+ "SetThreadpoolStackInformation");
}
return 0;
}
diff --git a/sql/transaction.cc b/sql/transaction.cc
index aecee04c364..82e04d35479 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -1,4 +1,5 @@
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2009, 2020, 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
@@ -24,6 +25,8 @@
#include "debug_sync.h" // DEBUG_SYNC
#include "sql_acl.h"
#include "semisync_master.h"
+#include <pfs_transaction_provider.h>
+#include <mysql/psi/mysql_transaction.h>
#ifdef WITH_WSREP
#include "wsrep_trans_observer.h"
#endif /* WITH_WSREP */
@@ -160,7 +163,7 @@ bool trans_begin(THD *thd, uint flags)
compatibility.
*/
const bool user_is_super=
- MY_TEST(thd->security_ctx->master_access & SUPER_ACL);
+ MY_TEST(thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY);
if (opt_readonly && !user_is_super)
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
@@ -208,6 +211,23 @@ bool trans_begin(THD *thd, uint flags)
#endif //EMBEDDED_LIBRARY
res= ha_start_consistent_snapshot(thd);
}
+ /*
+ Register transaction start in performance schema if not done already.
+ We handle explicitly started transactions here, implicitly started
+ transactions (and single-statement transactions in autocommit=1 mode)
+ are handled in trans_register_ha().
+ We can't handle explicit transactions in the same way as implicit
+ because we want to correctly attribute statements which follow
+ BEGIN but do not touch any transactional tables.
+ */
+ if (thd->m_transaction_psi == NULL)
+ {
+ thd->m_transaction_psi= MYSQL_START_TRANSACTION(&thd->m_transaction_state,
+ NULL, 0, thd->tx_isolation,
+ thd->tx_read_only, false);
+ DEBUG_SYNC(thd, "after_set_transaction_psi_before_set_transaction_gtid");
+ //gtid_set_performance_schema_values(thd);
+ }
DBUG_RETURN(MY_TEST(res));
}
@@ -244,22 +264,18 @@ bool trans_commit(THD *thd)
if res is non-zero, then ha_commit_trans has rolled back the
transaction, so the hooks for rollback will be called.
*/
- if (res)
- {
#ifdef HAVE_REPLICATION
+ if (res)
repl_semisync_master.wait_after_rollback(thd, FALSE);
-#endif
- }
else
- {
-#ifdef HAVE_REPLICATION
repl_semisync_master.wait_after_commit(thd, FALSE);
#endif
- }
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.reset();
thd->lex->start_transaction_opt= 0;
+ /* The transaction should be marked as complete in P_S. */
+ DBUG_ASSERT(thd->m_transaction_psi == NULL);
trans_track_end_trx(thd);
DBUG_RETURN(MY_TEST(res));
@@ -304,6 +320,9 @@ bool trans_commit_implicit(THD *thd)
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.reset();
+ /* The transaction should be marked as complete in P_S. */
+ DBUG_ASSERT(thd->m_transaction_psi == NULL);
+
/*
Upon implicit commit, reset the current transaction
isolation level and access mode. We do not care about
@@ -348,6 +367,9 @@ bool trans_rollback(THD *thd)
thd->transaction.all.reset();
thd->lex->start_transaction_opt= 0;
+ /* The transaction should be marked as complete in P_S. */
+ DBUG_ASSERT(thd->m_transaction_psi == NULL);
+
trans_track_end_trx(thd);
DBUG_RETURN(MY_TEST(res));
@@ -394,7 +416,9 @@ bool trans_rollback_implicit(THD *thd)
thd->transaction.all.reset();
/* Rollback should clear transaction_rollback_request flag. */
- DBUG_ASSERT(! thd->transaction_rollback_request);
+ DBUG_ASSERT(!thd->transaction_rollback_request);
+ /* The transaction should be marked as complete in P_S. */
+ DBUG_ASSERT(thd->m_transaction_psi == NULL);
trans_track_end_trx(thd);
@@ -462,6 +486,10 @@ bool trans_commit_stmt(THD *thd)
#endif
}
+ /* In autocommit=1 mode the transaction should be marked as complete in P_S */
+ DBUG_ASSERT(thd->in_active_multi_stmt_transaction() ||
+ thd->m_transaction_psi == NULL);
+
thd->transaction.stmt.reset();
DBUG_RETURN(MY_TEST(res));
@@ -501,6 +529,10 @@ bool trans_rollback_stmt(THD *thd)
repl_semisync_master.wait_after_rollback(thd, FALSE);
#endif
+ /* In autocommit=1 mode the transaction should be marked as complete in P_S */
+ DBUG_ASSERT(thd->in_active_multi_stmt_transaction() ||
+ thd->m_transaction_psi == NULL);
+
thd->transaction.stmt.reset();
DBUG_RETURN(FALSE);
@@ -514,7 +546,8 @@ find_savepoint(THD *thd, LEX_CSTRING name)
while (*sv)
{
- if (my_strnncoll(system_charset_info, (uchar *) name.str, name.length,
+ if (system_charset_info->strnncoll(
+ (uchar *) name.str, name.length,
(uchar *) (*sv)->name, (*sv)->length) == 0)
break;
sv= &(*sv)->prev;
diff --git a/sql/tztime.cc b/sql/tztime.cc
index 46a24a137e5..72db37fde9c 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -1543,6 +1543,8 @@ tz_init_table_list(TABLE_LIST *tz_tabs)
}
}
+static PSI_memory_key key_memory_tz_storage;
+
#ifdef HAVE_PSI_INTERFACE
static PSI_mutex_key key_tz_LOCK;
@@ -1551,6 +1553,11 @@ static PSI_mutex_info all_tz_mutexes[]=
{ & key_tz_LOCK, "tz_LOCK", PSI_FLAG_GLOBAL}
};
+static PSI_memory_info all_tz_memory[]=
+{
+ { &key_memory_tz_storage, "tz_storage", PSI_FLAG_GLOBAL}
+};
+
static void init_tz_psi_keys(void)
{
const char* category= "sql";
@@ -1561,6 +1568,9 @@ static void init_tz_psi_keys(void)
count= array_elements(all_tz_mutexes);
PSI_server->register_mutex(category, all_tz_mutexes, count);
+
+ count= array_elements(all_tz_memory);
+ mysql_memory_register(category, all_tz_memory, count);
}
#endif /* HAVE_PSI_INTERFACE */
@@ -1615,20 +1625,20 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
thd->store_globals();
/* Init all memory structures that require explicit destruction */
- if (my_hash_init(&tz_names, &my_charset_latin1, 20,
- 0, 0, (my_hash_get_key) my_tz_names_get_key, 0, 0))
+ if (my_hash_init(key_memory_tz_storage, &tz_names, &my_charset_latin1, 20, 0,
+ 0, (my_hash_get_key) my_tz_names_get_key, 0, 0))
{
sql_print_error("Fatal error: OOM while initializing time zones");
goto end;
}
- if (my_hash_init(&offset_tzs, &my_charset_latin1, 26, 0, 0,
- (my_hash_get_key)my_offset_tzs_get_key, 0, 0))
+ if (my_hash_init(key_memory_tz_storage, &offset_tzs, &my_charset_latin1, 26,
+ 0, 0, (my_hash_get_key)my_offset_tzs_get_key, 0, 0))
{
sql_print_error("Fatal error: OOM while initializing time zones");
my_hash_free(&tz_names);
goto end;
}
- init_sql_alloc(&tz_storage, "timezone_storage", 32 * 1024, 0, MYF(0));
+ init_sql_alloc(key_memory_tz_storage, &tz_storage, 32 * 1024, 0, MYF(0));
mysql_mutex_init(key_tz_LOCK, &tz_LOCK, MY_MUTEX_INIT_FAST);
tz_inited= 1;
@@ -2568,8 +2578,8 @@ scan_tz_dir(char * name_end, uint symlink_recursion_level, uint verbose)
}
else if (MY_S_ISREG(cur_dir->dir_entry[i].mystat->st_mode))
{
- init_alloc_root(&tz_storage, "timezone_storage", 32768, 0,
- MYF(MY_THREAD_SPECIFIC));
+ init_alloc_root(PSI_INSTRUMENT_ME, &tz_storage,
+ 32768, 0, MYF(MY_THREAD_SPECIFIC));
if (!tz_load(fullname, &tz_info, &tz_storage))
print_tz_as_sql(root_name_end + 1, &tz_info);
else
@@ -2641,8 +2651,7 @@ static struct my_option my_long_options[] =
C_MODE_START
-static my_bool get_one_option(int optid, const struct my_option *,
- char *argument);
+static my_bool get_one_option(const struct my_option *, char *, const char *);
C_MODE_END
static void print_version(void)
@@ -2664,9 +2673,9 @@ static void print_usage(void)
static my_bool
-get_one_option(int optid, const struct my_option *opt, char *argument)
+get_one_option(const struct my_option *opt, char *argument, const char *)
{
- switch(optid) {
+ switch(opt->id) {
case '#':
#ifndef DBUG_OFF
DBUG_PUSH(argument ? argument : "d:t:S:i:O,/tmp/mysq_tzinfo_to_sql.trace");
@@ -2759,7 +2768,7 @@ main(int argc, char **argv)
First argument is timezonefile.
The second is timezonename if opt_leap is not given
*/
- init_alloc_root(&tz_storage, "timezone_storage", 32768, 0, MYF(0));
+ init_alloc_root(PSI_INSTRUMENT_ME, &tz_storage, 32768, 0, MYF(0));
if (tz_load(argv[0], &tz_info, &tz_storage))
{
diff --git a/sql/uniques.cc b/sql/uniques.cc
index fafb44b56a0..4e327a4cc09 100644
--- a/sql/uniques.cc
+++ b/sql/uniques.cc
@@ -39,7 +39,6 @@
#include "my_tree.h" // element_count
#include "uniques.h" // Unique
#include "sql_sort.h"
-#include "myisamchk.h" // BUFFPEK
int unique_write_to_file(uchar* key, element_count count, Unique *unique)
{
@@ -94,8 +93,8 @@ Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg,
init_tree(&tree, (max_in_memory_size / 16), 0, size, comp_func,
NULL, comp_func_fixed_arg, MYF(MY_THREAD_SPECIFIC));
/* If the following fail's the next add will also fail */
- my_init_dynamic_array(&file_ptrs, sizeof(BUFFPEK), 16, 16,
- MYF(MY_THREAD_SPECIFIC));
+ my_init_dynamic_array(PSI_INSTRUMENT_ME, &file_ptrs, sizeof(Merge_chunk), 16,
+ 16, MYF(MY_THREAD_SPECIFIC));
/*
If you change the following, change it in get_max_elements function, too.
*/
@@ -375,10 +374,10 @@ Unique::~Unique()
/* Write tree to disk; clear tree */
bool Unique::flush()
{
- BUFFPEK file_ptr;
+ Merge_chunk file_ptr;
elements+= tree.elements_in_tree;
- file_ptr.count=tree.elements_in_tree;
- file_ptr.file_pos=my_b_tell(&file);
+ file_ptr.set_rowcount(tree.elements_in_tree);
+ file_ptr.set_file_position(my_b_tell(&file));
tree_walk_action action= min_dupl_count ?
(tree_walk_action) unique_write_to_file_with_count :
@@ -490,7 +489,7 @@ void put_counter_into_merged_element(void *ptr, uint ofs, element_count cnt)
*/
static bool merge_walk(uchar *merge_buffer, size_t merge_buffer_size,
- uint key_length, BUFFPEK *begin, BUFFPEK *end,
+ uint key_length, Merge_chunk *begin, Merge_chunk *end,
tree_walk_action walk_action, void *walk_action_arg,
qsort_cmp2 compare, void *compare_arg,
IO_CACHE *file, bool with_counters)
@@ -499,7 +498,8 @@ static bool merge_walk(uchar *merge_buffer, size_t merge_buffer_size,
QUEUE queue;
if (end <= begin ||
merge_buffer_size < (size_t) (key_length * (end - begin + 1)) ||
- init_queue(&queue, (uint) (end - begin), offsetof(BUFFPEK, key), 0,
+ init_queue(&queue, (uint) (end - begin),
+ offsetof(Merge_chunk, m_current_key), 0,
buffpek_compare, &compare_context, 0, 0))
return 1;
/* we need space for one key when a piece of merge buffer is re-read */
@@ -510,10 +510,16 @@ static bool merge_walk(uchar *merge_buffer, size_t merge_buffer_size,
/* if piece_size is aligned reuse_freed_buffer will always hit */
uint piece_size= max_key_count_per_piece * key_length;
ulong bytes_read; /* to hold return value of read_to_buffer */
- BUFFPEK *top;
+ Merge_chunk *top;
int res= 1;
uint cnt_ofs= key_length - (with_counters ? sizeof(element_count) : 0);
element_count cnt;
+
+ // read_to_buffer() needs only rec_length.
+ Sort_param sort_param;
+ sort_param.rec_length= key_length;
+ DBUG_ASSERT(!sort_param.using_addon_fields());
+
/*
Invariant: queue must contain top element from each tree, until a tree
is not completely walked through.
@@ -522,15 +528,16 @@ static bool merge_walk(uchar *merge_buffer, size_t merge_buffer_size,
*/
for (top= begin; top != end; ++top)
{
- top->base= merge_buffer + (top - begin) * piece_size;
- top->max_keys= max_key_count_per_piece;
- bytes_read= read_to_buffer(file, top, key_length);
+ top->set_buffer(merge_buffer + (top - begin) * piece_size,
+ merge_buffer + (top - begin) * piece_size + piece_size);
+ top->set_max_keys(max_key_count_per_piece);
+ bytes_read= read_to_buffer(file, top, &sort_param, false);
if (unlikely(bytes_read == (ulong) -1))
goto end;
DBUG_ASSERT(bytes_read);
queue_insert(&queue, (uchar *) top);
}
- top= (BUFFPEK *) queue_top(&queue);
+ top= (Merge_chunk *) queue_top(&queue);
while (queue.elements > 1)
{
/*
@@ -540,20 +547,21 @@ static bool merge_walk(uchar *merge_buffer, size_t merge_buffer_size,
elements in each tree are unique. Action is applied only to unique
elements.
*/
- void *old_key= top->key;
+ void *old_key= top->current_key();
/*
read next key from the cache or from the file and push it to the
queue; this gives new top.
*/
- top->key+= key_length;
- if (--top->mem_count)
+ top->advance_current_key(key_length);
+ top->decrement_mem_count();
+ if (top->mem_count())
queue_replace_top(&queue);
else /* next piece should be read */
{
/* save old_key not to overwrite it in read_to_buffer */
memcpy(save_key_buff, old_key, key_length);
old_key= save_key_buff;
- bytes_read= read_to_buffer(file, top, key_length);
+ bytes_read= read_to_buffer(file, top, &sort_param, false);
if (unlikely(bytes_read == (ulong) -1))
goto end;
else if (bytes_read) /* top->key, top->mem_count are reset */
@@ -568,9 +576,9 @@ static bool merge_walk(uchar *merge_buffer, size_t merge_buffer_size,
reuse_freed_buff(&queue, top, key_length);
}
}
- top= (BUFFPEK *) queue_top(&queue);
+ top= (Merge_chunk *) queue_top(&queue);
/* new top has been obtained; if old top is unique, apply the action */
- if (compare(compare_arg, old_key, top->key))
+ if (compare(compare_arg, old_key, top->current_key()))
{
cnt= with_counters ?
get_counter_from_merged_element(old_key, cnt_ofs) : 1;
@@ -579,9 +587,9 @@ static bool merge_walk(uchar *merge_buffer, size_t merge_buffer_size,
}
else if (with_counters)
{
- cnt= get_counter_from_merged_element(top->key, cnt_ofs);
+ cnt= get_counter_from_merged_element(top->current_key(), cnt_ofs);
cnt+= get_counter_from_merged_element(old_key, cnt_ofs);
- put_counter_into_merged_element(top->key, cnt_ofs, cnt);
+ put_counter_into_merged_element(top->current_key(), cnt_ofs, cnt);
}
}
/*
@@ -595,13 +603,13 @@ static bool merge_walk(uchar *merge_buffer, size_t merge_buffer_size,
{
cnt= with_counters ?
- get_counter_from_merged_element(top->key, cnt_ofs) : 1;
- if (walk_action(top->key, cnt, walk_action_arg))
+ get_counter_from_merged_element(top->current_key(), cnt_ofs) : 1;
+ if (walk_action(top->current_key(), cnt, walk_action_arg))
goto end;
- top->key+= key_length;
+ top->advance_current_key(key_length);
}
- while (--top->mem_count);
- bytes_read= read_to_buffer(file, top, key_length);
+ while (top->decrement_mem_count());
+ bytes_read= read_to_buffer(file, top, &sort_param, false);
if (unlikely(bytes_read == (ulong) -1))
goto end;
}
@@ -654,16 +662,18 @@ bool Unique::walk(TABLE *table, tree_walk_action action, void *walk_action_arg)
is needed when a piece of merge buffer is re-read, see merge_walk()
*/
size_t buff_sz= MY_MAX(MERGEBUFF2+1, max_in_memory_size/full_size+1) * full_size;
- if (!(merge_buffer = (uchar *)my_malloc(buff_sz, MYF(MY_WME))))
+ if (!(merge_buffer = (uchar *)my_malloc(key_memory_Unique_merge_buffer,
+ buff_sz, MYF(MY_THREAD_SPECIFIC|MY_WME))))
return 1;
if (buff_sz < full_size * (file_ptrs.elements + 1UL))
- res= merge(table, merge_buffer, buff_sz >= full_size * MERGEBUFF2) ;
+ res= merge(table, merge_buffer, buff_sz,
+ buff_sz >= full_size * MERGEBUFF2) ;
if (!res)
{
res= merge_walk(merge_buffer, buff_sz, full_size,
- (BUFFPEK *) file_ptrs.buffer,
- (BUFFPEK *) file_ptrs.buffer + file_ptrs.elements,
+ (Merge_chunk *) file_ptrs.buffer,
+ (Merge_chunk *) file_ptrs.buffer + file_ptrs.elements,
action, walk_action_arg,
tree.compare, tree.custom_arg, &file, with_counters);
}
@@ -684,16 +694,18 @@ bool Unique::walk(TABLE *table, tree_walk_action action, void *walk_action_arg)
All params are 'IN':
table the parameter to access sort context
buff merge buffer
+ buff_size size of merge buffer
without_last_merge TRUE <=> do not perform the last merge
RETURN VALUE
0 OK
<> 0 error
*/
-bool Unique::merge(TABLE *table, uchar *buff, bool without_last_merge)
+bool Unique::merge(TABLE *table, uchar *buff, size_t buff_size,
+ bool without_last_merge)
{
IO_CACHE *outfile= &sort.io_cache;
- BUFFPEK *file_ptr= (BUFFPEK*) file_ptrs.buffer;
+ Merge_chunk *file_ptr= (Merge_chunk*) file_ptrs.buffer;
uint maxbuffer= file_ptrs.elements - 1;
my_off_t save_pos;
bool error= 1;
@@ -724,7 +736,9 @@ bool Unique::merge(TABLE *table, uchar *buff, bool without_last_merge)
sort_param.cmp_context.key_compare_arg= tree.custom_arg;
/* Merge the buffers to one file, removing duplicates */
- if (merge_many_buff(&sort_param,buff,file_ptr,&maxbuffer,&file))
+ if (merge_many_buff(&sort_param,
+ Bounds_checked_array<uchar>(buff, buff_size),
+ file_ptr,&maxbuffer,&file))
goto err;
if (flush_io_cache(&file) ||
reinit_io_cache(&file,READ_CACHE,0L,0,0))
@@ -736,7 +750,8 @@ bool Unique::merge(TABLE *table, uchar *buff, bool without_last_merge)
file_ptrs.elements= maxbuffer+1;
return 0;
}
- if (merge_index(&sort_param, buff, file_ptr, maxbuffer, &file, outfile))
+ if (merge_index(&sort_param, Bounds_checked_array<uchar>(buff, buff_size),
+ file_ptr, maxbuffer, &file, outfile))
goto err;
error= 0;
err:
@@ -768,7 +783,8 @@ bool Unique::get(TABLE *table)
{
/* Whole tree is in memory; Don't use disk if you don't need to */
if ((sort.record_pointers= (uchar*)
- my_malloc(size * tree.elements_in_tree, MYF(MY_THREAD_SPECIFIC))))
+ my_malloc(key_memory_Filesort_info_record_pointers,
+ size * tree.elements_in_tree, MYF(MY_THREAD_SPECIFIC))))
{
uchar *save_record_pointers= sort.record_pointers;
tree_walk_action action= min_dupl_count ?
@@ -787,11 +803,11 @@ bool Unique::get(TABLE *table)
if (flush())
DBUG_RETURN(1);
size_t buff_sz= (max_in_memory_size / full_size + 1) * full_size;
- if (!(sort_buffer= (uchar*) my_malloc(buff_sz,
+ if (!(sort_buffer= (uchar*) my_malloc(key_memory_Unique_sort_buffer, buff_sz,
MYF(MY_THREAD_SPECIFIC|MY_WME))))
DBUG_RETURN(1);
- if (merge(table, sort_buffer, FALSE))
+ if (merge(table, sort_buffer, buff_sz, FALSE))
goto err;
rc= 0;
diff --git a/sql/uniques.h b/sql/uniques.h
index 7cdf6607dd0..663d5c1682a 100644
--- a/sql/uniques.h
+++ b/sql/uniques.h
@@ -45,7 +45,7 @@ class Unique :public Sql_alloc
always 0 for unions, > 0 for intersections */
bool with_counters;
- bool merge(TABLE *table, uchar *buff, bool without_last_merge);
+ bool merge(TABLE *table, uchar *buff, size_t size, bool without_last_merge);
bool flush();
public:
diff --git a/sql/unireg.cc b/sql/unireg.cc
index a1605dac2e6..2aa46131efb 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -152,6 +152,80 @@ static size_t extra2_str_size(size_t len)
return (len > 255 ? 3 : 1) + len;
}
+
+static uint gis_field_options_image(uchar *buff,
+ List<Create_field> &create_fields)
+{
+ uint image_size= 0;
+ List_iterator<Create_field> it(create_fields);
+ Create_field *field;
+ while ((field= it++))
+ {
+ if (field->real_field_type() != MYSQL_TYPE_GEOMETRY)
+ continue;
+ uchar *cbuf= buff ? buff + image_size : NULL;
+ image_size+= field->type_handler()->
+ Column_definition_gis_options_image(cbuf, *field);
+ }
+ return image_size;
+}
+
+
+class Field_data_type_info_image: public BinaryStringBuffer<512>
+{
+ static uchar *store_length(uchar *pos, ulonglong length)
+ {
+ return net_store_length(pos, length);
+ }
+ static uchar *store_string(uchar *pos, const LEX_CSTRING &str)
+ {
+ pos= store_length(pos, str.length);
+ memcpy(pos, str.str, str.length);
+ return pos + str.length;
+ }
+ static uint store_length_required_length(ulonglong length)
+ {
+ return net_length_size(length);
+ }
+public:
+ Field_data_type_info_image() { }
+ bool append(uint fieldnr, const Column_definition &def)
+ {
+ BinaryStringBuffer<64> type_info;
+ if (def.type_handler()->
+ Column_definition_data_type_info_image(&type_info, def) ||
+ type_info.length() > 0xFFFF/*Some reasonable limit*/)
+ return true; // Error
+ if (!type_info.length())
+ return false;
+ size_t need_length= store_length_required_length(fieldnr) +
+ store_length_required_length(type_info.length()) +
+ type_info.length();
+ if (reserve(need_length))
+ return true; // Error
+ uchar *pos= (uchar *) end();
+ pos= store_length(pos, fieldnr);
+ pos= store_string(pos, type_info.lex_cstring());
+ size_t new_length= (const char *) pos - ptr();
+ DBUG_ASSERT(new_length < alloced_length());
+ length((uint32) new_length);
+ return false;
+ }
+ bool append(List<Create_field> &fields)
+ {
+ uint fieldnr= 0;
+ Create_field *field;
+ List_iterator<Create_field> it(fields);
+ for (field= it++; field; field= it++, fieldnr++)
+ {
+ if (append(fieldnr, *field))
+ return true; // Error
+ }
+ return false;
+ }
+};
+
+
/**
Create a frm (table definition) file
@@ -191,6 +265,7 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
uchar *frm_ptr, *pos;
LEX_CUSTRING frm= {0,0};
StringBuffer<MAX_FIELD_WIDTH> vcols;
+ Field_data_type_info_image field_data_type_info_image;
DBUG_ENTER("build_frm_image");
/* If fixed row records, we need one bit to check for deleted rows */
@@ -241,11 +316,25 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
options_len= engine_table_options_frm_length(create_info->option_list,
create_fields,
keys, key_info);
-#ifdef HAVE_SPATIAL
gis_extra2_len= gis_field_options_image(NULL, create_fields);
-#endif /*HAVE_SPATIAL*/
DBUG_PRINT("info", ("Options length: %u", options_len));
+ if (field_data_type_info_image.append(create_fields))
+ {
+ my_printf_error(ER_CANT_CREATE_TABLE,
+ "Cannot create table %`s: "
+ "Building the field data type info image failed.",
+ MYF(0), table.str);
+ DBUG_RETURN(frm);
+ }
+ DBUG_PRINT("info", ("Field data type info length: %u",
+ (uint) field_data_type_info_image.length()));
+ DBUG_EXECUTE_IF("frm_data_type_info",
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_UNKNOWN_ERROR,
+ "build_frm_image: Field data type info length: %u",
+ (uint) field_data_type_info_image.length()););
+
if (validate_comment_length(thd, &create_info->comment, TABLE_COMMENT_MAXLEN,
ER_TOO_LONG_TABLE_COMMENT, table.str))
DBUG_RETURN(frm);
@@ -291,6 +380,9 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
if (gis_extra2_len)
extra2_size+= 1 + extra2_str_size(gis_extra2_len);
+ if (field_data_type_info_image.length())
+ extra2_size+= 1 + extra2_str_size(field_data_type_info_image.length());
+
if (create_info->versioned())
{
extra2_size+= 1 + extra2_str_size(2 * frm_fieldno_size);
@@ -333,8 +425,8 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
DBUG_RETURN(frm);
}
- frm_ptr= (uchar*) my_malloc(frm.length, MYF(MY_WME | MY_ZEROFILL |
- MY_THREAD_SPECIFIC));
+ frm_ptr= (uchar*) my_malloc(PSI_INSTRUMENT_ME, frm.length,
+ MYF(MY_WME | MY_ZEROFILL | MY_THREAD_SPECIFIC));
if (!frm_ptr)
DBUG_RETURN(frm);
@@ -356,14 +448,28 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
create_fields, keys, key_info);
}
-#ifdef HAVE_SPATIAL
if (gis_extra2_len)
{
*pos= EXTRA2_GIS;
pos= extra2_write_len(pos+1, gis_extra2_len);
pos+= gis_field_options_image(pos, create_fields);
}
-#endif /*HAVE_SPATIAL*/
+
+ if (field_data_type_info_image.length())
+ {
+ if (field_data_type_info_image.length() > 0xFFFF)
+ {
+ my_printf_error(ER_CANT_CREATE_TABLE,
+ "Cannot create table %`s: "
+ "field data type info image is too large. "
+ "Decrease the number of columns with "
+ "extended data types.",
+ MYF(0), table.str);
+ goto err;
+ }
+ *pos= EXTRA2_FIELD_DATA_TYPE_INFO;
+ pos= extra2_write_str(pos + 1, field_data_type_info_image.lex_cstring());
+ }
// PERIOD
if (create_info->period_info.is_set())
@@ -723,6 +829,7 @@ static bool pack_header(THD *thd, uchar *forminfo,
if (field->charset->mbminlen > 1)
{
+ TYPELIB *tmpint;
/*
Escape UCS2 intervals using HEX notation to avoid
problems with delimiters between enum elements.
@@ -731,16 +838,17 @@ static bool pack_header(THD *thd, uchar *forminfo,
filled with default values it is saved in save_interval
The HEX representation is created from this copy.
*/
+ uint count= field->interval->count;
field->save_interval= field->interval;
- field->interval= (TYPELIB*) thd->alloc(sizeof(TYPELIB));
- *field->interval= *field->save_interval;
- field->interval->type_names=
- (const char **) thd->alloc(sizeof(char*) *
- (field->interval->count+1));
- field->interval->type_names[field->interval->count]= 0;
- field->interval->type_lengths=
- (uint *) thd->alloc(sizeof(uint) * field->interval->count);
-
+ field->interval= tmpint= (TYPELIB*) thd->alloc(sizeof(TYPELIB));
+ *tmpint= *field->save_interval;
+ tmpint->type_names=
+ (const char **) thd->alloc(sizeof(char*) *
+ (count + 1));
+ tmpint->type_lengths= (uint *) thd->alloc(sizeof(uint) * (count + 1));
+ tmpint->type_names[count]= 0;
+ tmpint->type_lengths[count]= 0;
+
for (uint pos= 0; pos < field->interval->count; pos++)
{
char *dst;
@@ -748,9 +856,8 @@ static bool pack_header(THD *thd, uchar *forminfo,
size_t hex_length;
length= field->save_interval->type_lengths[pos];
hex_length= length * 2;
- field->interval->type_lengths[pos]= (uint)hex_length;
- field->interval->type_names[pos]= dst=
- (char*) thd->alloc(hex_length + 1);
+ tmpint->type_lengths[pos]= (uint) hex_length;
+ tmpint->type_names[pos]= dst= (char*) thd->alloc(hex_length + 1);
octet2hex(dst, src, length);
}
}
@@ -814,7 +921,7 @@ static uint get_interval_id(uint *int_count,List<Create_field> &create_fields,
{
List_iterator<Create_field> it(create_fields);
Create_field *field;
- TYPELIB *interval=last_field->interval;
+ const TYPELIB *interval= last_field->interval;
while ((field=it++) != last_field)
{
diff --git a/sql/unireg.h b/sql/unireg.h
index 8e9fa27ea6a..419fbc4bd80 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -176,7 +176,8 @@ enum extra2_frm_value_type {
#define EXTRA2_ENGINE_IMPORTANT 128
EXTRA2_ENGINE_TABLEOPTS=128,
- EXTRA2_FIELD_FLAGS=129
+ EXTRA2_FIELD_FLAGS=129,
+ EXTRA2_FIELD_DATA_TYPE_INFO=130
};
enum extra2_field_flags {
diff --git a/sql/upgrade_conf_file.cc b/sql/upgrade_conf_file.cc
index 4e167f0263f..7951fac1a4f 100644
--- a/sql/upgrade_conf_file.cc
+++ b/sql/upgrade_conf_file.cc
@@ -115,10 +115,15 @@ static const char *removed_variables[] =
"innodb_use_trim",
"log",
"log_slow_queries",
+"max_long_data_size",
+"multi_range_count",
"rpl_recovery_rank",
+"skip_bdb",
"sql_big_tables",
"sql_low_priority_updates",
-"sql_max_join_size"
+"sql_max_join_size",
+"thread_concurrency",
+"timed_mutexes"
};
diff --git a/sql/vers_string.h b/sql/vers_string.h
index 2349cc0cac1..4e173f86e6e 100644
--- a/sql/vers_string.h
+++ b/sql/vers_string.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2018, MariaDB Corporation.
+ Copyright (c) 2018, 2020, 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
@@ -17,6 +17,8 @@
#ifndef VERS_STRING_INCLUDED
#define VERS_STRING_INCLUDED
+#include "lex_string.h"
+
/*
LEX_CSTRING with comparison semantics.
*/
@@ -28,9 +30,8 @@ struct Compare_table_names
{
DBUG_ASSERT(a.str[a.length] == 0);
DBUG_ASSERT(b.str[b.length] == 0);
- return my_strnncoll(table_alias_charset,
- (uchar*)a.str, a.length,
- (uchar*)b.str, b.length);
+ return table_alias_charset->strnncoll(a.str, a.length,
+ b.str, b.length);
}
};
@@ -45,31 +46,6 @@ struct Compare_identifiers
}
};
-class Lex_cstring : public LEX_CSTRING
-{
- public:
- Lex_cstring()
- {
- str= NULL;
- length= 0;
- }
- Lex_cstring(const char *_str, size_t _len)
- {
- str= _str;
- length= _len;
- }
- Lex_cstring(const char *start, const char *end)
- {
- DBUG_ASSERT(start <= end);
- str= start;
- length= end - start;
- }
- void set(const char *_str, size_t _len)
- {
- str= _str;
- length= _len;
- }
-};
template <class Compare>
struct Lex_cstring_with_compare : public Lex_cstring
diff --git a/sql/vers_utils.h b/sql/vers_utils.h
deleted file mode 100644
index 2bea191da9e..00000000000
--- a/sql/vers_utils.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef VERS_UTILS_INCLUDED
-#define VERS_UTILS_INCLUDED
-
-#include "table.h"
-#include "sql_class.h"
-#include "vers_string.h"
-
-#endif // VERS_UTILS_INCLUDED
diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc
index fd51dbf9439..25a4e22aeb4 100644
--- a/sql/wsrep_applier.cc
+++ b/sql/wsrep_applier.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013-2015 Codership Oy <info@codership.com>
+/* Copyright (C) 2013-2019 Codership Oy <info@codership.com>
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
@@ -24,7 +24,6 @@
#include "wsrep_trans_observer.h"
#include "slave.h" // opt_log_slave_updates
-#include "log_event.h" // class THD, EVENT_LEN_OFFSET, etc.
#include "debug_sync.h"
/*
@@ -60,7 +59,6 @@ static Log_event* wsrep_read_log_event(
}
#include "transaction.h" // trans_commit(), trans_rollback()
-#include "rpl_rli.h" // class Relay_log_info;
void wsrep_set_apply_format(THD* thd, Format_description_log_event* ev)
{
@@ -84,7 +82,7 @@ wsrep_get_apply_format(THD* thd)
return thd->wsrep_rgi->rli->relay_log.description_event_for_exec;
}
-void wsrep_apply_error::store(const THD* const thd)
+void wsrep_store_error(const THD* const thd, wsrep::mutable_buffer& dst)
{
Diagnostics_area::Sql_condition_iterator it=
thd->get_stmt_da()->sql_conditions();
@@ -92,27 +90,10 @@ void wsrep_apply_error::store(const THD* const thd)
static size_t const max_len= 2*MAX_SLAVE_ERRMSG; // 2x so that we have enough
- if (NULL == str_)
- {
- // this must be freeable by standard free()
- str_= static_cast<char*>(malloc(max_len));
- if (NULL == str_)
- {
- WSREP_ERROR("Failed to allocate %zu bytes for error buffer.", max_len);
- len_= 0;
- return;
- }
- }
- else
- {
- /* This is possible when we invoke rollback after failed applying.
- * In this situation DA should not be reset yet and should contain
- * all previous errors from applying and new ones from rollbacking,
- * so we just overwrite is from scratch */
- }
+ dst.resize(max_len);
- char* slider= str_;
- const char* const buf_end= str_ + max_len - 1; // -1: leave space for \0
+ char* slider= dst.data();
+ const char* const buf_end= slider + max_len - 1; // -1: leave space for \0
for (cond= it++; cond && slider < buf_end; cond= it++)
{
@@ -123,12 +104,17 @@ void wsrep_apply_error::store(const THD* const thd)
err_str, err_code);
}
- *slider= '\0';
- len_= slider - str_ + 1; // +1: add \0
+ if (slider != dst.data())
+ {
+ *slider= '\0';
+ slider++;
+ }
+
+ dst.resize(slider - dst.data());
- WSREP_DEBUG("Error buffer for thd %llu seqno %lld, %zu bytes: %s",
+ WSREP_DEBUG("Error buffer for thd %llu seqno %lld, %zu bytes: '%s'",
thd->thread_id, (long long)wsrep_thd_trx_seqno(thd),
- len_, str_ ? str_ : "(null)");
+ dst.size(), dst.size() ? dst.data() : "(null)");
}
int wsrep_apply_events(THD* thd,
@@ -145,6 +131,12 @@ int wsrep_apply_events(THD* thd,
if (!buf_len) WSREP_DEBUG("empty rbr buffer to apply: %lld",
(long long) wsrep_thd_trx_seqno(thd));
+ thd->variables.gtid_seq_no= 0;
+ if (wsrep_gtid_mode)
+ thd->variables.gtid_domain_id= wsrep_gtid_server.domain_id;
+ else
+ thd->variables.gtid_domain_id= global_system_variables.gtid_domain_id;
+
while (buf_len)
{
int exec_res;
@@ -164,22 +156,38 @@ int wsrep_apply_events(THD* thd,
case FORMAT_DESCRIPTION_EVENT:
wsrep_set_apply_format(thd, (Format_description_log_event*)ev);
continue;
-#ifdef GTID_SUPPORT
- case GTID_LOG_EVENT:
- {
- Gtid_log_event* gev= (Gtid_log_event*)ev;
- if (gev->get_gno() == 0)
+ case GTID_EVENT:
{
- /* Skip GTID log event to make binlog to generate LTID on commit */
+ Gtid_log_event *gtid_ev= (Gtid_log_event*)ev;
+ thd->variables.server_id= gtid_ev->server_id;
+ thd->variables.gtid_domain_id= gtid_ev->domain_id;
+ if ((gtid_ev->server_id == wsrep_gtid_server.server_id) &&
+ (gtid_ev->domain_id == wsrep_gtid_server.domain_id))
+ {
+ thd->variables.wsrep_gtid_seq_no= gtid_ev->seq_no;
+ }
+ else
+ {
+ thd->variables.gtid_seq_no= gtid_ev->seq_no;
+ }
delete ev;
- continue;
}
- }
-#endif /* GTID_SUPPORT */
+ continue;
default:
break;
}
+
+ if (!thd->variables.gtid_seq_no && wsrep_thd_is_toi(thd) &&
+ (ev->get_type_code() == QUERY_EVENT))
+ {
+ uint64 seqno= wsrep_gtid_server.seqno_inc();
+ thd->wsrep_current_gtid_seqno= seqno;
+ if (mysql_bin_log.is_open() && wsrep_gtid_mode)
+ {
+ thd->variables.gtid_seq_no= seqno;
+ }
+ }
/* Use the original server id for logging. */
thd->set_server_id(ev->server_id);
thd->set_time(); // time the query
diff --git a/sql/wsrep_applier.h b/sql/wsrep_applier.h
index 70361987cc7..fefca306a70 100644
--- a/sql/wsrep_applier.h
+++ b/sql/wsrep_applier.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2015 Codership Oy <http://www.codership.com>
+/* Copyright 2013-2019 Codership Oy <http://www.codership.com>
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
@@ -16,16 +16,15 @@
#ifndef WSREP_APPLIER_H
#define WSREP_APPLIER_H
-#include <my_config.h>
-
#include "sql_class.h" // THD class
+#include "rpl_rli.h" // Relay_log_info
+#include "log_event.h" // Format_description_log_event
int wsrep_apply_events(THD* thd,
Relay_log_info* rli,
const void* events_buf,
size_t buf_len);
-
/* Applier error codes, when nothing better is available. */
#define WSREP_RET_SUCCESS 0 // Success
#define WSREP_ERR_GENERIC 1 // When in doubt (MySQL default error code)
@@ -36,38 +35,10 @@ int wsrep_apply_events(THD* thd,
#define WSREP_ERR_FAILED 6 // Operation failed for some internal reason
#define WSREP_ERR_ABORTED 7 // Operation was aborted externally
-class wsrep_apply_error
-{
-public:
- wsrep_apply_error() : str_(NULL), len_(0) {};
- ~wsrep_apply_error() { ::free(str_); }
- /* stores the current THD error info from the diagnostic area. Works only
- * once, subsequent invocations are ignored in order to preserve the original
- * condition. */
- void store(const THD* thd);
- const char* c_str() const { return str_; }
- size_t length() const { return len_; }
- bool is_null() const { return (c_str() == NULL && length() == 0); }
- wsrep_buf_t get_buf() const
- {
- wsrep_buf_t ret= { c_str(), length() };
- return ret;
- }
-private:
- char* str_;
- size_t len_;
-};
+void wsrep_store_error(const THD* thd, wsrep::mutable_buffer& buf);
class Format_description_log_event;
void wsrep_set_apply_format(THD*, Format_description_log_event*);
Format_description_log_event* wsrep_get_apply_format(THD* thd);
-int wsrep_apply(void* ctx,
- uint32_t flags,
- const wsrep_buf_t* buf,
- const wsrep_trx_meta_t* meta,
- wsrep_apply_error& err);
-
-wsrep_cb_status_t wsrep_unordered_cb(void* ctx,
- const wsrep_buf_t* data);
#endif /* WSREP_APPLIER_H */
diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc
index 787ebc042ae..da899321ba8 100644
--- a/sql/wsrep_binlog.cc
+++ b/sql/wsrep_binlog.cc
@@ -64,7 +64,7 @@ int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len)
wsrep_max_ws_size, total_length);
goto error;
}
- uchar* tmp= (uchar *)my_realloc(*buf, total_length,
+ uchar* tmp= (uchar *)my_realloc(PSI_INSTRUMENT_ME, *buf, total_length,
MYF(MY_ALLOW_ZERO_PTR));
if (!tmp)
{
@@ -381,7 +381,9 @@ void wsrep_register_for_group_commit(THD *thd)
void wsrep_unregister_from_group_commit(THD *thd)
{
- DBUG_ASSERT(thd->wsrep_trx().state() == wsrep::transaction::s_ordered_commit);
+ DBUG_ASSERT(thd->wsrep_trx().state() == wsrep::transaction::s_ordered_commit||
+ // ordered_commit() failure results in s_aborting state
+ thd->wsrep_trx().state() == wsrep::transaction::s_aborting);
wait_for_commit *wfc= thd->wait_for_commit_ptr;
if (wfc)
diff --git a/sql/wsrep_client_service.cc b/sql/wsrep_client_service.cc
index 20bb7748a95..696a097db21 100644
--- a/sql/wsrep_client_service.cc
+++ b/sql/wsrep_client_service.cc
@@ -15,7 +15,6 @@
#include "wsrep_client_service.h"
#include "wsrep_high_priority_service.h"
-#include "wsrep_applier.h" /* wsrep_apply_events() */
#include "wsrep_binlog.h" /* wsrep_dump_rbr_buf() */
#include "wsrep_schema.h" /* remove_fragments() */
#include "wsrep_thd.h"
diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc
index ac55dc5c843..ffc6acc8bd9 100644
--- a/sql/wsrep_dummy.cc
+++ b/sql/wsrep_dummy.cc
@@ -138,3 +138,11 @@ void wsrep_commit_ordered(THD* )
my_bool wsrep_thd_is_applying(const THD*)
{ return 0;}
+
+my_bool wsrep_thd_has_ignored_error(const THD*)
+{ return 0;}
+
+void wsrep_thd_set_ignored_error(THD*, my_bool)
+{ }
+ulong wsrep_OSU_method_get(const THD*)
+{ return 0;} \ No newline at end of file
diff --git a/sql/wsrep_high_priority_service.cc b/sql/wsrep_high_priority_service.cc
index ef9a46f1a8e..d73b9cb09ce 100644
--- a/sql/wsrep_high_priority_service.cc
+++ b/sql/wsrep_high_priority_service.cc
@@ -119,6 +119,23 @@ static void wsrep_setup_uk_and_fk_checks(THD* thd)
thd->variables.option_bits&= ~OPTION_NO_FOREIGN_KEY_CHECKS;
}
+static int apply_events(THD* thd,
+ Relay_log_info* rli,
+ const wsrep::const_buffer& data,
+ wsrep::mutable_buffer& err)
+{
+ int const ret= wsrep_apply_events(thd, rli, data.data(), data.size());
+ if (ret || wsrep_thd_has_ignored_error(thd))
+ {
+ if (ret)
+ {
+ wsrep_store_error(thd, err);
+ }
+ wsrep_dump_rbr_buf_with_header(thd, data.data(), data.size());
+ }
+ return ret;
+}
+
/****************************************************************************
High priority service
*****************************************************************************/
@@ -254,8 +271,8 @@ int Wsrep_high_priority_service::append_fragment_and_commit(
common utility function to deal with commit.
*/
const bool do_binlog_commit= (opt_log_slave_updates &&
- wsrep_gtid_mode &&
- m_thd->variables.gtid_seq_no);
+ wsrep_gtid_mode &&
+ m_thd->variables.gtid_seq_no);
/*
Write skip event into binlog if gtid_mode is on. This is to
maintain gtid continuity.
@@ -272,8 +289,7 @@ int Wsrep_high_priority_service::append_fragment_and_commit(
}
ret= ret || trans_commit(m_thd);
-
- m_thd->wsrep_cs().after_applying();
+ ret= ret || (m_thd->wsrep_cs().after_applying(), 0);
m_thd->mdl_context.release_transactional_locks();
thd_proc_info(m_thd, "wsrep applier committed");
@@ -342,7 +358,15 @@ int Wsrep_high_priority_service::rollback(const wsrep::ws_handle& ws_handle,
const wsrep::ws_meta& ws_meta)
{
DBUG_ENTER("Wsrep_high_priority_service::rollback");
- m_thd->wsrep_cs().prepare_for_ordering(ws_handle, ws_meta, false);
+ if (ws_meta.ordered())
+ {
+ m_thd->wsrep_cs().prepare_for_ordering(ws_handle, ws_meta, false);
+ }
+ else
+ {
+ assert(ws_meta == wsrep::ws_meta());
+ assert(ws_handle == wsrep::ws_handle());
+ }
int ret= (trans_rollback_stmt(m_thd) || trans_rollback(m_thd));
m_thd->mdl_context.release_transactional_locks();
m_thd->mdl_context.release_explicit_locks();
@@ -351,7 +375,7 @@ int Wsrep_high_priority_service::rollback(const wsrep::ws_handle& ws_handle,
int Wsrep_high_priority_service::apply_toi(const wsrep::ws_meta& ws_meta,
const wsrep::const_buffer& data,
- wsrep::mutable_buffer&)
+ wsrep::mutable_buffer& err)
{
DBUG_ENTER("Wsrep_high_priority_service::apply_toi");
THD* thd= m_thd;
@@ -365,19 +389,15 @@ int Wsrep_high_priority_service::apply_toi(const wsrep::ws_meta& ws_meta,
WSREP_DEBUG("Wsrep_high_priority_service::apply_toi: %lld",
client_state.toi_meta().seqno().get());
- int ret= wsrep_apply_events(thd, m_rli, data.data(), data.size());
- if (ret != 0 || thd->wsrep_has_ignored_error)
- {
- wsrep_dump_rbr_buf_with_header(thd, data.data(), data.size());
- thd->wsrep_has_ignored_error= false;
- /* todo: error voting */
- }
+ int ret= apply_events(thd, m_rli, data, err);
+ wsrep_thd_set_ignored_error(thd, false);
trans_commit(thd);
thd->close_temporary_tables();
thd->lex->sql_command= SQLCOM_END;
- wsrep_set_SE_checkpoint(client_state.toi_meta().gtid());
+ wsrep_gtid_server.signal_waiters(thd->wsrep_current_gtid_seqno, false);
+ wsrep_set_SE_checkpoint(client_state.toi_meta().gtid(), wsrep_gtid_server.gtid());
must_exit_= check_exit_status();
@@ -429,13 +449,18 @@ int Wsrep_high_priority_service::log_dummy_write_set(const wsrep::ws_handle& ws_
cs.before_rollback();
cs.after_rollback();
}
- wsrep_set_SE_checkpoint(ws_meta.gtid());
+ wsrep_set_SE_checkpoint(ws_meta.gtid(), wsrep_gtid_server.gtid());
ret= ret || cs.provider().commit_order_leave(ws_handle, ws_meta, err);
cs.after_applying();
}
DBUG_RETURN(ret);
}
+void Wsrep_high_priority_service::adopt_apply_error(wsrep::mutable_buffer& err)
+{
+ m_thd->wsrep_cs().adopt_apply_error(err);
+}
+
void Wsrep_high_priority_service::debug_crash(const char* crash_point)
{
DBUG_ASSERT(m_thd == current_thd);
@@ -467,7 +492,7 @@ Wsrep_applier_service::~Wsrep_applier_service()
int Wsrep_applier_service::apply_write_set(const wsrep::ws_meta& ws_meta,
const wsrep::const_buffer& data,
- wsrep::mutable_buffer&)
+ wsrep::mutable_buffer& err)
{
DBUG_ENTER("Wsrep_applier_service::apply_write_set");
THD* thd= m_thd;
@@ -493,13 +518,7 @@ int Wsrep_applier_service::apply_write_set(const wsrep::ws_meta& ws_meta,
};);
wsrep_setup_uk_and_fk_checks(thd);
-
- int ret= wsrep_apply_events(thd, m_rli, data.data(), data.size());
-
- if (ret || thd->wsrep_has_ignored_error)
- {
- wsrep_dump_rbr_buf_with_header(thd, data.data(), data.size());
- }
+ int ret= apply_events(thd, m_rli, data, err);
thd->close_temporary_tables();
if (!ret && !(ws_meta.flags() & wsrep::provider::flag::commit))
@@ -631,7 +650,7 @@ Wsrep_replayer_service::~Wsrep_replayer_service()
int Wsrep_replayer_service::apply_write_set(const wsrep::ws_meta& ws_meta,
const wsrep::const_buffer& data,
- wsrep::mutable_buffer&)
+ wsrep::mutable_buffer& err)
{
DBUG_ENTER("Wsrep_replayer_service::apply_write_set");
THD* thd= m_thd;
@@ -650,14 +669,7 @@ int Wsrep_replayer_service::apply_write_set(const wsrep::ws_meta& ws_meta,
ws_meta,
thd->wsrep_sr().fragments());
}
-
- ret= ret || wsrep_apply_events(thd, m_rli, data.data(), data.size());
-
- if (ret || thd->wsrep_has_ignored_error)
- {
- wsrep_dump_rbr_buf_with_header(thd, data.data(), data.size());
- }
-
+ ret= ret || apply_events(thd, m_rli, data, err);
thd->close_temporary_tables();
if (!ret && !(ws_meta.flags() & wsrep::provider::flag::commit))
{
diff --git a/sql/wsrep_high_priority_service.h b/sql/wsrep_high_priority_service.h
index 2c61f0126af..c275c352de2 100644
--- a/sql/wsrep_high_priority_service.h
+++ b/sql/wsrep_high_priority_service.h
@@ -17,7 +17,6 @@
#define WSREP_HIGH_PRIORITY_SERVICE_H
#include "wsrep/high_priority_service.hpp"
-#include "wsrep/client_state.hpp"
#include "my_global.h"
#include "sql_error.h" /* Diagnostics area */
#include "sql_class.h" /* rpl_group_info */
@@ -55,7 +54,7 @@ public:
int log_dummy_write_set(const wsrep::ws_handle&,
const wsrep::ws_meta&,
wsrep::mutable_buffer&);
- void adopt_apply_error(wsrep::mutable_buffer& err) {}
+ void adopt_apply_error(wsrep::mutable_buffer&);
virtual bool check_exit_status() const = 0;
void debug_crash(const char*);
@@ -76,7 +75,7 @@ protected:
my_hrtime_t user_time;
longlong row_count_func;
bool wsrep_applier;
-} m_shadow;
+ } m_shadow;
};
class Wsrep_applier_service : public Wsrep_high_priority_service
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index 6692e8c4ef0..99e8f0a52ec 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -52,11 +52,7 @@
/* wsrep-lib */
Wsrep_server_state* Wsrep_server_state::m_instance;
-my_bool wsrep_emulate_bin_log = FALSE; // activating parts of binlog interface
-#ifdef GTID_SUPPORT
-/* Sidno in global_sid_map corresponding to group uuid */
-rpl_sidno wsrep_sidno= -1;
-#endif /* GTID_SUPPORT */
+my_bool wsrep_emulate_bin_log= FALSE; // activating parts of binlog interface
my_bool wsrep_preordered_opt= FALSE;
/* Streaming Replication */
@@ -100,16 +96,18 @@ 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
// cluster
+my_bool wsrep_strict_ddl; // Reject DDL to
+ // effected tables not
+ // supporting Galera replication
long wsrep_slave_threads; // No. of slave appliers threads
ulong wsrep_retry_autocommit; // Retry aborted autocommit trx
ulong wsrep_max_ws_size; // Max allowed ws (RBR buffer) size
ulong wsrep_max_ws_rows; // Max number of rows in ws
ulong wsrep_forced_binlog_format;
ulong wsrep_mysql_replication_bundle;
-bool wsrep_gtid_mode; // Use wsrep_gtid_domain_id
- // for galera transactions?
-uint32 wsrep_gtid_domain_id; // gtid_domain_id for galera
- // transactions
+
+bool wsrep_gtid_mode; // Enable WSREP native GTID support
+Wsrep_gtid_server wsrep_gtid_server;
/* Other configuration variables and their default values. */
my_bool wsrep_incremental_data_collection= 0; // Incremental data collection
@@ -144,6 +142,7 @@ mysql_mutex_t LOCK_wsrep_replaying;
mysql_cond_t COND_wsrep_replaying;
mysql_mutex_t LOCK_wsrep_slave_threads;
mysql_cond_t COND_wsrep_slave_threads;
+mysql_mutex_t LOCK_wsrep_gtid_wait_upto;
mysql_mutex_t LOCK_wsrep_cluster_config;
mysql_mutex_t LOCK_wsrep_desync;
mysql_mutex_t LOCK_wsrep_config_state;
@@ -167,7 +166,8 @@ ulong my_bind_addr;
PSI_mutex_key
key_LOCK_wsrep_replaying, key_LOCK_wsrep_ready, key_LOCK_wsrep_sst,
key_LOCK_wsrep_sst_thread, key_LOCK_wsrep_sst_init,
- key_LOCK_wsrep_slave_threads, key_LOCK_wsrep_desync,
+ key_LOCK_wsrep_slave_threads, key_LOCK_wsrep_gtid_wait_upto,
+ key_LOCK_wsrep_desync,
key_LOCK_wsrep_config_state, key_LOCK_wsrep_cluster_config,
key_LOCK_wsrep_group_commit,
key_LOCK_wsrep_SR_pool,
@@ -179,7 +179,7 @@ PSI_mutex_key
PSI_cond_key key_COND_wsrep_thd,
key_COND_wsrep_replaying, key_COND_wsrep_ready, key_COND_wsrep_sst,
key_COND_wsrep_sst_init, key_COND_wsrep_sst_thread,
- key_COND_wsrep_thd_queue, key_COND_wsrep_slave_threads,
+ key_COND_wsrep_thd_queue, key_COND_wsrep_slave_threads, key_COND_wsrep_gtid_wait_upto,
key_COND_wsrep_joiner_monitor, key_COND_wsrep_donor_monitor;
PSI_file_key key_file_wsrep_gra_log;
@@ -193,6 +193,7 @@ static PSI_mutex_info wsrep_mutexes[]=
{ &key_LOCK_wsrep_sst, "LOCK_wsrep_sst", PSI_FLAG_GLOBAL},
{ &key_LOCK_wsrep_replaying, "LOCK_wsrep_replaying", PSI_FLAG_GLOBAL},
{ &key_LOCK_wsrep_slave_threads, "LOCK_wsrep_slave_threads", PSI_FLAG_GLOBAL},
+ { &key_LOCK_wsrep_gtid_wait_upto, "LOCK_wsrep_gtid_wait_upto", PSI_FLAG_GLOBAL},
{ &key_LOCK_wsrep_cluster_config, "LOCK_wsrep_cluster_config", PSI_FLAG_GLOBAL},
{ &key_LOCK_wsrep_desync, "LOCK_wsrep_desync", PSI_FLAG_GLOBAL},
{ &key_LOCK_wsrep_config_state, "LOCK_wsrep_config_state", PSI_FLAG_GLOBAL},
@@ -212,6 +213,7 @@ static PSI_cond_info wsrep_conds[]=
{ &key_COND_wsrep_thd, "THD::COND_wsrep_thd", 0},
{ &key_COND_wsrep_replaying, "COND_wsrep_replaying", PSI_FLAG_GLOBAL},
{ &key_COND_wsrep_slave_threads, "COND_wsrep_wsrep_slave_threads", PSI_FLAG_GLOBAL},
+ { &key_COND_wsrep_gtid_wait_upto, "COND_wsrep_gtid_wait_upto", PSI_FLAG_GLOBAL},
{ &key_COND_wsrep_joiner_monitor, "COND_wsrep_joiner_monitor", PSI_FLAG_GLOBAL},
{ &key_COND_wsrep_donor_monitor, "COND_wsrep_donor_monitor", PSI_FLAG_GLOBAL}
};
@@ -292,7 +294,7 @@ static void wsrep_log_cb(wsrep::log::level level, const char *msg)
sql_print_warning("WSREP: %s", msg);
break;
case wsrep::log::error:
- sql_print_error("WSREP: %s", msg);
+ sql_print_error("WSREP: %s", msg);
break;
case wsrep::log::debug:
if (wsrep_debug) sql_print_information ("[Debug] WSREP: %s", msg);
@@ -302,6 +304,58 @@ static void wsrep_log_cb(wsrep::log::level level, const char *msg)
}
}
+void wsrep_init_gtid()
+{
+ wsrep_server_gtid_t stored_gtid= wsrep_get_SE_checkpoint<wsrep_server_gtid_t>();
+ if (stored_gtid.server_id == 0)
+ {
+ rpl_gtid wsrep_last_gtid;
+ stored_gtid.domain_id= wsrep_gtid_server.domain_id;
+ if (mysql_bin_log.is_open() &&
+ mysql_bin_log.lookup_domain_in_binlog_state(stored_gtid.domain_id,
+ &wsrep_last_gtid))
+ {
+ stored_gtid.server_id= wsrep_last_gtid.server_id;
+ stored_gtid.seqno= wsrep_last_gtid.seq_no;
+ }
+ else
+ {
+ stored_gtid.server_id= global_system_variables.server_id;
+ stored_gtid.seqno= 0;
+ }
+ }
+ wsrep_gtid_server.gtid(stored_gtid);
+}
+
+bool wsrep_get_binlog_gtid_seqno(wsrep_server_gtid_t& gtid)
+{
+ rpl_gtid binlog_gtid;
+ int ret= 0;
+ if (mysql_bin_log.is_open() &&
+ mysql_bin_log.find_in_binlog_state(gtid.domain_id,
+ gtid.server_id,
+ &binlog_gtid))
+ {
+ gtid.domain_id= binlog_gtid.domain_id;
+ gtid.server_id= binlog_gtid.server_id;
+ gtid.seqno= binlog_gtid.seq_no;
+ ret= 1;
+ }
+ return ret;
+}
+
+bool wsrep_check_gtid_seqno(const uint32& domain, const uint32& server,
+ uint64& seqno)
+{
+ if (domain == wsrep_gtid_server.domain_id &&
+ server == wsrep_gtid_server.server_id)
+ {
+ if (wsrep_gtid_server.seqno_committed() < seqno) return 1;
+ return 0;
+ }
+ return 0;
+}
+
void wsrep_init_sidno(const wsrep::id& uuid)
{
/*
@@ -692,6 +746,15 @@ int wsrep_init_server()
void wsrep_init_globals()
{
wsrep_init_sidno(Wsrep_server_state::instance().connected_gtid().id());
+ wsrep_init_gtid();
+ /* Recover last written wsrep gtid */
+ if (wsrep_new_cluster)
+ {
+ wsrep_server_gtid_t gtid= {wsrep_gtid_server.domain_id,
+ wsrep_gtid_server.server_id, 0};
+ wsrep_get_binlog_gtid_seqno(gtid);
+ wsrep_gtid_server.seqno(gtid.seqno);
+ }
wsrep_init_schema();
if (WSREP_ON)
{
@@ -793,6 +856,7 @@ void wsrep_thr_init()
mysql_cond_init(key_COND_wsrep_replaying, &COND_wsrep_replaying, NULL);
mysql_mutex_init(key_LOCK_wsrep_slave_threads, &LOCK_wsrep_slave_threads, MY_MUTEX_INIT_FAST);
mysql_cond_init(key_COND_wsrep_slave_threads, &COND_wsrep_slave_threads, NULL);
+ mysql_mutex_init(key_LOCK_wsrep_gtid_wait_upto, &LOCK_wsrep_gtid_wait_upto, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_wsrep_cluster_config, &LOCK_wsrep_cluster_config, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_wsrep_desync, &LOCK_wsrep_desync, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_wsrep_config_state, &LOCK_wsrep_config_state, MY_MUTEX_INIT_FAST);
@@ -903,6 +967,7 @@ void wsrep_thr_deinit()
mysql_cond_destroy(&COND_wsrep_sst_init);
mysql_mutex_destroy(&LOCK_wsrep_replaying);
mysql_cond_destroy(&COND_wsrep_replaying);
+ mysql_mutex_destroy(&LOCK_wsrep_gtid_wait_upto);
mysql_mutex_destroy(&LOCK_wsrep_slave_threads);
mysql_cond_destroy(&COND_wsrep_slave_threads);
mysql_mutex_destroy(&LOCK_wsrep_cluster_config);
@@ -939,10 +1004,20 @@ void wsrep_recover()
uuid_str, (long long)local_seqno);
return;
}
- wsrep::gtid gtid= wsrep_get_SE_checkpoint();
+ wsrep::gtid gtid= wsrep_get_SE_checkpoint<wsrep::gtid>();
std::ostringstream oss;
oss << gtid;
- WSREP_INFO("Recovered position: %s", oss.str().c_str());
+ if (wsrep_gtid_mode)
+ {
+ wsrep_server_gtid_t server_gtid= wsrep_get_SE_checkpoint<wsrep_server_gtid_t>();
+ WSREP_INFO("Recovered position: %s,%d-%d-%llu", oss.str().c_str(), server_gtid.domain_id,
+ server_gtid.server_id, server_gtid.seqno);
+ }
+ else
+ {
+ WSREP_INFO("Recovered position: %s", oss.str().c_str());
+ }
+
}
@@ -1012,7 +1087,6 @@ bool wsrep_start_replication()
}
bool const bootstrap(TRUE == wsrep_new_cluster);
- wsrep_new_cluster= FALSE;
WSREP_INFO("Start replication");
@@ -1196,7 +1270,7 @@ static bool wsrep_prepare_key_for_isolation(const char* db,
wsrep_key_arr_t* ka)
{
wsrep_key_t* tmp;
- tmp= (wsrep_key_t*)my_realloc(ka->keys,
+ tmp= (wsrep_key_t*)my_realloc(PSI_INSTRUMENT_ME, ka->keys,
(ka->keys_len + 1) * sizeof(wsrep_key_t),
MYF(MY_ALLOW_ZERO_PTR));
if (!tmp)
@@ -1206,7 +1280,7 @@ static bool wsrep_prepare_key_for_isolation(const char* db,
}
ka->keys= tmp;
if (!(ka->keys[ka->keys_len].key_parts= (wsrep_buf_t*)
- my_malloc(sizeof(wsrep_buf_t)*2, MYF(0))))
+ my_malloc(PSI_INSTRUMENT_ME, sizeof(wsrep_buf_t)*2, MYF(0))))
{
WSREP_ERROR("Can't allocate memory for key_parts");
return false;
@@ -1225,11 +1299,11 @@ static bool wsrep_prepare_key_for_isolation(const char* db,
}
static bool wsrep_prepare_keys_for_alter_add_fk(const char* child_table_db,
- Alter_info* alter_info,
+ const Alter_info* alter_info,
wsrep_key_arr_t* ka)
{
Key *key;
- List_iterator<Key> key_iterator(alter_info->key_list);
+ List_iterator<Key> key_iterator(const_cast<Alter_info*>(alter_info)->key_list);
while ((key= key_iterator++))
{
if (key->type == Key::FOREIGN_KEY)
@@ -1365,12 +1439,12 @@ wsrep::key wsrep_prepare_key_for_toi(const char* db, const char* table,
wsrep::key_array
wsrep_prepare_keys_for_alter_add_fk(const char* child_table_db,
- Alter_info* alter_info)
+ const Alter_info* alter_info)
{
wsrep::key_array ret;
Key *key;
- List_iterator<Key> key_iterator(alter_info->key_list);
+ List_iterator<Key> key_iterator(const_cast<Alter_info*>(alter_info)->key_list);
while ((key= key_iterator++))
{
if (key->type == Key::FOREIGN_KEY)
@@ -1392,7 +1466,7 @@ wsrep_prepare_keys_for_alter_add_fk(const char* child_table_db,
wsrep::key_array wsrep_prepare_keys_for_toi(const char* db,
const char* table,
const TABLE_LIST* table_list,
- Alter_info* alter_info)
+ const Alter_info* alter_info)
{
wsrep::key_array ret;
if (db || table)
@@ -1445,16 +1519,36 @@ int wsrep_to_buf_helper(
if (!ret && writer.write(&gtid_ev)) ret= 1;
}
#endif /* GTID_SUPPORT */
- if (wsrep_gtid_mode && thd->variables.gtid_seq_no)
+ /*
+ * Check if this is applier thread, slave_thread or
+ * we have set manually WSREP GTID seqno. Add GTID event.
+ */
+ if (thd->slave_thread || wsrep_thd_is_applying(thd) ||
+ thd->variables.wsrep_gtid_seq_no)
{
- Gtid_log_event gtid_event(thd, thd->variables.gtid_seq_no,
- thd->variables.gtid_domain_id,
- true, LOG_EVENT_SUPPRESS_USE_F,
- true, 0);
- gtid_event.server_id= thd->variables.server_id;
+ uint64 seqno= thd->variables.gtid_seq_no;
+ uint32 domain_id= thd->variables.gtid_domain_id;
+ uint32 server_id= thd->variables.server_id;
+ if (!thd->variables.gtid_seq_no && thd->variables.wsrep_gtid_seq_no)
+ {
+ seqno= thd->variables.wsrep_gtid_seq_no;
+ domain_id= wsrep_gtid_server.domain_id;
+ server_id= wsrep_gtid_server.server_id;
+ }
+ Gtid_log_event gtid_event(thd, seqno, domain_id, true,
+ LOG_EVENT_SUPPRESS_USE_F, true, 0);
+ gtid_event.server_id= server_id;
if (!gtid_event.is_valid()) ret= 0;
ret= writer.write(&gtid_event);
}
+ /*
+ It's local DDL so in case of possible gtid seqno (SET gtid_seq_no=X)
+ manipulation, seqno value will be ignored.
+ */
+ else
+ {
+ thd->variables.gtid_seq_no= 0;
+ }
/* if there is prepare query, add event for it */
if (!ret && thd->wsrep_TOI_pre_query)
@@ -1468,6 +1562,9 @@ int wsrep_to_buf_helper(
/* continue to append the actual query */
Query_log_event ev(thd, query, query_len, FALSE, FALSE, FALSE, 0);
+ /* WSREP GTID mode, we need to change server_id */
+ if (wsrep_gtid_mode && !thd->variables.gtid_seq_no)
+ ev.server_id= wsrep_gtid_server.server_id;
ev.checksum_alg= current_binlog_check_alg;
if (!ret && writer.write(&ev)) ret= 1;
if (!ret && wsrep_write_cache_buf(&tmp_io_cache, buf, buf_len)) ret= 1;
@@ -1641,6 +1738,51 @@ static int wsrep_drop_table_query(THD* thd, uchar** buf, size_t* buf_len)
/* Forward declarations. */
int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len);
+bool wsrep_should_replicate_ddl_iterate(THD* thd, const TABLE_LIST* table_list)
+{
+ if (WSREP(thd))
+ {
+ for (const TABLE_LIST* it= table_list; it; it= it->next_global)
+ {
+ if (!wsrep_should_replicate_ddl(thd, it->table->s->db_type()->db_type))
+ return false;
+ }
+ }
+ return true;
+}
+
+bool wsrep_should_replicate_ddl(THD* thd,
+ const enum legacy_db_type db_type)
+{
+ if (!wsrep_strict_ddl)
+ return true;
+
+ switch (db_type)
+ {
+ case DB_TYPE_INNODB:
+ return true;
+ break;
+ case DB_TYPE_MYISAM:
+ if (wsrep_replicate_myisam)
+ return true;
+ else
+ WSREP_DEBUG("wsrep OSU failed for %s", wsrep_thd_query(thd));
+ break;
+ case DB_TYPE_ARIA:
+ /* if (wsrep_replicate_aria) */
+ /* fallthrough */
+ default:
+ WSREP_DEBUG("wsrep OSU failed for %s", wsrep_thd_query(thd));
+ break;
+ }
+
+ /* STRICT, treat as error */
+ my_error(ER_GALERA_REPLICATION_NOT_SUPPORTED, MYF(0));
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_ILLEGAL_HA,
+ "WSREP: wsrep_strict_ddl=true and storage engine does not support Galera replication.");
+ return false;
+}
/*
Decide if statement should run in TOI.
@@ -1651,24 +1793,28 @@ int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len);
should be rewritten at later time for replication to contain only
non-temporary tables.
*/
-static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
- const TABLE_LIST *table_list)
+bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
+ const TABLE_LIST *table_list,
+ const HA_CREATE_INFO* create_info)
{
DBUG_ASSERT(!table || db);
DBUG_ASSERT(table_list || db);
LEX* lex= thd->lex;
SELECT_LEX* select_lex= lex->first_select_lex();
- TABLE_LIST* first_table= select_lex->table_list.first;
+ const TABLE_LIST* first_table= select_lex->table_list.first;
switch (lex->sql_command)
{
case SQLCOM_CREATE_TABLE:
- DBUG_ASSERT(!table_list);
if (thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
{
return false;
}
+ if (!wsrep_should_replicate_ddl(thd, create_info->db_type->db_type))
+ {
+ return false;
+ }
/*
If mariadb master has replicated a CTAS, we should not replicate the create table
part separately as TOI, but to replicate both create table and following inserts
@@ -1677,7 +1823,8 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
as TOI. We have to do relay log event lookup to see if row events follow the
create table event.
*/
- if (thd->slave_thread && !(thd->rgi_slave->gtid_ev_flags2 & Gtid_log_event::FL_STANDALONE))
+ if (thd->slave_thread &&
+ !(thd->rgi_slave->gtid_ev_flags2 & Gtid_log_event::FL_STANDALONE))
{
/* this is CTAS, either empty or populated table */
ulonglong event_size = 0;
@@ -1703,7 +1850,7 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
}
/* no next async replication event */
return true;
-
+ break;
case SQLCOM_CREATE_VIEW:
DBUG_ASSERT(!table_list);
@@ -1712,7 +1859,7 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
If any of the remaining tables refer to temporary table error
is returned to client, so TOI can be skipped
*/
- for (TABLE_LIST* it= first_table->next_global; it; it= it->next_global)
+ for (const TABLE_LIST* it= first_table->next_global; it; it= it->next_global)
{
if (thd->find_temporary_table(it))
{
@@ -1720,7 +1867,7 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
}
}
return true;
-
+ break;
case SQLCOM_CREATE_TRIGGER:
DBUG_ASSERT(first_table);
@@ -1730,15 +1877,12 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
return false;
}
return true;
-
- case SQLCOM_DROP_TRIGGER:
- DBUG_ASSERT(table_list);
- if (thd->find_temporary_table(table_list))
- {
+ break;
+ case SQLCOM_ALTER_TABLE:
+ if (create_info &&
+ !wsrep_should_replicate_ddl(thd, create_info->db_type->db_type))
return false;
- }
- return true;
-
+ /* fallthrough */
default:
if (table && !thd->find_temporary_table(db, table))
{
@@ -1747,7 +1891,7 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
if (table_list)
{
- for (TABLE_LIST* table= first_table; table; table= table->next_global)
+ for (const TABLE_LIST* table= first_table; table; table= table->next_global)
{
if (!thd->find_temporary_table(table->db.str, table->table_name.str))
{
@@ -1755,11 +1899,12 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
}
}
}
+
return !(table || table_list);
+ break;
}
}
-
static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len)
{
String log_query;
@@ -1771,7 +1916,7 @@ static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len)
log_query.set_charset(system_charset_info);
- if (sp->m_handler->type() == TYPE_ENUM_FUNCTION)
+ if (sp->m_handler->type() == SP_TYPE_FUNCTION)
{
sp_returns_type(thd, retstr, sp);
returns= retstr.lex_cstring();
@@ -1840,13 +1985,16 @@ static void wsrep_TOI_begin_failed(THD* thd, const wsrep_buf_t* /* const err */)
if (wsrep_emulate_bin_log) wsrep_thd_binlog_trx_reset(thd);
if (wsrep_write_dummy_event(thd, "TOI begin failed")) { goto fail; }
wsrep::client_state& cs(thd->wsrep_cs());
- int const ret= cs.leave_toi_local(wsrep::mutable_buffer());
+ std::string const err(wsrep::to_c_string(cs.current_error()));
+ wsrep::mutable_buffer err_buf;
+ err_buf.push_back(err);
+ int const ret= cs.leave_toi_local(err_buf);
if (ret)
{
WSREP_ERROR("Leaving critical section for failed TOI failed: thd: %lld, "
"schema: %s, SQL: %s, rcode: %d wsrep_error: %s",
(long long)thd->real_id, thd->db.str,
- thd->query(), ret, wsrep::to_c_string(cs.current_error()));
+ thd->query(), ret, err.c_str());
goto fail;
}
}
@@ -1865,14 +2013,16 @@ fail:
*/
static int wsrep_TOI_begin(THD *thd, const char *db, const char *table,
const TABLE_LIST* table_list,
- Alter_info* alter_info)
+ const Alter_info* alter_info,
+ const HA_CREATE_INFO* create_info)
{
- DBUG_ASSERT(thd->variables.wsrep_OSU_method == WSREP_OSU_TOI);
+ DBUG_ASSERT(wsrep_OSU_method_get(thd) == WSREP_OSU_TOI);
- WSREP_DEBUG("TOI Begin");
- if (wsrep_can_run_in_toi(thd, db, table, table_list) == false)
+ WSREP_DEBUG("TOI Begin: %s", wsrep_thd_query(thd));
+
+ if (wsrep_can_run_in_toi(thd, db, table, table_list, create_info) == false)
{
- WSREP_DEBUG("No TOI for %s", WSREP_QUERY(thd));
+ WSREP_DEBUG("No TOI for %s", wsrep_thd_query(thd));
return 1;
}
@@ -1882,6 +2032,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table,
int rc;
buf_err= wsrep_TOI_event_buf(thd, &buf, &buf_len);
+
if (buf_err) {
WSREP_ERROR("Failed to create TOI event buf: %d", buf_err);
my_message(ER_UNKNOWN_ERROR,
@@ -1890,6 +2041,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table,
MYF(0));
return -1;
}
+
struct wsrep_buf buff= { buf, buf_len };
wsrep::key_array key_array=
@@ -1900,7 +2052,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table,
/* non replicated DDL, affecting temporary tables only */
WSREP_DEBUG("TO isolation skipped, sql: %s."
"Only temporary tables affected.",
- WSREP_QUERY(thd));
+ wsrep_thd_query(thd));
if (buf) my_free(buf);
return -1;
}
@@ -1908,6 +2060,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table,
thd_proc_info(thd, "acquiring total order isolation");
wsrep::client_state& cs(thd->wsrep_cs());
+
int ret= cs.enter_toi_local(key_array,
wsrep::const_buffer(buff.ptr, buff.len));
@@ -1915,7 +2068,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table,
{
DBUG_ASSERT(cs.current_error());
WSREP_DEBUG("to_execute_start() failed for %llu: %s, seqno: %lld",
- thd->thread_id, WSREP_QUERY(thd),
+ thd->thread_id, wsrep_thd_query(thd),
(long long)wsrep_thd_trx_seqno(thd));
/* jump to error handler in mysql_execute_command() */
@@ -1926,7 +2079,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table,
"Maximum size exceeded.",
ret,
(thd->db.str ? thd->db.str : "(null)"),
- WSREP_QUERY(thd));
+ wsrep_thd_query(thd));
my_error(ER_ERROR_DURING_COMMIT, MYF(0), WSREP_SIZE_EXCEEDED);
break;
default:
@@ -1934,7 +2087,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table,
"Check wsrep connection state and retry the query.",
ret,
(thd->db.str ? thd->db.str : "(null)"),
- WSREP_QUERY(thd));
+ wsrep_thd_query(thd));
if (!thd->is_error())
{
my_error(ER_LOCK_DEADLOCK, MYF(0), "WSREP replication failed. Check "
@@ -1944,6 +2097,28 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table,
rc= -1;
}
else {
+ if (!thd->variables.gtid_seq_no)
+ {
+ uint64 seqno= 0;
+ if (thd->variables.wsrep_gtid_seq_no &&
+ thd->variables.wsrep_gtid_seq_no > wsrep_gtid_server.seqno())
+ {
+ seqno= thd->variables.wsrep_gtid_seq_no;
+ wsrep_gtid_server.seqno(thd->variables.wsrep_gtid_seq_no);
+ }
+ else
+ {
+ seqno= wsrep_gtid_server.seqno_inc();
+ }
+ thd->variables.wsrep_gtid_seq_no= 0;
+ thd->wsrep_current_gtid_seqno= seqno;
+ if (mysql_bin_log.is_open() && wsrep_gtid_mode)
+ {
+ thd->variables.gtid_seq_no= seqno;
+ thd->variables.gtid_domain_id= wsrep_gtid_server.domain_id;
+ thd->variables.server_id= wsrep_gtid_server.server_id;
+ }
+ }
++wsrep_to_isolation;
rc= 0;
}
@@ -1960,12 +2135,24 @@ static void wsrep_TOI_end(THD *thd) {
wsrep::client_state& client_state(thd->wsrep_cs());
DBUG_ASSERT(wsrep_thd_is_local_toi(thd));
WSREP_DEBUG("TO END: %lld: %s", client_state.toi_meta().seqno().get(),
- WSREP_QUERY(thd));
+ wsrep_thd_query(thd));
+
+ wsrep_gtid_server.signal_waiters(thd->wsrep_current_gtid_seqno, false);
if (wsrep_thd_is_local_toi(thd))
{
- wsrep_set_SE_checkpoint(client_state.toi_meta().gtid());
- int ret= client_state.leave_toi_local(wsrep::mutable_buffer());
+ wsrep::mutable_buffer err;
+
+ thd->wsrep_last_written_gtid_seqno= thd->wsrep_current_gtid_seqno;
+ wsrep_set_SE_checkpoint(client_state.toi_meta().gtid(), wsrep_gtid_server.gtid());
+
+ if (thd->is_error() && !wsrep_must_ignore_error(thd))
+ {
+ wsrep_store_error(thd, err);
+ }
+
+ int const ret= client_state.leave_toi_local(err);
+
if (!ret)
{
WSREP_DEBUG("TO END: %lld", client_state.toi_meta().seqno().get());
@@ -1973,7 +2160,7 @@ static void wsrep_TOI_end(THD *thd) {
else
{
WSREP_WARN("TO isolation end failed for: %d, schema: %s, sql: %s",
- ret, (thd->db.str ? thd->db.str : "(null)"), WSREP_QUERY(thd));
+ ret, (thd->db.str ? thd->db.str : "(null)"), wsrep_thd_query(thd));
}
}
}
@@ -1981,7 +2168,7 @@ static void wsrep_TOI_end(THD *thd) {
static int wsrep_RSU_begin(THD *thd, const char *db_, const char *table_)
{
WSREP_DEBUG("RSU BEGIN: %lld, : %s", wsrep_thd_trx_seqno(thd),
- WSREP_QUERY(thd));
+ wsrep_thd_query(thd));
if (thd->wsrep_cs().begin_rsu(5000))
{
WSREP_WARN("RSU begin failed");
@@ -1996,7 +2183,7 @@ static int wsrep_RSU_begin(THD *thd, const char *db_, const char *table_)
static void wsrep_RSU_end(THD *thd)
{
WSREP_DEBUG("RSU END: %lld : %s", wsrep_thd_trx_seqno(thd),
- WSREP_QUERY(thd));
+ wsrep_thd_query(thd));
if (thd->wsrep_cs().end_rsu())
{
WSREP_WARN("Failed to end RSU, server may need to be restarted");
@@ -2006,7 +2193,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,
- Alter_info* alter_info)
+ const Alter_info* alter_info,
+ const HA_CREATE_INFO* create_info)
{
/*
No isolation for applier or replaying threads.
@@ -2031,14 +2219,14 @@ int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_,
if (thd->global_read_lock.is_acquired())
{
WSREP_DEBUG("Aborting TOI: Global Read-Lock (FTWRL) in place: %s %llu",
- WSREP_QUERY(thd), thd->thread_id);
+ wsrep_thd_query(thd), thd->thread_id);
return -1;
}
if (wsrep_debug && thd->mdl_context.has_locks())
{
WSREP_DEBUG("thread holds MDL locks at TI begin: %s %llu",
- WSREP_QUERY(thd), thd->thread_id);
+ wsrep_thd_query(thd), thd->thread_id);
}
/*
@@ -2056,24 +2244,24 @@ int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_,
if (thd->variables.wsrep_on && wsrep_thd_is_local(thd))
{
- switch (thd->variables.wsrep_OSU_method) {
+ switch (wsrep_OSU_method_get(thd)) {
case WSREP_OSU_TOI:
- ret= wsrep_TOI_begin(thd, db_, table_, table_list, alter_info);
+ ret= wsrep_TOI_begin(thd, db_, table_, table_list, alter_info, create_info);
break;
case WSREP_OSU_RSU:
ret= wsrep_RSU_begin(thd, db_, table_);
break;
default:
WSREP_ERROR("Unsupported OSU method: %lu",
- thd->variables.wsrep_OSU_method);
+ wsrep_OSU_method_get(thd));
ret= -1;
break;
}
switch (ret) {
- case 0: /* wsrep_TOI_begin sould set toi mode */ break;
+ case 0: /* wsrep_TOI_begin should set toi mode */ break;
case 1:
- /* TOI replication skipped, treat as success */
- ret= 0;
+ /* TOI replication skipped, treat as success */
+ ret= 0;
break;
case -1:
/* TOI replication failed, treat as error */
@@ -2090,12 +2278,12 @@ void wsrep_to_isolation_end(THD *thd)
wsrep_thd_is_in_rsu(thd));
if (wsrep_thd_is_local_toi(thd))
{
- DBUG_ASSERT(thd->variables.wsrep_OSU_method == WSREP_OSU_TOI);
+ DBUG_ASSERT(wsrep_OSU_method_get(thd) == WSREP_OSU_TOI);
wsrep_TOI_end(thd);
}
else if (wsrep_thd_is_in_rsu(thd))
{
- DBUG_ASSERT(thd->variables.wsrep_OSU_method == WSREP_OSU_RSU);
+ DBUG_ASSERT(wsrep_OSU_method_get(thd) == WSREP_OSU_RSU);
wsrep_RSU_end(thd);
}
else
@@ -2465,7 +2653,7 @@ int wsrep_must_ignore_error(THD* thd)
const uint flags= sql_command_flags[thd->lex->sql_command];
DBUG_ASSERT(error);
- DBUG_ASSERT(wsrep_thd_is_toi(thd) || wsrep_thd_is_applying(thd));
+ DBUG_ASSERT(wsrep_thd_is_toi(thd));
if ((wsrep_ignore_apply_errors & WSREP_IGNORE_ERRORS_ON_DDL))
goto ignore_error;
@@ -2547,17 +2735,17 @@ bool wsrep_create_like_table(THD* thd, TABLE_LIST* table,
if (create_info->tmp_table())
{
/* CREATE TEMPORARY TABLE LIKE must be skipped from replication */
- WSREP_DEBUG("CREATE TEMPORARY TABLE LIKE... skipped replication\n %s",
+ WSREP_DEBUG("CREATE TEMPORARY TABLE LIKE... skipped replication\n %s",
thd->query());
}
else if (!(thd->find_temporary_table(src_table)))
{
/* this is straight CREATE TABLE LIKE... with no tmp tables */
- WSREP_TO_ISOLATION_BEGIN(table->db.str, table->table_name.str, NULL);
+ WSREP_TO_ISOLATION_BEGIN_CREATE(table->db.str, table->table_name.str, table, create_info);
}
else
{
- /* here we have CREATE TABLE LIKE <temporary table>
+ /* here we have CREATE TABLE LIKE <temporary table>
the temporary table definition will be needed in slaves to
enable the create to succeed
*/
@@ -2576,7 +2764,7 @@ bool wsrep_create_like_table(THD* thd, TABLE_LIST* table,
thd->wsrep_TOI_pre_query= query.ptr();
thd->wsrep_TOI_pre_query_len= query.length();
- WSREP_TO_ISOLATION_BEGIN(table->db.str, table->table_name.str, NULL);
+ WSREP_TO_ISOLATION_BEGIN_CREATE(table->db.str, table->table_name.str, table, create_info);
thd->wsrep_TOI_pre_query= NULL;
thd->wsrep_TOI_pre_query_len= 0;
@@ -2658,12 +2846,6 @@ void* start_wsrep_THD(void *arg)
statistic_increment(thread_created, &LOCK_status);
- if (wsrep_gtid_mode)
- {
- /* Adjust domain_id. */
- thd->variables.gtid_domain_id= wsrep_gtid_domain_id;
- }
-
thd->real_id=pthread_self(); // Keep purify happy
my_net_init(&thd->net,(st_vio*) 0, thd, MYF(0));
@@ -2676,20 +2858,13 @@ void* start_wsrep_THD(void *arg)
/* from bootstrap()... */
thd->bootstrap=1;
thd->max_client_packet_length= thd->net.max_packet;
- thd->security_ctx->master_access= ~(ulong)0;
+ thd->security_ctx->master_access= ALL_KNOWN_ACL;
/* from handle_one_connection... */
pthread_detach_this_thread();
mysql_thread_set_psi_id(thd->thread_id);
thd->thr_create_utime= microsecond_interval_timer();
- if (MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0))
- {
- close_connection(thd, ER_OUT_OF_RESOURCES);
- statistic_increment(aborted_connects,&LOCK_status);
- MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
- goto error;
- }
// </5.1.17>
/*
@@ -2710,7 +2885,7 @@ void* start_wsrep_THD(void *arg)
{
close_connection(thd, ER_OUT_OF_RESOURCES);
statistic_increment(aborted_connects,&LOCK_status);
- MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
+ unlink_thd(thd);
delete thd;
delete thd_args;
goto error;
@@ -2786,7 +2961,7 @@ void* start_wsrep_THD(void *arg)
if (plugins_are_initialized)
{
net_end(&thd->net);
- MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 1));
+ unlink_thd(thd);
}
else
{
@@ -2795,9 +2970,9 @@ void* start_wsrep_THD(void *arg)
'Error in my_thread_global_end(): 2 threads didn't exit'
at server shutdown
*/
+ server_threads.erase(thd);
}
- server_threads.erase(thd);
delete thd;
my_thread_end();
return(NULL);
@@ -2836,3 +3011,54 @@ bool wsrep_consistency_check(THD *thd)
{
return thd->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING;
}
+
+
+/*
+ Commit an empty transaction.
+
+ If the transaction is real and the wsrep transaction is still active,
+ the transaction did not generate any rows or keys and is committed
+ as empty. Here the wsrep transaction is rolled back and after statement
+ step is performed to leave the wsrep transaction in the state as it
+ never existed.
+
+ This should not be an inline functions as it requires a lot of stack space
+ because of WSREP_DBUG() usage. It's also not a function that is
+ frequently called.
+*/
+
+void wsrep_commit_empty(THD* thd, bool all)
+{
+ DBUG_ENTER("wsrep_commit_empty");
+ WSREP_DEBUG("wsrep_commit_empty(%llu)", thd->thread_id);
+ if (wsrep_is_real(thd, all) &&
+ wsrep_thd_is_local(thd) &&
+ thd->wsrep_trx().active() &&
+ thd->wsrep_trx().state() != wsrep::transaction::s_committed)
+ {
+ /* @todo CTAS with STATEMENT binlog format and empty result set
+ seems to be committing empty. Figure out why and try to fix
+ elsewhere. */
+ DBUG_ASSERT(!wsrep_has_changes(thd) ||
+ (thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
+ !thd->is_current_stmt_binlog_format_row()));
+ bool have_error= wsrep_current_error(thd);
+ int ret= wsrep_before_rollback(thd, all) ||
+ wsrep_after_rollback(thd, all) ||
+ wsrep_after_statement(thd);
+ /* The committing transaction was empty but it held some locks and
+ got BF aborted. As there were no certified changes in the
+ data, we ignore the deadlock error and rely on error reporting
+ by storage engine/server. */
+ if (!ret && !have_error && wsrep_current_error(thd))
+ {
+ DBUG_ASSERT(wsrep_current_error(thd) == wsrep::e_deadlock_error);
+ thd->wsrep_cs().reset_error();
+ }
+ if (ret)
+ {
+ WSREP_DEBUG("wsrep_commit_empty failed: %d", wsrep_current_error(thd));
+ }
+ }
+ DBUG_VOID_RETURN;
+}
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
index a5da8e3bc44..8ccab45700e 100644
--- a/sql/wsrep_mysqld.h
+++ b/sql/wsrep_mysqld.h
@@ -38,6 +38,7 @@ typedef struct st_mysql_show_var SHOW_VAR;
#include "wsrep/streaming_context.hpp"
#include "wsrep_api.h"
#include <vector>
+#include <map>
#include "wsrep_server_state.h"
#define WSREP_UNDEFINED_TRX_ID ULONGLONG_MAX
@@ -97,7 +98,7 @@ extern ulong wsrep_running_applier_threads;
extern ulong wsrep_running_rollbacker_threads;
extern bool wsrep_new_cluster;
extern bool wsrep_gtid_mode;
-extern uint32 wsrep_gtid_domain_id;
+extern my_bool wsrep_strict_ddl;
enum enum_wsrep_reject_types {
WSREP_REJECT_NONE, /* nothing rejected */
@@ -108,7 +109,7 @@ enum enum_wsrep_reject_types {
enum enum_wsrep_OSU_method {
WSREP_OSU_TOI,
WSREP_OSU_RSU,
- WSREP_OSU_NONE,
+ WSREP_OSU_NONE
};
enum enum_wsrep_sync_wait {
@@ -251,14 +252,14 @@ extern wsrep_seqno_t wsrep_locked_seqno;
} while(0)
#define WSREP_DEBUG(...) \
- if (wsrep_debug) WSREP_LOG(sql_print_information, ##__VA_ARGS__)
-#define WSREP_INFO(...) WSREP_LOG(sql_print_information, ##__VA_ARGS__)
-#define WSREP_WARN(...) WSREP_LOG(sql_print_warning, ##__VA_ARGS__)
-#define WSREP_ERROR(...) WSREP_LOG(sql_print_error, ##__VA_ARGS__)
+ if (wsrep_debug) sql_print_information( "WSREP: " __VA_ARGS__)
+#define WSREP_INFO(...) sql_print_information( "WSREP: " __VA_ARGS__)
+#define WSREP_WARN(...) sql_print_warning( "WSREP: " __VA_ARGS__)
+#define WSREP_ERROR(...) sql_print_error( "WSREP: " __VA_ARGS__)
#define WSREP_LOG_CONFLICT_THD(thd, role) \
- WSREP_LOG(sql_print_information, \
- "%s: \n " \
+ sql_print_information( \
+ "WSREP: %s: \n " \
" THD: %lu, mode: %s, state: %s, conflict: %s, seqno: %lld\n " \
" SQL: %s", \
role, \
@@ -273,12 +274,12 @@ extern wsrep_seqno_t wsrep_locked_seqno;
#define WSREP_LOG_CONFLICT(bf_thd, victim_thd, bf_abort) \
if (wsrep_debug || wsrep_log_conflicts) \
{ \
- WSREP_LOG(sql_print_information, "cluster conflict due to %s for threads:", \
+ sql_print_information( "WSREP: cluster conflict due to %s for threads:", \
(bf_abort) ? "high priority abort" : "certification failure" \
); \
if (bf_thd) WSREP_LOG_CONFLICT_THD(bf_thd, "Winning thread"); \
if (victim_thd) WSREP_LOG_CONFLICT_THD(victim_thd, "Victim thread"); \
- WSREP_LOG(sql_print_information, "context: %s:%d", __FILE__, __LINE__); \
+ sql_print_information("WSREP: context: %s:%d", __FILE__, __LINE__); \
}
#define WSREP_PROVIDER_EXISTS \
@@ -303,6 +304,7 @@ extern mysql_mutex_t LOCK_wsrep_replaying;
extern mysql_cond_t COND_wsrep_replaying;
extern mysql_mutex_t LOCK_wsrep_slave_threads;
extern mysql_cond_t COND_wsrep_slave_threads;
+extern mysql_mutex_t LOCK_wsrep_gtid_wait_upto;
extern mysql_mutex_t LOCK_wsrep_cluster_config;
extern mysql_mutex_t LOCK_wsrep_desync;
extern mysql_mutex_t LOCK_wsrep_SR_pool;
@@ -316,9 +318,6 @@ extern mysql_cond_t COND_wsrep_donor_monitor;
extern my_bool wsrep_emulate_bin_log;
extern int wsrep_to_isolation;
-#ifdef GTID_SUPPORT
-extern rpl_sidno wsrep_sidno;
-#endif /* GTID_SUPPORT */
extern my_bool wsrep_preordered_opt;
#ifdef HAVE_PSI_INTERFACE
@@ -337,6 +336,8 @@ extern PSI_mutex_key key_LOCK_wsrep_replaying;
extern PSI_cond_key key_COND_wsrep_replaying;
extern PSI_mutex_key key_LOCK_wsrep_slave_threads;
extern PSI_cond_key key_COND_wsrep_slave_threads;
+extern PSI_mutex_key key_LOCK_wsrep_gtid_wait_upto;
+extern PSI_cond_key key_COND_wsrep_gtid_wait_upto;
extern PSI_mutex_key key_LOCK_wsrep_cluster_config;
extern PSI_mutex_key key_LOCK_wsrep_desync;
extern PSI_mutex_key key_LOCK_wsrep_SR_pool;
@@ -360,9 +361,15 @@ extern PSI_thread_key key_wsrep_sst_donor_monitor;
struct TABLE_LIST;
class Alter_info;
+struct HA_CREATE_INFO;
+
int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_,
const TABLE_LIST* table_list,
- Alter_info* alter_info= NULL);
+ const Alter_info* alter_info= NULL,
+ const HA_CREATE_INFO* create_info= NULL);
+
+bool wsrep_should_replicate_ddl(THD* thd, const enum legacy_db_type db_type);
+bool wsrep_should_replicate_ddl_iterate(THD* thd, const TABLE_LIST* table_list);
void wsrep_to_isolation_end(THD *thd);
@@ -387,7 +394,129 @@ class Log_event;
int wsrep_ignored_error_code(Log_event* ev, int error);
int wsrep_must_ignore_error(THD* thd);
-bool wsrep_replicate_GTID(THD* thd);
+struct wsrep_server_gtid_t
+{
+ uint32 domain_id;
+ uint32 server_id;
+ uint64 seqno;
+};
+class Wsrep_gtid_server
+{
+public:
+ uint32 domain_id;
+ uint32 server_id;
+ Wsrep_gtid_server()
+ : m_force_signal(false)
+ , m_seqno(0)
+ , m_committed_seqno(0)
+ { }
+ void gtid(const wsrep_server_gtid_t& gtid)
+ {
+ domain_id= gtid.domain_id;
+ server_id= gtid.server_id;
+ m_seqno= gtid.seqno;
+ }
+ wsrep_server_gtid_t gtid()
+ {
+ wsrep_server_gtid_t gtid;
+ gtid.domain_id= domain_id;
+ gtid.server_id= server_id;
+ gtid.seqno= m_seqno;
+ return gtid;
+ }
+ void seqno(const uint64 seqno) { m_seqno= seqno; }
+ uint64 seqno() const { return m_seqno; }
+ uint64 seqno_committed() const { return m_committed_seqno; }
+ uint64 seqno_inc()
+ {
+ m_seqno++;
+ return m_seqno;
+ }
+ const wsrep_server_gtid_t& undefined()
+ {
+ return m_undefined;
+ }
+ int wait_gtid_upto(const uint64_t seqno, uint timeout)
+ {
+ int wait_result= 0;
+ struct timespec wait_time;
+ int ret= 0;
+ mysql_cond_t wait_cond;
+ mysql_cond_init(key_COND_wsrep_gtid_wait_upto, &wait_cond, NULL);
+ set_timespec(wait_time, timeout);
+ mysql_mutex_lock(&LOCK_wsrep_gtid_wait_upto);
+ std::multimap<uint64, mysql_cond_t*>::iterator it;
+ if (seqno > m_seqno)
+ {
+ try
+ {
+ it= m_wait_map.insert(std::make_pair(seqno, &wait_cond));
+ }
+ catch (std::bad_alloc& e)
+ {
+ ret= ENOMEM;
+ }
+ while (!ret && (m_committed_seqno < seqno) && !m_force_signal)
+ {
+ wait_result= mysql_cond_timedwait(&wait_cond,
+ &LOCK_wsrep_gtid_wait_upto,
+ &wait_time);
+ if (wait_result == ETIMEDOUT || wait_result == ETIME)
+ {
+ ret= wait_result;
+ break;
+ }
+ }
+ if (ret != ENOMEM)
+ {
+ m_wait_map.erase(it);
+ }
+ }
+ mysql_mutex_unlock(&LOCK_wsrep_gtid_wait_upto);
+ mysql_cond_destroy(&wait_cond);
+ return ret;
+ }
+ void signal_waiters(uint64 seqno, bool signal_all)
+ {
+ mysql_mutex_lock(&LOCK_wsrep_gtid_wait_upto);
+ if (!signal_all && (m_committed_seqno >= seqno))
+ {
+ mysql_mutex_unlock(&LOCK_wsrep_gtid_wait_upto);
+ return;
+ }
+ m_force_signal= true;
+ std::multimap<uint64, mysql_cond_t*>::iterator it_end;
+ std::multimap<uint64, mysql_cond_t*>::iterator it_begin;
+ if (signal_all)
+ {
+ it_end= m_wait_map.end();
+ }
+ else
+ {
+ it_end= m_wait_map.upper_bound(seqno);
+ }
+ if (m_committed_seqno < seqno)
+ {
+ m_committed_seqno= seqno;
+ }
+ for (it_begin = m_wait_map.begin(); it_begin != it_end; ++it_begin)
+ {
+ mysql_cond_signal(it_begin->second);
+ }
+ m_force_signal= false;
+ mysql_mutex_unlock(&LOCK_wsrep_gtid_wait_upto);
+ }
+private:
+ const wsrep_server_gtid_t m_undefined= {0,0,0};
+ std::multimap<uint64, mysql_cond_t*> m_wait_map;
+ bool m_force_signal;
+ Atomic_counter<uint64_t> m_seqno;
+ Atomic_counter<uint64_t> m_committed_seqno;
+};
+extern Wsrep_gtid_server wsrep_gtid_server;
+void wsrep_init_gtid();
+bool wsrep_check_gtid_seqno(const uint32&, const uint32&, uint64&);
+bool wsrep_get_binlog_gtid_seqno(wsrep_server_gtid_t&);
typedef struct wsrep_key_arr
{
diff --git a/sql/wsrep_schema.cc b/sql/wsrep_schema.cc
index 619a535f916..95c788ba806 100644
--- a/sql/wsrep_schema.cc
+++ b/sql/wsrep_schema.cc
@@ -1281,7 +1281,7 @@ int Wsrep_schema::recover_sr_transactions(THD *orig_thd)
goto out;
}
- while (true)
+ while (0 == error)
{
if ((error= Wsrep_schema_impl::next_record(frag_table)) == 0)
{
@@ -1331,19 +1331,23 @@ int Wsrep_schema::recover_sr_transactions(THD *orig_thd)
}
applier->store_globals();
wsrep::mutable_buffer unused;
- applier->apply_write_set(ws_meta, data, unused);
- applier->after_apply();
+ if ((ret= applier->apply_write_set(ws_meta, data, unused)) != 0)
+ {
+ WSREP_ERROR("SR trx recovery applying returned %d", ret);
+ }
+ else
+ {
+ applier->after_apply();
+ }
storage_service.store_globals();
}
else if (error == HA_ERR_END_OF_FILE)
{
ret= 0;
- break;
}
else
{
WSREP_ERROR("SR table scan returned error %d", error);
- break;
}
}
Wsrep_schema_impl::end_scan(frag_table);
diff --git a/sql/wsrep_server_service.cc b/sql/wsrep_server_service.cc
index d0a9b54ac1b..6d737463f07 100644
--- a/sql/wsrep_server_service.cc
+++ b/sql/wsrep_server_service.cc
@@ -153,7 +153,7 @@ void Wsrep_server_service::bootstrap()
wsrep::log_info()
<< "Bootstrapping a new cluster, setting initial position to "
<< wsrep::gtid::undefined();
- wsrep_set_SE_checkpoint(wsrep::gtid::undefined());
+ wsrep_set_SE_checkpoint(wsrep::gtid::undefined(), wsrep_gtid_server.undefined());
}
void Wsrep_server_service::log_message(enum wsrep::log::level level,
@@ -212,7 +212,7 @@ void Wsrep_server_service::log_view(
if (prev_view.state_id().id() != view.state_id().id())
{
WSREP_DEBUG("New cluster UUID was generated, resetting position info");
- wsrep_set_SE_checkpoint(wsrep::gtid::undefined());
+ wsrep_set_SE_checkpoint(wsrep::gtid::undefined(), wsrep_gtid_server.undefined());
checkpoint_was_reset= true;
}
@@ -263,9 +263,9 @@ void Wsrep_server_service::log_view(
Wsrep_server_state::instance().provider().last_committed_gtid().seqno();
if (checkpoint_was_reset || last_committed != view.state_id().seqno())
{
- wsrep_set_SE_checkpoint(view.state_id());
+ wsrep_set_SE_checkpoint(view.state_id(), wsrep_gtid_server.gtid());
}
- DBUG_ASSERT(wsrep_get_SE_checkpoint().id() == view.state_id().id());
+ DBUG_ASSERT(wsrep_get_SE_checkpoint<wsrep::gtid>().id() == view.state_id().id());
}
else
{
@@ -299,13 +299,13 @@ wsrep::view Wsrep_server_service::get_view(wsrep::client_service& c,
wsrep::gtid Wsrep_server_service::get_position(wsrep::client_service&)
{
- return wsrep_get_SE_checkpoint();
+ return wsrep_get_SE_checkpoint<wsrep::gtid>();
}
void Wsrep_server_service::set_position(wsrep::client_service&,
const wsrep::gtid& gtid)
{
- wsrep_set_SE_checkpoint(gtid);
+ wsrep_set_SE_checkpoint(gtid, wsrep_gtid_server.gtid());
}
void Wsrep_server_service::log_state_change(
diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc
index 02f7d4b6760..0bb8a9eb675 100644
--- a/sql/wsrep_sst.cc
+++ b/sql/wsrep_sst.cc
@@ -245,7 +245,7 @@ static bool sst_auth_real_set (const char* value)
if (value)
{
- v= my_strdup(value, MYF(0));
+ v= my_strdup(PSI_INSTRUMENT_ME, value, MYF(0));
}
else // its NULL
{
@@ -263,7 +263,7 @@ static bool sst_auth_real_set (const char* value)
if (strlen(sst_auth_real))
{
if (wsrep_sst_auth) { my_free((void*) wsrep_sst_auth); }
- wsrep_sst_auth= my_strdup(WSREP_SST_AUTH_MASK, MYF(0));
+ wsrep_sst_auth= my_strdup(PSI_INSTRUMENT_ME, WSREP_SST_AUTH_MASK, MYF(0));
}
return 0;
}
@@ -351,8 +351,8 @@ void wsrep_sst_received (THD* thd,
wsrep::seqno(seqno));
if (!wsrep_before_SE()) {
- wsrep_set_SE_checkpoint(wsrep::gtid::undefined());
- wsrep_set_SE_checkpoint(sst_gtid);
+ wsrep_set_SE_checkpoint(wsrep::gtid::undefined(), wsrep_gtid_server.undefined());
+ wsrep_set_SE_checkpoint(sst_gtid, wsrep_gtid_server.gtid());
}
wsrep_verify_SE_checkpoint(uuid, seqno);
@@ -414,7 +414,7 @@ static char* generate_name_value(const char* name, const char* value)
size_t name_len= strlen(name);
size_t value_len= strlen(value);
char* buf=
- (char*) my_malloc((name_len + value_len + 5) * sizeof(char), MYF(0));
+ (char*) my_malloc(PSI_INSTRUMENT_ME, (name_len + value_len + 5), MYF(0));
if (buf)
{
char* ref= buf;
@@ -449,11 +449,11 @@ static int generate_binlog_opt_val(char** ret)
*ret= strcmp(opt_bin_logname, "0") ?
generate_name_value(WSREP_SST_OPT_BINLOG,
opt_bin_logname) :
- my_strdup("", MYF(0));
+ my_strdup(PSI_INSTRUMENT_ME, "", MYF(0));
}
else
{
- *ret= my_strdup("", MYF(0));
+ *ret= my_strdup(PSI_INSTRUMENT_ME, "", MYF(0));
}
if (!*ret) return -ENOMEM;
return 0;
@@ -468,11 +468,11 @@ static int generate_binlog_index_opt_val(char** ret)
*ret= strcmp(opt_binlog_index_name, "0") ?
generate_name_value(WSREP_SST_OPT_BINLOG_INDEX,
opt_binlog_index_name) :
- my_strdup("", MYF(0));
+ my_strdup(PSI_INSTRUMENT_ME, "", MYF(0));
}
else
{
- *ret= my_strdup("", MYF(0));
+ *ret= my_strdup(PSI_INSTRUMENT_ME, "", MYF(0));
}
if (!*ret) return -ENOMEM;
return 0;
@@ -594,7 +594,7 @@ static void* sst_joiner_thread (void* a)
err= EINVAL;
goto err;
} else {
- wsrep_gtid_domain_id= (uint32) domain_id;
+ wsrep_gtid_server.domain_id= (uint32) domain_id;
}
}
}
@@ -1365,13 +1365,15 @@ static int sst_donate_mysqldump (const char* addr,
WSREP_SST_OPT_LPORT " '%u' "
WSREP_SST_OPT_SOCKET " '%s' "
"%s"
- WSREP_SST_OPT_GTID " '%s:%lld' "
+ WSREP_SST_OPT_GTID " '%s:%lld,%d-%d-%llu' "
WSREP_SST_OPT_GTID_DOMAIN_ID " '%d'"
"%s",
addr, port, mysqld_port, mysqld_unix_port,
wsrep_defaults_file,
uuid_oss.str().c_str(), gtid.seqno().get(),
- wsrep_gtid_domain_id,
+ wsrep_gtid_server.domain_id, wsrep_gtid_server.server_id,
+ wsrep_gtid_server.seqno(),
+ wsrep_gtid_server.domain_id,
bypass ? " " WSREP_SST_OPT_BYPASS : "");
if (ret < 0 || size_t(ret) >= cmd_len)
@@ -1538,7 +1540,7 @@ static int sst_flush_tables(THD* thd)
*/
char content[100];
snprintf(content, sizeof(content), "%s:%lld %d\n", wsrep_cluster_state_uuid,
- (long long)wsrep_locked_seqno, wsrep_gtid_domain_id);
+ (long long)wsrep_locked_seqno, wsrep_gtid_server.domain_id);
err= sst_create_file(flush_success, content);
const char base_name[]= "tables_flushed";
@@ -1563,7 +1565,7 @@ static int sst_flush_tables(THD* thd)
fprintf(file, "%s:%lld %u\n",
uuid_oss.str().c_str(), server_state.pause_seqno().get(),
- wsrep_gtid_domain_id);
+ wsrep_gtid_server.domain_id);
fsync(fileno(file));
fclose(file);
if (rename(tmp_name, real_name) == -1)
@@ -1783,7 +1785,7 @@ static int sst_donate_other (const char* method,
"%s",
method, addr, mysqld_unix_port, mysql_real_data_home,
wsrep_defaults_file,
- uuid_oss.str().c_str(), gtid.seqno().get(), wsrep_gtid_domain_id,
+ uuid_oss.str().c_str(), gtid.seqno().get(), wsrep_gtid_server.domain_id,
binlog_opt_val, binlog_index_opt_val,
bypass ? " " WSREP_SST_OPT_BYPASS : "");
diff --git a/sql/wsrep_trans_observer.h b/sql/wsrep_trans_observer.h
index 98fc63cf783..cb58026207b 100644
--- a/sql/wsrep_trans_observer.h
+++ b/sql/wsrep_trans_observer.h
@@ -26,6 +26,8 @@
class THD;
+void wsrep_commit_empty(THD* thd, bool all);
+
/*
Return true if THD has active wsrep transaction.
*/
@@ -123,7 +125,7 @@ static inline bool wsrep_streaming_enabled(THD* thd)
}
/*
- Return number of fragments succesfully certified for the
+ Return number of fragments successfully certified for the
current statement.
*/
static inline size_t wsrep_fragments_certified_for_stmt(THD* thd)
@@ -231,7 +233,8 @@ static inline int wsrep_before_prepare(THD* thd, bool all)
{
DBUG_ASSERT(!thd->wsrep_trx().ws_meta().gtid().is_undefined());
wsrep_xid_init(&thd->wsrep_xid,
- thd->wsrep_trx().ws_meta().gtid());
+ thd->wsrep_trx().ws_meta().gtid(),
+ wsrep_gtid_server.gtid());
}
DBUG_RETURN(ret);
}
@@ -271,8 +274,33 @@ static inline int wsrep_before_commit(THD* thd, bool all)
if ((ret= thd->wsrep_cs().before_commit()) == 0)
{
DBUG_ASSERT(!thd->wsrep_trx().ws_meta().gtid().is_undefined());
+ if (!thd->variables.gtid_seq_no &&
+ (thd->wsrep_trx().ws_meta().flags() & wsrep::provider::flag::commit))
+ {
+ uint64 seqno= 0;
+ if (thd->variables.wsrep_gtid_seq_no &&
+ thd->variables.wsrep_gtid_seq_no > wsrep_gtid_server.seqno())
+ {
+ seqno= thd->variables.wsrep_gtid_seq_no;
+ wsrep_gtid_server.seqno(thd->variables.wsrep_gtid_seq_no);
+ }
+ else
+ {
+ seqno= wsrep_gtid_server.seqno_inc();
+ }
+ thd->variables.wsrep_gtid_seq_no= 0;
+ thd->wsrep_current_gtid_seqno= seqno;
+ if (mysql_bin_log.is_open() && wsrep_gtid_mode)
+ {
+ thd->variables.gtid_seq_no= seqno;
+ thd->variables.gtid_domain_id= wsrep_gtid_server.domain_id;
+ thd->variables.server_id= wsrep_gtid_server.server_id;
+ }
+ }
+
wsrep_xid_init(&thd->wsrep_xid,
- thd->wsrep_trx().ws_meta().gtid());
+ thd->wsrep_trx().ws_meta().gtid(),
+ wsrep_gtid_server.gtid());
wsrep_register_for_group_commit(thd);
}
DBUG_RETURN(ret);
@@ -290,9 +318,7 @@ static inline int wsrep_before_commit(THD* thd, bool all)
Return zero on succes, non-zero on failure.
*/
-static inline int wsrep_ordered_commit(THD* thd,
- bool all,
- const wsrep_apply_error&)
+static inline int wsrep_ordered_commit(THD* thd, bool all)
{
DBUG_ENTER("wsrep_ordered_commit");
WSREP_DEBUG("wsrep_ordered_commit: %d", wsrep_is_real(thd, all));
@@ -484,50 +510,4 @@ wsrep_current_error_status(THD* thd)
return thd->wsrep_cs().current_error_status();
}
-
-/*
- Commit an empty transaction.
-
- If the transaction is real and the wsrep transaction is still active,
- the transaction did not generate any rows or keys and is committed
- as empty. Here the wsrep transaction is rolled back and after statement
- step is performed to leave the wsrep transaction in the state as it
- never existed.
-*/
-static inline void wsrep_commit_empty(THD* thd, bool all)
-{
- DBUG_ENTER("wsrep_commit_empty");
- WSREP_DEBUG("wsrep_commit_empty(%llu)", thd->thread_id);
- if (wsrep_is_real(thd, all) &&
- wsrep_thd_is_local(thd) &&
- thd->wsrep_trx().active() &&
- thd->wsrep_trx().state() != wsrep::transaction::s_committed)
- {
- /* @todo CTAS with STATEMENT binlog format and empty result set
- seems to be committing empty. Figure out why and try to fix
- elsewhere. */
- DBUG_ASSERT(!wsrep_has_changes(thd) ||
- (thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
- !thd->is_current_stmt_binlog_format_row()));
- bool have_error= wsrep_current_error(thd);
- int ret= wsrep_before_rollback(thd, all) ||
- wsrep_after_rollback(thd, all) ||
- wsrep_after_statement(thd);
- /* The committing transaction was empty but it held some locks and
- got BF aborted. As there were no certified changes in the
- data, we ignore the deadlock error and rely on error reporting
- by storage engine/server. */
- if (!ret && !have_error && wsrep_current_error(thd))
- {
- DBUG_ASSERT(wsrep_current_error(thd) == wsrep::e_deadlock_error);
- thd->wsrep_cs().reset_error();
- }
- if (ret)
- {
- WSREP_DEBUG("wsrep_commit_empty failed: %d", wsrep_current_error(thd));
- }
- }
- DBUG_VOID_RETURN;
-}
-
#endif /* WSREP_TRANS_OBSERVER */
diff --git a/sql/wsrep_utils.cc b/sql/wsrep_utils.cc
index 49ea78a3872..59fa68db6c0 100644
--- a/sql/wsrep_utils.cc
+++ b/sql/wsrep_utils.cc
@@ -426,7 +426,7 @@ thd::thd (my_bool won) : init(), ptr(new THD(0))
wsrep_store_threadvars(ptr);
ptr->variables.option_bits&= ~OPTION_BIN_LOG; // disable binlog
ptr->variables.wsrep_on= won;
- ptr->security_ctx->master_access= ~(ulong)0;
+ ptr->security_ctx->master_access= ALL_KNOWN_ACL;
lex_start(ptr);
}
}
diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc
index 8ec251d8915..28dbe4096f7 100644
--- a/sql/wsrep_var.cc
+++ b/sql/wsrep_var.cc
@@ -30,14 +30,17 @@ ulong wsrep_reject_queries;
int wsrep_init_vars()
{
- wsrep_provider = my_strdup(WSREP_NONE, MYF(MY_WME));
- wsrep_provider_options= my_strdup("", MYF(MY_WME));
- wsrep_cluster_address = my_strdup("", MYF(MY_WME));
- wsrep_cluster_name = my_strdup(WSREP_CLUSTER_NAME, MYF(MY_WME));
- wsrep_node_name = my_strdup("", MYF(MY_WME));
- wsrep_node_address = my_strdup("", MYF(MY_WME));
- wsrep_node_incoming_address= my_strdup(WSREP_NODE_INCOMING_AUTO, MYF(MY_WME));
- wsrep_start_position = my_strdup(WSREP_START_POSITION_ZERO, MYF(MY_WME));
+ wsrep_provider = my_strdup(PSI_INSTRUMENT_ME, WSREP_NONE, MYF(MY_WME));
+ wsrep_provider_options= my_strdup(PSI_INSTRUMENT_ME, "", MYF(MY_WME));
+ wsrep_cluster_address = my_strdup(PSI_INSTRUMENT_ME, "", MYF(MY_WME));
+ wsrep_cluster_name = my_strdup(PSI_INSTRUMENT_ME, WSREP_CLUSTER_NAME, MYF(MY_WME));
+ wsrep_node_name = my_strdup(PSI_INSTRUMENT_ME, "", MYF(MY_WME));
+ wsrep_node_address = my_strdup(PSI_INSTRUMENT_ME, "", MYF(MY_WME));
+ wsrep_node_incoming_address= my_strdup(PSI_INSTRUMENT_ME, WSREP_NODE_INCOMING_AUTO, MYF(MY_WME));
+ if (wsrep_gtid_mode)
+ wsrep_start_position = my_strdup(PSI_INSTRUMENT_ME, WSREP_START_POSITION_ZERO_GTID, MYF(MY_WME));
+ else
+ wsrep_start_position = my_strdup(PSI_INSTRUMENT_ME, WSREP_START_POSITION_ZERO, MYF(MY_WME));
return 0;
}
@@ -47,7 +50,7 @@ static int get_provider_option_value(const char* opts,
{
int ret= 1;
ulong opt_value_tmp;
- char *opt_value_str, *s, *opts_copy= my_strdup(opts, MYF(MY_WME));
+ char *opt_value_str, *s, *opts_copy= my_strdup(PSI_INSTRUMENT_ME, opts, MYF(MY_WME));
if ((opt_value_str= strstr(opts_copy, opt_name)) == NULL)
goto end;
@@ -171,6 +174,13 @@ bool wsrep_sync_wait_update (sys_var* self, THD* thd, enum_var_type var_type)
return false;
}
+template<typename T>
+static T parse_value(char** startptr, char** endptr)
+{
+ T val= strtoll(*startptr, *&endptr, 10);
+ *startptr= *endptr;
+ return val;
+}
/*
Verify the format of the given UUID:seqno.
@@ -204,8 +214,25 @@ bool wsrep_start_position_verify (const char* start_str)
return true;
char* endptr;
+ char* startptr= (char *)start_str + uuid_len + 1;
wsrep_seqno_t const seqno __attribute__((unused)) // to avoid GCC warnings
- (strtoll(&start_str[uuid_len + 1], &endptr, 10));
+ (parse_value<uint64_t>(&startptr, &endptr));
+
+ // Start parsing native GTID part
+ if (*startptr == ',')
+ {
+ startptr++;
+ uint32_t domain __attribute__((unused))
+ (parse_value<uint32_t>(&startptr, &endptr));
+ if (*endptr != '-') return true;
+ startptr++;
+ uint32_t server __attribute__((unused))
+ (parse_value<uint32_t>(&startptr, &endptr));
+ if (*endptr != '-') return true;
+ startptr++;
+ uint64_t seq __attribute__((unused))
+ (parse_value<uint64_t>(&startptr, &endptr));
+ }
// Remaining string was seqno.
if (*endptr == '\0') return false;
@@ -218,9 +245,22 @@ static
bool wsrep_set_local_position(THD* thd, const char* const value,
size_t length, bool const sst)
{
+ char* endptr;
+ char* startptr;
wsrep_uuid_t uuid;
size_t const uuid_len= wsrep_uuid_scan(value, length, &uuid);
- wsrep_seqno_t const seqno= strtoll(value + uuid_len + 1, NULL, 10);
+ startptr= (char *)value + uuid_len + 1;
+ wsrep_seqno_t const seqno= parse_value<uint64_t>(&startptr, &endptr);
+
+ if (*startptr == ',')
+ {
+ startptr++;
+ wsrep_gtid_server.domain_id= parse_value<uint32_t>(&startptr, &endptr);
+ startptr++;
+ wsrep_gtid_server.server_id= parse_value<uint32_t>(&startptr, &endptr);
+ startptr++;
+ wsrep_gtid_server.seqno(parse_value<uint64_t>(&startptr, &endptr));
+ }
if (sst) {
wsrep_sst_received (thd, uuid, seqno, NULL, 0);
@@ -396,7 +436,7 @@ void wsrep_provider_init (const char* value)
}
if (wsrep_provider) my_free((void *)wsrep_provider);
- wsrep_provider= my_strdup(value, MYF(0));
+ wsrep_provider= my_strdup(PSI_INSTRUMENT_MEM, value, MYF(0));
}
bool wsrep_provider_options_check(sys_var *self, THD* thd, set_var* var)
@@ -426,7 +466,7 @@ void wsrep_provider_options_init(const char* value)
{
if (wsrep_provider_options && wsrep_provider_options != value)
my_free((void *)wsrep_provider_options);
- wsrep_provider_options= (value) ? my_strdup(value, MYF(0)) : NULL;
+ wsrep_provider_options= value ? my_strdup(PSI_INSTRUMENT_MEM, value, MYF(0)) : NULL;
}
bool wsrep_reject_queries_update(sys_var *self, THD* thd, enum_var_type type)
@@ -457,6 +497,15 @@ bool wsrep_debug_update(sys_var *self, THD* thd, enum_var_type type)
return false;
}
+bool
+wsrep_gtid_seq_no_check(sys_var *self, THD *thd, set_var *var)
+{
+ ulonglong new_wsrep_gtid_seq_no= var->save_result.ulonglong_value;
+ if (wsrep_gtid_mode && new_wsrep_gtid_seq_no > wsrep_gtid_server.seqno())
+ return false;
+ return true;
+}
+
static int wsrep_cluster_address_verify (const char* cluster_address_str)
{
/* There is no predefined address format, it depends on provider. */
@@ -529,8 +578,8 @@ void wsrep_cluster_address_init (const char* value)
(wsrep_cluster_address) ? wsrep_cluster_address : "null",
(value) ? value : "null");
- my_free((void*) wsrep_cluster_address);
- wsrep_cluster_address= my_strdup(value ? value : "", MYF(0));
+ my_free(const_cast<char*>(wsrep_cluster_address));
+ wsrep_cluster_address= my_strdup(PSI_INSTRUMENT_MEM, safe_str(value), MYF(0));
}
/* wsrep_cluster_name cannot be NULL or an empty string. */
@@ -603,7 +652,7 @@ void wsrep_node_address_init (const char* value)
if (wsrep_node_address && strcmp(wsrep_node_address, value))
my_free ((void*)wsrep_node_address);
- wsrep_node_address= (value) ? my_strdup(value, MYF(0)) : NULL;
+ wsrep_node_address= value ? my_strdup(PSI_INSTRUMENT_MEM, value, MYF(0)) : NULL;
}
static void wsrep_slave_count_change_update ()
diff --git a/sql/wsrep_var.h b/sql/wsrep_var.h
index 481df02f2d5..810ed4f3dd7 100644
--- a/sql/wsrep_var.h
+++ b/sql/wsrep_var.h
@@ -20,9 +20,10 @@
#ifdef WITH_WSREP
-#define WSREP_CLUSTER_NAME "my_wsrep_cluster"
-#define WSREP_NODE_INCOMING_AUTO "AUTO"
-#define WSREP_START_POSITION_ZERO "00000000-0000-0000-0000-000000000000:-1"
+#define WSREP_CLUSTER_NAME "my_wsrep_cluster"
+#define WSREP_NODE_INCOMING_AUTO "AUTO"
+#define WSREP_START_POSITION_ZERO "00000000-0000-0000-0000-000000000000:-1"
+#define WSREP_START_POSITION_ZERO_GTID "00000000-0000-0000-0000-000000000000:-1,0-0-0"
// MySQL variables funcs
@@ -102,6 +103,8 @@ extern bool wsrep_reject_queries_update UPDATE_ARGS;
extern bool wsrep_debug_update UPDATE_ARGS;
+extern bool wsrep_gtid_seq_no_check CHECK_ARGS;
+
#else /* WITH_WSREP */
#define wsrep_provider_init(X)
diff --git a/sql/wsrep_xid.cc b/sql/wsrep_xid.cc
index d8f6e013820..c84071e13d0 100644
--- a/sql/wsrep_xid.cc
+++ b/sql/wsrep_xid.cc
@@ -33,20 +33,24 @@
#define WSREP_XID_VERSION_OFFSET WSREP_XID_PREFIX_LEN
#define WSREP_XID_VERSION_1 'd'
#define WSREP_XID_VERSION_2 'e'
+#define WSREP_XID_VERSION_3 'f'
#define WSREP_XID_UUID_OFFSET 8
#define WSREP_XID_SEQNO_OFFSET (WSREP_XID_UUID_OFFSET + sizeof(wsrep_uuid_t))
-#define WSREP_XID_GTRID_LEN (WSREP_XID_SEQNO_OFFSET + sizeof(wsrep_seqno_t))
+#define WSREP_XID_GTRID_LEN_V_1_2 (WSREP_XID_SEQNO_OFFSET + sizeof(wsrep_seqno_t))
+#define WSREP_XID_RPL_GTID_OFFSET (WSREP_XID_SEQNO_OFFSET + sizeof(wsrep_seqno_t))
+#define WSREP_XID_GTRID_LEN_V_3 (WSREP_XID_RPL_GTID_OFFSET + sizeof(wsrep_server_gtid_t))
-void wsrep_xid_init(XID* xid, const wsrep::gtid& wsgtid)
+void wsrep_xid_init(XID* xid, const wsrep::gtid& wsgtid, const wsrep_server_gtid_t& gtid)
{
xid->formatID= 1;
- xid->gtrid_length= WSREP_XID_GTRID_LEN;
+ xid->gtrid_length= WSREP_XID_GTRID_LEN_V_3;
xid->bqual_length= 0;
memset(xid->data, 0, sizeof(xid->data));
memcpy(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN);
- xid->data[WSREP_XID_VERSION_OFFSET]= WSREP_XID_VERSION_2;
+ xid->data[WSREP_XID_VERSION_OFFSET]= WSREP_XID_VERSION_3;
memcpy(xid->data + WSREP_XID_UUID_OFFSET, wsgtid.id().data(),sizeof(wsrep::id));
int8store(xid->data + WSREP_XID_SEQNO_OFFSET, wsgtid.seqno().get());
+ memcpy(xid->data + WSREP_XID_RPL_GTID_OFFSET, &gtid, sizeof(wsrep_server_gtid_t));
}
extern "C"
@@ -54,11 +58,13 @@ int wsrep_is_wsrep_xid(const void* xid_ptr)
{
const XID* xid= static_cast<const XID*>(xid_ptr);
return (xid->formatID == 1 &&
- xid->gtrid_length == WSREP_XID_GTRID_LEN &&
xid->bqual_length == 0 &&
- !memcmp(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN) &&
- (xid->data[WSREP_XID_VERSION_OFFSET] == WSREP_XID_VERSION_1 ||
- xid->data[WSREP_XID_VERSION_OFFSET] == WSREP_XID_VERSION_2));
+ !memcmp(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN) &&
+ (((xid->data[WSREP_XID_VERSION_OFFSET] == WSREP_XID_VERSION_1 ||
+ xid->data[WSREP_XID_VERSION_OFFSET] == WSREP_XID_VERSION_2) &&
+ xid->gtrid_length == WSREP_XID_GTRID_LEN_V_1_2) ||
+ (xid->data[WSREP_XID_VERSION_OFFSET] == WSREP_XID_VERSION_3 &&
+ xid->gtrid_length == WSREP_XID_GTRID_LEN_V_3)));
}
const unsigned char* wsrep_xid_uuid(const xid_t* xid)
@@ -90,6 +96,7 @@ long long wsrep_xid_seqno(const xid_t* xid)
memcpy(&ret, xid->data + WSREP_XID_SEQNO_OFFSET, sizeof ret);
break;
case WSREP_XID_VERSION_2:
+ case WSREP_XID_VERSION_3:
ret= sint8korr(xid->data + WSREP_XID_SEQNO_OFFSET);
break;
default:
@@ -127,10 +134,10 @@ bool wsrep_set_SE_checkpoint(XID& xid)
&xid);
}
-bool wsrep_set_SE_checkpoint(const wsrep::gtid& wsgtid)
+bool wsrep_set_SE_checkpoint(const wsrep::gtid& wsgtid, const wsrep_server_gtid_t& gtid)
{
XID xid;
- wsrep_xid_init(&xid, wsgtid);
+ wsrep_xid_init(&xid, wsgtid, gtid);
return wsrep_set_SE_checkpoint(xid);
}
@@ -158,30 +165,61 @@ bool wsrep_get_SE_checkpoint(XID& xid)
&xid);
}
-wsrep::gtid wsrep_get_SE_checkpoint()
+static bool wsrep_get_SE_checkpoint_common(XID& xid)
{
- XID xid;
xid.null();
if (wsrep_get_SE_checkpoint(xid))
{
- return wsrep::gtid();
+ return FALSE;
}
if (xid.is_null())
{
- return wsrep::gtid();
+ return FALSE;
}
if (!wsrep_is_wsrep_xid(&xid))
{
WSREP_WARN("Read non-wsrep XID from storage engines.");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+template<>
+wsrep::gtid wsrep_get_SE_checkpoint()
+{
+ XID xid;
+
+ if (!wsrep_get_SE_checkpoint_common(xid))
+ {
return wsrep::gtid();
}
return wsrep::gtid(wsrep_xid_uuid(xid),wsrep_xid_seqno(xid));
}
+template<>
+wsrep_server_gtid_t wsrep_get_SE_checkpoint()
+{
+ XID xid;
+ wsrep_server_gtid_t gtid= {0,0,0};
+
+ if (!wsrep_get_SE_checkpoint_common(xid))
+ {
+ return gtid;
+ }
+
+ if (xid.data[WSREP_XID_VERSION_OFFSET] == WSREP_XID_VERSION_3)
+ {
+ memcpy(&gtid, &xid.data[WSREP_XID_RPL_GTID_OFFSET], sizeof(wsrep_server_gtid_t));
+ }
+
+ return gtid;
+}
+
/*
Sort order for XIDs. Wsrep XIDs are sorted according to
seqno in ascending order. Non-wsrep XIDs are considered
diff --git a/sql/wsrep_xid.h b/sql/wsrep_xid.h
index a1b9afc1817..45ba6ffee6b 100644
--- a/sql/wsrep_xid.h
+++ b/sql/wsrep_xid.h
@@ -20,15 +20,16 @@
#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
#include "wsrep/gtid.hpp"
#include "handler.h" // XID typedef
-void wsrep_xid_init(xid_t*, const wsrep::gtid&);
+void wsrep_xid_init(xid_t*, const wsrep::gtid&, const wsrep_server_gtid_t&);
const wsrep::id& wsrep_xid_uuid(const XID&);
wsrep::seqno wsrep_xid_seqno(const XID&);
-wsrep::gtid wsrep_get_SE_checkpoint();
-bool wsrep_set_SE_checkpoint(const wsrep::gtid& gtid);
+template<typename T> T wsrep_get_SE_checkpoint();
+bool wsrep_set_SE_checkpoint(const wsrep::gtid& gtid, const wsrep_server_gtid_t&);
//void wsrep_get_SE_checkpoint(XID&); /* uncomment if needed */
//void wsrep_set_SE_checkpoint(XID&); /* uncomment if needed */
diff --git a/sql/xa.cc b/sql/xa.cc
index 9ee1cefbaf9..cde6350f38d 100644
--- a/sql/xa.cc
+++ b/sql/xa.cc
@@ -19,14 +19,14 @@
#include "mariadb.h"
#include "sql_class.h"
#include "transaction.h"
+#include <pfs_transaction_provider.h>
+#include <mysql/psi/mysql_transaction.h>
+static bool slave_applier_reset_xa_trans(THD *thd);
/***************************************************************************
- Handling of XA id cacheing
+ Handling of XA id caching
***************************************************************************/
-enum xa_states { XA_ACTIVE= 0, XA_IDLE, XA_PREPARED, XA_ROLLBACK_ONLY };
-
-
struct XID_cache_insert_element
{
enum xa_states xa_state;
@@ -158,6 +158,12 @@ static LF_HASH xid_cache;
static bool xid_cache_inited;
+enum xa_states XID_STATE::get_state_code() const
+{
+ return xid_cache_element ? xid_cache_element->xa_state : XA_NO_STATE;
+}
+
+
bool THD::fix_xid_hash_pins()
{
if (!xid_hash_pins)
@@ -176,9 +182,8 @@ void XID_STATE::set_error(uint error)
void XID_STATE::er_xaer_rmfail() const
{
static const char *xa_state_names[]=
- { "ACTIVE", "IDLE", "PREPARED", "ROLLBACK ONLY" };
- my_error(ER_XAER_RMFAIL, MYF(0), is_explicit_XA() ?
- xa_state_names[xid_cache_element->xa_state] : "NON-EXISTING");
+ { "ACTIVE", "IDLE", "PREPARED", "ROLLBACK ONLY", "NON-EXISTING"};
+ my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[get_state_code()]);
}
@@ -380,7 +385,7 @@ static bool xa_trans_rolled_back(XID_cache_element *element)
@return TRUE if the rollback failed, FALSE otherwise.
*/
-static bool xa_trans_force_rollback(THD *thd)
+bool xa_trans_force_rollback(THD *thd)
{
bool rc= false;
@@ -389,8 +394,8 @@ static bool xa_trans_force_rollback(THD *thd)
my_error(ER_XAER_RMERR, MYF(0));
rc= true;
}
-
- thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->variables.option_bits&=
+ ~(OPTION_BEGIN | OPTION_KEEP_LOG | OPTION_GTID_BEGIN);
thd->transaction.all.reset();
thd->server_status&=
~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
@@ -425,19 +430,25 @@ bool trans_xa_start(THD *thd)
if (not_equal)
my_error(ER_XAER_NOTA, MYF(0));
else
+ {
thd->transaction.xid_state.xid_cache_element->xa_state= XA_ACTIVE;
+ MYSQL_SET_TRANSACTION_XA_STATE(thd->m_transaction_psi, XA_ACTIVE);
+ }
DBUG_RETURN(not_equal);
}
/* TODO: JOIN is not supported yet. */
if (thd->lex->xa_opt != XA_NONE)
my_error(ER_XAER_INVAL, MYF(0));
+ else if (!thd->lex->xid->gtrid_length)
+ my_error(ER_XAER_INVAL, MYF(0));
else if (thd->transaction.xid_state.is_explicit_XA())
thd->transaction.xid_state.er_xaer_rmfail();
else if (thd->locked_tables_mode || thd->in_active_multi_stmt_transaction())
my_error(ER_XAER_OUTSIDE, MYF(0));
else if (!trans_begin(thd))
{
+ MYSQL_SET_TRANSACTION_XID(thd->m_transaction_psi, thd->lex->xid, XA_ACTIVE);
if (xid_cache_insert(thd, &thd->transaction.xid_state, thd->lex->xid))
{
trans_rollback(thd);
@@ -472,7 +483,10 @@ bool trans_xa_end(THD *thd)
else if (!thd->transaction.xid_state.xid_cache_element->xid.eq(thd->lex->xid))
my_error(ER_XAER_NOTA, MYF(0));
else if (!xa_trans_rolled_back(thd->transaction.xid_state.xid_cache_element))
+ {
thd->transaction.xid_state.xid_cache_element->xa_state= XA_IDLE;
+ MYSQL_SET_TRANSACTION_XA_STATE(thd->m_transaction_psi, XA_IDLE);
+ }
DBUG_RETURN(thd->is_error() ||
thd->transaction.xid_state.xid_cache_element->xa_state != XA_IDLE);
@@ -490,6 +504,8 @@ bool trans_xa_end(THD *thd)
bool trans_xa_prepare(THD *thd)
{
+ int res= 1;
+
DBUG_ENTER("trans_xa_prepare");
if (!thd->transaction.xid_state.is_explicit_XA() ||
@@ -497,16 +513,41 @@ bool trans_xa_prepare(THD *thd)
thd->transaction.xid_state.er_xaer_rmfail();
else if (!thd->transaction.xid_state.xid_cache_element->xid.eq(thd->lex->xid))
my_error(ER_XAER_NOTA, MYF(0));
- else if (ha_prepare(thd))
+ else
{
- xid_cache_delete(thd, &thd->transaction.xid_state);
- my_error(ER_XA_RBROLLBACK, MYF(0));
+ /*
+ Acquire metadata lock which will ensure that COMMIT is blocked
+ by active FLUSH TABLES WITH READ LOCK (and vice versa COMMIT in
+ progress blocks FTWRL).
+
+ We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
+ */
+ MDL_request mdl_request;
+ MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
+ MDL_STATEMENT);
+ if (thd->mdl_context.acquire_lock(&mdl_request,
+ thd->variables.lock_wait_timeout) ||
+ ha_prepare(thd))
+ {
+ if (!mdl_request.ticket)
+ ha_rollback_trans(thd, TRUE);
+ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->transaction.all.reset();
+ thd->server_status&=
+ ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
+ xid_cache_delete(thd, &thd->transaction.xid_state);
+ my_error(ER_XA_RBROLLBACK, MYF(0));
+ }
+ else
+ {
+ thd->transaction.xid_state.xid_cache_element->xa_state= XA_PREPARED;
+ MYSQL_SET_TRANSACTION_XA_STATE(thd->m_transaction_psi, XA_PREPARED);
+ res= thd->variables.pseudo_slave_mode || thd->slave_thread ?
+ slave_applier_reset_xa_trans(thd) : 0;
+ }
}
- else
- thd->transaction.xid_state.xid_cache_element->xa_state= XA_PREPARED;
- DBUG_RETURN(thd->is_error() ||
- thd->transaction.xid_state.xid_cache_element->xa_state != XA_PREPARED);
+ DBUG_RETURN(res);
}
@@ -521,12 +562,32 @@ bool trans_xa_prepare(THD *thd)
bool trans_xa_commit(THD *thd)
{
- bool res= TRUE;
+ bool res= true;
+ XID_STATE &xid_state= thd->transaction.xid_state;
+
DBUG_ENTER("trans_xa_commit");
- if (!thd->transaction.xid_state.is_explicit_XA() ||
- !thd->transaction.xid_state.xid_cache_element->xid.eq(thd->lex->xid))
+ if (!xid_state.is_explicit_XA() ||
+ !xid_state.xid_cache_element->xid.eq(thd->lex->xid))
{
+ if (thd->in_multi_stmt_transaction_mode())
+ {
+ /*
+ Not allow to commit from inside an not-"native" to xid
+ ongoing transaction: the commit effect can't be reversed.
+ */
+ my_error(ER_XAER_OUTSIDE, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ if (thd->lex->xa_opt != XA_NONE)
+ {
+ /*
+ Not allow to commit with one phase a prepared xa out of compatibility
+ with the native commit branch's error out.
+ */
+ my_error(ER_XAER_INVAL, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
if (thd->fix_xid_hash_pins())
{
my_error(ER_OUT_OF_RESOURCES, MYF(0));
@@ -536,7 +597,44 @@ bool trans_xa_commit(THD *thd)
if (auto xs= xid_cache_search(thd, thd->lex->xid))
{
res= xa_trans_rolled_back(xs);
+ /*
+ Acquire metadata lock which will ensure that COMMIT is blocked
+ by active FLUSH TABLES WITH READ LOCK (and vice versa COMMIT in
+ progress blocks FTWRL).
+
+ We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
+ */
+ MDL_request mdl_request;
+ MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
+ MDL_STATEMENT);
+ if (thd->mdl_context.acquire_lock(&mdl_request,
+ thd->variables.lock_wait_timeout))
+ {
+ /*
+ We can't rollback an XA transaction on lock failure due to
+ Innodb redo log and bin log update is involved in rollback.
+ Return error to user for a retry.
+ */
+ DBUG_ASSERT(thd->is_error());
+
+ xs->acquired_to_recovered();
+ DBUG_RETURN(true);
+ }
+ DBUG_ASSERT(!xid_state.xid_cache_element);
+
+ if (thd->wait_for_prior_commit())
+ {
+ DBUG_ASSERT(thd->is_error());
+
+ xs->acquired_to_recovered();
+ DBUG_RETURN(true);
+ }
+
+ xid_state.xid_cache_element= xs;
ha_commit_or_rollback_by_xid(thd->lex->xid, !res);
+ xid_state.xid_cache_element= 0;
+
+ res= res || thd->is_error();
xid_cache_delete(thd, xs);
}
else
@@ -544,22 +642,26 @@ bool trans_xa_commit(THD *thd)
DBUG_RETURN(res);
}
- if (xa_trans_rolled_back(thd->transaction.xid_state.xid_cache_element))
+ if (xa_trans_rolled_back(xid_state.xid_cache_element))
{
xa_trans_force_rollback(thd);
DBUG_RETURN(thd->is_error());
}
- else if (thd->transaction.xid_state.xid_cache_element->xa_state == XA_IDLE &&
+ else if (xid_state.xid_cache_element->xa_state == XA_IDLE &&
thd->lex->xa_opt == XA_ONE_PHASE)
{
int r= ha_commit_trans(thd, TRUE);
if ((res= MY_TEST(r)))
my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
}
- else if (thd->transaction.xid_state.xid_cache_element->xa_state == XA_PREPARED &&
- thd->lex->xa_opt == XA_NONE)
+ else if (thd->transaction.xid_state.xid_cache_element->xa_state == XA_PREPARED)
{
MDL_request mdl_request;
+ if (thd->lex->xa_opt != XA_NONE)
+ {
+ my_error(ER_XAER_INVAL, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
/*
Acquire metadata lock which will ensure that COMMIT is blocked
@@ -568,27 +670,41 @@ bool trans_xa_commit(THD *thd)
We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
*/
- mdl_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
+ MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
MDL_TRANSACTION);
if (thd->mdl_context.acquire_lock(&mdl_request,
thd->variables.lock_wait_timeout))
{
- ha_rollback_trans(thd, TRUE);
+ /*
+ We can't rollback an XA transaction on lock failure due to
+ Innodb redo log and bin log update is involved in rollback.
+ Return error to user for a retry.
+ */
my_error(ER_XAER_RMERR, MYF(0));
+ DBUG_RETURN(true);
}
else
{
DEBUG_SYNC(thd, "trans_xa_commit_after_acquire_commit_lock");
- res= MY_TEST(ha_commit_one_phase(thd, 1));
- if (res)
+ if ((res= MY_TEST(ha_commit_one_phase(thd, 1))))
my_error(ER_XAER_RMERR, MYF(0));
+ else
+ {
+ /*
+ Since we don't call ha_commit_trans() for prepared transactions,
+ we need to explicitly mark the transaction as committed.
+ */
+ MYSQL_COMMIT_TRANSACTION(thd->m_transaction_psi);
+ }
+
+ thd->m_transaction_psi= NULL;
}
}
else
{
- thd->transaction.xid_state.er_xaer_rmfail();
+ xid_state.er_xaer_rmfail();
DBUG_RETURN(TRUE);
}
@@ -597,10 +713,11 @@ bool trans_xa_commit(THD *thd)
thd->server_status&=
~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
- xid_cache_delete(thd, &thd->transaction.xid_state);
+ xid_cache_delete(thd, &xid_state);
trans_track_end_trx(thd);
-
+ /* The transaction should be marked as complete in P_S. */
+ DBUG_ASSERT(thd->m_transaction_psi == NULL || res);
DBUG_RETURN(res);
}
@@ -616,11 +733,18 @@ bool trans_xa_commit(THD *thd)
bool trans_xa_rollback(THD *thd)
{
+ XID_STATE &xid_state= thd->transaction.xid_state;
+
DBUG_ENTER("trans_xa_rollback");
- if (!thd->transaction.xid_state.is_explicit_XA() ||
- !thd->transaction.xid_state.xid_cache_element->xid.eq(thd->lex->xid))
+ if (!xid_state.is_explicit_XA() ||
+ !xid_state.xid_cache_element->xid.eq(thd->lex->xid))
{
+ if (thd->in_multi_stmt_transaction_mode())
+ {
+ my_error(ER_XAER_OUTSIDE, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
if (thd->fix_xid_hash_pins())
{
my_error(ER_OUT_OF_RESOURCES, MYF(0));
@@ -629,8 +753,35 @@ bool trans_xa_rollback(THD *thd)
if (auto xs= xid_cache_search(thd, thd->lex->xid))
{
+ MDL_request mdl_request;
+ MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
+ MDL_STATEMENT);
+ if (thd->mdl_context.acquire_lock(&mdl_request,
+ thd->variables.lock_wait_timeout))
+ {
+ /*
+ We can't rollback an XA transaction on lock failure due to
+ Innodb redo log and bin log update is involved in rollback.
+ Return error to user for a retry.
+ */
+ DBUG_ASSERT(thd->is_error());
+
+ xs->acquired_to_recovered();
+ DBUG_RETURN(true);
+ }
xa_trans_rolled_back(xs);
+ DBUG_ASSERT(!xid_state.xid_cache_element);
+
+ if (thd->wait_for_prior_commit())
+ {
+ DBUG_ASSERT(thd->is_error());
+ xs->acquired_to_recovered();
+ DBUG_RETURN(true);
+ }
+
+ xid_state.xid_cache_element= xs;
ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
+ xid_state.xid_cache_element= 0;
xid_cache_delete(thd, xs);
}
else
@@ -638,11 +789,27 @@ bool trans_xa_rollback(THD *thd)
DBUG_RETURN(thd->get_stmt_da()->is_error());
}
- if (thd->transaction.xid_state.xid_cache_element->xa_state == XA_ACTIVE)
+ if (xid_state.xid_cache_element->xa_state == XA_ACTIVE)
{
- thd->transaction.xid_state.er_xaer_rmfail();
+ xid_state.er_xaer_rmfail();
DBUG_RETURN(TRUE);
}
+
+ MDL_request mdl_request;
+ MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
+ MDL_STATEMENT);
+ if (thd->mdl_context.acquire_lock(&mdl_request,
+ thd->variables.lock_wait_timeout))
+ {
+ /*
+ We can't rollback an XA transaction on lock failure due to
+ Innodb redo log and bin log update is involved in rollback.
+ Return error to user for a retry.
+ */
+ my_error(ER_XAER_RMERR, MYF(0));
+ DBUG_RETURN(true);
+ }
+
DBUG_RETURN(xa_trans_force_rollback(thd));
}
@@ -650,11 +817,15 @@ bool trans_xa_rollback(THD *thd)
bool trans_xa_detach(THD *thd)
{
DBUG_ASSERT(thd->transaction.xid_state.is_explicit_XA());
-#if 1
- return xa_trans_force_rollback(thd);
-#else
+
if (thd->transaction.xid_state.xid_cache_element->xa_state != XA_PREPARED)
return xa_trans_force_rollback(thd);
+ else if (!thd->transaction.all.is_trx_read_write())
+ {
+ thd->transaction.xid_state.set_error(ER_XA_RBROLLBACK);
+ ha_rollback_trans(thd, true);
+ }
+
thd->transaction.xid_state.xid_cache_element->acquired_to_recovered();
thd->transaction.xid_state.xid_cache_element= 0;
thd->transaction.cleanup();
@@ -671,7 +842,6 @@ bool trans_xa_detach(THD *thd)
thd->transaction.all.ha_list= 0;
thd->transaction.all.no_2pc= 0;
return false;
-#endif
}
@@ -814,7 +984,7 @@ static my_bool xa_recover_callback_verbose(XID_cache_element *xs,
char buf[SQL_XIDSIZE];
uint len= get_sql_xid(&xs->xid, buf);
return xa_recover_callback(xs, protocol, buf, len,
- &my_charset_utf8_general_ci);
+ &my_charset_utf8mb3_general_ci);
}
@@ -842,7 +1012,7 @@ bool mysql_xa_recover(THD *thd)
if (thd->lex->verbose)
{
len= SQL_XIDSIZE;
- cs= &my_charset_utf8_general_ci;
+ cs= &my_charset_utf8mb3_general_ci;
action= (my_hash_walk_action) xa_recover_callback_verbose;
}
else
@@ -865,3 +1035,45 @@ bool mysql_xa_recover(THD *thd)
my_eof(thd);
DBUG_RETURN(0);
}
+
+
+/**
+ This is a specific to (pseudo-) slave applier collection of standard cleanup
+ actions to reset XA transaction state sim to @c ha_commit_one_phase.
+ THD of the slave applier is dissociated from a transaction object in engine
+ that continues to exist there.
+
+ @param THD current thread
+ @return the value of is_error()
+*/
+
+static bool slave_applier_reset_xa_trans(THD *thd)
+{
+ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->server_status&=
+ ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
+ DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
+
+ thd->transaction.xid_state.xid_cache_element->acquired_to_recovered();
+ thd->transaction.xid_state.xid_cache_element= 0;
+
+ for (Ha_trx_info *ha_info= thd->transaction.all.ha_list, *ha_info_next;
+ ha_info; ha_info= ha_info_next)
+ {
+ ha_info_next= ha_info->next();
+ ha_info->reset();
+ }
+ thd->transaction.all.ha_list= 0;
+
+ ha_close_connection(thd);
+ thd->transaction.cleanup();
+ thd->transaction.all.reset();
+
+ DBUG_ASSERT(!thd->transaction.all.ha_list);
+ DBUG_ASSERT(!thd->transaction.all.no_2pc);
+
+ thd->has_waiter= false;
+ MYSQL_COMMIT_TRANSACTION(thd->m_transaction_psi); // TODO/Fixme: commit?
+ thd->m_transaction_psi= NULL;
+ return thd->is_error();
+}
diff --git a/sql/xa.h b/sql/xa.h
index 7cf74efad35..0b2d0696642 100644
--- a/sql/xa.h
+++ b/sql/xa.h
@@ -1,3 +1,5 @@
+#ifndef XA_INCLUDED
+#define XA_INCLUDED
/*
Copyright (c) 2000, 2016, Oracle and/or its affiliates.
Copyright (c) 2009, 2019, MariaDB Corporation.
@@ -16,8 +18,15 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
-
class XID_cache_element;
+enum xa_states
+{
+ XA_ACTIVE= 0,
+ XA_IDLE,
+ XA_PREPARED,
+ XA_ROLLBACK_ONLY,
+ XA_NO_STATE
+};
struct XID_STATE {
XID_cache_element *xid_cache_element;
@@ -27,6 +36,7 @@ struct XID_STATE {
void set_error(uint error);
void er_xaer_rmfail() const;
XID *get_xid() const;
+ enum xa_states get_state_code() const;
};
void xid_cache_init(void);
@@ -42,3 +52,5 @@ bool trans_xa_commit(THD *thd);
bool trans_xa_rollback(THD *thd);
bool trans_xa_detach(THD *thd);
bool mysql_xa_recover(THD *thd);
+
+#endif /* XA_INCLUDED */