summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt49
-rw-r--r--client/mysqltest.cc3
-rw-r--r--cmake/build_configurations/mysql_release.cmake1
-rw-r--r--cmake/build_depends.cmake6
-rw-r--r--cmake/cpack_rpm.cmake3
-rw-r--r--cmake/plugin.cmake8
-rw-r--r--cmake/wsrep.cmake7
-rw-r--r--include/my_dbug.h8
-rw-r--r--include/my_global.h28
-rw-r--r--include/my_sys.h3
-rw-r--r--include/my_time.h2
-rw-r--r--include/mysql/service_my_print_error.h2
m---------libmariadb0
-rw-r--r--mysql-test/include/mix1.inc13
-rw-r--r--mysql-test/include/type_hrtime.inc2
-rw-r--r--mysql-test/lib/My/Handles.pm4
-rw-r--r--mysql-test/lib/My/SafeProcess/safe_process.cc2
-rw-r--r--mysql-test/main/analyze_stmt_privileges2.result142
-rw-r--r--mysql-test/main/constraints.result55
-rw-r--r--mysql-test/main/constraints.test37
-rw-r--r--mysql-test/main/cte_nonrecursive.result24
-rw-r--r--mysql-test/main/func_time.result4
-rw-r--r--mysql-test/main/group_by.result3
-rw-r--r--mysql-test/main/index_merge_myisam.result5
-rw-r--r--mysql-test/main/innodb_ext_key.result8
-rw-r--r--mysql-test/main/invisible_field_debug.result12
-rw-r--r--mysql-test/main/invisible_field_debug.test9
-rw-r--r--mysql-test/main/join.result326
-rw-r--r--mysql-test/main/join.test59
-rw-r--r--mysql-test/main/long_unique.result15
-rw-r--r--mysql-test/main/long_unique.test14
-rw-r--r--mysql-test/main/opt_trace.result546
-rw-r--r--mysql-test/main/opt_trace.test31
-rw-r--r--mysql-test/main/opt_tvc.result72
-rw-r--r--mysql-test/main/partition_range.result27
-rw-r--r--mysql-test/main/partition_range.test27
-rw-r--r--mysql-test/main/rowid_filter_innodb.result4
-rw-r--r--mysql-test/main/selectivity.result34
-rw-r--r--mysql-test/main/selectivity.test24
-rw-r--r--mysql-test/main/selectivity_innodb.result34
-rw-r--r--mysql-test/main/subselect.result8
-rw-r--r--mysql-test/main/subselect3.result18
-rw-r--r--mysql-test/main/subselect3_jcl6.result20
-rw-r--r--mysql-test/main/subselect_mat.result16
-rw-r--r--mysql-test/main/subselect_no_mat.result10
-rw-r--r--mysql-test/main/subselect_no_scache.result8
-rw-r--r--mysql-test/main/subselect_sj.result60
-rw-r--r--mysql-test/main/subselect_sj.test25
-rw-r--r--mysql-test/main/subselect_sj2.result55
-rw-r--r--mysql-test/main/subselect_sj2.test3
-rw-r--r--mysql-test/main/subselect_sj2_jcl6.result54
-rw-r--r--mysql-test/main/subselect_sj2_mat.result83
-rw-r--r--mysql-test/main/subselect_sj_jcl6.result61
-rw-r--r--mysql-test/main/subselect_sj_mat.result26
-rw-r--r--mysql-test/main/table_value_constr.result24
-rw-r--r--mysql-test/main/timezone2.result48
-rw-r--r--mysql-test/main/timezone2.test44
-rw-r--r--mysql-test/main/type_date.result31
-rw-r--r--mysql-test/main/type_date.test24
-rw-r--r--mysql-test/main/type_datetime.result42
-rw-r--r--mysql-test/main/type_datetime.test37
-rw-r--r--mysql-test/main/type_datetime_hires.result543
-rw-r--r--mysql-test/main/type_datetime_hires.test70
-rw-r--r--mysql-test/main/type_int.result24
-rw-r--r--mysql-test/main/type_int.test21
-rw-r--r--mysql-test/main/type_time_hires.result315
-rw-r--r--mysql-test/main/type_time_hires.test63
-rw-r--r--mysql-test/main/type_timestamp.result30
-rw-r--r--mysql-test/main/type_timestamp.test18
-rw-r--r--mysql-test/main/type_timestamp_hires.result299
-rw-r--r--mysql-test/main/type_timestamp_hires.test70
-rwxr-xr-xmysql-test/mysql-test-run.pl33
-rw-r--r--mysql-test/suite.pm6
-rw-r--r--mysql-test/suite/binlog/include/drop_temp_table.test8
-rw-r--r--mysql-test/suite/binlog/r/binlog_row_drop_tmp_tbl.result8
-rw-r--r--mysql-test/suite/binlog/r/binlog_stm_drop_tmp_tbl.result8
-rw-r--r--mysql-test/suite/compat/oracle/r/table_value_constr.result24
-rw-r--r--mysql-test/suite/encryption/r/file_creation.result26
-rw-r--r--mysql-test/suite/encryption/t/file_creation.opt1
-rw-r--r--mysql-test/suite/encryption/t/file_creation.test41
-rw-r--r--mysql-test/suite/galera/r/galera_performance_schema.result1
-rw-r--r--mysql-test/suite/galera/t/galera_load_data.test17
-rw-r--r--mysql-test/suite/gcol/r/gcol_select_innodb.result8
-rw-r--r--mysql-test/suite/gcol/r/gcol_select_myisam.result8
-rw-r--r--mysql-test/suite/innodb/r/foreign-keys.result59
-rw-r--r--mysql-test/suite/innodb/r/innodb-fk-warnings.result4
-rw-r--r--mysql-test/suite/innodb/r/innodb-read-view.result222
-rw-r--r--mysql-test/suite/innodb/r/innodb-system-table-view.result5
-rw-r--r--mysql-test/suite/innodb/r/innodb_bug68148.result2
-rw-r--r--mysql-test/suite/innodb/r/innodb_bug84958.result12
-rw-r--r--mysql-test/suite/innodb/r/innodb_mysql.result18
-rw-r--r--mysql-test/suite/innodb/r/instant_alter.result71
-rw-r--r--mysql-test/suite/innodb/r/instant_alter_bugs.result8
-rw-r--r--mysql-test/suite/innodb/t/foreign-keys.test46
-rw-r--r--mysql-test/suite/innodb/t/innodb-read-view.test208
-rw-r--r--mysql-test/suite/innodb/t/innodb-system-table-view.test7
-rw-r--r--mysql-test/suite/innodb/t/innodb_bug68148.test3
-rw-r--r--mysql-test/suite/innodb/t/innodb_bug84958.test9
-rw-r--r--mysql-test/suite/innodb/t/innodb_mysql.test1
-rw-r--r--mysql-test/suite/innodb/t/instant_alter.test24
-rw-r--r--mysql-test/suite/innodb/t/instant_alter_bugs.test11
-rw-r--r--mysql-test/suite/innodb_gis/r/point_basic.result6
-rw-r--r--mysql-test/suite/maria/partition.result4
-rw-r--r--mysql-test/suite/maria/partition.test11
-rw-r--r--mysql-test/suite/mariabackup/compress_qpress.result1
-rw-r--r--mysql-test/suite/mariabackup/disabled.def12
-rw-r--r--mysql-test/suite/rpl/r/rpl_extra_col_master_innodb.result4
-rw-r--r--mysql-test/suite/rpl/r/rpl_extra_col_master_myisam.result4
-rw-r--r--mysql-test/suite/rpl/r/rpl_extra_col_slave_innodb.result10
-rw-r--r--mysql-test/suite/rpl/r/rpl_extra_col_slave_myisam.result10
-rw-r--r--mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result4
-rw-r--r--mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result4
-rw-r--r--mysql-test/suite/rpl/r/rpl_row_colSize.result8
-rw-r--r--mysql-test/suite/rpl/r/rpl_row_type_conv_err_msg.result164
-rw-r--r--mysql-test/suite/rpl/t/rpl_row_type_conv_err_msg.test356
-rw-r--r--mysql-test/suite/sys_vars/r/sysvars_innodb.result1
-rw-r--r--mysql-test/suite/sys_vars/t/sysvars_innodb.test1
-rw-r--r--mysql-test/suite/versioning/r/cte.result6
-rw-r--r--mysql-test/suite/versioning/r/partition.result11
-rw-r--r--mysql-test/suite/versioning/r/partition_rotation.result4
-rw-r--r--mysql-test/suite/versioning/t/partition.test21
-rw-r--r--mysys/my_static.c5
-rw-r--r--plugin/auth_pam/testing/pam_mariadb_mtr.c2
-rw-r--r--scripts/mysqld_multi.sh14
-rwxr-xr-xscripts/wsrep_sst_common.sh72
-rw-r--r--scripts/wsrep_sst_mariabackup.sh62
-rw-r--r--scripts/wsrep_sst_rsync.sh10
-rw-r--r--sql-common/my_time.c2
-rw-r--r--sql/create_options.cc5
-rw-r--r--sql/field.cc45
-rw-r--r--sql/field.h8
-rw-r--r--sql/ha_partition.cc4
-rw-r--r--sql/handler.cc48
-rw-r--r--sql/item.cc32
-rw-r--r--sql/item.h6
-rw-r--r--sql/item_cmpfunc.h3
-rw-r--r--sql/item_func.cc66
-rw-r--r--sql/item_func.h19
-rw-r--r--sql/item_sum.cc72
-rw-r--r--sql/item_sum.h1
-rw-r--r--sql/mysqld.cc6
-rw-r--r--sql/opt_subselect.cc111
-rw-r--r--sql/opt_subselect.h15
-rw-r--r--sql/partition_element.h23
-rw-r--r--sql/partition_info.cc36
-rw-r--r--sql/partition_info.h7
-rw-r--r--sql/rpl_utility_server.cc40
-rw-r--r--sql/select_handler.cc2
-rw-r--r--sql/service_wsrep.cc16
-rw-r--r--sql/share/errmsg-utf8.txt2
-rw-r--r--sql/sql_base.cc13
-rw-r--r--sql/sql_class.h5
-rw-r--r--sql/sql_connect.cc18
-rw-r--r--sql/sql_explain.cc2
-rw-r--r--sql/sql_insert.cc2
-rw-r--r--sql/sql_lex.cc9
-rw-r--r--sql/sql_parse.cc102
-rw-r--r--sql/sql_partition.cc28
-rw-r--r--sql/sql_select.cc70
-rw-r--r--sql/sql_select.h2
-rw-r--r--sql/sql_show.cc5
-rw-r--r--sql/sql_statistics.cc8
-rw-r--r--sql/sql_string.cc2
-rw-r--r--sql/sql_table.cc86
-rw-r--r--sql/sql_time.cc3
-rw-r--r--sql/sql_time.h2
-rw-r--r--sql/sql_type.cc41
-rw-r--r--sql/sql_type.h139
-rw-r--r--sql/sql_yacc.yy8
-rw-r--r--sql/sql_yacc_ora.yy8
-rw-r--r--sql/table.cc7
-rw-r--r--sql/threadpool_common.cc11
-rw-r--r--sql/wsrep_client_service.cc10
-rw-r--r--sql/wsrep_high_priority_service.cc26
-rw-r--r--sql/wsrep_mysqld.cc12
-rw-r--r--sql/wsrep_mysqld.h15
-rw-r--r--sql/wsrep_schema.cc26
-rw-r--r--sql/wsrep_server_service.cc51
-rw-r--r--sql/wsrep_server_service.h9
-rw-r--r--sql/wsrep_sst.cc406
-rw-r--r--sql/wsrep_sst.h1
-rw-r--r--sql/wsrep_storage_service.cc12
-rw-r--r--sql/wsrep_thd.cc365
-rw-r--r--sql/wsrep_thd.h84
-rw-r--r--sql/wsrep_trans_observer.h11
-rw-r--r--sql/wsrep_utils.cc4
-rw-r--r--storage/connect/CMakeLists.txt37
-rw-r--r--storage/connect/array.cpp127
-rw-r--r--storage/connect/block.h4
-rw-r--r--storage/connect/connect.h2
-rw-r--r--storage/connect/global.h1
-rw-r--r--storage/connect/ha_connect.cc613
-rw-r--r--storage/connect/ha_connect.h2
-rw-r--r--storage/connect/inihandl.cpp2
-rw-r--r--storage/connect/jsonudf.cpp8
-rw-r--r--storage/connect/libdoc.cpp2
-rw-r--r--storage/connect/mini-global.h33
-rw-r--r--storage/connect/mycat.cc162
-rw-r--r--storage/connect/mycat.h4
-rw-r--r--storage/connect/mysql-test/connect/r/jdbc_postgresql.result2
-rw-r--r--storage/connect/osutil.h4
-rw-r--r--storage/connect/plgdbsem.h6
-rw-r--r--storage/connect/plugutil.cpp36
-rw-r--r--storage/connect/reldef.cpp299
-rw-r--r--storage/connect/rest.def4
-rw-r--r--storage/connect/rest.h33
-rw-r--r--storage/connect/restget.cpp94
-rw-r--r--storage/connect/tabfmt.cpp2
-rw-r--r--storage/connect/tabjdbc.cpp4
-rw-r--r--storage/connect/tabjson.cpp1941
-rw-r--r--storage/connect/tabrest.cpp201
-rw-r--r--storage/connect/tabrest.h29
-rw-r--r--storage/connect/tabtbl.cpp2
-rw-r--r--storage/connect/user_connect.cc2
-rw-r--r--storage/connect/user_connect.h2
-rw-r--r--storage/heap/hp_scan.c4
-rw-r--r--storage/innobase/btr/btr0scrub.cc7
-rw-r--r--storage/innobase/buf/buf0buf.cc8
-rw-r--r--storage/innobase/dict/dict0dict.cc110
-rw-r--r--storage/innobase/dict/dict0load.cc21
-rw-r--r--storage/innobase/fil/fil0crypt.cc30
-rw-r--r--storage/innobase/fil/fil0fil.cc28
-rw-r--r--storage/innobase/fsp/fsp0file.cc5
-rw-r--r--storage/innobase/handler/ha_innodb.cc43
-rw-r--r--storage/innobase/handler/handler0alter.cc31
-rw-r--r--storage/innobase/include/dict0dict.h30
-rw-r--r--storage/innobase/include/dict0types.h8
-rw-r--r--storage/innobase/include/fil0crypt.h6
-rw-r--r--storage/innobase/include/srv0srv.h1
-rw-r--r--storage/innobase/include/trx0sys.h7
-rw-r--r--storage/innobase/lock/lock0lock.cc7
-rw-r--r--storage/innobase/mtr/mtr0mtr.cc2
-rw-r--r--storage/innobase/row/row0ins.cc79
-rw-r--r--storage/innobase/row/row0log.cc2
-rw-r--r--storage/innobase/row/row0mysql.cc12
-rw-r--r--storage/innobase/row/row0uins.cc3
-rw-r--r--storage/innobase/row/row0upd.cc62
-rw-r--r--storage/innobase/srv/srv0start.cc13
-rw-r--r--storage/innobase/trx/trx0trx.cc45
-rw-r--r--storage/maria/ma_ft_nlq_search.c2
-rw-r--r--storage/myisam/ft_nlq_search.c2
-rw-r--r--storage/perfschema/pfs_instr.cc5
-rw-r--r--storage/rocksdb/mysql-test/rocksdb/include/index_merge1.inc60
-rw-r--r--storage/rocksdb/mysql-test/rocksdb/include/index_merge2.inc28
-rw-r--r--storage/rocksdb/mysql-test/rocksdb/include/index_merge_ror.inc36
-rw-r--r--storage/rocksdb/mysql-test/rocksdb/include/index_merge_ror_cpk.inc8
-rw-r--r--storage/rocksdb/mysql-test/rocksdb/r/index_merge_rocksdb2.result38
-rw-r--r--storage/rocksdb/mysql-test/rocksdb/t/allow_to_start_after_corruption.test2
-rw-r--r--storage/rocksdb/mysql-test/rocksdb/t/autoinc_debug.test2
-rw-r--r--storage/rocksdb/mysql-test/rocksdb/t/disabled.def5
-rw-r--r--storage/sphinx/ha_sphinx.cc9
-rw-r--r--storage/tokudb/mysql-test/rpl/r/rpl_extra_col_master_tokudb.result4
-rw-r--r--storage/tokudb/mysql-test/rpl/r/rpl_extra_col_slave_tokudb.result10
-rw-r--r--storage/tokudb/mysql-test/rpl/r/rpl_row_basic_3tokudb.result4
m---------wsrep-lib0
-rw-r--r--zlib/CMakeLists.txt4
256 files changed, 9043 insertions, 3079 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 33b69a9a1e3..085d7f07fe6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (c) 2006, 2017, Oracle and/or its affiliates.
-# Copyright (c) 2008, 2018, MariaDB Corporation
+# Copyright (c) 2008, 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
@@ -150,9 +150,6 @@ INCLUDE(mysql_version)
INCLUDE(cpack_source_ignore_files)
INCLUDE(install_layout)
INCLUDE(submodules)
-INCLUDE(wsrep)
-INCLUDE(cpack_rpm)
-INCLUDE(cpack_deb)
# Add macros
INCLUDE(character_sets)
@@ -225,9 +222,6 @@ ENDIF()
OPTION(WITH_TSAN "Enable thread sanitizer" OFF)
IF (WITH_TSAN)
- IF(SECURITY_HARDENED)
- MESSAGE(FATAL_ERROR "WITH_TSAN and SECURITY_HARDENED are mutually exclusive")
- ENDIF()
MY_CHECK_AND_SET_COMPILER_FLAG("-fsanitize=thread" DEBUG RELWITHDEBINFO)
ENDIF()
@@ -236,27 +230,26 @@ IF (WITH_UBSAN)
MY_CHECK_AND_SET_COMPILER_FLAG("-fsanitize=undefined -fno-sanitize=alignment -U_FORTIFY_SOURCE" DEBUG RELWITHDEBINFO)
ENDIF()
-IF(NOT WITH_TSAN)
- # enable security hardening features, like most distributions do
- # in our benchmarks that costs about ~1% of performance, depending on the load
- IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "4.6" OR WITH_ASAN OR WITH_UBSAN)
- SET(security_default OFF)
- ELSE()
- SET(security_default ON)
- ENDIF()
- OPTION(SECURITY_HARDENED "Use security-enhancing compiler features (stack protector, relro, etc)" ${security_default})
- IF(SECURITY_HARDENED)
- IF(WITH_ASAN OR WITH_UBSAN)
- MESSAGE(FATAL_ERROR "WITH_ASAN/WITH_UBSAN and SECURITY_HARDENED are mutually exclusive")
- ENDIF()
- # security-enhancing flags
- MY_CHECK_AND_SET_COMPILER_FLAG("-pie -fPIC")
- MY_CHECK_AND_SET_COMPILER_FLAG("-Wl,-z,relro,-z,now")
- MY_CHECK_AND_SET_COMPILER_FLAG("-fstack-protector --param=ssp-buffer-size=4")
- MY_CHECK_AND_SET_COMPILER_FLAG("-D_FORTIFY_SOURCE=2" RELEASE RELWITHDEBINFO)
- ENDIF()
+OPTION(WITH_MSAN "Enable memory sanitizer" OFF)
+IF (WITH_MSAN)
+ MY_CHECK_AND_SET_COMPILER_FLAG("-fsanitize=memory -fsanitize-memory-track-origins -U_FORTIFY_SOURCE" DEBUG RELWITHDEBINFO)
ENDIF()
+# enable security hardening features, like most distributions do
+# in our benchmarks that costs about ~1% of performance, depending on the load
+OPTION(SECURITY_HARDENED "Use security-enhancing compiler features (stack protector, relro, etc)" ON)
+IF(SECURITY_HARDENED AND NOT WITH_ASAN AND NOT WITH_UBSAN AND NOT WITH_TSAN)
+ # security-enhancing flags
+ MY_CHECK_AND_SET_COMPILER_FLAG("-pie -fPIC")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wl,-z,relro,-z,now")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-fstack-protector --param=ssp-buffer-size=4")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-D_FORTIFY_SOURCE=2" RELEASE RELWITHDEBINFO)
+ENDIF()
+
+INCLUDE(wsrep)
+INCLUDE(cpack_rpm)
+INCLUDE(cpack_deb)
+
# Always enable debug sync for debug builds.
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DENABLED_DEBUG_SYNC")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DENABLED_DEBUG_SYNC")
@@ -438,10 +431,6 @@ IF(NOT WITHOUT_SERVER)
ADD_SUBDIRECTORY(unittest/embedded)
ENDIF(WITH_EMBEDDED_SERVER)
- IF(WITH_WSREP)
- ADD_SUBDIRECTORY(wsrep-lib)
- ENDIF()
-
ADD_SUBDIRECTORY(mysql-test)
ADD_SUBDIRECTORY(mysql-test/lib/My/SafeProcess)
ADD_SUBDIRECTORY(sql-bench)
diff --git a/client/mysqltest.cc b/client/mysqltest.cc
index 21f5780ffcb..bb3effafc84 100644
--- a/client/mysqltest.cc
+++ b/client/mysqltest.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2009, 2017, MariaDB
+ 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
@@ -1687,6 +1687,7 @@ void abort_not_supported_test(const char *fmt, ...)
cur_file->file_name, cur_file->lineno);
char buff[DIE_BUFF_SIZE];
+ buff[0] = '\0';
print_file_stack(buff, buff + sizeof(buff));
fprintf(stderr, "%s", buff);
diff --git a/cmake/build_configurations/mysql_release.cmake b/cmake/build_configurations/mysql_release.cmake
index 592c1a20686..f097a1923cc 100644
--- a/cmake/build_configurations/mysql_release.cmake
+++ b/cmake/build_configurations/mysql_release.cmake
@@ -124,6 +124,7 @@ ENDIF()
IF(UNIX)
SET(WITH_EXTRA_CHARSETS all CACHE STRING "")
+ SET(PLUGIN_AUTH_PAM YES)
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
IF(NOT IGNORE_AIO_CHECK)
diff --git a/cmake/build_depends.cmake b/cmake/build_depends.cmake
index 333df580200..5adaee33740 100644
--- a/cmake/build_depends.cmake
+++ b/cmake/build_depends.cmake
@@ -39,6 +39,8 @@ IF(RPM)
SET(BUILD_DEPS ${BUILD_DEPS} ${${V}_DEP})
ENDIF()
ENDFOREACH()
- LIST(REMOVE_DUPLICATES BUILD_DEPS)
- STRING(REPLACE ";" " " CPACK_RPM_BUILDREQUIRES "${BUILD_DEPS}")
+ IF (BUILD_DEPS)
+ LIST(REMOVE_DUPLICATES BUILD_DEPS)
+ STRING(REPLACE ";" " " CPACK_RPM_BUILDREQUIRES "${BUILD_DEPS}")
+ ENDIF()
ENDIF(RPM)
diff --git a/cmake/cpack_rpm.cmake b/cmake/cpack_rpm.cmake
index c17cb1ca19a..4c8835f8c08 100644
--- a/cmake/cpack_rpm.cmake
+++ b/cmake/cpack_rpm.cmake
@@ -37,7 +37,8 @@ IF(CMAKE_VERSION VERSION_LESS "3.6.0")
SET(CPACK_PACKAGE_FILE_NAME "${CPACK_RPM_PACKAGE_NAME}-${VERSION}-${RPM}-${CMAKE_SYSTEM_PROCESSOR}")
ELSE()
SET(CPACK_RPM_FILE_NAME "RPM-DEFAULT")
- SET(CPACK_RPM_DEBUGINFO_PACKAGE ON CACHE INTERNAL "")
+ OPTION(CPACK_RPM_DEBUGINFO_PACKAGE "" ON)
+ MARK_AS_ADVANCED(CPACK_RPM_DEBUGINFO_PACKAGE)
ENDIF()
SET(CPACK_RPM_PACKAGE_RELEASE "1%{?dist}")
diff --git a/cmake/plugin.cmake b/cmake/plugin.cmake
index 89dfdbb306b..eec4fc6a33e 100644
--- a/cmake/plugin.cmake
+++ b/cmake/plugin.cmake
@@ -1,6 +1,6 @@
# Copyright (c) 2009, 2018, Oracle and/or its affiliates.
-# Copyright (c) 2011, 2019, MariaDB Corporation
-#
+# Copyright (c) 2011, 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.
@@ -12,7 +12,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
INCLUDE(CMakeParseArguments)
@@ -223,7 +223,7 @@ MACRO(MYSQL_ADD_PLUGIN)
ELSEIF(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
TARGET_LINK_LIBRARIES (${target} mysqld)
ENDIF()
- ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT WITH_ASAN AND NOT WITH_TSAN AND NOT WITH_UBSAN)
+ ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT WITH_ASAN AND NOT WITH_TSAN AND NOT WITH_UBSAN AND NOT WITH_MSAN)
TARGET_LINK_LIBRARIES (${target} "-Wl,--no-undefined")
ENDIF()
diff --git a/cmake/wsrep.cmake b/cmake/wsrep.cmake
index 0f97c0740ff..a6d843e5591 100644
--- a/cmake/wsrep.cmake
+++ b/cmake/wsrep.cmake
@@ -17,6 +17,7 @@
#
# Galera library does not compile with windows
#
+IF (NOT WITHOUT_SERVER)
IF(UNIX)
SET(with_wsrep_default ON)
ELSE()
@@ -57,4 +58,10 @@ Then restart the build.
endif()
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/wsrep-lib/include)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/wsrep-lib/wsrep-API/v26)
+
+ SET(old_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS})
+ SET(BUILD_SHARED_LIBS OFF)
+ ADD_SUBDIRECTORY(wsrep-lib)
+ SET(BUILD_SHARED_LIBS ${old_BUILD_SHARED_LIBS})
ENDIF()
+ENDIF(NOT WITHOUT_SERVER)
diff --git a/include/my_dbug.h b/include/my_dbug.h
index 4b69787c2fe..bce33285788 100644
--- a/include/my_dbug.h
+++ b/include/my_dbug.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates.
- Copyright (C) 2000, 2017, MariaDB Corporation Ab
+ Copyright (C) 2000, 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
@@ -35,6 +35,7 @@ struct _db_stack_frame_ {
};
struct _db_code_state_;
+extern MYSQL_PLUGIN_IMPORT my_bool my_assert;
extern my_bool _dbug_on_;
extern my_bool _db_keyword_(struct _db_code_state_ *, const char *, int);
extern int _db_explain_(struct _db_code_state_ *cs, char *buf, size_t len);
@@ -103,7 +104,10 @@ extern int (*dbug_sanity)(void);
#define DBUG_END() _db_end_ ()
#define DBUG_LOCK_FILE _db_lock_file_()
#define DBUG_UNLOCK_FILE _db_unlock_file_()
-#define DBUG_ASSERT(A) do { if (!(A)) { _db_flush_(); assert(A); }} while (0)
+#define DBUG_ASSERT(A) do { if (!(A)) { _db_flush_(); \
+ if (my_assert) assert(A); \
+ else fprintf(stderr, "%s:%d: assert: %s\n", __FILE__, __LINE__, #A); \
+}} while (0)
#define DBUG_SLOW_ASSERT(A) DBUG_ASSERT(A)
#define DBUG_ASSERT_EXISTS
#define DBUG_EXPLAIN(buf,len) _db_explain_(0, (buf),(len))
diff --git a/include/my_global.h b/include/my_global.h
index c0774146166..b47633b44ae 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -1,6 +1,6 @@
/*
Copyright (c) 2001, 2013, Oracle and/or its affiliates.
- Copyright (c) 2009, 2017, MariaDB Corporation
+ Copyright (c) 2009, 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
@@ -1037,6 +1037,19 @@ typedef ulong myf; /* Type of MyFlags in my_funcs */
#define reg16 register
#endif
+/*
+ MYSQL_PLUGIN_IMPORT macro is used to export mysqld data
+ (i.e variables) for usage in storage engine loadable plugins.
+ Outside of Windows, it is dummy.
+*/
+#ifndef MYSQL_PLUGIN_IMPORT
+#if (defined(_WIN32) && defined(MYSQL_DYNAMIC_PLUGIN))
+#define MYSQL_PLUGIN_IMPORT __declspec(dllimport)
+#else
+#define MYSQL_PLUGIN_IMPORT
+#endif
+#endif
+
#include <my_dbug.h>
/* Some helper macros */
@@ -1163,19 +1176,6 @@ typedef struct { const char *dli_fname, dli_fbase; } Dl_info;
#endif
#endif /* !defined(__func__) */
-/*
- MYSQL_PLUGIN_IMPORT macro is used to export mysqld data
- (i.e variables) for usage in storage engine loadable plugins.
- Outside of Windows, it is dummy.
-*/
-#ifndef MYSQL_PLUGIN_IMPORT
-#if (defined(_WIN32) && defined(MYSQL_DYNAMIC_PLUGIN))
-#define MYSQL_PLUGIN_IMPORT __declspec(dllimport)
-#else
-#define MYSQL_PLUGIN_IMPORT
-#endif
-#endif
-
/* Defines that are unique to the embedded version of MySQL */
#ifdef EMBEDDED_LIBRARY
diff --git a/include/my_sys.h b/include/my_sys.h
index b216f5d2a41..8bd0e7e2cce 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2010, 2017, MariaDB Corporation.
+ 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
@@ -266,6 +266,7 @@ extern ulong my_sync_count;
extern uint mysys_usage_id;
extern int32 my_file_opened;
extern my_bool my_init_done, my_thr_key_mysys_exists;
+extern MYSQL_PLUGIN_IMPORT my_bool my_assert;
extern my_bool my_assert_on_error;
extern myf my_global_flags; /* Set to MY_WME for more error messages */
/* Point to current my_message() */
diff --git a/include/my_time.h b/include/my_time.h
index 02e2b01efca..bad2b8bf4b0 100644
--- a/include/my_time.h
+++ b/include/my_time.h
@@ -27,7 +27,7 @@
C_MODE_START
-extern ulonglong log_10_int[20];
+extern MYSQL_PLUGIN_IMPORT ulonglong log_10_int[20];
extern uchar days_in_month[];
#define MY_TIME_T_MAX LONG_MAX
diff --git a/include/mysql/service_my_print_error.h b/include/mysql/service_my_print_error.h
index e9af51c20cc..74ba6a2adb8 100644
--- a/include/mysql/service_my_print_error.h
+++ b/include/mysql/service_my_print_error.h
@@ -51,11 +51,9 @@ extern struct my_print_error_service_st {
#define my_printv_error(A,B,C,D) my_print_error_service->my_printv_error_func(A,B,C,D)
#else
-#ifndef MY_ERROR_DEFINED
extern void my_error(unsigned int nr, unsigned long MyFlags, ...);
extern void my_printf_error(unsigned int my_err, const char *format, unsigned long MyFlags, ...);
extern void my_printv_error(unsigned int error, const char *format, unsigned long MyFlags,va_list ap);
-#endif /* MY_ERROR_DEFINED */
#endif /* MYSQL_DYNAMIC_PLUGIN */
#ifdef __cplusplus
diff --git a/libmariadb b/libmariadb
-Subproject ed3a91c139175746c5d6903d67ca902d91228f6
+Subproject 7de639518ffe56a99ac805654381d17f42796be
diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc
index 6a47b39e5bc..30b17c2e063 100644
--- a/mysql-test/include/mix1.inc
+++ b/mysql-test/include/mix1.inc
@@ -455,6 +455,16 @@ INSERT INTO t1(id, dept, age, name) VALUES
(4011, 'cs7', 10, 'rs4'), (4012, 'cs8', 20, 'rs4'), (4019, 'cs9', 10, 'rs5'),
(4020, 'cs10', 20, 'rs5'),(4027, 'cs11', 10, 'rs6'),(4028, 'cs12', 20, 'rs6');
+set
+ @tmp_uss=@@use_stat_tables,
+ @tmp_occ=@@optimizer_use_condition_selectivity;
+set
+ use_stat_tables='preferably',
+ optimizer_use_condition_selectivity=4;
+
+analyze table t1 persistent for all;
+flush tables;
+
EXPLAIN SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5';
SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5';
DELETE FROM t1;
@@ -464,6 +474,9 @@ EXPLAIN SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5';
SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5';
DROP TABLE t1;
+set
+ use_stat_tables=@tmp_uss,
+ optimizer_use_condition_selectivity=@tmp_occ;
--source include/innodb_rollback_on_timeout.inc
diff --git a/mysql-test/include/type_hrtime.inc b/mysql-test/include/type_hrtime.inc
index d666dc63bba..128e3295133 100644
--- a/mysql-test/include/type_hrtime.inc
+++ b/mysql-test/include/type_hrtime.inc
@@ -18,7 +18,7 @@ insert t1 values (20101211030405.789e0);
insert ignore t1 values (99991231235959e1);
select * from t1;
--replace_regex /121000/121094/ /457000/457031/ /789000/789062/
-select truncate(a, 6) from t1; # Field::val_real()
+select cast(a AS double(30,6)) from t1; # Field::val_real()
select a DIV 1 from t1; # Field::val_int()
select group_concat(distinct a) from t1; # Field::cmp()
alter table t1 engine=innodb;
diff --git a/mysql-test/lib/My/Handles.pm b/mysql-test/lib/My/Handles.pm
index 3c9513fec8f..c07e2edb09e 100644
--- a/mysql-test/lib/My/Handles.pm
+++ b/mysql-test/lib/My/Handles.pm
@@ -32,8 +32,8 @@ if (IS_WINDOWS){
my $list= `handle.exe -? -accepteula 2>&1`;
foreach my $line (split('\n', $list))
{
- $handle_exe= "$1.$2"
- if ($line =~ /Handle v([0-9]*)\.([0-9]*)/);
+ $handle_exe= "$2.$3"
+ if ($line =~ /(Nth|H)andle v([0-9]*)\.([0-9]*)/);
}
if ($handle_exe){
print "Found handle.exe version $handle_exe\n";
diff --git a/mysql-test/lib/My/SafeProcess/safe_process.cc b/mysql-test/lib/My/SafeProcess/safe_process.cc
index 9b544a25178..4d0d1e2a3a0 100644
--- a/mysql-test/lib/My/SafeProcess/safe_process.cc
+++ b/mysql-test/lib/My/SafeProcess/safe_process.cc
@@ -1,4 +1,5 @@
/* Copyright (c) 2008, 2012, Oracle and/or its affiliates
+ 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
@@ -219,6 +220,7 @@ int main(int argc, char* const argv[] )
sigemptyset(&sa.sa_mask);
sa_abort.sa_handler= handle_abort;
+ sa_abort.sa_flags= 0;
sigemptyset(&sa_abort.sa_mask);
/* Install signal handlers */
sigaction(SIGTERM, &sa,NULL);
diff --git a/mysql-test/main/analyze_stmt_privileges2.result b/mysql-test/main/analyze_stmt_privileges2.result
index cf38810b598..f269aaf540b 100644
--- a/mysql-test/main/analyze_stmt_privileges2.result
+++ b/mysql-test/main/analyze_stmt_privileges2.result
@@ -376,13 +376,13 @@ SELECT * FROM t1 WHERE a IN ( SELECT a FROM t2 );
a b
EXPLAIN SELECT * FROM t1 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3
ANALYZE SELECT * FROM t1 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3 3.00 100.00 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 4.00 100.00 0.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4 4.00 100.00 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 0.00 100.00 100.00
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 3.00 100.00 100.00
#------------------------------------------------------------------------
# I/R/U/D/S on the inner view
@@ -491,14 +491,14 @@ SELECT * FROM v1 WHERE a IN ( SELECT a FROM t2 );
a b
EXPLAIN SELECT * FROM v1 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3
ANALYZE SELECT * FROM v1 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3 3.00 100.00 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 8 8.00 100.00 0.00 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 3.00 100.00 100.00
+1 PRIMARY t1 ALL NULL NULL NULL NULL 8 8.00 100.00 0.00 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 NULL 100.00 NULL
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 NULL 100.00 NULL
#------------------------------------------------------------------------
# I/R/U/D/S on the outer view
# Expectation: Can run everything
@@ -598,14 +598,14 @@ SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
a b
EXPLAIN SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where
+1 PRIMARY t1 ALL NULL NULL NULL NULL 12 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3
ANALYZE SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3 3.00 100.00 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 12 12.00 100.00 0.00 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 3.00 100.00 100.00 Using where
+1 PRIMARY t1 ALL NULL NULL NULL NULL 12 12.00 100.00 0.00 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 NULL 100.00 NULL
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 NULL 100.00 NULL
#========================================================================
# Test: Grant INSERT on the table
@@ -1591,14 +1591,14 @@ SELECT * FROM v1 WHERE a IN ( SELECT a FROM t2 );
a b
EXPLAIN SELECT * FROM v1 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3
ANALYZE SELECT * FROM v1 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3 3.00 100.00 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 4.00 100.00 0.00 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 3.00 100.00 100.00
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4 4.00 100.00 0.00 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 NULL 100.00 NULL
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 NULL 100.00 NULL
#------------------------------------------------------------------------
# I/R/U/D/S on the outer view
# Expectation: Can run everything: SELECT access to the column `a`
@@ -1708,14 +1708,14 @@ SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
a b
EXPLAIN SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where
+1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3
ANALYZE SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3 3.00 100.00 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 8 8.00 100.00 0.00 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 3.00 100.00 100.00 Using where
+1 PRIMARY t1 ALL NULL NULL NULL NULL 8 8.00 100.00 0.00 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 NULL 100.00 NULL
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 NULL 100.00 NULL
#========================================================================
# Test: Grant SELECT, INSERT, UPDATE, DELETE on the table
@@ -1940,14 +1940,14 @@ SELECT * FROM v1 WHERE a IN ( SELECT a FROM t2 );
a b
EXPLAIN SELECT * FROM v1 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3
ANALYZE SELECT * FROM v1 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3 3.00 100.00 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 4.00 100.00 0.00 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 3.00 100.00 100.00
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4 4.00 100.00 0.00 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 NULL 100.00 NULL
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 NULL 100.00 NULL
#------------------------------------------------------------------------
# I/R/U/D/S on the outer view
# Expectation: Can run everything
@@ -2048,14 +2048,14 @@ SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
a b
EXPLAIN SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where
+1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3
ANALYZE SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3 3.00 100.00 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 8 8.00 100.00 0.00 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 3.00 100.00 100.00 Using where
+1 PRIMARY t1 ALL NULL NULL NULL NULL 8 8.00 100.00 0.00 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 NULL 100.00 NULL
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 NULL 100.00 NULL
#########################################################################
# Inner view permission tests
@@ -2697,14 +2697,14 @@ SELECT * FROM v1 WHERE a IN ( SELECT a FROM t2 );
a b
EXPLAIN SELECT * FROM v1 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 14 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 14 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3
ANALYZE SELECT * FROM v1 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3 3.00 100.00 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 14 14.00 100.00 0.00 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 3.00 100.00 100.00
+1 PRIMARY t1 ALL NULL NULL NULL NULL 14 14.00 100.00 0.00 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 NULL 100.00 NULL
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 NULL 100.00 NULL
#------------------------------------------------------------------------
# I/R/U/D/S on the outer view
# Expectation: Can run everything
@@ -2804,14 +2804,14 @@ SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
a b
EXPLAIN SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where
+1 PRIMARY t1 ALL NULL NULL NULL NULL 18 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3
ANALYZE SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3 3.00 100.00 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 18 18.00 100.00 0.00 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 3.00 100.00 100.00 Using where
+1 PRIMARY t1 ALL NULL NULL NULL NULL 18 18.00 100.00 0.00 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 NULL 100.00 NULL
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 NULL 100.00 NULL
#========================================================================
# Test: Grant INSERT on the inner view
@@ -3987,14 +3987,14 @@ SELECT * FROM v1 WHERE a IN ( SELECT a FROM t2 );
a b
EXPLAIN SELECT * FROM v1 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 35 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 35 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3
ANALYZE SELECT * FROM v1 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3 3.00 100.00 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 35 35.00 100.00 0.00 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 3.00 100.00 100.00
+1 PRIMARY t1 ALL NULL NULL NULL NULL 35 35.00 100.00 0.00 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 NULL 100.00 NULL
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 NULL 100.00 NULL
#------------------------------------------------------------------------
# I/R/U/D/S on the outer view
# Expectation: Can run everything
@@ -4094,14 +4094,14 @@ SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
a b
EXPLAIN SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 39 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where
+1 PRIMARY t1 ALL NULL NULL NULL NULL 39 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3
ANALYZE SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3 3.00 100.00 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 39 39.00 100.00 0.00 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 3.00 100.00 100.00 Using where
+1 PRIMARY t1 ALL NULL NULL NULL NULL 39 39.00 100.00 0.00 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 NULL 100.00 NULL
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 NULL 100.00 NULL
#########################################################################
# Outer view permission tests
@@ -4614,14 +4614,14 @@ SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
a b
EXPLAIN SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 39 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where
+1 PRIMARY t1 ALL NULL NULL NULL NULL 39 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3
ANALYZE SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3 3.00 100.00 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 39 39.00 100.00 0.00 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 3.00 100.00 100.00 Using where
+1 PRIMARY t1 ALL NULL NULL NULL NULL 39 39.00 100.00 0.00 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 NULL 100.00 NULL
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 NULL 100.00 NULL
#========================================================================
# Test: Grant INSERT on the outer view
@@ -5221,14 +5221,14 @@ SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
a b
EXPLAIN SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 44 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where
+1 PRIMARY t1 ALL NULL NULL NULL NULL 44 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3
ANALYZE SELECT * FROM v2 WHERE a IN ( SELECT a FROM t2 );
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3 3.00 100.00 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 44 44.00 100.00 0.00 Using where; Using join buffer (flat, BNL join)
-2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 3.00 100.00 100.00 Using where
+1 PRIMARY t1 ALL NULL NULL NULL NULL 44 44.00 100.00 0.00 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 NULL 100.00 NULL
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 NULL 100.00 NULL
disconnect con1;
connection default;
DROP USER 'privtest'@localhost;
diff --git a/mysql-test/main/constraints.result b/mysql-test/main/constraints.result
index 0b7577dd3ac..24f8417d313 100644
--- a/mysql-test/main/constraints.result
+++ b/mysql-test/main/constraints.result
@@ -129,6 +129,61 @@ t CREATE TABLE `t` (
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP table test.t;
SET @@SQL_MODE=@OLD_SQL_MODE;
+#
+# MDEV-16932 - ASAN heap-use-after-free in my_charlen_utf8 /
+# my_well_formed_char_length_utf8 on 2nd execution of SP with
+# ALTER trying to add bad CHECK
+#
+CREATE TABLE t1 (a INT);
+CREATE PROCEDURE sp() ALTER TABLE t1 ADD CONSTRAINT CHECK (b > 0);
+CALL sp;
+ERROR 42S22: Unknown column 'b' in 'CHECK'
+CALL sp;
+ERROR 42S22: Unknown column 'b' in 'CHECK'
+CALL sp;
+ERROR 42S22: Unknown column 'b' in 'CHECK'
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+alter table t1 add column b int;
+CALL sp;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL,
+ CONSTRAINT `CONSTRAINT_1` CHECK (`b` > 0)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+CALL sp;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL,
+ CONSTRAINT `CONSTRAINT_1` CHECK (`b` > 0),
+ CONSTRAINT `CONSTRAINT_2` CHECK (`b` > 0)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP PROCEDURE sp;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+CREATE PROCEDURE sp() ALTER TABLE t1 ADD CONSTRAINT CHECK (b > 0);
+CALL sp;
+ERROR 42S22: Unknown column 'b' in 'CHECK'
+alter table t1 add column b int, add constraint check (b < 10);
+CALL sp;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL,
+ CONSTRAINT `CONSTRAINT_1` CHECK (`b` < 10),
+ CONSTRAINT `CONSTRAINT_2` CHECK (`b` > 0)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP PROCEDURE sp;
+DROP TABLE t1;
+# End of 10.2 tests
create table t1 (a int check (a>10)) select 100 as 'a';
show create table t1;
Table Create Table
diff --git a/mysql-test/main/constraints.test b/mysql-test/main/constraints.test
index d7a5b41d708..2f4dadcee9d 100644
--- a/mysql-test/main/constraints.test
+++ b/mysql-test/main/constraints.test
@@ -116,6 +116,43 @@ SHOW CREATE TABLE t;
DROP table test.t;
SET @@SQL_MODE=@OLD_SQL_MODE;
+--echo #
+--echo # MDEV-16932 - ASAN heap-use-after-free in my_charlen_utf8 /
+--echo # my_well_formed_char_length_utf8 on 2nd execution of SP with
+--echo # ALTER trying to add bad CHECK
+--echo #
+
+CREATE TABLE t1 (a INT);
+CREATE PROCEDURE sp() ALTER TABLE t1 ADD CONSTRAINT CHECK (b > 0);
+--error ER_BAD_FIELD_ERROR
+CALL sp;
+--error ER_BAD_FIELD_ERROR
+CALL sp;
+--error ER_BAD_FIELD_ERROR
+CALL sp;
+show create table t1;
+alter table t1 add column b int;
+CALL sp;
+show create table t1;
+CALL sp;
+show create table t1;
+# Cleanup
+DROP PROCEDURE sp;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INT);
+CREATE PROCEDURE sp() ALTER TABLE t1 ADD CONSTRAINT CHECK (b > 0);
+--error ER_BAD_FIELD_ERROR
+CALL sp;
+alter table t1 add column b int, add constraint check (b < 10);
+CALL sp;
+show create table t1;
+# Cleanup
+DROP PROCEDURE sp;
+DROP TABLE t1;
+
+--echo # End of 10.2 tests
+
#
# Check that we don't lose constraints as part of CREATE ... SELECT
#
diff --git a/mysql-test/main/cte_nonrecursive.result b/mysql-test/main/cte_nonrecursive.result
index 2556fd4b06b..12a7e2ea789 100644
--- a/mysql-test/main/cte_nonrecursive.result
+++ b/mysql-test/main/cte_nonrecursive.result
@@ -1159,9 +1159,9 @@ with cte as
union
(select a from t1 where a < 2);
a
-7
-5
4
+5
+7
1
prepare stmt from "with cte as
(select a from t1 where a between 4 and 7 group by a)
@@ -1170,15 +1170,15 @@ union
(select a from t1 where a < 2)";
execute stmt;
a
-7
-5
4
+5
+7
1
execute stmt;
a
-7
-5
4
+5
+7
1
deallocate prepare stmt;
with cte as
@@ -1188,9 +1188,9 @@ union
(select a from cte where exists( select a from t1 where cte.a=t1.a ));
a
1
-7
-5
4
+5
+7
prepare stmt from "with cte as
(select a from t1 where a between 4 and 7 group by a)
(select a from t1 where a < 2)
@@ -1199,15 +1199,15 @@ union
execute stmt;
a
1
-7
-5
4
+5
+7
execute stmt;
a
1
-7
-5
4
+5
+7
deallocate prepare stmt;
with cte as
(select a from t1 where a between 4 and 7)
diff --git a/mysql-test/main/func_time.result b/mysql-test/main/func_time.result
index 38b157c8bb1..a85b8c965ba 100644
--- a/mysql-test/main/func_time.result
+++ b/mysql-test/main/func_time.result
@@ -2180,13 +2180,13 @@ CREATE TABLE t1 (a TIMESTAMP(3));
INSERT INTO t1 VALUES ('2001-01-01 10:20:30.999');
SELECT CAST(COALESCE(a,a) AS SIGNED) AS c1, CAST(COALESCE(a,a) AS DECIMAL(25,3)) AS c2, ROUND(COALESCE(a,a)) AS c2 FROM t1;
c1 c2 c2
-20010101102030 20010101102030.999 20010101102031
+20010101102030 20010101102030.999 2001-01-01 10:20:31
DROP TABLE t1;
CREATE TABLE t1 (a TIME(3));
INSERT INTO t1 VALUES ('10:20:30.999');
SELECT CAST(COALESCE(a,a) AS SIGNED) AS c1, CAST(COALESCE(a,a) AS DECIMAL(25,3)) AS c2, ROUND(COALESCE(a,a)) AS c2 FROM t1;
c1 c2 c2
-102030 102030.999 102031
+102030 102030.999 10:20:31
DROP TABLE t1;
SELECT
CAST(COALESCE(DATE('2001-01-01'),TIMESTAMP('2001-01-02 10:20:30')) AS SIGNED) AS c1,
diff --git a/mysql-test/main/group_by.result b/mysql-test/main/group_by.result
index 2eaec8a08b4..44ebce66b22 100644
--- a/mysql-test/main/group_by.result
+++ b/mysql-test/main/group_by.result
@@ -1608,7 +1608,8 @@ EXPLAIN SELECT 1 FROM t2 WHERE a IN
(SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index a a 5 NULL 4 Using index
-1 PRIMARY t1 ALL NULL NULL NULL NULL 144 Using where; FirstMatch(t2)
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED t1 ALL NULL NULL NULL NULL 144
SET optimizer_switch=@save_optimizer_switch;
DROP TABLE t1, t2;
CREATE TABLE t1(
diff --git a/mysql-test/main/index_merge_myisam.result b/mysql-test/main/index_merge_myisam.result
index 484ee626b98..7e57c916d04 100644
--- a/mysql-test/main/index_merge_myisam.result
+++ b/mysql-test/main/index_merge_myisam.result
@@ -558,8 +558,9 @@ where exists (select 1 from t2, t3
where t2.a=t1.a and (t3.a=t2.b or t3.b=t2.b or t3.b=t2.b+1));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2
-1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
-1 PRIMARY t3 ALL a,b NULL NULL NULL 1002 Range checked for each record (index map: 0x3); FirstMatch(t1)
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2
+2 MATERIALIZED t3 ALL a,b NULL NULL NULL 1002 Range checked for each record (index map: 0x3)
select * from t1
where exists (select 1 from t2, t3
where t2.a=t1.a and (t3.a=t2.b or t3.b=t2.b or t3.b=t2.b+1));
diff --git a/mysql-test/main/innodb_ext_key.result b/mysql-test/main/innodb_ext_key.result
index b4572174fcb..2ec3a9ae951 100644
--- a/mysql-test/main/innodb_ext_key.result
+++ b/mysql-test/main/innodb_ext_key.result
@@ -732,8 +732,8 @@ SELECT a FROM t1 AS t, t2
WHERE c = a AND b IN (SELECT b FROM t1, t2 WHERE b = t.b);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t index a,b b 7 NULL 10 Using index
-1 PRIMARY t1 ref b b 3 test.t.b 2 Using index
-1 PRIMARY t2 index NULL PRIMARY 4 NULL 11 Using index; FirstMatch(t)
+1 PRIMARY t1 ref b b 3 test.t.b 2 Using index; Start temporary
+1 PRIMARY t2 index NULL PRIMARY 4 NULL 11 Using index; End temporary; Using join buffer (flat, BNL join)
1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t.a 1 Using index
SELECT a FROM t1 AS t, t2
WHERE c = a AND b IN (SELECT b FROM t1, t2 WHERE b = t.b);
@@ -745,8 +745,8 @@ SELECT a FROM t1 AS t, t2
WHERE c = a AND b IN (SELECT b FROM t1, t2 WHERE b = t.b);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t index a,b b 7 NULL 10 Using index
-1 PRIMARY t1 ref b b 3 test.t.b 2 Using index
-1 PRIMARY t2 index NULL PRIMARY 4 NULL 11 Using index; FirstMatch(t)
+1 PRIMARY t1 ref b b 3 test.t.b 2 Using index; Start temporary
+1 PRIMARY t2 index NULL PRIMARY 4 NULL 11 Using index; End temporary; Using join buffer (flat, BNL join)
1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t.a 1 Using index
SELECT a FROM t1 AS t, t2
WHERE c = a AND b IN (SELECT b FROM t1, t2 WHERE b = t.b);
diff --git a/mysql-test/main/invisible_field_debug.result b/mysql-test/main/invisible_field_debug.result
index 32eb3a274d8..582c935333c 100644
--- a/mysql-test/main/invisible_field_debug.result
+++ b/mysql-test/main/invisible_field_debug.result
@@ -385,3 +385,15 @@ SET debug_dbug="+d,test_completely_invisible,test_invisible_index";
CREATE TABLE t2 LIKE t1;
SET debug_dbug= DEFAULT;
DROP TABLE t1, t2;
+#
+# MDEV-20210
+# If you have an INVISIBLE VIRTUAL column, SHOW CREATE TABLE doesn't list it as INVISIBLE
+#
+CREATE TABLE t1 (i INT, v int GENERATED ALWAYS AS (1) VIRTUAL INVISIBLE);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `i` int(11) DEFAULT NULL,
+ `v` int(11) GENERATED ALWAYS AS (1) VIRTUAL INVISIBLE
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
diff --git a/mysql-test/main/invisible_field_debug.test b/mysql-test/main/invisible_field_debug.test
index 77e65cf7a6b..3e844fc4521 100644
--- a/mysql-test/main/invisible_field_debug.test
+++ b/mysql-test/main/invisible_field_debug.test
@@ -281,3 +281,12 @@ SET debug_dbug="+d,test_completely_invisible,test_invisible_index";
CREATE TABLE t2 LIKE t1;
SET debug_dbug= DEFAULT;
DROP TABLE t1, t2;
+
+--echo #
+--echo # MDEV-20210
+--echo # If you have an INVISIBLE VIRTUAL column, SHOW CREATE TABLE doesn't list it as INVISIBLE
+--echo #
+
+CREATE TABLE t1 (i INT, v int GENERATED ALWAYS AS (1) VIRTUAL INVISIBLE);
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
diff --git a/mysql-test/main/join.result b/mysql-test/main/join.result
index edca2905380..f714785593d 100644
--- a/mysql-test/main/join.result
+++ b/mysql-test/main/join.result
@@ -2935,6 +2935,332 @@ NULL NULL NULL 9
NULL NULL NULL 5
drop table t1,t2,t3,t4,s1,s2;
#
+# MDEV-20265: Mix of comma joins with JOIN expressions
+# (correction of the fix for MDEV-19421)
+# MDEV-20330: duplicate
+#
+create table t1 (a int);
+insert into t1 values (7), (5), (3);
+create table t2 (a int);
+insert into t2 values (5), (1), (7);
+create table t3 (a int);
+insert into t3 values (2), (7), (3);
+create table t4 (a int);
+insert into t4 values (4), (7), (9), (5);
+create table t5 (a int);
+insert into t5 values (3), (7), (9), (2);
+explain extended select t1.a as t1_a, t2.a as t2_a, t3.a as t3_a, t4.a as t4_a
+from t1, t2 join t3 left join t4 on t3.a=t4.a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
+1 SIMPLE t3 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (incremental, BNL join)
+1 SIMPLE t4 ALL NULL NULL NULL NULL 4 100.00 Using where; Using join buffer (incremental, BNL join)
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `t1_a`,`test`.`t2`.`a` AS `t2_a`,`test`.`t3`.`a` AS `t3_a`,`test`.`t4`.`a` AS `t4_a` from `test`.`t1` join `test`.`t2` join `test`.`t3` left join `test`.`t4` on(`test`.`t4`.`a` = `test`.`t3`.`a`) where 1
+select t1.a as t1_a, t2.a as t2_a, t3.a as t3_a, t4.a as t4_a
+from t1, t2 join t3 left join t4 on t3.a=t4.a;
+t1_a t2_a t3_a t4_a
+7 5 7 7
+5 5 7 7
+3 5 7 7
+7 1 7 7
+5 1 7 7
+3 1 7 7
+7 7 7 7
+5 7 7 7
+3 7 7 7
+7 5 2 NULL
+5 5 2 NULL
+3 5 2 NULL
+7 1 2 NULL
+5 1 2 NULL
+3 1 2 NULL
+7 7 2 NULL
+5 7 2 NULL
+3 7 2 NULL
+7 5 3 NULL
+5 5 3 NULL
+3 5 3 NULL
+7 1 3 NULL
+5 1 3 NULL
+3 1 3 NULL
+7 7 3 NULL
+5 7 3 NULL
+3 7 3 NULL
+explain extended select t1.a as t1_a, t2.a as t2_a, t3.a as t3_a, t4.a as t4_a
+from t1, t2 join t3 right join t4 on t3.a=t4.a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
+1 SIMPLE t4 ALL NULL NULL NULL NULL 4 100.00 Using join buffer (flat, BNL join)
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (incremental, BNL join)
+1 SIMPLE t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join)
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `t1_a`,`test`.`t2`.`a` AS `t2_a`,`test`.`t3`.`a` AS `t3_a`,`test`.`t4`.`a` AS `t4_a` from `test`.`t1` join `test`.`t4` left join (`test`.`t2` join `test`.`t3`) on(`test`.`t3`.`a` = `test`.`t4`.`a`) where 1
+select t1.a as t1_a, t2.a as t2_a, t3.a as t3_a, t4.a as t4_a
+from t1, t2 join t3 right join t4 on t3.a=t4.a;
+t1_a t2_a t3_a t4_a
+7 5 7 7
+5 5 7 7
+3 5 7 7
+7 1 7 7
+5 1 7 7
+3 1 7 7
+7 7 7 7
+5 7 7 7
+3 7 7 7
+7 NULL NULL 4
+5 NULL NULL 4
+3 NULL NULL 4
+7 NULL NULL 9
+5 NULL NULL 9
+3 NULL NULL 9
+7 NULL NULL 5
+5 NULL NULL 5
+3 NULL NULL 5
+explain extended select t1.a as t1_a, t2.a as t2_a, t3.a as t3_a, t4.a as t4_a, t5.a as t5_a
+from t1, t2 join t3 join t4 left join t5 on t4.a=t5.a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
+1 SIMPLE t3 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (incremental, BNL join)
+1 SIMPLE t4 ALL NULL NULL NULL NULL 4 100.00 Using join buffer (incremental, BNL join)
+1 SIMPLE t5 ALL NULL NULL NULL NULL 4 100.00 Using where; Using join buffer (incremental, BNL join)
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `t1_a`,`test`.`t2`.`a` AS `t2_a`,`test`.`t3`.`a` AS `t3_a`,`test`.`t4`.`a` AS `t4_a`,`test`.`t5`.`a` AS `t5_a` from `test`.`t1` join `test`.`t2` join `test`.`t3` join `test`.`t4` left join `test`.`t5` on(`test`.`t5`.`a` = `test`.`t4`.`a`) where 1
+select t1.a as t1_a, t2.a as t2_a, t3.a as t3_a, t4.a as t4_a, t5.a as t5_a
+from t1, t2 join t3 join t4 left join t5 on t4.a=t5.a;
+t1_a t2_a t3_a t4_a t5_a
+7 5 2 7 7
+5 5 2 7 7
+3 5 2 7 7
+7 1 2 7 7
+5 1 2 7 7
+3 1 2 7 7
+7 7 2 7 7
+5 7 2 7 7
+3 7 2 7 7
+7 5 7 7 7
+5 5 7 7 7
+3 5 7 7 7
+7 1 7 7 7
+5 1 7 7 7
+3 1 7 7 7
+7 7 7 7 7
+5 7 7 7 7
+3 7 7 7 7
+7 5 3 7 7
+5 5 3 7 7
+3 5 3 7 7
+7 1 3 7 7
+5 1 3 7 7
+3 1 3 7 7
+7 7 3 7 7
+5 7 3 7 7
+3 7 3 7 7
+7 5 2 9 9
+5 5 2 9 9
+3 5 2 9 9
+7 1 2 9 9
+5 1 2 9 9
+3 1 2 9 9
+7 7 2 9 9
+5 7 2 9 9
+3 7 2 9 9
+7 5 7 9 9
+5 5 7 9 9
+3 5 7 9 9
+7 1 7 9 9
+5 1 7 9 9
+3 1 7 9 9
+7 7 7 9 9
+5 7 7 9 9
+3 7 7 9 9
+7 5 3 9 9
+5 5 3 9 9
+3 5 3 9 9
+7 1 3 9 9
+5 1 3 9 9
+3 1 3 9 9
+7 7 3 9 9
+5 7 3 9 9
+3 7 3 9 9
+7 5 2 4 NULL
+5 5 2 4 NULL
+3 5 2 4 NULL
+7 1 2 4 NULL
+5 1 2 4 NULL
+3 1 2 4 NULL
+7 7 2 4 NULL
+5 7 2 4 NULL
+3 7 2 4 NULL
+7 5 7 4 NULL
+5 5 7 4 NULL
+3 5 7 4 NULL
+7 1 7 4 NULL
+5 1 7 4 NULL
+3 1 7 4 NULL
+7 7 7 4 NULL
+5 7 7 4 NULL
+3 7 7 4 NULL
+7 5 3 4 NULL
+5 5 3 4 NULL
+3 5 3 4 NULL
+7 1 3 4 NULL
+5 1 3 4 NULL
+3 1 3 4 NULL
+7 7 3 4 NULL
+5 7 3 4 NULL
+3 7 3 4 NULL
+7 5 2 5 NULL
+5 5 2 5 NULL
+3 5 2 5 NULL
+7 1 2 5 NULL
+5 1 2 5 NULL
+3 1 2 5 NULL
+7 7 2 5 NULL
+5 7 2 5 NULL
+3 7 2 5 NULL
+7 5 7 5 NULL
+5 5 7 5 NULL
+3 5 7 5 NULL
+7 1 7 5 NULL
+5 1 7 5 NULL
+3 1 7 5 NULL
+7 7 7 5 NULL
+5 7 7 5 NULL
+3 7 7 5 NULL
+7 5 3 5 NULL
+5 5 3 5 NULL
+3 5 3 5 NULL
+7 1 3 5 NULL
+5 1 3 5 NULL
+3 1 3 5 NULL
+7 7 3 5 NULL
+5 7 3 5 NULL
+3 7 3 5 NULL
+explain extended select t1.a as t1_a, t2.a as t2_a, t3.a as t3_a, t4.a as t4_a, t5.a as t5_a
+from t1, t2 join t3 join t4 right join t5 on t4.a=t5.a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
+1 SIMPLE t5 ALL NULL NULL NULL NULL 4 100.00 Using join buffer (flat, BNL join)
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (incremental, BNL join)
+1 SIMPLE t3 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (incremental, BNL join)
+1 SIMPLE t4 ALL NULL NULL NULL NULL 4 100.00 Using where; Using join buffer (incremental, BNL join)
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `t1_a`,`test`.`t2`.`a` AS `t2_a`,`test`.`t3`.`a` AS `t3_a`,`test`.`t4`.`a` AS `t4_a`,`test`.`t5`.`a` AS `t5_a` from `test`.`t1` join `test`.`t5` left join (`test`.`t2` join `test`.`t3` join `test`.`t4`) on(`test`.`t4`.`a` = `test`.`t5`.`a`) where 1
+select t1.a as t1_a, t2.a as t2_a, t3.a as t3_a, t4.a as t4_a, t5.a as t5_a
+from t1, t2 join t3 join t4 right join t5 on t4.a=t5.a;
+t1_a t2_a t3_a t4_a t5_a
+7 5 2 7 7
+5 5 2 7 7
+3 5 2 7 7
+7 1 2 7 7
+5 1 2 7 7
+3 1 2 7 7
+7 7 2 7 7
+5 7 2 7 7
+3 7 2 7 7
+7 5 7 7 7
+5 5 7 7 7
+3 5 7 7 7
+7 1 7 7 7
+5 1 7 7 7
+3 1 7 7 7
+7 7 7 7 7
+5 7 7 7 7
+3 7 7 7 7
+7 5 3 7 7
+5 5 3 7 7
+3 5 3 7 7
+7 1 3 7 7
+5 1 3 7 7
+3 1 3 7 7
+7 7 3 7 7
+5 7 3 7 7
+3 7 3 7 7
+7 5 2 9 9
+5 5 2 9 9
+3 5 2 9 9
+7 1 2 9 9
+5 1 2 9 9
+3 1 2 9 9
+7 7 2 9 9
+5 7 2 9 9
+3 7 2 9 9
+7 5 7 9 9
+5 5 7 9 9
+3 5 7 9 9
+7 1 7 9 9
+5 1 7 9 9
+3 1 7 9 9
+7 7 7 9 9
+5 7 7 9 9
+3 7 7 9 9
+7 5 3 9 9
+5 5 3 9 9
+3 5 3 9 9
+7 1 3 9 9
+5 1 3 9 9
+3 1 3 9 9
+7 7 3 9 9
+5 7 3 9 9
+3 7 3 9 9
+7 NULL NULL NULL 3
+5 NULL NULL NULL 3
+3 NULL NULL NULL 3
+7 NULL NULL NULL 2
+5 NULL NULL NULL 2
+3 NULL NULL NULL 2
+explain extended select t1.a as t1_a, t2.a as t2_a, t3.a as t3_a, t4.a as t4_a, t5.a as t5_a
+from t1 left join t2 on t1.a=t2.a, t3 join t4 right join t5 on t4.a=t5.a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join)
+1 SIMPLE t5 ALL NULL NULL NULL NULL 4 100.00 Using join buffer (incremental, BNL join)
+1 SIMPLE t3 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (incremental, BNL join)
+1 SIMPLE t4 ALL NULL NULL NULL NULL 4 100.00 Using where; Using join buffer (incremental, BNL join)
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `t1_a`,`test`.`t2`.`a` AS `t2_a`,`test`.`t3`.`a` AS `t3_a`,`test`.`t4`.`a` AS `t4_a`,`test`.`t5`.`a` AS `t5_a` from `test`.`t1` left join `test`.`t2` on(`test`.`t2`.`a` = `test`.`t1`.`a`) join `test`.`t5` left join (`test`.`t3` join `test`.`t4`) on(`test`.`t4`.`a` = `test`.`t5`.`a`) where 1
+select t1.a as t1_a, t2.a as t2_a, t3.a as t3_a, t4.a as t4_a, t5.a as t5_a
+from t1 left join t2 on t1.a=t2.a, t3 join t4 right join t5 on t4.a=t5.a;
+t1_a t2_a t3_a t4_a t5_a
+5 5 2 7 7
+7 7 2 7 7
+3 NULL 2 7 7
+5 5 7 7 7
+7 7 7 7 7
+3 NULL 7 7 7
+5 5 3 7 7
+7 7 3 7 7
+3 NULL 3 7 7
+5 5 2 9 9
+7 7 2 9 9
+3 NULL 2 9 9
+5 5 7 9 9
+7 7 7 9 9
+3 NULL 7 9 9
+5 5 3 9 9
+7 7 3 9 9
+3 NULL 3 9 9
+5 5 NULL NULL 3
+7 7 NULL NULL 3
+3 NULL NULL NULL 3
+5 5 NULL NULL 2
+7 7 NULL NULL 2
+3 NULL NULL NULL 2
+drop table t1,t2,t3,t4,t5;
+select a.a
+from (select 1 as a) a,
+(select 2 as b) b
+cross join
+(select 3 as c) c
+left join
+(select 4 as d) d
+on 1;
+a
+1
+#
# End of MariaDB 5.5 tests
#
#
diff --git a/mysql-test/main/join.test b/mysql-test/main/join.test
index b36b0ac8f35..cf24fb04e4a 100644
--- a/mysql-test/main/join.test
+++ b/mysql-test/main/join.test
@@ -1615,6 +1615,65 @@ eval $q;
drop table t1,t2,t3,t4,s1,s2;
--echo #
+--echo # MDEV-20265: Mix of comma joins with JOIN expressions
+--echo # (correction of the fix for MDEV-19421)
+--echo # MDEV-20330: duplicate
+--echo #
+
+create table t1 (a int);
+insert into t1 values (7), (5), (3);
+create table t2 (a int);
+insert into t2 values (5), (1), (7);
+create table t3 (a int);
+insert into t3 values (2), (7), (3);
+create table t4 (a int);
+insert into t4 values (4), (7), (9), (5);
+create table t5 (a int);
+insert into t5 values (3), (7), (9), (2);
+
+
+let $q=
+select t1.a as t1_a, t2.a as t2_a, t3.a as t3_a, t4.a as t4_a
+from t1, t2 join t3 left join t4 on t3.a=t4.a;
+eval explain extended $q;
+eval $q;
+
+let $q=
+select t1.a as t1_a, t2.a as t2_a, t3.a as t3_a, t4.a as t4_a
+from t1, t2 join t3 right join t4 on t3.a=t4.a;
+eval explain extended $q;
+eval $q;
+
+let $q=
+select t1.a as t1_a, t2.a as t2_a, t3.a as t3_a, t4.a as t4_a, t5.a as t5_a
+from t1, t2 join t3 join t4 left join t5 on t4.a=t5.a;
+eval explain extended $q;
+eval $q;
+
+let $q=
+select t1.a as t1_a, t2.a as t2_a, t3.a as t3_a, t4.a as t4_a, t5.a as t5_a
+from t1, t2 join t3 join t4 right join t5 on t4.a=t5.a;
+eval explain extended $q;
+eval $q;
+
+let $q=
+select t1.a as t1_a, t2.a as t2_a, t3.a as t3_a, t4.a as t4_a, t5.a as t5_a
+from t1 left join t2 on t1.a=t2.a, t3 join t4 right join t5 on t4.a=t5.a;
+eval explain extended $q;
+eval $q;
+
+drop table t1,t2,t3,t4,t5;
+
+select a.a
+from (select 1 as a) a,
+ (select 2 as b) b
+ cross join
+ (select 3 as c) c
+ left join
+ (select 4 as d) d
+ on 1;
+
+--echo #
--echo # End of MariaDB 5.5 tests
--echo #
diff --git a/mysql-test/main/long_unique.result b/mysql-test/main/long_unique.result
index 8ea6d36c321..a4955b3e7b5 100644
--- a/mysql-test/main/long_unique.result
+++ b/mysql-test/main/long_unique.result
@@ -1462,4 +1462,19 @@ t1 CREATE TABLE `t1` (
KEY `pk` (`pk`,`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
+#
+# MDEV-19705: Assertion `tmp >= 0' failed in best_access_path
+#
+CREATE TABLE t1 (d varchar(10)) ENGINE=MyISAM;
+INSERT INTO t1 VALUES ('a'),('q');
+CREATE TABLE t2 (f varchar(10), a2 datetime, b int, a1 varchar(1024), pk int NOT NULL, PRIMARY KEY (pk), UNIQUE KEY (f,a1,a2), KEY f2 (f(4),a2)) ENGINE=MyISAM;
+INSERT INTO t2 VALUES ('aaa','1985-09-06',-163,'s',1),('bbb','1995-01-05',3,'pucaz',2),('ccc','0000-00-00',NULL,'help',3),('ddd',NULL,618,'v',4),('eee','1995-12-20',410,'m',5),('ffq','1976-06-12 20:02:56',NULL,'POKNC',6),('dddd','0000-00-00',-328,'hgsu',7);
+explain
+SELECT t2.b FROM t1 JOIN t2 ON t1.d = t2.f WHERE t2.pk >= 20;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range PRIMARY,f,f2 PRIMARY 4 NULL 1 Using index condition
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join)
+SELECT t2.b FROM t1 JOIN t2 ON t1.d = t2.f WHERE t2.pk >= 20;
+b
+drop table t1,t2;
set @@GLOBAL.max_allowed_packet= @allowed_packet;
diff --git a/mysql-test/main/long_unique.test b/mysql-test/main/long_unique.test
index a6bc68f54dc..c0bd77ca5c9 100644
--- a/mysql-test/main/long_unique.test
+++ b/mysql-test/main/long_unique.test
@@ -542,4 +542,18 @@ alter table t1 modify a varchar(1000);
show create table t1;
drop table t1;
+--echo #
+--echo # MDEV-19705: Assertion `tmp >= 0' failed in best_access_path
+--echo #
+
+CREATE TABLE t1 (d varchar(10)) ENGINE=MyISAM;
+INSERT INTO t1 VALUES ('a'),('q');
+
+CREATE TABLE t2 (f varchar(10), a2 datetime, b int, a1 varchar(1024), pk int NOT NULL, PRIMARY KEY (pk), UNIQUE KEY (f,a1,a2), KEY f2 (f(4),a2)) ENGINE=MyISAM;
+INSERT INTO t2 VALUES ('aaa','1985-09-06',-163,'s',1),('bbb','1995-01-05',3,'pucaz',2),('ccc','0000-00-00',NULL,'help',3),('ddd',NULL,618,'v',4),('eee','1995-12-20',410,'m',5),('ffq','1976-06-12 20:02:56',NULL,'POKNC',6),('dddd','0000-00-00',-328,'hgsu',7);
+explain
+SELECT t2.b FROM t1 JOIN t2 ON t1.d = t2.f WHERE t2.pk >= 20;
+SELECT t2.b FROM t1 JOIN t2 ON t1.d = t2.f WHERE t2.pk >= 20;
+drop table t1,t2;
+
set @@GLOBAL.max_allowed_packet= @allowed_packet;
diff --git a/mysql-test/main/opt_trace.result b/mysql-test/main/opt_trace.result
index e315b0212f7..13110f0bc73 100644
--- a/mysql-test/main/opt_trace.result
+++ b/mysql-test/main/opt_trace.result
@@ -2663,6 +2663,11 @@ explain extended select * from t1 where a in (select pk from t10) {
]
},
{
+ "semijoin_table_pullout": {
+ "pulled_out_tables": []
+ }
+ },
+ {
"execution_plan_for_potential_materialization": {
"steps": [
{
@@ -2705,6 +2710,7 @@ explain extended select * from t1 where a in (select pk from t10) {
},
"rows_for_plan": 3,
"cost_for_plan": 2.6066,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": ["t1"],
@@ -2720,7 +2726,27 @@ explain extended select * from t1 where a in (select pk from t10) {
]
},
"rows_for_plan": 30,
- "cost_for_plan": 10.629
+ "cost_for_plan": 10.629,
+ "semijoin_strategy_choice": [
+ {
+ "strategy": "FirstMatch",
+ "records": 3,
+ "read_time": 10.629
+ },
+ {
+ "strategy": "SJ-Materialization",
+ "records": 3,
+ "read_time": 5.2786
+ },
+ {
+ "strategy": "DuplicateWeedout",
+ "records": 3,
+ "read_time": 27.129
+ },
+ {
+ "chosen_strategy": "SJ-Materialize"
+ }
+ ]
}
]
},
@@ -2739,6 +2765,7 @@ explain extended select * from t1 where a in (select pk from t10) {
},
"rows_for_plan": 10,
"cost_for_plan": 4.022,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
}
]
@@ -2746,7 +2773,7 @@ explain extended select * from t1 where a in (select pk from t10) {
{
"fix_semijoin_strategies_for_picked_join_order": [
{
- "semi_join_strategy": "sj_materialize",
+ "semi_join_strategy": "SJ-Materialization",
"join_order": [
{
"table": "t10"
@@ -4082,6 +4109,11 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
]
},
{
+ "semijoin_table_pullout": {
+ "pulled_out_tables": []
+ }
+ },
+ {
"execution_plan_for_potential_materialization": {
"steps": [
{
@@ -4159,6 +4191,7 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": ["t1"],
@@ -4175,6 +4208,7 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
},
"rows_for_plan": 9,
"cost_for_plan": 6.4103,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": ["t1", "t_inner_1"],
@@ -4190,7 +4224,27 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
]
},
"rows_for_plan": 27,
- "cost_for_plan": 13.815
+ "cost_for_plan": 13.815,
+ "semijoin_strategy_choice": [
+ {
+ "strategy": "FirstMatch",
+ "records": 3,
+ "read_time": 33.867
+ },
+ {
+ "strategy": "SJ-Materialization",
+ "records": 3,
+ "read_time": 7.2154
+ },
+ {
+ "strategy": "DuplicateWeedout",
+ "records": 3,
+ "read_time": 18.315
+ },
+ {
+ "chosen_strategy": "SJ-Materialize"
+ }
+ ]
}
]
},
@@ -4209,6 +4263,7 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
},
"rows_for_plan": 9,
"cost_for_plan": 6.4103,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
}
]
@@ -4228,6 +4283,7 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
},
{
@@ -4245,6 +4301,7 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
}
]
@@ -4252,7 +4309,7 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
{
"fix_semijoin_strategies_for_picked_join_order": [
{
- "semi_join_strategy": "sj_materialize",
+ "semi_join_strategy": "SJ-Materialization",
"join_order": [
{
"table": "t_inner_1"
@@ -4308,11 +4365,11 @@ explain select * from t1 t_outer_1,t2 t_outer_2 where t_outer_1.a in (select t_
t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t_outer_1 ALL NULL NULL NULL NULL 3
-1 PRIMARY t_inner_1 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join)
-1 PRIMARY t_inner_2 ALL NULL NULL NULL NULL 9 FirstMatch(t_outer_1); Using join buffer (incremental, BNL join)
+1 PRIMARY t_inner_1 ALL NULL NULL NULL NULL 3 Using where; Start temporary; Using join buffer (flat, BNL join)
+1 PRIMARY t_inner_2 ALL NULL NULL NULL NULL 9 End temporary; Using join buffer (incremental, BNL join)
+1 PRIMARY t_inner_4 ALL NULL NULL NULL NULL 3 Start temporary; Using join buffer (incremental, BNL join)
1 PRIMARY t_outer_2 ALL NULL NULL NULL NULL 9 Using join buffer (incremental, BNL join)
-1 PRIMARY t_inner_4 ALL NULL NULL NULL NULL 3 Using join buffer (incremental, BNL join)
-1 PRIMARY t_inner_3 ALL NULL NULL NULL NULL 9 Using where; FirstMatch(t_outer_2); Using join buffer (incremental, BNL join)
+1 PRIMARY t_inner_3 ALL NULL NULL NULL NULL 9 Using where; End temporary; Using join buffer (incremental, BNL join)
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain select * from t1 t_outer_1,t2 t_outer_2 where t_outer_1.a in (select t_inner_1.a from t2 t_inner_2, t1 t_inner_1) and
@@ -4512,6 +4569,16 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
]
},
{
+ "semijoin_table_pullout": {
+ "pulled_out_tables": []
+ }
+ },
+ {
+ "semijoin_table_pullout": {
+ "pulled_out_tables": []
+ }
+ },
+ {
"execution_plan_for_potential_materialization": {
"steps": []
}
@@ -4533,6 +4600,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": ["t_outer_1"],
@@ -4549,6 +4617,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 9,
"cost_for_plan": 6.4103,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": ["t_outer_1", "t_inner_1"],
@@ -4565,6 +4634,21 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 81,
"cost_for_plan": 24.626,
+ "semijoin_strategy_choice": [
+ {
+ "strategy": "FirstMatch",
+ "records": 3,
+ "read_time": 44.759
+ },
+ {
+ "strategy": "DuplicateWeedout",
+ "records": 3,
+ "read_time": 37.226
+ },
+ {
+ "chosen_strategy": "DuplicateWeedout"
+ }
+ ],
"rest_of_plan": [
{
"plan_prefix": ["t_outer_1", "t_inner_1", "t_inner_2"],
@@ -4580,7 +4664,8 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
]
},
"rows_for_plan": 27,
- "cost_for_plan": 34.174,
+ "cost_for_plan": 44.641,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": [
@@ -4601,7 +4686,8 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
]
},
"rows_for_plan": 81,
- "cost_for_plan": 52.379,
+ "cost_for_plan": 62.846,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": [
@@ -4623,7 +4709,22 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
]
},
"rows_for_plan": 729,
- "cost_for_plan": 200.19
+ "cost_for_plan": 210.66,
+ "semijoin_strategy_choice": [
+ {
+ "strategy": "FirstMatch",
+ "records": 27,
+ "read_time": 424.03
+ },
+ {
+ "strategy": "DuplicateWeedout",
+ "records": 27,
+ "read_time": 324.06
+ },
+ {
+ "chosen_strategy": "DuplicateWeedout"
+ }
+ ]
}
]
},
@@ -4646,7 +4747,8 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
]
},
"rows_for_plan": 243,
- "cost_for_plan": 84.79,
+ "cost_for_plan": 95.256,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
}
]
@@ -4665,7 +4767,8 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
]
},
"rows_for_plan": 9,
- "cost_for_plan": 30.564,
+ "cost_for_plan": 41.031,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": [
@@ -4686,7 +4789,8 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
]
},
"rows_for_plan": 81,
- "cost_for_plan": 48.779,
+ "cost_for_plan": 59.246,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": [
@@ -4708,8 +4812,17 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
]
},
"rows_for_plan": 729,
- "cost_for_plan": 196.59,
- "pruned_by_cost": true
+ "cost_for_plan": 207.06,
+ "semijoin_strategy_choice": [
+ {
+ "strategy": "DuplicateWeedout",
+ "records": 27,
+ "read_time": 320.46
+ },
+ {
+ "chosen_strategy": "DuplicateWeedout"
+ }
+ ]
}
]
},
@@ -4732,7 +4845,8 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
]
},
"rows_for_plan": 81,
- "cost_for_plan": 48.779,
+ "cost_for_plan": 59.246,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
}
]
@@ -4751,7 +4865,8 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
]
},
"rows_for_plan": 27,
- "cost_for_plan": 34.174,
+ "cost_for_plan": 44.641,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
}
]
@@ -4771,6 +4886,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 81,
"cost_for_plan": 24.626,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": ["t_outer_1", "t_inner_1", "t_outer_2"],
@@ -4787,7 +4903,98 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 729,
"cost_for_plan": 172.44,
- "pruned_by_cost": true
+ "semijoin_strategy_choice": [
+ {
+ "strategy": "DuplicateWeedout",
+ "records": 27,
+ "read_time": 285.84
+ },
+ {
+ "chosen_strategy": "DuplicateWeedout"
+ }
+ ],
+ "rest_of_plan": [
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_outer_2",
+ "t_inner_2"
+ ],
+ "table": "t_inner_4",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rows_for_plan": 81,
+ "cost_for_plan": 304.05,
+ "semijoin_strategy_choice": [],
+ "rest_of_plan": [
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_outer_2",
+ "t_inner_2",
+ "t_inner_4"
+ ],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "rows_for_plan": 729,
+ "cost_for_plan": 451.86,
+ "semijoin_strategy_choice": [
+ {
+ "strategy": "DuplicateWeedout",
+ "records": 27,
+ "read_time": 565.26
+ },
+ {
+ "chosen_strategy": "DuplicateWeedout"
+ }
+ ],
+ "pruned_by_cost": true
+ }
+ ]
+ },
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_outer_2",
+ "t_inner_2"
+ ],
+ "table": "t_inner_3",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "rows_for_plan": 243,
+ "cost_for_plan": 336.46,
+ "semijoin_strategy_choice": [],
+ "pruned_by_cost": true
+ }
+ ]
},
{
"plan_prefix": ["t_outer_1", "t_inner_1", "t_outer_2"],
@@ -4804,6 +5011,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 243,
"cost_for_plan": 75.231,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": [
@@ -4825,6 +5033,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 2187,
"cost_for_plan": 514.65,
+ "semijoin_strategy_choice": [],
"pruned_by_cost": true
},
{
@@ -4847,6 +5056,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 2187,
"cost_for_plan": 514.65,
+ "semijoin_strategy_choice": [],
"pruned_by_cost": true
}
]
@@ -4866,7 +5076,64 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 729,
"cost_for_plan": 172.44,
- "pruned_by_heuristic": true
+ "semijoin_strategy_choice": [],
+ "rest_of_plan": [
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_outer_2",
+ "t_inner_3"
+ ],
+ "table": "t_inner_4",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 3,
+ "cost": 2.0051,
+ "chosen": true
+ }
+ ]
+ },
+ "rows_for_plan": 2187,
+ "cost_for_plan": 611.85,
+ "semijoin_strategy_choice": [
+ {
+ "strategy": "FirstMatch",
+ "records": 81,
+ "read_time": 2232.8
+ },
+ {
+ "chosen_strategy": "FirstMatch"
+ }
+ ],
+ "pruned_by_cost": true
+ },
+ {
+ "plan_prefix": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_outer_2",
+ "t_inner_3"
+ ],
+ "table": "t_inner_2",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "resulting_rows": 9,
+ "cost": 2.0154,
+ "chosen": true
+ }
+ ]
+ },
+ "rows_for_plan": 6561,
+ "cost_for_plan": 1486.7,
+ "semijoin_strategy_choice": [],
+ "pruned_by_cost": true
+ }
+ ]
}
]
},
@@ -4885,6 +5152,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 27,
"cost_for_plan": 13.815,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": ["t_outer_1", "t_inner_1", "t_inner_4"],
@@ -4901,6 +5169,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 243,
"cost_for_plan": 64.431,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": [
@@ -4922,6 +5191,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 2187,
"cost_for_plan": 503.85,
+ "semijoin_strategy_choice": [],
"pruned_by_cost": true
},
{
@@ -4944,6 +5214,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 2187,
"cost_for_plan": 503.85,
+ "semijoin_strategy_choice": [],
"pruned_by_cost": true
}
]
@@ -4963,6 +5234,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 243,
"cost_for_plan": 64.431,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
},
{
@@ -4980,6 +5252,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 243,
"cost_for_plan": 64.431,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
}
]
@@ -4999,6 +5272,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 81,
"cost_for_plan": 24.626,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": ["t_outer_1", "t_inner_1", "t_inner_3"],
@@ -5015,6 +5289,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 729,
"cost_for_plan": 172.44,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": [
@@ -5036,6 +5311,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 2187,
"cost_for_plan": 611.85,
+ "semijoin_strategy_choice": [],
"pruned_by_cost": true
},
{
@@ -5058,6 +5334,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 6561,
"cost_for_plan": 1486.7,
+ "semijoin_strategy_choice": [],
"pruned_by_cost": true
}
]
@@ -5077,6 +5354,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 243,
"cost_for_plan": 75.231,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": [
@@ -5098,6 +5376,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 2187,
"cost_for_plan": 514.65,
+ "semijoin_strategy_choice": [],
"pruned_by_cost": true
},
{
@@ -5120,6 +5399,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 2187,
"cost_for_plan": 514.65,
+ "semijoin_strategy_choice": [],
"pruned_by_cost": true
}
]
@@ -5139,6 +5419,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 729,
"cost_for_plan": 172.44,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
}
]
@@ -5160,6 +5441,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 27,
"cost_for_plan": 10.021,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
},
{
@@ -5177,6 +5459,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 27,
"cost_for_plan": 10.021,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
},
{
@@ -5194,6 +5477,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 9,
"cost_for_plan": 6.4103,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
},
{
@@ -5211,6 +5495,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 27,
"cost_for_plan": 10.021,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
}
]
@@ -5230,6 +5515,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
},
{
@@ -5247,6 +5533,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 9,
"cost_for_plan": 3.8154,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
},
{
@@ -5264,6 +5551,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 9,
"cost_for_plan": 3.8154,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
},
{
@@ -5281,6 +5569,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
},
{
@@ -5298,75 +5587,13 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 9,
"cost_for_plan": 3.8154,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
}
]
},
{
- "fix_semijoin_strategies_for_picked_join_order": [
- {
- "semi_join_strategy": "firstmatch",
- "join_order": [
- {
- "table": "t_inner_4"
- },
- "best_access_path": {
- "considered_access_paths": [
- {
- "access_type": "scan",
- "resulting_rows": 3,
- "cost": 162.42,
- "chosen": true
- }
- ]
- },
- {
- "table": "t_inner_3"
- },
- "best_access_path": {
- "considered_access_paths": [
- {
- "access_type": "scan",
- "resulting_rows": 9,
- "cost": 489.74,
- "chosen": true
- }
- ]
- }
- ]
- },
- {
- "semi_join_strategy": "firstmatch",
- "join_order": [
- {
- "table": "t_inner_1"
- },
- "best_access_path": {
- "considered_access_paths": [
- {
- "access_type": "scan",
- "resulting_rows": 3,
- "cost": 18.046,
- "chosen": true
- }
- ]
- },
- {
- "table": "t_inner_2"
- },
- "best_access_path": {
- "considered_access_paths": [
- {
- "access_type": "scan",
- "resulting_rows": 9,
- "cost": 54.415,
- "chosen": true
- }
- ]
- }
- ]
- }
- ]
+ "fix_semijoin_strategies_for_picked_join_order": []
},
{
"attaching_conditions_to_tables": {
@@ -5386,11 +5613,11 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"attached": null
},
{
- "table": "t_outer_2",
+ "table": "t_inner_4",
"attached": null
},
{
- "table": "t_inner_4",
+ "table": "t_outer_2",
"attached": null
},
{
@@ -5622,6 +5849,16 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
]
},
{
+ "semijoin_table_pullout": {
+ "pulled_out_tables": []
+ }
+ },
+ {
+ "semijoin_table_pullout": {
+ "pulled_out_tables": []
+ }
+ },
+ {
"execution_plan_for_potential_materialization": {
"steps": [
{
@@ -5754,6 +5991,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": ["t_outer_1"],
@@ -5770,6 +6008,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 9,
"cost_for_plan": 6.4103,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": ["t_outer_1", "t_inner_1"],
@@ -5786,6 +6025,26 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 81,
"cost_for_plan": 24.626,
+ "semijoin_strategy_choice": [
+ {
+ "strategy": "FirstMatch",
+ "records": 3,
+ "read_time": 44.759
+ },
+ {
+ "strategy": "SJ-Materialization",
+ "records": 3,
+ "read_time": 8.1256
+ },
+ {
+ "strategy": "DuplicateWeedout",
+ "records": 3,
+ "read_time": 37.226
+ },
+ {
+ "chosen_strategy": "SJ-Materialize"
+ }
+ ],
"rest_of_plan": [
{
"plan_prefix": ["t_outer_1", "t_inner_1", "t_inner_2"],
@@ -5802,6 +6061,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 27,
"cost_for_plan": 15.541,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": [
@@ -5823,6 +6083,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 81,
"cost_for_plan": 33.746,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": [
@@ -5844,7 +6105,27 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
]
},
"rows_for_plan": 729,
- "cost_for_plan": 181.56
+ "cost_for_plan": 181.56,
+ "semijoin_strategy_choice": [
+ {
+ "strategy": "FirstMatch",
+ "records": 27,
+ "read_time": 394.93
+ },
+ {
+ "strategy": "SJ-Materialization",
+ "records": 27,
+ "read_time": 22.262
+ },
+ {
+ "strategy": "DuplicateWeedout",
+ "records": 27,
+ "read_time": 294.96
+ },
+ {
+ "chosen_strategy": "SJ-Materialize"
+ }
+ ]
}
]
},
@@ -5868,6 +6149,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 243,
"cost_for_plan": 66.156,
+ "semijoin_strategy_choice": [],
"pruned_by_cost": true
}
]
@@ -5887,6 +6169,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 9,
"cost_for_plan": 11.931,
+ "semijoin_strategy_choice": [],
"rest_of_plan": [
{
"plan_prefix": [
@@ -5908,6 +6191,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 81,
"cost_for_plan": 30.146,
+ "semijoin_strategy_choice": [],
"pruned_by_cost": true
},
{
@@ -5930,6 +6214,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 81,
"cost_for_plan": 30.146,
+ "semijoin_strategy_choice": [],
"pruned_by_cost": true
}
]
@@ -5949,6 +6234,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 27,
"cost_for_plan": 15.541,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
}
]
@@ -5968,6 +6254,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 81,
"cost_for_plan": 24.626,
+ "semijoin_strategy_choice": [],
"pruned_by_cost": true
},
{
@@ -5985,6 +6272,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 27,
"cost_for_plan": 13.815,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
},
{
@@ -6002,6 +6290,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 81,
"cost_for_plan": 24.626,
+ "semijoin_strategy_choice": [],
"pruned_by_cost": true
}
]
@@ -6021,6 +6310,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 27,
"cost_for_plan": 10.021,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
},
{
@@ -6038,6 +6328,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 27,
"cost_for_plan": 10.021,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
},
{
@@ -6055,6 +6346,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 9,
"cost_for_plan": 6.4103,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
},
{
@@ -6072,6 +6364,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 27,
"cost_for_plan": 10.021,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
}
]
@@ -6091,6 +6384,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
},
{
@@ -6108,6 +6402,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 9,
"cost_for_plan": 3.8154,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
},
{
@@ -6125,6 +6420,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 9,
"cost_for_plan": 3.8154,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
},
{
@@ -6142,6 +6438,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
},
{
@@ -6159,6 +6456,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
},
"rows_for_plan": 9,
"cost_for_plan": 3.8154,
+ "semijoin_strategy_choice": [],
"pruned_by_heuristic": true
}
]
@@ -6166,7 +6464,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
{
"fix_semijoin_strategies_for_picked_join_order": [
{
- "semi_join_strategy": "sj_materialize",
+ "semi_join_strategy": "SJ-Materialization",
"join_order": [
{
"table": "t_inner_4"
@@ -6177,7 +6475,7 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
]
},
{
- "semi_join_strategy": "sj_materialize",
+ "semi_join_strategy": "SJ-Materialization",
"join_order": [
{
"table": "t_inner_1"
@@ -6984,4 +7282,74 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans'))
]
]
drop table t0, one_k;
+#
+# Assertion `to_len >= 8' failed in convert_to_printable
+#
+CREATE TABLE t1 ( a blob, KEY (a(255)));
+insert into t1 values ('foo'), ('bar');
+EXPLAIN SELECT * FROM t1 WHERE a= REPEAT('a', 0);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref a a 258 const 1 Using where
+SELECT * FROM t1 WHERE a= REPEAT('a', 0);
+a
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
+[
+
+ {
+ "range_scan_alternatives":
+ [
+
+ {
+ "index": "a",
+ "ranges":
+ [
+ "() <= (a) <= ()"
+ ],
+ "rowid_ordered": false,
+ "using_mrr": false,
+ "index_only": false,
+ "rows": 1,
+ "cost": 2.4265,
+ "chosen": true
+ }
+ ],
+ "analyzing_roworder_intersect":
+ {
+ "cause": "too few roworder scans"
+ },
+ "analyzing_index_merge_union":
+ [
+ ]
+ }
+]
+DROP TABLE t1;
+#
+# Test for Semi-Join table pullout element
+#
+create table t1 (a int primary key, b int);
+insert into t1 (a) values (1),(2),(3),(4),(5);
+create table t2 (a int primary key, b int);
+insert into t2 (a) values (1),(2),(3),(4),(5);
+create table t3 (a int);
+insert into t3 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+explain
+select * from t3 where (a,a) in (select t1.a, t2.a from t1, t2 where t1.b=t2.b);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 5
+1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 Using where
+1 PRIMARY t3 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join)
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.semijoin_table_pullout')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+JSON_DETAILED(JSON_EXTRACT(trace, '$**.semijoin_table_pullout'))
+[
+
+ {
+ "pulled_out_tables":
+ [
+ "t2",
+ "t1"
+ ]
+ }
+]
+drop table t1,t2,t3;
set optimizer_trace='enabled=off';
diff --git a/mysql-test/main/opt_trace.test b/mysql-test/main/opt_trace.test
index e5d635db042..51950f00781 100644
--- a/mysql-test/main/opt_trace.test
+++ b/mysql-test/main/opt_trace.test
@@ -536,4 +536,35 @@ explain select * from t0 A, one_k B where A.a=B.b and B.a<800;
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
drop table t0, one_k;
+--echo #
+--echo # Assertion `to_len >= 8' failed in convert_to_printable
+--echo #
+
+CREATE TABLE t1 ( a blob, KEY (a(255)));
+insert into t1 values ('foo'), ('bar');
+
+EXPLAIN SELECT * FROM t1 WHERE a= REPEAT('a', 0);
+SELECT * FROM t1 WHERE a= REPEAT('a', 0);
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+
+DROP TABLE t1;
+
+--echo #
+--echo # Test for Semi-Join table pullout element
+--echo #
+create table t1 (a int primary key, b int);
+insert into t1 (a) values (1),(2),(3),(4),(5);
+
+create table t2 (a int primary key, b int);
+insert into t2 (a) values (1),(2),(3),(4),(5);
+
+create table t3 (a int);
+insert into t3 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+
+explain
+select * from t3 where (a,a) in (select t1.a, t2.a from t1, t2 where t1.b=t2.b);
+
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.semijoin_table_pullout')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+
+drop table t1,t2,t3;
set optimizer_trace='enabled=off';
diff --git a/mysql-test/main/opt_tvc.result b/mysql-test/main/opt_tvc.result
index d503dab4d99..5329a9f64be 100644
--- a/mysql-test/main/opt_tvc.result
+++ b/mysql-test/main/opt_tvc.result
@@ -46,12 +46,12 @@ a b
2 5
explain extended select * from t1 where a in (1,2);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 2 100.00
3 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where `test`.`t1`.`a` = `tvc_0`.`_col_1`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where 1
explain extended select * from t1
where a in
(
@@ -59,12 +59,12 @@ select *
from (values (1),(2)) as tvc_0
);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 2 100.00
3 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where `test`.`t1`.`a` = `tvc_0`.`1`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where 1
# AND-condition with IN-predicates in WHERE-part
select * from t1
where a in (1,2) and
@@ -90,15 +90,15 @@ explain extended select * from t1
where a in (1,2) and
b in (1,5);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery4> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery4> eq_ref distinct_key distinct_key 4 func 1 100.00
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
4 MATERIALIZED <derived5> ALL NULL NULL NULL NULL 2 100.00
2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 2 100.00
5 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
3 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) semi join ((values (1),(5)) `tvc_1`) where `test`.`t1`.`b` = `tvc_1`.`_col_1`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) semi join ((values (1),(5)) `tvc_1`) where 1
explain extended select * from t1
where a in
(
@@ -111,15 +111,15 @@ select *
from (values (1),(5)) as tvc_1
);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery4> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery4> eq_ref distinct_key distinct_key 4 func 1 100.00
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
4 MATERIALIZED <derived5> ALL NULL NULL NULL NULL 2 100.00
2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 2 100.00
5 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
3 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) semi join ((values (1),(5)) `tvc_1`) where `test`.`t1`.`b` = `tvc_1`.`1`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) semi join ((values (1),(5)) `tvc_1`) where 1
# subquery with IN-predicate
select * from t1
where a in
@@ -206,12 +206,12 @@ from t1
where a in (1,2)
) as dr_table;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery3> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery3> eq_ref distinct_key distinct_key 4 func 1 100.00
3 MATERIALIZED <derived4> ALL NULL NULL NULL NULL 2 100.00
4 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where `test`.`t1`.`a` = `tvc_0`.`_col_1`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where 1
explain extended select * from
(
select *
@@ -224,12 +224,12 @@ as tvc_0
)
) as dr_table;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery3> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery3> eq_ref distinct_key distinct_key 4 func 1 100.00
3 MATERIALIZED <derived4> ALL NULL NULL NULL NULL 2 100.00
4 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where `test`.`t1`.`a` = `tvc_0`.`1`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where 1
# non-recursive CTE with IN-predicate
with tvc_0 as
(
@@ -265,12 +265,12 @@ where a in (1,2)
)
select * from tvc_0;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery3> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery3> eq_ref distinct_key distinct_key 4 func 1 100.00
3 MATERIALIZED <derived4> ALL NULL NULL NULL NULL 2 100.00
4 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 with tvc_0 as (/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where `test`.`t1`.`a` in (1,2))/* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where `test`.`t1`.`a` = `tvc_0`.`_col_1`
+Note 1003 with tvc_0 as (/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where `test`.`t1`.`a` in (1,2))/* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where 1
explain extended select * from
(
select *
@@ -283,12 +283,12 @@ as tvc_0
)
) as dr_table;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery3> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery3> eq_ref distinct_key distinct_key 4 func 1 100.00
3 MATERIALIZED <derived4> ALL NULL NULL NULL NULL 2 100.00
4 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where `test`.`t1`.`a` = `tvc_0`.`1`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where 1
# VIEW with IN-predicate
create view v1 as
select *
@@ -316,20 +316,20 @@ a b
2 5
explain extended select * from v1;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery3> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery3> eq_ref distinct_key distinct_key 4 func 1 100.00
3 MATERIALIZED <derived4> ALL NULL NULL NULL NULL 2 100.00
4 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where `test`.`t1`.`a` = `tvc_0`.`_col_1`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where 1
explain extended select * from v2;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery3> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery3> eq_ref distinct_key distinct_key 4 func 1 100.00
3 MATERIALIZED <derived4> ALL NULL NULL NULL NULL 2 100.00
4 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where `test`.`t1`.`a` = `tvc_0`.`1`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where 1
drop view v1,v2;
# subselect defined by derived table with IN-predicate
select * from t1
@@ -519,12 +519,12 @@ a b
1 2
explain extended select * from t1 where (a,b) in ((1,2),(3,4));
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1 100.00
2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 2 100.00
3 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1,2),(3,4)) `tvc_0`) where `test`.`t1`.`a` = `tvc_0`.`_col_1` and `test`.`t1`.`b` = `tvc_0`.`_col_2`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1,2),(3,4)) `tvc_0`) where 1
set @@in_predicate_conversion_threshold= 2;
# trasformation works for the one IN predicate and doesn't work for the other
set @@in_predicate_conversion_threshold= 5;
@@ -538,12 +538,12 @@ explain extended select * from t2
where (a,b) in ((1,2),(8,9)) and
(a,c) in ((1,3),(8,0),(5,1));
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3 100.00
-1 PRIMARY t2 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t2 ALL NULL NULL NULL NULL 6 100.00 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1 100.00
2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 3 100.00
3 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` semi join ((values (1,3),(8,0),(5,1)) `tvc_0`) where `test`.`t2`.`a` = `tvc_0`.`_col_1` and `test`.`t2`.`c` = `tvc_0`.`_col_2` and (`tvc_0`.`_col_1`,`test`.`t2`.`b`) in (<cache>((1,2)),<cache>((8,9)))
+Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` semi join ((values (1,3),(8,0),(5,1)) `tvc_0`) where (`test`.`t2`.`a`,`test`.`t2`.`b`) in (<cache>((1,2)),<cache>((8,9)))
set @@in_predicate_conversion_threshold= 2;
#
# mdev-14281: conversion of NOT IN predicate into subquery predicate
diff --git a/mysql-test/main/partition_range.result b/mysql-test/main/partition_range.result
index 48b1ce87555..2cb9e3f4ab8 100644
--- a/mysql-test/main/partition_range.result
+++ b/mysql-test/main/partition_range.result
@@ -987,4 +987,31 @@ a MAX(b)
SHOW status LIKE 'handler_read_key';
Variable_name Value
Handler_read_key 2
+#
+# MDEV-18501 Partition pruning doesn't work for historical queries
+#
+set time_zone= '+00:00';
+create or replace table t1 (d datetime(6))
+partition by range (unix_timestamp(d)) (
+partition p0 values less than (1),
+partition p1 values less than (maxvalue));
+ERROR HY000: Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed
+# DECIMAL functions are now allowed, partitioning is done by integer part
+create or replace table t1 (d timestamp(6))
+partition by range (unix_timestamp(d)) (
+partition p0 values less than (946684801),
+partition p1 values less than (maxvalue));
+insert into t1 values
+# go to p0
+('2000-01-01 00:00:00'),
+('2000-01-01 00:00:00.000001'),
+# goes to p1
+('2000-01-01 00:00:01');
+select * from t1 partition (p0);
+d
+2000-01-01 00:00:00.000000
+2000-01-01 00:00:00.000001
+select * from t1 partition (p1);
+d
+2000-01-01 00:00:01.000000
DROP TABLE t1, t2;
diff --git a/mysql-test/main/partition_range.test b/mysql-test/main/partition_range.test
index 7f637f83ed9..37702db052b 100644
--- a/mysql-test/main/partition_range.test
+++ b/mysql-test/main/partition_range.test
@@ -973,4 +973,31 @@ SELECT a, MAX(b) FROM t2 WHERE a IN (10, 100) GROUP BY a;
--echo # Should be no more than 4 reads.
SHOW status LIKE 'handler_read_key';
+--echo #
+--echo # MDEV-18501 Partition pruning doesn't work for historical queries
+--echo #
+set time_zone= '+00:00';
+let $ts= `select unix_timestamp('2000-01-01 00:00:00') + 1`;
+
+--error ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
+create or replace table t1 (d datetime(6))
+partition by range (unix_timestamp(d)) (
+ partition p0 values less than (1),
+ partition p1 values less than (maxvalue));
+
+--echo # DECIMAL functions are now allowed, partitioning is done by integer part
+eval create or replace table t1 (d timestamp(6))
+partition by range (unix_timestamp(d)) (
+ partition p0 values less than ($ts),
+ partition p1 values less than (maxvalue));
+
+insert into t1 values
+ # go to p0
+ ('2000-01-01 00:00:00'),
+ ('2000-01-01 00:00:00.000001'),
+ # goes to p1
+ ('2000-01-01 00:00:01');
+select * from t1 partition (p0);
+select * from t1 partition (p1);
+
DROP TABLE t1, t2;
diff --git a/mysql-test/main/rowid_filter_innodb.result b/mysql-test/main/rowid_filter_innodb.result
index d83239eb25f..390c7834a0a 100644
--- a/mysql-test/main/rowid_filter_innodb.result
+++ b/mysql-test/main/rowid_filter_innodb.result
@@ -2179,7 +2179,7 @@ count(*)
6
explain extended select count(*) from t1 where a in (22,83,11) and b=2;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE t1 ref b,a b 5 const 59 55.93 Using where
+1 SIMPLE t1 ref b,a b 5 const 59 3.30 Using where
Warnings:
Note 1003 select count(0) AS `count(*)` from `test`.`t1` where `test`.`t1`.`b` = 2 and `test`.`t1`.`a` in (22,83,11)
select * from t1 where a in (22,83,11) and b=2;
@@ -2196,7 +2196,7 @@ count(*)
6
explain extended select count(*) from t1 where a in (22,83,11) and b=2;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE t1 ref|filter b,a b|a 5|5 const 59 (3%) 55.93 Using where; Using rowid filter
+1 SIMPLE t1 ref|filter b,a b|a 5|5 const 59 (3%) 3.30 Using where; Using rowid filter
Warnings:
Note 1003 select count(0) AS `count(*)` from `test`.`t1` where `test`.`t1`.`b` = 2 and `test`.`t1`.`a` in (22,83,11)
select * from t1 where a in (22,83,11) and b=2;
diff --git a/mysql-test/main/selectivity.result b/mysql-test/main/selectivity.result
index 33c7c9be47a..7db951ccafe 100644
--- a/mysql-test/main/selectivity.result
+++ b/mysql-test/main/selectivity.result
@@ -1637,3 +1637,37 @@ set @@use_stat_tables= @save_use_stat_tables;
set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
drop table t1;
drop function f1;
+#
+# MDEV-19834 Selectivity of an equality condition discounted twice
+#
+set @@optimizer_use_condition_selectivity=4;
+set @@use_stat_tables='preferably';
+create table t1 (a int, b int, key (b), key (a));
+insert into t1
+select (rand(1)*1000)/10, (rand(1001)*1000)/50 from seq_1_to_1000;
+analyze table t1 ;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status Table is already up to date
+# Check what info the optimizer has about selectivities
+explain extended select * from t1 use index () where a in (17,51,5);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 1000 3.90 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` USE INDEX () where `test`.`t1`.`a` in (17,51,5)
+explain extended select * from t1 use index () where b=2;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 1000 5.47 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` USE INDEX () where `test`.`t1`.`b` = 2
+# Now, the equality is used for ref access, while the range condition
+# gives selectivity data
+explain extended select * from t1 where a in (17,51,5) and b=2;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ref|filter b,a b|a 5|5 const 58 (3%) 2.90 Using where; Using rowid filter
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where `test`.`t1`.`b` = 2 and `test`.`t1`.`a` in (17,51,5)
+drop table t1;
+set use_stat_tables= @save_use_stat_tables;
+set optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
+# End of 10.1 tests
diff --git a/mysql-test/main/selectivity.test b/mysql-test/main/selectivity.test
index eb3f6e2893a..d911957ddc7 100644
--- a/mysql-test/main/selectivity.test
+++ b/mysql-test/main/selectivity.test
@@ -1,4 +1,5 @@
--source include/have_stat_tables.inc
+--source include/have_sequence.inc
--disable_warnings
drop table if exists t0,t1,t2,t3;
@@ -1104,3 +1105,26 @@ set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectiv
drop table t1;
drop function f1;
+--echo #
+--echo # MDEV-19834 Selectivity of an equality condition discounted twice
+--echo #
+set @@optimizer_use_condition_selectivity=4;
+set @@use_stat_tables='preferably';
+create table t1 (a int, b int, key (b), key (a));
+insert into t1
+select (rand(1)*1000)/10, (rand(1001)*1000)/50 from seq_1_to_1000;
+analyze table t1 ;
+
+--echo # Check what info the optimizer has about selectivities
+explain extended select * from t1 use index () where a in (17,51,5);
+explain extended select * from t1 use index () where b=2;
+
+--echo # Now, the equality is used for ref access, while the range condition
+--echo # gives selectivity data
+explain extended select * from t1 where a in (17,51,5) and b=2;
+drop table t1;
+
+set use_stat_tables= @save_use_stat_tables;
+set optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
+--echo # End of 10.1 tests
+
diff --git a/mysql-test/main/selectivity_innodb.result b/mysql-test/main/selectivity_innodb.result
index 92091f0d6db..16f84ff3402 100644
--- a/mysql-test/main/selectivity_innodb.result
+++ b/mysql-test/main/selectivity_innodb.result
@@ -1647,6 +1647,40 @@ set @@use_stat_tables= @save_use_stat_tables;
set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
drop table t1;
drop function f1;
+#
+# MDEV-19834 Selectivity of an equality condition discounted twice
+#
+set @@optimizer_use_condition_selectivity=4;
+set @@use_stat_tables='preferably';
+create table t1 (a int, b int, key (b), key (a));
+insert into t1
+select (rand(1)*1000)/10, (rand(1001)*1000)/50 from seq_1_to_1000;
+analyze table t1 ;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+# Check what info the optimizer has about selectivities
+explain extended select * from t1 use index () where a in (17,51,5);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 1000 3.90 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` USE INDEX () where `test`.`t1`.`a` in (17,51,5)
+explain extended select * from t1 use index () where b=2;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 1000 5.47 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` USE INDEX () where `test`.`t1`.`b` = 2
+# Now, the equality is used for ref access, while the range condition
+# gives selectivity data
+explain extended select * from t1 where a in (17,51,5) and b=2;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ref|filter b,a b|a 5|5 const 59 (3%) 2.90 Using where; Using rowid filter
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where `test`.`t1`.`b` = 2 and `test`.`t1`.`a` in (17,51,5)
+drop table t1;
+set use_stat_tables= @save_use_stat_tables;
+set optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
+# End of 10.1 tests
set optimizer_switch=@save_optimizer_switch_for_selectivity_test;
set @tmp_ust= @@use_stat_tables;
set @tmp_oucs= @@optimizer_use_condition_selectivity;
diff --git a/mysql-test/main/subselect.result b/mysql-test/main/subselect.result
index fc0049db997..5e446a171fe 100644
--- a/mysql-test/main/subselect.result
+++ b/mysql-test/main/subselect.result
@@ -5703,8 +5703,8 @@ EXPLAIN
SELECT * FROM t1
WHERE EXISTS (SELECT a FROM t2 USE INDEX() WHERE t2.a = t1.a);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3
SELECT * FROM t1
WHERE EXISTS (SELECT a FROM t2 WHERE t2.a = t1.a);
@@ -5714,8 +5714,8 @@ EXPLAIN
SELECT * FROM t1
WHERE EXISTS (SELECT a FROM t2 WHERE t2.a = t1.a);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 index idx idx 5 NULL 3 Using index
DROP TABLE t1,t2;
#
diff --git a/mysql-test/main/subselect3.result b/mysql-test/main/subselect3.result
index ca151daf146..3c33182b3ef 100644
--- a/mysql-test/main/subselect3.result
+++ b/mysql-test/main/subselect3.result
@@ -1139,8 +1139,8 @@ create table t3 (a int);
insert into t3 select A.a + 10*B.a from t0 A, t0 B;
explain select * from t3 where a in (select kp1 from t1 where kp1<20);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 range kp1 kp1 5 NULL 48 Using where; Using index; LooseScan
-1 PRIMARY t3 ALL NULL NULL NULL NULL 100 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t3 ALL NULL NULL NULL NULL 100 Using where
+1 PRIMARY t1 ref kp1 kp1 5 test.t3.a 1 Using index; FirstMatch(t3)
create table t4 (pk int primary key);
insert into t4 select a from t3;
explain select * from t3 where a in (select t1.kp1 from t1,t4 where kp1<20
@@ -1276,12 +1276,12 @@ insert into t1 select A.a, B.a, 'filler' from t0 A, t0 B;
create table t2 as select * from t1;
explain select * from t2 where a in (select b from t1 where a=3);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 ref a a 5 const 8 Using index; LooseScan
-1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Using where
+1 PRIMARY t1 ref a a 10 const,test.t2.a 1 Using index; FirstMatch(t2)
explain select * from t2 where (b,a) in (select a,b from t1 where a=3);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 ref a a 5 const 8 Using index; LooseScan
-1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Using where
+1 PRIMARY t1 ref a a 10 const,test.t2.a 1 Using index; FirstMatch(t2)
drop table t1,t2;
set @@optimizer_switch=@save_optimizer_switch;
create table t1 (a int, b int);
@@ -1339,9 +1339,9 @@ insert into t2 select * from t2;
explain select * from t1 where (a,b,c) in (select X.a, Y.a, Z.a from t2 X, t2 Y, t2 Z where X.b=33);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3
-1 PRIMARY X ALL NULL NULL NULL NULL 6 Using where
-1 PRIMARY Y ALL NULL NULL NULL NULL 6 Using where
-1 PRIMARY Z ALL NULL NULL NULL NULL 6 Using where; FirstMatch(t1)
+1 PRIMARY X ALL NULL NULL NULL NULL 6 Using where; Start temporary; Using join buffer (flat, BNL join)
+1 PRIMARY Y ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY Z ALL NULL NULL NULL NULL 6 Using where; End temporary; Using join buffer (flat, BNL join)
drop table t0,t1,t2;
set @@optimizer_switch=@save_optimizer_switch;
diff --git a/mysql-test/main/subselect3_jcl6.result b/mysql-test/main/subselect3_jcl6.result
index adb3ec80394..69f720a95b7 100644
--- a/mysql-test/main/subselect3_jcl6.result
+++ b/mysql-test/main/subselect3_jcl6.result
@@ -1149,8 +1149,8 @@ create table t3 (a int);
insert into t3 select A.a + 10*B.a from t0 A, t0 B;
explain select * from t3 where a in (select kp1 from t1 where kp1<20);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 range kp1 kp1 5 NULL 48 Using where; Using index; LooseScan
-1 PRIMARY t3 ALL NULL NULL NULL NULL 100 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t3 ALL NULL NULL NULL NULL 100 Using where
+1 PRIMARY t1 ref kp1 kp1 5 test.t3.a 1 Using index; FirstMatch(t3)
create table t4 (pk int primary key);
insert into t4 select a from t3;
explain select * from t3 where a in (select t1.kp1 from t1,t4 where kp1<20
@@ -1286,12 +1286,12 @@ insert into t1 select A.a, B.a, 'filler' from t0 A, t0 B;
create table t2 as select * from t1;
explain select * from t2 where a in (select b from t1 where a=3);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 ref a a 5 const 8 Using index; LooseScan
-1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Using where
+1 PRIMARY t1 ref a a 10 const,test.t2.a 1 Using index; FirstMatch(t2)
explain select * from t2 where (b,a) in (select a,b from t1 where a=3);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 ref a a 5 const 8 Using index; LooseScan
-1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Using where
+1 PRIMARY t1 ref a a 10 const,test.t2.a 1 Using index; FirstMatch(t2)
drop table t1,t2;
set @@optimizer_switch=@save_optimizer_switch;
create table t1 (a int, b int);
@@ -1348,10 +1348,10 @@ create table t2 as select a as a, a as b from t0 where a < 3;
insert into t2 select * from t2;
explain select * from t1 where (a,b,c) in (select X.a, Y.a, Z.a from t2 X, t2 Y, t2 Z where X.b=33);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 ALL NULL NULL NULL NULL 3
-1 PRIMARY X ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join)
-1 PRIMARY Y ALL NULL NULL NULL NULL 6 Using where; Using join buffer (incremental, BNL join)
-1 PRIMARY Z ALL NULL NULL NULL NULL 6 Using where; FirstMatch(t1); Using join buffer (incremental, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
+1 PRIMARY X hash_ALL NULL #hash#$hj 5 test.t1.a 6 Using where; Start temporary; Using join buffer (flat, BNLH join)
+1 PRIMARY Y hash_ALL NULL #hash#$hj 5 test.t1.b 6 Using where; Using join buffer (incremental, BNLH join)
+1 PRIMARY Z hash_ALL NULL #hash#$hj 5 test.t1.c 6 Using where; End temporary; Using join buffer (incremental, BNLH join)
drop table t0,t1,t2;
set @@optimizer_switch=@save_optimizer_switch;
diff --git a/mysql-test/main/subselect_mat.result b/mysql-test/main/subselect_mat.result
index 4e03d9663ef..ee680d40b75 100644
--- a/mysql-test/main/subselect_mat.result
+++ b/mysql-test/main/subselect_mat.result
@@ -1510,8 +1510,8 @@ set @@optimizer_switch=@optimizer_switch_local_default;
SET @@optimizer_switch='semijoin=on,materialization=on';
EXPLAIN SELECT COUNT(*) FROM t1 WHERE (f1,f2) IN (SELECT f1,f2 FROM t2);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2
-1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 7 func,func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2
SELECT COUNT(*) FROM t1 WHERE (f1,f2) IN (SELECT f1,f2 FROM t2);
COUNT(*)
@@ -2437,8 +2437,8 @@ INSERT INTO t2 VALUES (11,11),(12,12),(13,13);
explain
SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 hash_ALL NULL #hash#$hj 4 test.t2.i1 9 Using where; Using join buffer (flat, BNLH join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 9
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where
SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2);
1
@@ -2450,8 +2450,8 @@ alter table t1 add key(id);
explain
SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ref id id 4 test.t2.i1 2 Using index
+1 PRIMARY t1 index id id 4 NULL 9 Using index
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where
SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2);
1
@@ -2507,8 +2507,8 @@ INSERT INTO t2 VALUES (11,11),(12,12),(13,13);
CREATE VIEW v1 AS SELECT t2.i1 FROM t2 where t2.i1 = t2.i2;
explain SELECT 1 FROM t1 where t1.id IN (SELECT v1.i1 from v1);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ref id id 4 test.t2.i1 2 Using index
+1 PRIMARY t1 index id id 4 NULL 9 Using index
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where
SELECT 1 FROM t1 where t1.id IN (SELECT v1.i1 from v1);
1
diff --git a/mysql-test/main/subselect_no_mat.result b/mysql-test/main/subselect_no_mat.result
index 4ebf04b1f55..ecd973da09d 100644
--- a/mysql-test/main/subselect_no_mat.result
+++ b/mysql-test/main/subselect_no_mat.result
@@ -5683,9 +5683,9 @@ WHERE (ot1.a,ot4.a) IN (SELECT it2.a,it3.a
FROM it2,it3);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY ot1 ALL NULL NULL NULL NULL 2
-1 PRIMARY ot4 ALL NULL NULL NULL NULL 8 Using join buffer (flat, BNL join)
-1 PRIMARY it2 ALL NULL NULL NULL NULL 4 Using where
-1 PRIMARY it3 ALL NULL NULL NULL NULL 6 Using where; FirstMatch(ot4)
+1 PRIMARY it2 ALL NULL NULL NULL NULL 4 Using where; Start temporary; Using join buffer (flat, BNL join)
+1 PRIMARY it3 ALL NULL NULL NULL NULL 6 Using join buffer (flat, BNL join)
+1 PRIMARY ot4 ALL NULL NULL NULL NULL 8 Using where; End temporary; Using join buffer (flat, BNL join)
DROP TABLE IF EXISTS ot1, ot4, it2, it3;
#
# Bug#729039: NULL keys used to evaluate subquery
@@ -5712,8 +5712,8 @@ EXPLAIN
SELECT * FROM t1
WHERE EXISTS (SELECT a FROM t2 WHERE t2.a = t1.a);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t2 index idx idx 5 NULL 3 Using index; LooseScan
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
+1 PRIMARY t2 ref idx idx 5 test.t1.a 2 Using index; FirstMatch(t1)
DROP TABLE t1,t2;
#
# BUG#752992: Wrong results for a subquery with 'semijoin=on'
diff --git a/mysql-test/main/subselect_no_scache.result b/mysql-test/main/subselect_no_scache.result
index 71d61e797f3..318ad02d473 100644
--- a/mysql-test/main/subselect_no_scache.result
+++ b/mysql-test/main/subselect_no_scache.result
@@ -5709,8 +5709,8 @@ EXPLAIN
SELECT * FROM t1
WHERE EXISTS (SELECT a FROM t2 USE INDEX() WHERE t2.a = t1.a);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3
SELECT * FROM t1
WHERE EXISTS (SELECT a FROM t2 WHERE t2.a = t1.a);
@@ -5720,8 +5720,8 @@ EXPLAIN
SELECT * FROM t1
WHERE EXISTS (SELECT a FROM t2 WHERE t2.a = t1.a);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 index idx idx 5 NULL 3 Using index
DROP TABLE t1,t2;
#
diff --git a/mysql-test/main/subselect_sj.result b/mysql-test/main/subselect_sj.result
index 98143246673..7c15cbf721e 100644
--- a/mysql-test/main/subselect_sj.result
+++ b/mysql-test/main/subselect_sj.result
@@ -729,8 +729,8 @@ SELECT int_key FROM ot1
WHERE int_nokey IN (SELECT it2.int_key
FROM it1 LEFT JOIN it2 ON it2.datetime_key);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 10
-1 PRIMARY ot1 ALL NULL NULL NULL NULL 20 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY ot1 ALL NULL NULL NULL NULL 20
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED it1 index NULL int_key 4 NULL 2 Using index
2 MATERIALIZED it2 ALL int_key,datetime_key NULL NULL NULL 20 Using where
DROP TABLE ot1, it1, it2;
@@ -972,11 +972,11 @@ SELECT `varchar_key` , `varchar_nokey`
FROM t1
WHERE `varchar_nokey` < 'n' XOR `pk` ) ;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 15 100.00
-1 PRIMARY t2 ALL NULL NULL NULL NULL 18 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t2 ALL NULL NULL NULL NULL 18 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1 100.00
2 MATERIALIZED t1 ALL varchar_key NULL NULL NULL 15 100.00 Using where
Warnings:
-Note 1003 select `test`.`t2`.`varchar_nokey` AS `varchar_nokey` from `test`.`t2` semi join (`test`.`t1`) where `test`.`t1`.`varchar_nokey` = `test`.`t1`.`varchar_key` and `test`.`t2`.`varchar_nokey` = `test`.`t1`.`varchar_key` and (`test`.`t1`.`varchar_key` < 'n' xor `test`.`t1`.`pk`)
+Note 1003 select `test`.`t2`.`varchar_nokey` AS `varchar_nokey` from `test`.`t2` semi join (`test`.`t1`) where `test`.`t1`.`varchar_nokey` = `test`.`t1`.`varchar_key` and (`test`.`t1`.`varchar_key` < 'n' xor `test`.`t1`.`pk`)
SELECT varchar_nokey
FROM t2
WHERE ( `varchar_nokey` , `varchar_nokey` ) IN (
@@ -1246,8 +1246,8 @@ INSERT INTO t2 VALUES (1, 0), (1, 1), (2, 0), (2, 1);
EXPLAIN
SELECT * FROM t1 WHERE (i) IN (SELECT i FROM t2 where j > 0);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t2 index k k 10 NULL 4 Using where; Using index; LooseScan
-1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t2 index k k 10 NULL 4 Using where; Using index; Start temporary
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Using where; End temporary; Using join buffer (flat, BNL join)
SELECT * FROM t1 WHERE (i) IN (SELECT i FROM t2 where j > 0);
i
1
@@ -1757,8 +1757,8 @@ insert into t3 values('three'),( 'four');
insert into t3 values('three'),( 'four');
explain select * from t3 where t3.b in (select t2.b from t1 left join t2 on t1.a=t2.a);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2
-1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t3 ALL NULL NULL NULL NULL 8
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 10 func 1
2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using where
select * from t3 where t3.b in (select t2.b from t1 left join t2 on t1.a=t2.a);
@@ -1991,12 +1991,13 @@ CREATE VIEW v4 AS SELECT DISTINCT f2 FROM t4 ;
explain extended
SELECT * FROM t1 NATURAL LEFT JOIN (t2, t3) WHERE t2.f3 IN (SELECT * FROM t4);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where
-1 PRIMARY t4 ref f2 f2 5 test.t2.f3 2 100.00 Using index; FirstMatch(t2)
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join)
1 PRIMARY t3 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join)
+2 MATERIALIZED t4 index f2 f2 5 NULL 2 100.00 Using index
Warnings:
-Note 1003 select `test`.`t1`.`f1` AS `f1`,`test`.`t1`.`f2` AS `f2`,`test`.`t2`.`f3` AS `f3`,`test`.`t3`.`f3` AS `f3` from `test`.`t1` semi join (`test`.`t4`) join `test`.`t2` join `test`.`t3` where `test`.`t4`.`f2` = `test`.`t2`.`f3` and `test`.`t3`.`f1` = `test`.`t1`.`f1` and `test`.`t1`.`f2` = `test`.`t2`.`f2`
+Note 1003 select `test`.`t1`.`f1` AS `f1`,`test`.`t1`.`f2` AS `f2`,`test`.`t2`.`f3` AS `f3`,`test`.`t3`.`f3` AS `f3` from `test`.`t1` semi join (`test`.`t4`) join `test`.`t2` join `test`.`t3` where `test`.`t3`.`f1` = `test`.`t1`.`f1` and `test`.`t1`.`f2` = `test`.`t2`.`f2`
SELECT * FROM t1 NATURAL LEFT JOIN (t2, t3) WHERE t2.f3 IN (SELECT * FROM t4);
f1 f2 f3 f3
2 0 0 0
@@ -2495,8 +2496,8 @@ WHERE t1.a = t2.a AND t2.a IN (SELECT b FROM t3 STRAIGHT_JOIN t4);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 system NULL NULL NULL NULL 1
1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 1
-1 PRIMARY t1 ref a a 5 const 1 Using index
-1 PRIMARY t2 ref a a 5 func 1 Using index
+1 PRIMARY t2 ref a a 5 const 1 Using index
+1 PRIMARY t1 ref a a 5 func 1 Using index
2 MATERIALIZED t4 ALL NULL NULL NULL NULL 0
SELECT * FROM t1, t2
WHERE t1.a = t2.a AND t2.a IN (SELECT b FROM t3 STRAIGHT_JOIN t4);
@@ -2706,8 +2707,8 @@ a
19
explain select * from t3 where a in (select kp1 from t1 where kp1<20);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 range kp1 kp1 5 NULL 48 Using where; Using index; LooseScan
-1 PRIMARY t3 ALL NULL NULL NULL NULL 100 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t3 ALL NULL NULL NULL NULL 100 Using where
+1 PRIMARY t1 ref kp1 kp1 5 test.t3.a 1 Using index; FirstMatch(t3)
drop table t0,t1,t3;
set optimizer_switch= @tmp_923246;
#
@@ -2923,8 +2924,8 @@ WHERE alias1.pk = 58 OR alias1.col_varchar_key = 'o'
);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2
-1 PRIMARY alias1 index_merge PRIMARY,col_int_key,col_varchar_key PRIMARY,col_varchar_key 4,4 NULL 2 Using sort_union(PRIMARY,col_varchar_key); Using where
-1 PRIMARY alias2 ALL col_int_key NULL NULL NULL 12 Range checked for each record (index map: 0x2); FirstMatch(t2)
+1 PRIMARY alias1 index_merge PRIMARY,col_int_key,col_varchar_key PRIMARY,col_varchar_key 4,4 NULL 2 Using sort_union(PRIMARY,col_varchar_key); Using where; Start temporary
+1 PRIMARY alias2 ALL col_int_key NULL NULL NULL 12 Range checked for each record (index map: 0x2); End temporary
SELECT *
FROM t2
WHERE (field1) IN (SELECT alias1.col_varchar_nokey AS field1
@@ -3264,4 +3265,27 @@ create table t2 (a2 varchar(25)) ;
insert into t1 select 'xxx' from dual where 'xxx' in (select a2 from t2);
drop table t1,t2;
# End of 5.5 test
+#
+# MDEV-20109: Optimizer ignores distinct key created for materialized
+# semi-join subquery when searching for best execution plan
+#
+create table t1(a int);
+insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t2(a int);
+insert into t2 select A.a + B.a* 10 + C.a * 100 from t1 A, t1 B, t1 C;
+create table t3 (a int);
+create table t4 (a int);
+insert into t3 select A.a +1000*B.a from t2 A, t1 B;
+insert into t4 select floor(rand()*1000) from t2 limit 500;
+# The following must not use this query plan that does a cross join:
+# | 1 | PRIMARY | <subquery2> | ALL | distinct_key | ... | 500 | |
+# | 1 | PRIMARY | t3 | ALL | NULL | ... | 10000 | Using where; Using join buffer (flat, BNL join) |
+#
+# Instead, it should use eq_ref on the materialized table.
+explain select * from t3 where a in (select a from t4);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t3 ALL NULL NULL NULL NULL 10000
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED t4 ALL NULL NULL NULL NULL 500
+drop table t1, t2, t3, t4;
set optimizer_switch=@subselect_sj_tmp;
diff --git a/mysql-test/main/subselect_sj.test b/mysql-test/main/subselect_sj.test
index b693f7b5b93..13f6bece181 100644
--- a/mysql-test/main/subselect_sj.test
+++ b/mysql-test/main/subselect_sj.test
@@ -2940,5 +2940,30 @@ drop table t1,t2;
--echo # End of 5.5 test
+--echo #
+--echo # MDEV-20109: Optimizer ignores distinct key created for materialized
+--echo # semi-join subquery when searching for best execution plan
+--echo #
+create table t1(a int);
+insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+
+create table t2(a int);
+insert into t2 select A.a + B.a* 10 + C.a * 100 from t1 A, t1 B, t1 C;
+
+create table t3 (a int);
+create table t4 (a int);
+insert into t3 select A.a +1000*B.a from t2 A, t1 B;
+insert into t4 select floor(rand()*1000) from t2 limit 500;
+
+--echo # The following must not use this query plan that does a cross join:
+--echo # | 1 | PRIMARY | <subquery2> | ALL | distinct_key | ... | 500 | |
+--echo # | 1 | PRIMARY | t3 | ALL | NULL | ... | 10000 | Using where; Using join buffer (flat, BNL join) |
+--echo #
+--echo # Instead, it should use eq_ref on the materialized table.
+
+explain select * from t3 where a in (select a from t4);
+
+drop table t1, t2, t3, t4;
+
# The following command must be the last one the file
set optimizer_switch=@subselect_sj_tmp;
diff --git a/mysql-test/main/subselect_sj2.result b/mysql-test/main/subselect_sj2.result
index a127c18280e..bab21da8243 100644
--- a/mysql-test/main/subselect_sj2.result
+++ b/mysql-test/main/subselect_sj2.result
@@ -131,8 +131,9 @@ set join_buffer_size= @save_join_buffer_size;
set max_heap_table_size= @save_max_heap_table_size;
explain select * from t1 where a in (select b from t2);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
-1 PRIMARY t2 ref b b 5 test.t1.a 1 Using index; FirstMatch(t1)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED t2 index b b 5 NULL 20 Using index
select * from t1;
a b
1 1
@@ -159,8 +160,8 @@ explain select
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
from t1 ot where a in (select a from t2 it);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 22
-1 PRIMARY ot ALL NULL NULL NULL NULL 32 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY ot ALL NULL NULL NULL NULL 32
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED it ALL NULL NULL NULL NULL 22
select
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
@@ -227,8 +228,8 @@ explain select
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
from t1 ot where a in (select a from t2 it);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 22
-1 PRIMARY ot ALL NULL NULL NULL NULL 52 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY ot ALL NULL NULL NULL NULL 52
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED it ALL NULL NULL NULL NULL 22
select
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
@@ -730,8 +731,9 @@ alter table t3 add primary key(id), add key(a);
The following must use loose index scan over t3, key a:
explain select count(a) from t2 where a in ( SELECT a FROM t3);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t2 index a a 5 NULL 1000 Using where; Using index
-1 PRIMARY t3 ref a a 5 test.t2.a 30 Using index; FirstMatch(t2)
+1 PRIMARY t2 index a a 5 NULL 1000 Using index
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED t3 index a a 5 NULL 30000 Using index
select count(a) from t2 where a in ( SELECT a FROM t3);
count(a)
1000
@@ -757,9 +759,10 @@ c2 in (select 1 from t3, t2) and
c1 in (select convert(c6,char(1)) from t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where
-1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; FirstMatch(t2)
+1 PRIMARY <subquery3> eq_ref distinct_key distinct_key 4 func 1 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 1
-1 PRIMARY t3 ALL NULL NULL NULL NULL 2 FirstMatch(t2)
+1 PRIMARY t3 ALL NULL NULL NULL NULL 2 FirstMatch((sj-nest))
+3 MATERIALIZED t2 ALL NULL NULL NULL NULL 1
drop table t2, t3;
#
# BUG#761598: InnoDB: Error: row_search_for_mysql() is called without ha_innobase::external_lock() in maria-5.3
@@ -810,6 +813,14 @@ CREATE TABLE t2 (f14 int(11) NOT NULL, f12 varchar(1) NOT NULL, KEY (f12,f14)) E
INSERT INTO t2 VALUES (6,'y');
CREATE TABLE t3 (f12 varchar(1) NOT NULL) ENGINE=InnoDB;
INSERT INTO t3 VALUES ('r'),('s'),('t'),('v'),('w'),('x'),('y');
+analyze table t1,t2,t3 persistent for all;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+test.t2 analyze status Engine-independent statistics collected
+test.t2 analyze status OK
+test.t3 analyze status Engine-independent statistics collected
+test.t3 analyze status OK
# The following must use LooseScan but not join buffering
explain
SELECT * FROM t3
@@ -1099,6 +1110,14 @@ INSERT INTO t2 VALUES
(9,'d','d'),(10,'s','s'),(11,'r','r'),(12,'m','m'),
(13,'b','b'),(14,'x','x'),(15,'g','g'),(16,'p','p'),
(17,'q','q'),(18,'w','w'),(19,'d','d');
+analyze table t1 persistent for all;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+analyze table t2 persistent for all;
+Table Op Msg_type Msg_text
+test.t2 analyze status Engine-independent statistics collected
+test.t2 analyze status OK
EXPLAIN
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
@@ -1107,11 +1126,11 @@ WHERE alias5.b = alias4.b
AND ( alias5.b >= alias3.b OR alias5.c != alias3.c )
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL #
-1 PRIMARY alias5 index PRIMARY c 4 NULL # Using where; Using index
-1 PRIMARY alias4 eq_ref PRIMARY,c PRIMARY 4 test.alias5.b # Using where; FirstMatch(alias3)
-1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
+1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL # Using where
+1 PRIMARY alias4 ref PRIMARY,c c 4 test.alias3.d # Using index
+1 PRIMARY alias5 eq_ref PRIMARY PRIMARY 4 test.alias4.b # Using where; FirstMatch(alias3)
1 PRIMARY alias2 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
+1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
SELECT alias4.c FROM t2 AS alias4, t2 AS alias5
@@ -1128,11 +1147,11 @@ WHERE alias5.b = alias4.b
AND ( alias5.b >= alias3.b OR alias3.c != alias5.c )
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL #
-1 PRIMARY alias5 index PRIMARY c 4 NULL # Using where; Using index
-1 PRIMARY alias4 eq_ref PRIMARY,c PRIMARY 4 test.alias5.b # Using where; FirstMatch(alias3)
-1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
+1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL # Using where
+1 PRIMARY alias4 ref PRIMARY,c c 4 test.alias3.d # Using index
+1 PRIMARY alias5 eq_ref PRIMARY PRIMARY 4 test.alias4.b # Using where; FirstMatch(alias3)
1 PRIMARY alias2 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
+1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
SELECT alias4.c FROM t2 AS alias4, t2 AS alias5
diff --git a/mysql-test/main/subselect_sj2.test b/mysql-test/main/subselect_sj2.test
index 2b4f619a615..8886c42eb55 100644
--- a/mysql-test/main/subselect_sj2.test
+++ b/mysql-test/main/subselect_sj2.test
@@ -994,6 +994,7 @@ INSERT INTO t2 VALUES (6,'y');
CREATE TABLE t3 (f12 varchar(1) NOT NULL) ENGINE=InnoDB;
INSERT INTO t3 VALUES ('r'),('s'),('t'),('v'),('w'),('x'),('y');
+analyze table t1,t2,t3 persistent for all;
--echo # The following must use LooseScan but not join buffering
--replace_column 9 #
@@ -1225,6 +1226,8 @@ INSERT INTO t2 VALUES
(13,'b','b'),(14,'x','x'),(15,'g','g'),(16,'p','p'),
(17,'q','q'),(18,'w','w'),(19,'d','d');
+analyze table t1 persistent for all;
+analyze table t2 persistent for all;
--replace_column 9 #
EXPLAIN
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
diff --git a/mysql-test/main/subselect_sj2_jcl6.result b/mysql-test/main/subselect_sj2_jcl6.result
index 56c11e8c9af..ac2d12fc5df 100644
--- a/mysql-test/main/subselect_sj2_jcl6.result
+++ b/mysql-test/main/subselect_sj2_jcl6.result
@@ -171,9 +171,9 @@ explain select
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
from t1 ot where a in (select a from t2 it);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 22
-1 PRIMARY ot hash_ALL NULL #hash#$hj 5 test.it.a 32 Using where; Using join buffer (flat, BNLH join)
-2 MATERIALIZED it ALL NULL NULL NULL NULL 22 Using where
+1 PRIMARY ot ALL NULL NULL NULL NULL 32
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED it ALL NULL NULL NULL NULL 22
select
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
from t1 ot where a in (select a from t2 it);
@@ -239,9 +239,9 @@ explain select
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
from t1 ot where a in (select a from t2 it);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 22
-1 PRIMARY ot hash_ALL NULL #hash#$hj 5 test.it.a 52 Using where; Using join buffer (flat, BNLH join)
-2 MATERIALIZED it ALL NULL NULL NULL NULL 22 Using where
+1 PRIMARY ot ALL NULL NULL NULL NULL 52
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED it ALL NULL NULL NULL NULL 22
select
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
from t1 ot where a in (select a from t2 it);
@@ -826,6 +826,14 @@ CREATE TABLE t2 (f14 int(11) NOT NULL, f12 varchar(1) NOT NULL, KEY (f12,f14)) E
INSERT INTO t2 VALUES (6,'y');
CREATE TABLE t3 (f12 varchar(1) NOT NULL) ENGINE=InnoDB;
INSERT INTO t3 VALUES ('r'),('s'),('t'),('v'),('w'),('x'),('y');
+analyze table t1,t2,t3 persistent for all;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+test.t2 analyze status Engine-independent statistics collected
+test.t2 analyze status OK
+test.t3 analyze status Engine-independent statistics collected
+test.t3 analyze status OK
# The following must use LooseScan but not join buffering
explain
SELECT * FROM t3
@@ -1115,6 +1123,14 @@ INSERT INTO t2 VALUES
(9,'d','d'),(10,'s','s'),(11,'r','r'),(12,'m','m'),
(13,'b','b'),(14,'x','x'),(15,'g','g'),(16,'p','p'),
(17,'q','q'),(18,'w','w'),(19,'d','d');
+analyze table t1 persistent for all;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+analyze table t2 persistent for all;
+Table Op Msg_type Msg_text
+test.t2 analyze status Engine-independent statistics collected
+test.t2 analyze status OK
EXPLAIN
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
@@ -1123,11 +1139,11 @@ WHERE alias5.b = alias4.b
AND ( alias5.b >= alias3.b OR alias5.c != alias3.c )
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL #
-1 PRIMARY alias5 index PRIMARY c 4 NULL # Using where; Using index; Using join buffer (flat, BNL join)
-1 PRIMARY alias4 eq_ref PRIMARY,c PRIMARY 4 test.alias5.b # Using where; FirstMatch(alias3); Using join buffer (incremental, BKA join); Key-ordered scan
+1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL # Using where
+1 PRIMARY alias4 ref PRIMARY,c c 4 test.alias3.d # Using index
+1 PRIMARY alias5 eq_ref PRIMARY PRIMARY 4 test.alias4.b # Using where; FirstMatch(alias3)
+1 PRIMARY alias2 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (incremental, BNL join)
-1 PRIMARY alias2 ALL NULL NULL NULL NULL # Using join buffer (incremental, BNL join)
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
SELECT alias4.c FROM t2 AS alias4, t2 AS alias5
@@ -1144,11 +1160,11 @@ WHERE alias5.b = alias4.b
AND ( alias5.b >= alias3.b OR alias3.c != alias5.c )
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL #
-1 PRIMARY alias5 index PRIMARY c 4 NULL # Using where; Using index; Using join buffer (flat, BNL join)
-1 PRIMARY alias4 eq_ref PRIMARY,c PRIMARY 4 test.alias5.b # Using where; FirstMatch(alias3); Using join buffer (incremental, BKA join); Key-ordered scan
+1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL # Using where
+1 PRIMARY alias4 ref PRIMARY,c c 4 test.alias3.d # Using index
+1 PRIMARY alias5 eq_ref PRIMARY PRIMARY 4 test.alias4.b # Using where; FirstMatch(alias3)
+1 PRIMARY alias2 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (incremental, BNL join)
-1 PRIMARY alias2 ALL NULL NULL NULL NULL # Using join buffer (incremental, BNL join)
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
SELECT alias4.c FROM t2 AS alias4, t2 AS alias5
@@ -1410,9 +1426,10 @@ SELECT t3.* FROM t1 JOIN t3 ON t3.b = t1.b
WHERE c IN (SELECT t4.b FROM t4 JOIN t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 1 Using where
-1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using join buffer (flat, BNL join)
-1 PRIMARY t4 ALL NULL NULL NULL NULL 2 Using where; FirstMatch(t3); Using join buffer (incremental, BNL join)
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
1 PRIMARY t1 ref b b 4 test.t3.b 1 Using index
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 1
+2 MATERIALIZED t4 ALL NULL NULL NULL NULL 2 Using join buffer (flat, BNL join)
SELECT t3.* FROM t1 JOIN t3 ON t3.b = t1.b
WHERE c IN (SELECT t4.b FROM t4 JOIN t2);
b c
@@ -1438,9 +1455,10 @@ EXPLAIN
SELECT * FROM t1, t2 WHERE b IN (SELECT a FROM t3, t4 WHERE b = pk);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 1
-1 PRIMARY t4 ALL NULL NULL NULL NULL 1 Using where
-1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t4.b 1 Using where; FirstMatch(t2)
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using join buffer (flat, BNL join)
+2 MATERIALIZED t4 ALL NULL NULL NULL NULL 1 Using where
+2 MATERIALIZED t3 eq_ref PRIMARY PRIMARY 4 test.t4.b 1
SELECT * FROM t1, t2 WHERE b IN (SELECT a FROM t3, t4 WHERE b = pk);
pk a b
1 6 8
diff --git a/mysql-test/main/subselect_sj2_mat.result b/mysql-test/main/subselect_sj2_mat.result
index 73f682755da..e55025f4fa8 100644
--- a/mysql-test/main/subselect_sj2_mat.result
+++ b/mysql-test/main/subselect_sj2_mat.result
@@ -133,8 +133,9 @@ set join_buffer_size= @save_join_buffer_size;
set max_heap_table_size= @save_max_heap_table_size;
explain select * from t1 where a in (select b from t2);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
-1 PRIMARY t2 ref b b 5 test.t1.a 1 Using index; FirstMatch(t1)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED t2 index b b 5 NULL 20 Using index
select * from t1;
a b
1 1
@@ -161,8 +162,8 @@ explain select
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
from t1 ot where a in (select a from t2 it);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 22
-1 PRIMARY ot ALL NULL NULL NULL NULL 32 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY ot ALL NULL NULL NULL NULL 32
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED it ALL NULL NULL NULL NULL 22
select
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
@@ -229,8 +230,8 @@ explain select
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
from t1 ot where a in (select a from t2 it);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 22
-1 PRIMARY ot ALL NULL NULL NULL NULL 52 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY ot ALL NULL NULL NULL NULL 52
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED it ALL NULL NULL NULL NULL 22
select
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
@@ -732,8 +733,9 @@ alter table t3 add primary key(id), add key(a);
The following must use loose index scan over t3, key a:
explain select count(a) from t2 where a in ( SELECT a FROM t3);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t2 index a a 5 NULL 1000 Using where; Using index
-1 PRIMARY t3 ref a a 5 test.t2.a 30 Using index; FirstMatch(t2)
+1 PRIMARY t2 index a a 5 NULL 1000 Using index
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED t3 index a a 5 NULL 30000 Using index
select count(a) from t2 where a in ( SELECT a FROM t3);
count(a)
1000
@@ -759,9 +761,10 @@ c2 in (select 1 from t3, t2) and
c1 in (select convert(c6,char(1)) from t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where
-1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; FirstMatch(t2)
+1 PRIMARY <subquery3> eq_ref distinct_key distinct_key 4 func 1 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 1
-1 PRIMARY t3 ALL NULL NULL NULL NULL 2 FirstMatch(t2)
+1 PRIMARY t3 ALL NULL NULL NULL NULL 2 FirstMatch((sj-nest))
+3 MATERIALIZED t2 ALL NULL NULL NULL NULL 1
drop table t2, t3;
#
# BUG#761598: InnoDB: Error: row_search_for_mysql() is called without ha_innobase::external_lock() in maria-5.3
@@ -812,6 +815,14 @@ CREATE TABLE t2 (f14 int(11) NOT NULL, f12 varchar(1) NOT NULL, KEY (f12,f14)) E
INSERT INTO t2 VALUES (6,'y');
CREATE TABLE t3 (f12 varchar(1) NOT NULL) ENGINE=InnoDB;
INSERT INTO t3 VALUES ('r'),('s'),('t'),('v'),('w'),('x'),('y');
+analyze table t1,t2,t3 persistent for all;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+test.t2 analyze status Engine-independent statistics collected
+test.t2 analyze status OK
+test.t3 analyze status Engine-independent statistics collected
+test.t3 analyze status OK
# The following must use LooseScan but not join buffering
explain
SELECT * FROM t3
@@ -1101,6 +1112,14 @@ INSERT INTO t2 VALUES
(9,'d','d'),(10,'s','s'),(11,'r','r'),(12,'m','m'),
(13,'b','b'),(14,'x','x'),(15,'g','g'),(16,'p','p'),
(17,'q','q'),(18,'w','w'),(19,'d','d');
+analyze table t1 persistent for all;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+analyze table t2 persistent for all;
+Table Op Msg_type Msg_text
+test.t2 analyze status Engine-independent statistics collected
+test.t2 analyze status OK
EXPLAIN
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
@@ -1109,11 +1128,11 @@ WHERE alias5.b = alias4.b
AND ( alias5.b >= alias3.b OR alias5.c != alias3.c )
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL #
-1 PRIMARY alias5 index PRIMARY c 4 NULL # Using where; Using index
-1 PRIMARY alias4 eq_ref PRIMARY,c PRIMARY 4 test.alias5.b # Using where; FirstMatch(alias3)
-1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
+1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL # Using where
+1 PRIMARY alias4 ref PRIMARY,c c 4 test.alias3.d # Using index
+1 PRIMARY alias5 eq_ref PRIMARY PRIMARY 4 test.alias4.b # Using where; FirstMatch(alias3)
1 PRIMARY alias2 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
+1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
SELECT alias4.c FROM t2 AS alias4, t2 AS alias5
@@ -1130,11 +1149,11 @@ WHERE alias5.b = alias4.b
AND ( alias5.b >= alias3.b OR alias3.c != alias5.c )
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL #
-1 PRIMARY alias5 index PRIMARY c 4 NULL # Using where; Using index
-1 PRIMARY alias4 eq_ref PRIMARY,c PRIMARY 4 test.alias5.b # Using where; FirstMatch(alias3)
-1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
+1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL # Using where
+1 PRIMARY alias4 ref PRIMARY,c c 4 test.alias3.d # Using index
+1 PRIMARY alias5 eq_ref PRIMARY PRIMARY 4 test.alias4.b # Using where; FirstMatch(alias3)
1 PRIMARY alias2 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
+1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
SELECT alias4.c FROM t2 AS alias4, t2 AS alias5
@@ -1638,12 +1657,12 @@ set optimizer_switch='materialization=on,semijoin=on';
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE i1 IN (SELECT i3 FROM t2, t3 WHERE i3 = i2 OR 1=2);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3 100.00
-1 PRIMARY t1 hash_ALL NULL #hash#$hj 5 test.t2.i2 5 100.00 Using where; Using join buffer (flat, BNLH join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 100.00 Using where
2 MATERIALIZED t3 hash_ALL NULL #hash#$hj 5 test.t2.i2 3 100.00 Using where; Using join buffer (flat, BNLH join)
Warnings:
-Note 1003 select `test`.`t1`.`i1` AS `i1` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where `test`.`t3`.`i3` = `test`.`t2`.`i2` and `test`.`t1`.`i1` = `test`.`t2`.`i2`
+Note 1003 select `test`.`t1`.`i1` AS `i1` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where `test`.`t3`.`i3` = `test`.`t2`.`i2`
SELECT * FROM t1 WHERE i1 IN (SELECT i3 FROM t2, t3 WHERE i3 = i2 OR 1=2);
i1
7
@@ -1651,12 +1670,12 @@ EXPLAIN EXTENDED
SELECT * FROM t1
WHERE i1 IN (SELECT i3 FROM t2, t3 WHERE i3 > 0 AND i3 = i2 OR 1=2);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3 100.00
-1 PRIMARY t1 hash_ALL NULL #hash#$hj 5 test.t2.i2 5 100.00 Using where; Using join buffer (flat, BNLH join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 100.00 Using where
2 MATERIALIZED t3 hash_ALL NULL #hash#$hj 5 test.t2.i2 3 100.00 Using where; Using join buffer (flat, BNLH join)
Warnings:
-Note 1003 select `test`.`t1`.`i1` AS `i1` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where `test`.`t3`.`i3` = `test`.`t2`.`i2` and `test`.`t1`.`i1` = `test`.`t2`.`i2` and `test`.`t3`.`i3` > 0
+Note 1003 select `test`.`t1`.`i1` AS `i1` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where `test`.`t3`.`i3` = `test`.`t2`.`i2` and `test`.`t3`.`i3` > 0
SELECT * FROM t1
WHERE i1 IN (SELECT i3 FROM t2, t3 WHERE i3 > 0 AND i3 = i2 OR 1=2);
i1
@@ -1748,8 +1767,8 @@ OR
);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t index PRIMARY PRIMARY 4 NULL 13 Using where; Using index
-2 MATERIALIZED <subquery3> ALL distinct_key NULL NULL NULL 8
-2 MATERIALIZED A ALL PRIMARY NULL NULL NULL 13 Using where; Using join buffer (flat, BNL join)
+2 MATERIALIZED A ALL PRIMARY NULL NULL NULL 13
+2 MATERIALIZED <subquery3> eq_ref distinct_key distinct_key 67 func 1
3 MATERIALIZED B range PRIMARY PRIMARY 4 NULL 8 Using where
SELECT SQL_NO_CACHE t.id
FROM t1 t
@@ -1914,18 +1933,16 @@ AND t3.id_product IN (SELECT id_product FROM t2 t2_5 WHERE t2_5.id_t2 = 29 OR t2
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <subquery3> ALL distinct_key NULL NULL NULL 12
1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t2_2.id_product 1 Using where; Using index
-1 PRIMARY <subquery5> eq_ref distinct_key distinct_key 4 func 1 Using where
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 Using where
+1 PRIMARY t2_3 ref id_t2,id_product id_product 5 test.t3.id_product 44 Using index condition; Using where; Start temporary; End temporary
+1 PRIMARY t2_5 ref id_t2,id_product id_product 5 test.t3.id_product 44 Using index condition; Using where; Start temporary; End temporary
1 PRIMARY t5 ALL NULL NULL NULL NULL 18 Using where; Using join buffer (flat, BNL join)
-1 PRIMARY <subquery6> eq_ref distinct_key distinct_key 4 func 1 Using where
1 PRIMARY t4 eq_ref PRIMARY PRIMARY 8 test.t3.id_product,const 1 Using where; Using index
-1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 Using where
-1 PRIMARY <subquery4> eq_ref distinct_key distinct_key 4 func 1 Using where
+1 PRIMARY <subquery5> eq_ref distinct_key distinct_key 4 func 1 Using where
1 PRIMARY t1 index NULL PRIMARY 8 NULL 73 Using where; Using index; Using join buffer (flat, BNL join)
3 MATERIALIZED t2_2 ref id_t2,id_product id_t2 5 const 12 Using where
-5 MATERIALIZED t2_4 range id_t2,id_product id_t2 5 NULL 18 Using index condition; Using where
-6 MATERIALIZED t2_5 range id_t2,id_product id_t2 5 NULL 31 Using index condition; Using where
2 MATERIALIZED t2_1 ref id_t2,id_product id_t2 5 const 51
-4 MATERIALIZED t2_3 range id_t2,id_product id_t2 5 NULL 33 Using index condition; Using where
+5 MATERIALIZED t2_4 range id_t2,id_product id_t2 5 NULL 18 Using index condition; Using where
set optimizer_switch='rowid_filter=default';
drop table t1,t2,t3,t4,t5;
set global innodb_stats_persistent= @innodb_stats_persistent_save;
diff --git a/mysql-test/main/subselect_sj_jcl6.result b/mysql-test/main/subselect_sj_jcl6.result
index acfafde6d7e..91892156e76 100644
--- a/mysql-test/main/subselect_sj_jcl6.result
+++ b/mysql-test/main/subselect_sj_jcl6.result
@@ -742,8 +742,8 @@ SELECT int_key FROM ot1
WHERE int_nokey IN (SELECT it2.int_key
FROM it1 LEFT JOIN it2 ON it2.datetime_key);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 10
-1 PRIMARY ot1 ALL NULL NULL NULL NULL 20 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY ot1 ALL NULL NULL NULL NULL 20
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED it1 index NULL int_key 4 NULL 2 Using index
2 MATERIALIZED it2 ALL int_key,datetime_key NULL NULL NULL 20 Using where; Using join buffer (flat, BNL join)
DROP TABLE ot1, it1, it2;
@@ -985,11 +985,11 @@ SELECT `varchar_key` , `varchar_nokey`
FROM t1
WHERE `varchar_nokey` < 'n' XOR `pk` ) ;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 15 100.00
-1 PRIMARY t2 ALL NULL NULL NULL NULL 18 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t2 ALL NULL NULL NULL NULL 18 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 func,func 1 100.00
2 MATERIALIZED t1 ALL varchar_key NULL NULL NULL 15 100.00 Using where
Warnings:
-Note 1003 select `test`.`t2`.`varchar_nokey` AS `varchar_nokey` from `test`.`t2` semi join (`test`.`t1`) where `test`.`t1`.`varchar_nokey` = `test`.`t1`.`varchar_key` and `test`.`t2`.`varchar_nokey` = `test`.`t1`.`varchar_key` and (`test`.`t1`.`varchar_key` < 'n' xor `test`.`t1`.`pk`)
+Note 1003 select `test`.`t2`.`varchar_nokey` AS `varchar_nokey` from `test`.`t2` semi join (`test`.`t1`) where `test`.`t1`.`varchar_nokey` = `test`.`t1`.`varchar_key` and (`test`.`t1`.`varchar_key` < 'n' xor `test`.`t1`.`pk`)
SELECT varchar_nokey
FROM t2
WHERE ( `varchar_nokey` , `varchar_nokey` ) IN (
@@ -1259,8 +1259,8 @@ INSERT INTO t2 VALUES (1, 0), (1, 1), (2, 0), (2, 1);
EXPLAIN
SELECT * FROM t1 WHERE (i) IN (SELECT i FROM t2 where j > 0);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t2 index k k 10 NULL 4 Using where; Using index; LooseScan
-1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t2 index k k 10 NULL 4 Using where; Using index; Start temporary
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Using where; End temporary; Using join buffer (flat, BNL join)
SELECT * FROM t1 WHERE (i) IN (SELECT i FROM t2 where j > 0);
i
1
@@ -1770,8 +1770,8 @@ insert into t3 values('three'),( 'four');
insert into t3 values('three'),( 'four');
explain select * from t3 where t3.b in (select t2.b from t1 left join t2 on t1.a=t2.a);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2
-1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t3 ALL NULL NULL NULL NULL 8
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 10 func 1
2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join)
select * from t3 where t3.b in (select t2.b from t1 left join t2 on t1.a=t2.a);
@@ -2509,8 +2509,8 @@ WHERE t1.a = t2.a AND t2.a IN (SELECT b FROM t3 STRAIGHT_JOIN t4);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 system NULL NULL NULL NULL 1
1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 1
-1 PRIMARY t1 ref a a 5 const 1 Using index
-1 PRIMARY t2 ref a a 5 func 1 Using index
+1 PRIMARY t2 ref a a 5 const 1 Using index
+1 PRIMARY t1 ref a a 5 func 1 Using index
2 MATERIALIZED t4 ALL NULL NULL NULL NULL 0
SELECT * FROM t1, t2
WHERE t1.a = t2.a AND t2.a IN (SELECT b FROM t3 STRAIGHT_JOIN t4);
@@ -2720,8 +2720,8 @@ a
19
explain select * from t3 where a in (select kp1 from t1 where kp1<20);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 range kp1 kp1 5 NULL 48 Using where; Using index; LooseScan
-1 PRIMARY t3 ALL NULL NULL NULL NULL 100 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t3 ALL NULL NULL NULL NULL 100 Using where
+1 PRIMARY t1 ref kp1 kp1 5 test.t3.a 1 Using index; FirstMatch(t3)
drop table t0,t1,t3;
set optimizer_switch= @tmp_923246;
#
@@ -2937,8 +2937,8 @@ WHERE alias1.pk = 58 OR alias1.col_varchar_key = 'o'
);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2
-1 PRIMARY alias1 index_merge PRIMARY,col_int_key,col_varchar_key PRIMARY,col_varchar_key 4,4 NULL 2 Using sort_union(PRIMARY,col_varchar_key); Using where
-1 PRIMARY alias2 ALL col_int_key NULL NULL NULL 12 Range checked for each record (index map: 0x2); FirstMatch(t2)
+1 PRIMARY alias1 index_merge PRIMARY,col_int_key,col_varchar_key PRIMARY,col_varchar_key 4,4 NULL 2 Using sort_union(PRIMARY,col_varchar_key); Using where; Start temporary; Using join buffer (flat, BNL join)
+1 PRIMARY alias2 ALL col_int_key NULL NULL NULL 12 Range checked for each record (index map: 0x2); End temporary
SELECT *
FROM t2
WHERE (field1) IN (SELECT alias1.col_varchar_nokey AS field1
@@ -3278,6 +3278,29 @@ create table t2 (a2 varchar(25)) ;
insert into t1 select 'xxx' from dual where 'xxx' in (select a2 from t2);
drop table t1,t2;
# End of 5.5 test
+#
+# MDEV-20109: Optimizer ignores distinct key created for materialized
+# semi-join subquery when searching for best execution plan
+#
+create table t1(a int);
+insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t2(a int);
+insert into t2 select A.a + B.a* 10 + C.a * 100 from t1 A, t1 B, t1 C;
+create table t3 (a int);
+create table t4 (a int);
+insert into t3 select A.a +1000*B.a from t2 A, t1 B;
+insert into t4 select floor(rand()*1000) from t2 limit 500;
+# The following must not use this query plan that does a cross join:
+# | 1 | PRIMARY | <subquery2> | ALL | distinct_key | ... | 500 | |
+# | 1 | PRIMARY | t3 | ALL | NULL | ... | 10000 | Using where; Using join buffer (flat, BNL join) |
+#
+# Instead, it should use eq_ref on the materialized table.
+explain select * from t3 where a in (select a from t4);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t3 ALL NULL NULL NULL NULL 10000
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+2 MATERIALIZED t4 ALL NULL NULL NULL NULL 500
+drop table t1, t2, t3, t4;
set optimizer_switch=@subselect_sj_tmp;
#
# BUG#49129: Wrong result with IN-subquery with join_cache_level=6 and firstmatch=off
@@ -3485,8 +3508,8 @@ EXPLAIN
SELECT a FROM t1 t WHERE a IN (SELECT b FROM t1, t2 WHERE b = a)
GROUP BY a HAVING a != 'z';
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t range idx_a idx_a 4 NULL 3 Using where; Using index
-1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2 Using temporary; Using filesort
+1 PRIMARY t ref idx_a idx_a 4 test.t2.b 2 Using index
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using where
2 MATERIALIZED t1 ref idx_a idx_a 4 test.t2.b 2 Using index
SELECT a FROM t1 t WHERE a IN (SELECT b FROM t1, t2 WHERE b = a)
@@ -3499,8 +3522,8 @@ EXPLAIN
SELECT a FROM t1 t WHERE a IN (SELECT b FROM t1, t2 WHERE b = a)
GROUP BY a HAVING a != 'z';
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t range idx_a idx_a 4 NULL 3 Using where; Using index
-1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
+1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2 Using temporary; Using filesort
+1 PRIMARY t ref idx_a idx_a 4 test.t2.b 2 Using index
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using where
2 MATERIALIZED t1 ref idx_a idx_a 4 test.t2.b 2 Using index
SELECT a FROM t1 t WHERE a IN (SELECT b FROM t1, t2 WHERE b = a)
diff --git a/mysql-test/main/subselect_sj_mat.result b/mysql-test/main/subselect_sj_mat.result
index 203dbee6374..432f6c648fc 100644
--- a/mysql-test/main/subselect_sj_mat.result
+++ b/mysql-test/main/subselect_sj_mat.result
@@ -491,15 +491,15 @@ where (c1, c2) in (select b1, b2 from t2i where b2 > '0')) and
a1 = c1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where
-1 PRIMARY <subquery4> ALL distinct_key NULL NULL NULL 4 100.00 Using where
1 PRIMARY t3 ALL NULL NULL NULL NULL 4 99.22 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY <subquery4> eq_ref distinct_key distinct_key 16 func,func 1 100.00
4 MATERIALIZED t3 ALL NULL NULL NULL NULL 4 99.22 Using where
4 MATERIALIZED t2i ref it2i1,it2i2,it2i3 it2i3 18 test.t3.c1,test.t3.c2 1 100.00 Using index
2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 99.22 Using where
3 DEPENDENT UNION t2 ALL NULL NULL NULL NULL 5 99.22 Using where
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL NULL
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2`,`test`.`t3`.`c1` AS `c1`,`test`.`t3`.`c2` AS `c2` from `test`.`t1` semi join (`test`.`t2i` join `test`.`t3`) join `test`.`t3` where `test`.`t3`.`c1` = `test`.`t1`.`a1` and `test`.`t2i`.`b1` = `test`.`t3`.`c1` and `test`.`t3`.`c1` = `test`.`t1`.`a1` and `test`.`t2i`.`b2` = `test`.`t3`.`c2` and `test`.`t3`.`c2` = `test`.`t3`.`c2` and <expr_cache><`test`.`t1`.`a1`,`test`.`t1`.`a2`>(<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(/* select#2 */ select `test`.`t1`.`a1`,`test`.`t1`.`a2` from `test`.`t1` where `test`.`t1`.`a1` > '0' and <cache>(`test`.`t1`.`a1`) = `test`.`t1`.`a1` and <cache>(`test`.`t1`.`a2`) = `test`.`t1`.`a2` union /* select#3 */ select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where `test`.`t2`.`b1` < '9' and <cache>(`test`.`t1`.`a1`) = `test`.`t2`.`b1` and <cache>(`test`.`t1`.`a2`) = `test`.`t2`.`b2`))) and `test`.`t3`.`c2` > '0'
+Note 1003 /* select#1 */ select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2`,`test`.`t3`.`c1` AS `c1`,`test`.`t3`.`c2` AS `c2` from `test`.`t1` semi join (`test`.`t2i` join `test`.`t3`) join `test`.`t3` where `test`.`t3`.`c1` = `test`.`t1`.`a1` and `test`.`t2i`.`b1` = `test`.`t3`.`c1` and `test`.`t2i`.`b2` = `test`.`t3`.`c2` and <expr_cache><`test`.`t1`.`a1`,`test`.`t1`.`a2`>(<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(/* select#2 */ select `test`.`t1`.`a1`,`test`.`t1`.`a2` from `test`.`t1` where `test`.`t1`.`a1` > '0' and <cache>(`test`.`t1`.`a1`) = `test`.`t1`.`a1` and <cache>(`test`.`t1`.`a2`) = `test`.`t1`.`a2` union /* select#3 */ select `test`.`t2`.`b1`,`test`.`t2`.`b2` from `test`.`t2` where `test`.`t2`.`b1` < '9' and <cache>(`test`.`t1`.`a1`) = `test`.`t2`.`b1` and <cache>(`test`.`t1`.`a2`) = `test`.`t2`.`b2`))) and `test`.`t3`.`c2` > '0'
select * from t1, t3
where (a1, a2) in (select * from t1 where a1 > '0' UNION select * from t2 where b1 < '9') and
(c1, c2) in (select c1, c2 from t3
@@ -1132,11 +1132,11 @@ insert into t3 values (30);
explain extended
select a from t1 where a in (select c from t2 where d >= 20);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 6 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 6 100.00 Using where
Warnings:
-Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where `test`.`t1`.`a` = `test`.`t2`.`c` and `test`.`t2`.`d` >= 20
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where `test`.`t2`.`d` >= 20
select a from t1 where a in (select c from t2 where d >= 20);
a
2
@@ -1543,8 +1543,8 @@ set @@optimizer_switch=@optimizer_switch_local_default;
SET @@optimizer_switch='semijoin=on,materialization=on';
EXPLAIN SELECT COUNT(*) FROM t1 WHERE (f1,f2) IN (SELECT f1,f2 FROM t2);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2
-1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 7 func,func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2
SELECT COUNT(*) FROM t1 WHERE (f1,f2) IN (SELECT f1,f2 FROM t2);
COUNT(*)
@@ -2473,8 +2473,8 @@ INSERT INTO t2 VALUES (11,11),(12,12),(13,13);
explain
SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 hash_ALL NULL #hash#$hj 4 test.t2.i1 9 Using where; Using join buffer (flat, BNLH join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 9
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where
SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2);
1
@@ -2486,8 +2486,8 @@ alter table t1 add key(id);
explain
SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ref id id 4 test.t2.i1 2 Using index
+1 PRIMARY t1 index id id 4 NULL 9 Using index
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where
SELECT 1 FROM t1 where t1.id IN (SELECT t2.i1 FROM t2 WHERE t2.i1 = t2.i2);
1
@@ -2543,8 +2543,8 @@ INSERT INTO t2 VALUES (11,11),(12,12),(13,13);
CREATE VIEW v1 AS SELECT t2.i1 FROM t2 where t2.i1 = t2.i2;
explain SELECT 1 FROM t1 where t1.id IN (SELECT v1.i1 from v1);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 3
-1 PRIMARY t1 ref id id 4 test.t2.i1 2 Using index
+1 PRIMARY t1 index id id 4 NULL 9 Using index
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where
SELECT 1 FROM t1 where t1.id IN (SELECT v1.i1 from v1);
1
diff --git a/mysql-test/main/table_value_constr.result b/mysql-test/main/table_value_constr.result
index 7fe7000c95d..1518cee174e 100644
--- a/mysql-test/main/table_value_constr.result
+++ b/mysql-test/main/table_value_constr.result
@@ -743,21 +743,21 @@ a b
explain extended select * from t1
where a in (values (1));
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery3> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery3> eq_ref distinct_key distinct_key 4 func 1 100.00
3 MATERIALIZED <derived2> ALL NULL NULL NULL NULL 2 100.00
2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1)) `tvc_0`) where `test`.`t1`.`a` = `tvc_0`.`1`
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1)) `tvc_0`) where 1
explain extended select * from t1
where a in (select * from (values (1)) as tvc_0);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 2 100.00
3 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1)) `tvc_0`) where `test`.`t1`.`a` = `tvc_0`.`1`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1)) `tvc_0`) where 1
# IN-subquery with VALUES structure(s) : UNION with VALUES on the first place
select * from t1
where a in (values (1) union select 2);
@@ -978,21 +978,21 @@ a b
explain extended select * from t1
where a = any (values (1),(2));
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery3> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery3> eq_ref distinct_key distinct_key 4 func 1 100.00
3 MATERIALIZED <derived2> ALL NULL NULL NULL NULL 2 100.00
2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where `test`.`t1`.`a` = `tvc_0`.`1`
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where 1
explain extended select * from t1
where a = any (select * from (values (1),(2)) as tvc_0);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 2 100.00
3 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where `test`.`t1`.`a` = `tvc_0`.`1`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where 1
# ANY-subquery with VALUES structure(s) : UNION with VALUES on the first place
select * from t1
where a = any (values (1) union select 2);
diff --git a/mysql-test/main/timezone2.result b/mysql-test/main/timezone2.result
index cf3c6e01e25..b858e761a81 100644
--- a/mysql-test/main/timezone2.result
+++ b/mysql-test/main/timezone2.result
@@ -588,5 +588,53 @@ ts cts uts ucts
DROP TABLE t1,t2;
SET time_zone=DEFAULT;
#
+# MDEV-19961 MIN(timestamp_column) returns a wrong result in a GROUP BY query
+#
+SET time_zone='Europe/Moscow';
+CREATE OR REPLACE TABLE t1 (i INT, d TIMESTAMP);
+SET timestamp=1288477526 /* this is summer time */ ;
+INSERT INTO t1 VALUES (3,NULL);
+SET timestamp=1288477526+3599 /* this is winter time*/ ;
+INSERT INTO t1 VALUES (3,NULL);
+SELECT i, d, UNIX_TIMESTAMP(d) FROM t1 ORDER BY d;
+i d UNIX_TIMESTAMP(d)
+3 2010-10-31 02:25:26 1288477526
+3 2010-10-31 02:25:25 1288481125
+SELECT i, MIN(d) FROM t1 GROUP BY i;
+i MIN(d)
+3 2010-10-31 02:25:26
+SELECT i, MAX(d) FROM t1 GROUP BY i;
+i MAX(d)
+3 2010-10-31 02:25:25
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+SET time_zone=DEFAULT;
+#
+# MDEV-20397 Support TIMESTAMP, DATETIME, TIME in ROUND() and TRUNCATE()
+#
+SET time_zone='Europe/Moscow';
+CREATE TABLE t1 (i INT, d TIMESTAMP(6));
+SET timestamp=1288479599.999999 /* this is the last second in summer time */ ;
+INSERT INTO t1 VALUES (1,NULL);
+SET timestamp=1288479600.000000 /* this is the first second in winter time */ ;
+INSERT INTO t1 VALUES (2,NULL);
+SELECT i, d, UNIX_TIMESTAMP(d) FROM t1 ORDER BY d;
+i d UNIX_TIMESTAMP(d)
+1 2010-10-31 02:59:59.999999 1288479599.999999
+2 2010-10-31 02:00:00.000000 1288479600.000000
+CREATE TABLE t2 (i INT, d TIMESTAMP, expected_unix_timestamp INT UNSIGNED);
+INSERT INTO t2 SELECT i, ROUND(d) AS d, ROUND(UNIX_TIMESTAMP(d)) FROM t1;
+# UNIX_TIMESTAMP(d) and expected_unix_timestamp should return the same value.
+# Currently they do not, because ROUND(timestamp) is performed as DATETIME.
+# We should fix this eventually.
+SELECT i, d, UNIX_TIMESTAMP(d), expected_unix_timestamp FROM t2 ORDER BY i;
+i d UNIX_TIMESTAMP(d) expected_unix_timestamp
+1 2010-10-31 03:00:00 1288483200 1288479600
+2 2010-10-31 02:00:00 1288476000 1288479600
+DROP TABLE t2;
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+SET time_zone=DEFAULT;
+#
# End of 10.4 tests
#
diff --git a/mysql-test/main/timezone2.test b/mysql-test/main/timezone2.test
index e945923da7a..9d364224311 100644
--- a/mysql-test/main/timezone2.test
+++ b/mysql-test/main/timezone2.test
@@ -535,5 +535,49 @@ DROP TABLE t1,t2;
SET time_zone=DEFAULT;
--echo #
+--echo # MDEV-19961 MIN(timestamp_column) returns a wrong result in a GROUP BY query
+--echo #
+
+SET time_zone='Europe/Moscow';
+CREATE OR REPLACE TABLE t1 (i INT, d TIMESTAMP);
+SET timestamp=1288477526 /* this is summer time */ ;
+INSERT INTO t1 VALUES (3,NULL);
+SET timestamp=1288477526+3599 /* this is winter time*/ ;
+INSERT INTO t1 VALUES (3,NULL);
+SELECT i, d, UNIX_TIMESTAMP(d) FROM t1 ORDER BY d;
+SELECT i, MIN(d) FROM t1 GROUP BY i;
+SELECT i, MAX(d) FROM t1 GROUP BY i;
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+SET time_zone=DEFAULT;
+
+--echo #
+--echo # MDEV-20397 Support TIMESTAMP, DATETIME, TIME in ROUND() and TRUNCATE()
+--echo #
+
+SET time_zone='Europe/Moscow';
+CREATE TABLE t1 (i INT, d TIMESTAMP(6));
+SET timestamp=1288479599.999999 /* this is the last second in summer time */ ;
+INSERT INTO t1 VALUES (1,NULL);
+SET timestamp=1288479600.000000 /* this is the first second in winter time */ ;
+INSERT INTO t1 VALUES (2,NULL);
+SELECT i, d, UNIX_TIMESTAMP(d) FROM t1 ORDER BY d;
+
+CREATE TABLE t2 (i INT, d TIMESTAMP, expected_unix_timestamp INT UNSIGNED);
+INSERT INTO t2 SELECT i, ROUND(d) AS d, ROUND(UNIX_TIMESTAMP(d)) FROM t1;
+
+--echo # UNIX_TIMESTAMP(d) and expected_unix_timestamp should return the same value.
+--echo # Currently they do not, because ROUND(timestamp) is performed as DATETIME.
+--echo # We should fix this eventually.
+
+SELECT i, d, UNIX_TIMESTAMP(d), expected_unix_timestamp FROM t2 ORDER BY i;
+DROP TABLE t2;
+
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+SET time_zone=DEFAULT;
+
+
+--echo #
--echo # End of 10.4 tests
--echo #
diff --git a/mysql-test/main/type_date.result b/mysql-test/main/type_date.result
index a9d17b8eb83..fbf348c1a2f 100644
--- a/mysql-test/main/type_date.result
+++ b/mysql-test/main/type_date.result
@@ -890,6 +890,37 @@ DROP TABLE t2;
DROP VIEW v1;
DROP TABLE t1;
#
+# MDEV-19699 Server crashes in Item_null_result::field_type upon SELECT with ROLLUP on constant table
+#
+CREATE TABLE t1 (d DATE) ENGINE=MyISAM;
+INSERT INTO t1 VALUES ('1999-11-04');
+SELECT d FROM t1 GROUP BY d WITH ROLLUP HAVING d > '1990-01-01';
+d
+1999-11-04
+DROP TABLE t1;
+#
+# MDEV-20431 GREATEST(int_col,date_col) returns wrong results in a view
+#
+CREATE TABLE t1 (pk INT NOT NULL, d DATE NOT NULL);
+CREATE VIEW v1 AS SELECT * FROM t1;
+INSERT INTO t1 VALUES (1,'2018-06-22'),(2,'2018-07-11');
+SELECT GREATEST(pk, d) FROM t1;
+GREATEST(pk, d)
+2018-06-22
+2018-07-11
+Warnings:
+Warning 1292 Incorrect datetime value: '1' for column `test`.`t1`.`pk` at row 1
+Warning 1292 Incorrect datetime value: '2' for column `test`.`t1`.`pk` at row 2
+SELECT GREATEST(pk, d) FROM v1;
+GREATEST(pk, d)
+2018-06-22
+2018-07-11
+Warnings:
+Warning 1292 Incorrect datetime value: '1' for column `test`.`t1`.`pk` at row 1
+Warning 1292 Incorrect datetime value: '2' for column `test`.`t1`.`pk` at row 2
+DROP VIEW v1;
+DROP TABLE t1;
+#
# End of 10.1 tests
#
#
diff --git a/mysql-test/main/type_date.test b/mysql-test/main/type_date.test
index d795a01fd36..bd874ec51fb 100644
--- a/mysql-test/main/type_date.test
+++ b/mysql-test/main/type_date.test
@@ -606,6 +606,30 @@ DROP TABLE t2;
DROP VIEW v1;
DROP TABLE t1;
+
+--echo #
+--echo # MDEV-19699 Server crashes in Item_null_result::field_type upon SELECT with ROLLUP on constant table
+--echo #
+
+CREATE TABLE t1 (d DATE) ENGINE=MyISAM;
+INSERT INTO t1 VALUES ('1999-11-04');
+SELECT d FROM t1 GROUP BY d WITH ROLLUP HAVING d > '1990-01-01';
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-20431 GREATEST(int_col,date_col) returns wrong results in a view
+--echo #
+
+CREATE TABLE t1 (pk INT NOT NULL, d DATE NOT NULL);
+CREATE VIEW v1 AS SELECT * FROM t1;
+INSERT INTO t1 VALUES (1,'2018-06-22'),(2,'2018-07-11');
+SELECT GREATEST(pk, d) FROM t1;
+SELECT GREATEST(pk, d) FROM v1;
+DROP VIEW v1;
+DROP TABLE t1;
+
+
--echo #
--echo # End of 10.1 tests
--echo #
diff --git a/mysql-test/main/type_datetime.result b/mysql-test/main/type_datetime.result
index 0c33ddc3df1..5afb0257757 100644
--- a/mysql-test/main/type_datetime.result
+++ b/mysql-test/main/type_datetime.result
@@ -1156,6 +1156,48 @@ ExtractValue('foo','bar') i MIN(d)
3 1976-12-14 13:21:07
DROP TABLE t1;
#
+# MDEV-19034 ASAN unknown-crash in get_date_time_separator with PAD_CHAR_TO_FULL_LENGTH
+#
+SET SQL_MODE=DEFAULT;
+CREATE OR REPLACE TABLE t1 (a CHAR(11));
+CREATE OR REPLACE TABLE t2 (b DATETIME);
+INSERT INTO t1 VALUES ('2010-02-19') ;
+SET SQL_MODE= 'PAD_CHAR_TO_FULL_LENGTH';
+INSERT INTO t2 SELECT * FROM t1;
+DROP TABLE t1, t2;
+SET SQL_MODE=DEFAULT;
+#
+# MDEV-19699 Server crashes in Item_null_result::field_type upon SELECT with ROLLUP on constant table
+#
+CREATE TABLE t1 (d DATETIME) ENGINE=MyISAM;
+INSERT INTO t1 VALUES ('1999-11-04');
+SELECT d FROM t1 GROUP BY d WITH ROLLUP HAVING d > '1990-01-01';
+d
+1999-11-04 00:00:00
+DROP TABLE t1;
+#
+# MDEV-20431 GREATEST(int_col,date_col) returns wrong results in a view
+#
+CREATE TABLE t1 (pk INT NOT NULL, d DATETIME NOT NULL);
+CREATE VIEW v1 AS SELECT * FROM t1;
+INSERT INTO t1 VALUES (1,'2018-06-22 00:00:00'),(2,'2018-07-11 00:00:00');
+SELECT GREATEST(pk, d) FROM t1;
+GREATEST(pk, d)
+2018-06-22 00:00:00
+2018-07-11 00:00:00
+Warnings:
+Warning 1292 Incorrect datetime value: '1' for column `test`.`t1`.`pk` at row 1
+Warning 1292 Incorrect datetime value: '2' for column `test`.`t1`.`pk` at row 2
+SELECT GREATEST(pk, d) FROM v1;
+GREATEST(pk, d)
+2018-06-22 00:00:00
+2018-07-11 00:00:00
+Warnings:
+Warning 1292 Incorrect datetime value: '1' for column `test`.`t1`.`pk` at row 1
+Warning 1292 Incorrect datetime value: '2' for column `test`.`t1`.`pk` at row 2
+DROP VIEW v1;
+DROP TABLE t1;
+#
# End of 10.1 tests
#
#
diff --git a/mysql-test/main/type_datetime.test b/mysql-test/main/type_datetime.test
index cecdda593d0..b4b5fe95bbf 100644
--- a/mysql-test/main/type_datetime.test
+++ b/mysql-test/main/type_datetime.test
@@ -711,6 +711,43 @@ SELECT ExtractValue('foo','bar'), i, MIN(d) FROM t1 GROUP BY i;
DROP TABLE t1;
--echo #
+--echo # MDEV-19034 ASAN unknown-crash in get_date_time_separator with PAD_CHAR_TO_FULL_LENGTH
+--echo #
+
+SET SQL_MODE=DEFAULT;
+CREATE OR REPLACE TABLE t1 (a CHAR(11));
+CREATE OR REPLACE TABLE t2 (b DATETIME);
+INSERT INTO t1 VALUES ('2010-02-19') ;
+SET SQL_MODE= 'PAD_CHAR_TO_FULL_LENGTH';
+INSERT INTO t2 SELECT * FROM t1;
+DROP TABLE t1, t2;
+SET SQL_MODE=DEFAULT;
+
+
+--echo #
+--echo # MDEV-19699 Server crashes in Item_null_result::field_type upon SELECT with ROLLUP on constant table
+--echo #
+
+CREATE TABLE t1 (d DATETIME) ENGINE=MyISAM;
+INSERT INTO t1 VALUES ('1999-11-04');
+SELECT d FROM t1 GROUP BY d WITH ROLLUP HAVING d > '1990-01-01';
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-20431 GREATEST(int_col,date_col) returns wrong results in a view
+--echo #
+
+CREATE TABLE t1 (pk INT NOT NULL, d DATETIME NOT NULL);
+CREATE VIEW v1 AS SELECT * FROM t1;
+INSERT INTO t1 VALUES (1,'2018-06-22 00:00:00'),(2,'2018-07-11 00:00:00');
+SELECT GREATEST(pk, d) FROM t1;
+SELECT GREATEST(pk, d) FROM v1;
+DROP VIEW v1;
+DROP TABLE t1;
+
+
+--echo #
--echo # End of 10.1 tests
--echo #
diff --git a/mysql-test/main/type_datetime_hires.result b/mysql-test/main/type_datetime_hires.result
index 38e2c2a5ac8..ebb9c6032b9 100644
--- a/mysql-test/main/type_datetime_hires.result
+++ b/mysql-test/main/type_datetime_hires.result
@@ -17,8 +17,8 @@ a
2010-12-11 01:02:03.456
2010-12-11 03:04:05.789
2010-12-11 15:47:11.123
-select truncate(a, 6) from t1;
-truncate(a, 6)
+select cast(a AS double(30,6)) from t1;
+cast(a AS double(30,6))
0.000000
20101211002003.120000
20101211010203.457031
@@ -352,3 +352,542 @@ NULL
978307200.0000
DROP TABLE t1;
SET @@time_zone=DEFAULT;
+#
+# Start of 10.4 tests
+#
+#
+# MDEV-20397 Support TIMESTAMP, DATETIME, TIME in ROUND() and TRUNCATE()
+#
+CREATE TABLE t1 (a1 DATETIME(6), a2 DATETIME(6) NOT NULL);
+CREATE TABLE t2 AS SELECT
+ROUND(a1) AS r1,
+ROUND(a2) AS r2,
+TRUNCATE(a1,0) AS t1,
+TRUNCATE(a2,0) AS t2
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `r1` datetime DEFAULT NULL,
+ `r2` datetime DEFAULT NULL,
+ `t1` datetime DEFAULT NULL,
+ `t2` datetime NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a DATETIME(6));
+INSERT INTO t1 VALUES
+('0000-00-00 00:00:00.999999'),
+('0000-00-00 23:59:59.999999'),
+('0000-00-01 00:00:00.999999'),
+('0000-00-01 23:59:59.999999'),
+('0000-00-31 23:59:59.999999'),
+('0000-01-01 00:00:00.999999'),
+('0000-01-01 23:59:59.999999'),
+('0000-01-31 23:59:59.999999'),
+('0000-02-28 23:59:59.999999'),
+('0000-12-31 23:59:59.999999'),
+('0001-01-01 00:00:00.999999'),
+('0001-02-28 23:59:59.999999'),
+('0001-12-31 23:59:59.999999'),
+('0004-02-28 23:59:59.999999'),
+('0004-02-29 23:59:59.999999'),
+('2000-02-29 23:59:59.999999'),
+('2000-12-31 23:59:59.999999'),
+('9999-12-31 23:59:59.999999');
+SELECT a, TRUNCATE(a,0) FROM t1;
+a TRUNCATE(a,0)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:00
+0000-00-00 23:59:59.999999 0000-00-00 23:59:59
+0000-00-01 00:00:00.999999 0000-00-01 00:00:00
+0000-00-01 23:59:59.999999 0000-00-01 23:59:59
+0000-00-31 23:59:59.999999 0000-00-31 23:59:59
+0000-01-01 00:00:00.999999 0000-01-01 00:00:00
+0000-01-01 23:59:59.999999 0000-01-01 23:59:59
+0000-01-31 23:59:59.999999 0000-01-31 23:59:59
+0000-02-28 23:59:59.999999 0000-02-28 23:59:59
+0000-12-31 23:59:59.999999 0000-12-31 23:59:59
+0001-01-01 00:00:00.999999 0001-01-01 00:00:00
+0001-02-28 23:59:59.999999 0001-02-28 23:59:59
+0001-12-31 23:59:59.999999 0001-12-31 23:59:59
+0004-02-28 23:59:59.999999 0004-02-28 23:59:59
+0004-02-29 23:59:59.999999 0004-02-29 23:59:59
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59
+SELECT a, TRUNCATE(a,1) FROM t1;
+a TRUNCATE(a,1)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:00.9
+0000-00-00 23:59:59.999999 0000-00-00 23:59:59.9
+0000-00-01 00:00:00.999999 0000-00-01 00:00:00.9
+0000-00-01 23:59:59.999999 0000-00-01 23:59:59.9
+0000-00-31 23:59:59.999999 0000-00-31 23:59:59.9
+0000-01-01 00:00:00.999999 0000-01-01 00:00:00.9
+0000-01-01 23:59:59.999999 0000-01-01 23:59:59.9
+0000-01-31 23:59:59.999999 0000-01-31 23:59:59.9
+0000-02-28 23:59:59.999999 0000-02-28 23:59:59.9
+0000-12-31 23:59:59.999999 0000-12-31 23:59:59.9
+0001-01-01 00:00:00.999999 0001-01-01 00:00:00.9
+0001-02-28 23:59:59.999999 0001-02-28 23:59:59.9
+0001-12-31 23:59:59.999999 0001-12-31 23:59:59.9
+0004-02-28 23:59:59.999999 0004-02-28 23:59:59.9
+0004-02-29 23:59:59.999999 0004-02-29 23:59:59.9
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.9
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.9
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59.9
+SELECT a, TRUNCATE(a,2) FROM t1;
+a TRUNCATE(a,2)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:00.99
+0000-00-00 23:59:59.999999 0000-00-00 23:59:59.99
+0000-00-01 00:00:00.999999 0000-00-01 00:00:00.99
+0000-00-01 23:59:59.999999 0000-00-01 23:59:59.99
+0000-00-31 23:59:59.999999 0000-00-31 23:59:59.99
+0000-01-01 00:00:00.999999 0000-01-01 00:00:00.99
+0000-01-01 23:59:59.999999 0000-01-01 23:59:59.99
+0000-01-31 23:59:59.999999 0000-01-31 23:59:59.99
+0000-02-28 23:59:59.999999 0000-02-28 23:59:59.99
+0000-12-31 23:59:59.999999 0000-12-31 23:59:59.99
+0001-01-01 00:00:00.999999 0001-01-01 00:00:00.99
+0001-02-28 23:59:59.999999 0001-02-28 23:59:59.99
+0001-12-31 23:59:59.999999 0001-12-31 23:59:59.99
+0004-02-28 23:59:59.999999 0004-02-28 23:59:59.99
+0004-02-29 23:59:59.999999 0004-02-29 23:59:59.99
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.99
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.99
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59.99
+SELECT a, TRUNCATE(a,3) FROM t1;
+a TRUNCATE(a,3)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:00.999
+0000-00-00 23:59:59.999999 0000-00-00 23:59:59.999
+0000-00-01 00:00:00.999999 0000-00-01 00:00:00.999
+0000-00-01 23:59:59.999999 0000-00-01 23:59:59.999
+0000-00-31 23:59:59.999999 0000-00-31 23:59:59.999
+0000-01-01 00:00:00.999999 0000-01-01 00:00:00.999
+0000-01-01 23:59:59.999999 0000-01-01 23:59:59.999
+0000-01-31 23:59:59.999999 0000-01-31 23:59:59.999
+0000-02-28 23:59:59.999999 0000-02-28 23:59:59.999
+0000-12-31 23:59:59.999999 0000-12-31 23:59:59.999
+0001-01-01 00:00:00.999999 0001-01-01 00:00:00.999
+0001-02-28 23:59:59.999999 0001-02-28 23:59:59.999
+0001-12-31 23:59:59.999999 0001-12-31 23:59:59.999
+0004-02-28 23:59:59.999999 0004-02-28 23:59:59.999
+0004-02-29 23:59:59.999999 0004-02-29 23:59:59.999
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.999
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.999
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59.999
+SELECT a, TRUNCATE(a,4) FROM t1;
+a TRUNCATE(a,4)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:00.9999
+0000-00-00 23:59:59.999999 0000-00-00 23:59:59.9999
+0000-00-01 00:00:00.999999 0000-00-01 00:00:00.9999
+0000-00-01 23:59:59.999999 0000-00-01 23:59:59.9999
+0000-00-31 23:59:59.999999 0000-00-31 23:59:59.9999
+0000-01-01 00:00:00.999999 0000-01-01 00:00:00.9999
+0000-01-01 23:59:59.999999 0000-01-01 23:59:59.9999
+0000-01-31 23:59:59.999999 0000-01-31 23:59:59.9999
+0000-02-28 23:59:59.999999 0000-02-28 23:59:59.9999
+0000-12-31 23:59:59.999999 0000-12-31 23:59:59.9999
+0001-01-01 00:00:00.999999 0001-01-01 00:00:00.9999
+0001-02-28 23:59:59.999999 0001-02-28 23:59:59.9999
+0001-12-31 23:59:59.999999 0001-12-31 23:59:59.9999
+0004-02-28 23:59:59.999999 0004-02-28 23:59:59.9999
+0004-02-29 23:59:59.999999 0004-02-29 23:59:59.9999
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.9999
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.9999
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59.9999
+SELECT a, TRUNCATE(a,5) FROM t1;
+a TRUNCATE(a,5)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:00.99999
+0000-00-00 23:59:59.999999 0000-00-00 23:59:59.99999
+0000-00-01 00:00:00.999999 0000-00-01 00:00:00.99999
+0000-00-01 23:59:59.999999 0000-00-01 23:59:59.99999
+0000-00-31 23:59:59.999999 0000-00-31 23:59:59.99999
+0000-01-01 00:00:00.999999 0000-01-01 00:00:00.99999
+0000-01-01 23:59:59.999999 0000-01-01 23:59:59.99999
+0000-01-31 23:59:59.999999 0000-01-31 23:59:59.99999
+0000-02-28 23:59:59.999999 0000-02-28 23:59:59.99999
+0000-12-31 23:59:59.999999 0000-12-31 23:59:59.99999
+0001-01-01 00:00:00.999999 0001-01-01 00:00:00.99999
+0001-02-28 23:59:59.999999 0001-02-28 23:59:59.99999
+0001-12-31 23:59:59.999999 0001-12-31 23:59:59.99999
+0004-02-28 23:59:59.999999 0004-02-28 23:59:59.99999
+0004-02-29 23:59:59.999999 0004-02-29 23:59:59.99999
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.99999
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.99999
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59.99999
+SELECT a, TRUNCATE(a,6) FROM t1;
+a TRUNCATE(a,6)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:00.999999
+0000-00-00 23:59:59.999999 0000-00-00 23:59:59.999999
+0000-00-01 00:00:00.999999 0000-00-01 00:00:00.999999
+0000-00-01 23:59:59.999999 0000-00-01 23:59:59.999999
+0000-00-31 23:59:59.999999 0000-00-31 23:59:59.999999
+0000-01-01 00:00:00.999999 0000-01-01 00:00:00.999999
+0000-01-01 23:59:59.999999 0000-01-01 23:59:59.999999
+0000-01-31 23:59:59.999999 0000-01-31 23:59:59.999999
+0000-02-28 23:59:59.999999 0000-02-28 23:59:59.999999
+0000-12-31 23:59:59.999999 0000-12-31 23:59:59.999999
+0001-01-01 00:00:00.999999 0001-01-01 00:00:00.999999
+0001-02-28 23:59:59.999999 0001-02-28 23:59:59.999999
+0001-12-31 23:59:59.999999 0001-12-31 23:59:59.999999
+0004-02-28 23:59:59.999999 0004-02-28 23:59:59.999999
+0004-02-29 23:59:59.999999 0004-02-29 23:59:59.999999
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.999999
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.999999
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59.999999
+SELECT a, TRUNCATE(a,7) FROM t1;
+a TRUNCATE(a,7)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:00.999999
+0000-00-00 23:59:59.999999 0000-00-00 23:59:59.999999
+0000-00-01 00:00:00.999999 0000-00-01 00:00:00.999999
+0000-00-01 23:59:59.999999 0000-00-01 23:59:59.999999
+0000-00-31 23:59:59.999999 0000-00-31 23:59:59.999999
+0000-01-01 00:00:00.999999 0000-01-01 00:00:00.999999
+0000-01-01 23:59:59.999999 0000-01-01 23:59:59.999999
+0000-01-31 23:59:59.999999 0000-01-31 23:59:59.999999
+0000-02-28 23:59:59.999999 0000-02-28 23:59:59.999999
+0000-12-31 23:59:59.999999 0000-12-31 23:59:59.999999
+0001-01-01 00:00:00.999999 0001-01-01 00:00:00.999999
+0001-02-28 23:59:59.999999 0001-02-28 23:59:59.999999
+0001-12-31 23:59:59.999999 0001-12-31 23:59:59.999999
+0004-02-28 23:59:59.999999 0004-02-28 23:59:59.999999
+0004-02-29 23:59:59.999999 0004-02-29 23:59:59.999999
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.999999
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.999999
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59.999999
+SELECT a, TRUNCATE(a,-1) FROM t1;
+a TRUNCATE(a,-1)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:00
+0000-00-00 23:59:59.999999 0000-00-00 23:59:59
+0000-00-01 00:00:00.999999 0000-00-01 00:00:00
+0000-00-01 23:59:59.999999 0000-00-01 23:59:59
+0000-00-31 23:59:59.999999 0000-00-31 23:59:59
+0000-01-01 00:00:00.999999 0000-01-01 00:00:00
+0000-01-01 23:59:59.999999 0000-01-01 23:59:59
+0000-01-31 23:59:59.999999 0000-01-31 23:59:59
+0000-02-28 23:59:59.999999 0000-02-28 23:59:59
+0000-12-31 23:59:59.999999 0000-12-31 23:59:59
+0001-01-01 00:00:00.999999 0001-01-01 00:00:00
+0001-02-28 23:59:59.999999 0001-02-28 23:59:59
+0001-12-31 23:59:59.999999 0001-12-31 23:59:59
+0004-02-28 23:59:59.999999 0004-02-28 23:59:59
+0004-02-29 23:59:59.999999 0004-02-29 23:59:59
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59
+SELECT a, TRUNCATE(a,-6) FROM t1;
+a TRUNCATE(a,-6)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:00
+0000-00-00 23:59:59.999999 0000-00-00 23:59:59
+0000-00-01 00:00:00.999999 0000-00-01 00:00:00
+0000-00-01 23:59:59.999999 0000-00-01 23:59:59
+0000-00-31 23:59:59.999999 0000-00-31 23:59:59
+0000-01-01 00:00:00.999999 0000-01-01 00:00:00
+0000-01-01 23:59:59.999999 0000-01-01 23:59:59
+0000-01-31 23:59:59.999999 0000-01-31 23:59:59
+0000-02-28 23:59:59.999999 0000-02-28 23:59:59
+0000-12-31 23:59:59.999999 0000-12-31 23:59:59
+0001-01-01 00:00:00.999999 0001-01-01 00:00:00
+0001-02-28 23:59:59.999999 0001-02-28 23:59:59
+0001-12-31 23:59:59.999999 0001-12-31 23:59:59
+0004-02-28 23:59:59.999999 0004-02-28 23:59:59
+0004-02-29 23:59:59.999999 0004-02-29 23:59:59
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59
+SELECT a, ROUND(a) FROM t1;
+a ROUND(a)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:01
+0000-00-00 23:59:59.999999 NULL
+0000-00-01 00:00:00.999999 0000-00-01 00:00:01
+0000-00-01 23:59:59.999999 NULL
+0000-00-31 23:59:59.999999 NULL
+0000-01-01 00:00:00.999999 0000-01-01 00:00:01
+0000-01-01 23:59:59.999999 NULL
+0000-01-31 23:59:59.999999 NULL
+0000-02-28 23:59:59.999999 NULL
+0000-12-31 23:59:59.999999 NULL
+0001-01-01 00:00:00.999999 0001-01-01 00:00:01
+0001-02-28 23:59:59.999999 0001-03-01 00:00:00
+0001-12-31 23:59:59.999999 0002-01-01 00:00:00
+0004-02-28 23:59:59.999999 0004-02-29 00:00:00
+0004-02-29 23:59:59.999999 0004-03-01 00:00:00
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59
+Warnings:
+Warning 1411 Incorrect date value: '0000-00-00' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-02-28' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-12-31' for function round(datetime)
+SELECT a, ROUND(a,0) FROM t1;
+a ROUND(a,0)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:01
+0000-00-00 23:59:59.999999 NULL
+0000-00-01 00:00:00.999999 0000-00-01 00:00:01
+0000-00-01 23:59:59.999999 NULL
+0000-00-31 23:59:59.999999 NULL
+0000-01-01 00:00:00.999999 0000-01-01 00:00:01
+0000-01-01 23:59:59.999999 NULL
+0000-01-31 23:59:59.999999 NULL
+0000-02-28 23:59:59.999999 NULL
+0000-12-31 23:59:59.999999 NULL
+0001-01-01 00:00:00.999999 0001-01-01 00:00:01
+0001-02-28 23:59:59.999999 0001-03-01 00:00:00
+0001-12-31 23:59:59.999999 0002-01-01 00:00:00
+0004-02-28 23:59:59.999999 0004-02-29 00:00:00
+0004-02-29 23:59:59.999999 0004-03-01 00:00:00
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59
+Warnings:
+Warning 1411 Incorrect date value: '0000-00-00' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-02-28' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-12-31' for function round(datetime)
+SELECT a, ROUND(a,1) FROM t1;
+a ROUND(a,1)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:01.0
+0000-00-00 23:59:59.999999 NULL
+0000-00-01 00:00:00.999999 0000-00-01 00:00:01.0
+0000-00-01 23:59:59.999999 NULL
+0000-00-31 23:59:59.999999 NULL
+0000-01-01 00:00:00.999999 0000-01-01 00:00:01.0
+0000-01-01 23:59:59.999999 NULL
+0000-01-31 23:59:59.999999 NULL
+0000-02-28 23:59:59.999999 NULL
+0000-12-31 23:59:59.999999 NULL
+0001-01-01 00:00:00.999999 0001-01-01 00:00:01.0
+0001-02-28 23:59:59.999999 0001-03-01 00:00:00.0
+0001-12-31 23:59:59.999999 0002-01-01 00:00:00.0
+0004-02-28 23:59:59.999999 0004-02-29 00:00:00.0
+0004-02-29 23:59:59.999999 0004-03-01 00:00:00.0
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00.0
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00.0
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59.9
+Warnings:
+Warning 1411 Incorrect date value: '0000-00-00' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-02-28' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-12-31' for function round(datetime)
+SELECT a, ROUND(a,2) FROM t1;
+a ROUND(a,2)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:01.00
+0000-00-00 23:59:59.999999 NULL
+0000-00-01 00:00:00.999999 0000-00-01 00:00:01.00
+0000-00-01 23:59:59.999999 NULL
+0000-00-31 23:59:59.999999 NULL
+0000-01-01 00:00:00.999999 0000-01-01 00:00:01.00
+0000-01-01 23:59:59.999999 NULL
+0000-01-31 23:59:59.999999 NULL
+0000-02-28 23:59:59.999999 NULL
+0000-12-31 23:59:59.999999 NULL
+0001-01-01 00:00:00.999999 0001-01-01 00:00:01.00
+0001-02-28 23:59:59.999999 0001-03-01 00:00:00.00
+0001-12-31 23:59:59.999999 0002-01-01 00:00:00.00
+0004-02-28 23:59:59.999999 0004-02-29 00:00:00.00
+0004-02-29 23:59:59.999999 0004-03-01 00:00:00.00
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00.00
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00.00
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59.99
+Warnings:
+Warning 1411 Incorrect date value: '0000-00-00' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-02-28' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-12-31' for function round(datetime)
+SELECT a, ROUND(a,3) FROM t1;
+a ROUND(a,3)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:01.000
+0000-00-00 23:59:59.999999 NULL
+0000-00-01 00:00:00.999999 0000-00-01 00:00:01.000
+0000-00-01 23:59:59.999999 NULL
+0000-00-31 23:59:59.999999 NULL
+0000-01-01 00:00:00.999999 0000-01-01 00:00:01.000
+0000-01-01 23:59:59.999999 NULL
+0000-01-31 23:59:59.999999 NULL
+0000-02-28 23:59:59.999999 NULL
+0000-12-31 23:59:59.999999 NULL
+0001-01-01 00:00:00.999999 0001-01-01 00:00:01.000
+0001-02-28 23:59:59.999999 0001-03-01 00:00:00.000
+0001-12-31 23:59:59.999999 0002-01-01 00:00:00.000
+0004-02-28 23:59:59.999999 0004-02-29 00:00:00.000
+0004-02-29 23:59:59.999999 0004-03-01 00:00:00.000
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00.000
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00.000
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59.999
+Warnings:
+Warning 1411 Incorrect date value: '0000-00-00' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-02-28' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-12-31' for function round(datetime)
+SELECT a, ROUND(a,4) FROM t1;
+a ROUND(a,4)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:01.0000
+0000-00-00 23:59:59.999999 NULL
+0000-00-01 00:00:00.999999 0000-00-01 00:00:01.0000
+0000-00-01 23:59:59.999999 NULL
+0000-00-31 23:59:59.999999 NULL
+0000-01-01 00:00:00.999999 0000-01-01 00:00:01.0000
+0000-01-01 23:59:59.999999 NULL
+0000-01-31 23:59:59.999999 NULL
+0000-02-28 23:59:59.999999 NULL
+0000-12-31 23:59:59.999999 NULL
+0001-01-01 00:00:00.999999 0001-01-01 00:00:01.0000
+0001-02-28 23:59:59.999999 0001-03-01 00:00:00.0000
+0001-12-31 23:59:59.999999 0002-01-01 00:00:00.0000
+0004-02-28 23:59:59.999999 0004-02-29 00:00:00.0000
+0004-02-29 23:59:59.999999 0004-03-01 00:00:00.0000
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00.0000
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00.0000
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59.9999
+Warnings:
+Warning 1411 Incorrect date value: '0000-00-00' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-02-28' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-12-31' for function round(datetime)
+SELECT a, ROUND(a,5) FROM t1;
+a ROUND(a,5)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:01.00000
+0000-00-00 23:59:59.999999 NULL
+0000-00-01 00:00:00.999999 0000-00-01 00:00:01.00000
+0000-00-01 23:59:59.999999 NULL
+0000-00-31 23:59:59.999999 NULL
+0000-01-01 00:00:00.999999 0000-01-01 00:00:01.00000
+0000-01-01 23:59:59.999999 NULL
+0000-01-31 23:59:59.999999 NULL
+0000-02-28 23:59:59.999999 NULL
+0000-12-31 23:59:59.999999 NULL
+0001-01-01 00:00:00.999999 0001-01-01 00:00:01.00000
+0001-02-28 23:59:59.999999 0001-03-01 00:00:00.00000
+0001-12-31 23:59:59.999999 0002-01-01 00:00:00.00000
+0004-02-28 23:59:59.999999 0004-02-29 00:00:00.00000
+0004-02-29 23:59:59.999999 0004-03-01 00:00:00.00000
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00.00000
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00.00000
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59.99999
+Warnings:
+Warning 1411 Incorrect date value: '0000-00-00' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-02-28' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-12-31' for function round(datetime)
+SELECT a, ROUND(a,6) FROM t1;
+a ROUND(a,6)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:00.999999
+0000-00-00 23:59:59.999999 0000-00-00 23:59:59.999999
+0000-00-01 00:00:00.999999 0000-00-01 00:00:00.999999
+0000-00-01 23:59:59.999999 0000-00-01 23:59:59.999999
+0000-00-31 23:59:59.999999 0000-00-31 23:59:59.999999
+0000-01-01 00:00:00.999999 0000-01-01 00:00:00.999999
+0000-01-01 23:59:59.999999 0000-01-01 23:59:59.999999
+0000-01-31 23:59:59.999999 0000-01-31 23:59:59.999999
+0000-02-28 23:59:59.999999 0000-02-28 23:59:59.999999
+0000-12-31 23:59:59.999999 0000-12-31 23:59:59.999999
+0001-01-01 00:00:00.999999 0001-01-01 00:00:00.999999
+0001-02-28 23:59:59.999999 0001-02-28 23:59:59.999999
+0001-12-31 23:59:59.999999 0001-12-31 23:59:59.999999
+0004-02-28 23:59:59.999999 0004-02-28 23:59:59.999999
+0004-02-29 23:59:59.999999 0004-02-29 23:59:59.999999
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.999999
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.999999
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59.999999
+SELECT a, ROUND(a,7) FROM t1;
+a ROUND(a,7)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:00.999999
+0000-00-00 23:59:59.999999 0000-00-00 23:59:59.999999
+0000-00-01 00:00:00.999999 0000-00-01 00:00:00.999999
+0000-00-01 23:59:59.999999 0000-00-01 23:59:59.999999
+0000-00-31 23:59:59.999999 0000-00-31 23:59:59.999999
+0000-01-01 00:00:00.999999 0000-01-01 00:00:00.999999
+0000-01-01 23:59:59.999999 0000-01-01 23:59:59.999999
+0000-01-31 23:59:59.999999 0000-01-31 23:59:59.999999
+0000-02-28 23:59:59.999999 0000-02-28 23:59:59.999999
+0000-12-31 23:59:59.999999 0000-12-31 23:59:59.999999
+0001-01-01 00:00:00.999999 0001-01-01 00:00:00.999999
+0001-02-28 23:59:59.999999 0001-02-28 23:59:59.999999
+0001-12-31 23:59:59.999999 0001-12-31 23:59:59.999999
+0004-02-28 23:59:59.999999 0004-02-28 23:59:59.999999
+0004-02-29 23:59:59.999999 0004-02-29 23:59:59.999999
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.999999
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.999999
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59.999999
+SELECT a, ROUND(a,-1) FROM t1;
+a ROUND(a,-1)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:01
+0000-00-00 23:59:59.999999 NULL
+0000-00-01 00:00:00.999999 0000-00-01 00:00:01
+0000-00-01 23:59:59.999999 NULL
+0000-00-31 23:59:59.999999 NULL
+0000-01-01 00:00:00.999999 0000-01-01 00:00:01
+0000-01-01 23:59:59.999999 NULL
+0000-01-31 23:59:59.999999 NULL
+0000-02-28 23:59:59.999999 NULL
+0000-12-31 23:59:59.999999 NULL
+0001-01-01 00:00:00.999999 0001-01-01 00:00:01
+0001-02-28 23:59:59.999999 0001-03-01 00:00:00
+0001-12-31 23:59:59.999999 0002-01-01 00:00:00
+0004-02-28 23:59:59.999999 0004-02-29 00:00:00
+0004-02-29 23:59:59.999999 0004-03-01 00:00:00
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59
+Warnings:
+Warning 1411 Incorrect date value: '0000-00-00' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-02-28' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-12-31' for function round(datetime)
+SELECT a, ROUND(a,-6) FROM t1;
+a ROUND(a,-6)
+0000-00-00 00:00:00.999999 0000-00-00 00:00:01
+0000-00-00 23:59:59.999999 NULL
+0000-00-01 00:00:00.999999 0000-00-01 00:00:01
+0000-00-01 23:59:59.999999 NULL
+0000-00-31 23:59:59.999999 NULL
+0000-01-01 00:00:00.999999 0000-01-01 00:00:01
+0000-01-01 23:59:59.999999 NULL
+0000-01-31 23:59:59.999999 NULL
+0000-02-28 23:59:59.999999 NULL
+0000-12-31 23:59:59.999999 NULL
+0001-01-01 00:00:00.999999 0001-01-01 00:00:01
+0001-02-28 23:59:59.999999 0001-03-01 00:00:00
+0001-12-31 23:59:59.999999 0002-01-01 00:00:00
+0004-02-28 23:59:59.999999 0004-02-29 00:00:00
+0004-02-29 23:59:59.999999 0004-03-01 00:00:00
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00
+9999-12-31 23:59:59.999999 9999-12-31 23:59:59
+Warnings:
+Warning 1411 Incorrect date value: '0000-00-00' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-00-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-01' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-01-31' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-02-28' for function round(datetime)
+Warning 1411 Incorrect date value: '0000-12-31' for function round(datetime)
+DROP TABLE t1;
+#
+# End of 10.4 tests
+#
diff --git a/mysql-test/main/type_datetime_hires.test b/mysql-test/main/type_datetime_hires.test
index d220a4601eb..ed9a85bcda3 100644
--- a/mysql-test/main/type_datetime_hires.test
+++ b/mysql-test/main/type_datetime_hires.test
@@ -79,3 +79,73 @@ INSERT INTO t1 VALUES ('2001-01-01 00:00:00'),('2000-00-00 00:00:00');
SELECT UNIX_TIMESTAMP(a) FROM t1 ORDER BY 1;
DROP TABLE t1;
SET @@time_zone=DEFAULT;
+
+
+--echo #
+--echo # Start of 10.4 tests
+--echo #
+
+--echo #
+--echo # MDEV-20397 Support TIMESTAMP, DATETIME, TIME in ROUND() and TRUNCATE()
+--echo #
+
+CREATE TABLE t1 (a1 DATETIME(6), a2 DATETIME(6) NOT NULL);
+CREATE TABLE t2 AS SELECT
+ ROUND(a1) AS r1,
+ ROUND(a2) AS r2,
+ TRUNCATE(a1,0) AS t1,
+ TRUNCATE(a2,0) AS t2
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a DATETIME(6));
+INSERT INTO t1 VALUES
+('0000-00-00 00:00:00.999999'),
+('0000-00-00 23:59:59.999999'),
+('0000-00-01 00:00:00.999999'),
+('0000-00-01 23:59:59.999999'),
+('0000-00-31 23:59:59.999999'),
+('0000-01-01 00:00:00.999999'),
+('0000-01-01 23:59:59.999999'),
+('0000-01-31 23:59:59.999999'),
+('0000-02-28 23:59:59.999999'),
+('0000-12-31 23:59:59.999999'),
+('0001-01-01 00:00:00.999999'),
+('0001-02-28 23:59:59.999999'),
+('0001-12-31 23:59:59.999999'),
+('0004-02-28 23:59:59.999999'),
+('0004-02-29 23:59:59.999999'),
+('2000-02-29 23:59:59.999999'),
+('2000-12-31 23:59:59.999999'),
+('9999-12-31 23:59:59.999999');
+SELECT a, TRUNCATE(a,0) FROM t1;
+SELECT a, TRUNCATE(a,1) FROM t1;
+SELECT a, TRUNCATE(a,2) FROM t1;
+SELECT a, TRUNCATE(a,3) FROM t1;
+SELECT a, TRUNCATE(a,4) FROM t1;
+SELECT a, TRUNCATE(a,5) FROM t1;
+SELECT a, TRUNCATE(a,6) FROM t1;
+SELECT a, TRUNCATE(a,7) FROM t1;
+SELECT a, TRUNCATE(a,-1) FROM t1;
+SELECT a, TRUNCATE(a,-6) FROM t1;
+
+SELECT a, ROUND(a) FROM t1;
+SELECT a, ROUND(a,0) FROM t1;
+SELECT a, ROUND(a,1) FROM t1;
+SELECT a, ROUND(a,2) FROM t1;
+SELECT a, ROUND(a,3) FROM t1;
+SELECT a, ROUND(a,4) FROM t1;
+SELECT a, ROUND(a,5) FROM t1;
+SELECT a, ROUND(a,6) FROM t1;
+SELECT a, ROUND(a,7) FROM t1;
+SELECT a, ROUND(a,-1) FROM t1;
+SELECT a, ROUND(a,-6) FROM t1;
+
+DROP TABLE t1;
+
+--echo #
+--echo # End of 10.4 tests
+--echo #
diff --git a/mysql-test/main/type_int.result b/mysql-test/main/type_int.result
index 8edaa25194d..3b1321d9a60 100644
--- a/mysql-test/main/type_int.result
+++ b/mysql-test/main/type_int.result
@@ -1,4 +1,28 @@
#
+# Start of 5.5 tests
+#
+#
+# MDEV-15955 Assertion `field_types == 0 || field_types[field_pos] == MYSQL_TYPE_LONGLONG' failed in Protocol_text::store_longlong
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2);
+SELECT @a := 1 FROM t1 ORDER BY STRCMP(STDDEV_SAMP(a), 'bar');
+@a := 1
+1
+SELECT COALESCE(1) FROM t1 ORDER BY STRCMP(STDDEV_SAMP(a), 'bar');
+COALESCE(1)
+1
+SELECT COALESCE(@a:=1) FROM t1 ORDER BY STRCMP(STDDEV_SAMP(a), 'bar');
+COALESCE(@a:=1)
+1
+SELECT COALESCE(@a) FROM t1 ORDER BY STRCMP(STDDEV_SAMP(a), 'bar');
+COALESCE(@a)
+1
+DROP TABLE t1;
+#
+# End of 5.5 tests
+#
+#
# Start of 10.1 tests
#
#
diff --git a/mysql-test/main/type_int.test b/mysql-test/main/type_int.test
index 8d96ed70b0b..77c532ff4ac 100644
--- a/mysql-test/main/type_int.test
+++ b/mysql-test/main/type_int.test
@@ -1,4 +1,25 @@
--echo #
+--echo # Start of 5.5 tests
+--echo #
+
+--echo #
+--echo # MDEV-15955 Assertion `field_types == 0 || field_types[field_pos] == MYSQL_TYPE_LONGLONG' failed in Protocol_text::store_longlong
+--echo #
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2);
+SELECT @a := 1 FROM t1 ORDER BY STRCMP(STDDEV_SAMP(a), 'bar');
+SELECT COALESCE(1) FROM t1 ORDER BY STRCMP(STDDEV_SAMP(a), 'bar');
+SELECT COALESCE(@a:=1) FROM t1 ORDER BY STRCMP(STDDEV_SAMP(a), 'bar');
+SELECT COALESCE(@a) FROM t1 ORDER BY STRCMP(STDDEV_SAMP(a), 'bar');
+DROP TABLE t1;
+
+--echo #
+--echo # End of 5.5 tests
+--echo #
+
+
+--echo #
--echo # Start of 10.1 tests
--echo #
diff --git a/mysql-test/main/type_time_hires.result b/mysql-test/main/type_time_hires.result
index ca19e9ed5bf..6122afcfc47 100644
--- a/mysql-test/main/type_time_hires.result
+++ b/mysql-test/main/type_time_hires.result
@@ -25,8 +25,8 @@ a
03:04:05.789
15:47:11.123
838:59:59.999
-select truncate(a, 6) from t1;
-truncate(a, 6)
+select cast(a AS double(30,6)) from t1;
+cast(a AS double(30,6))
2003.123000
10203.456000
30405.789062
@@ -359,3 +359,314 @@ drop table t1;
select cast(1e-6 as time(6));
cast(1e-6 as time(6))
00:00:00.000001
+#
+# Start of 10.4 tests
+#
+#
+# MDEV-20397 Support TIMESTAMP, DATETIME, TIME in ROUND() and TRUNCATE()
+#
+CREATE TABLE t1 (a1 TIME(6), a2 TIME(6) NOT NULL);
+CREATE TABLE t2 AS SELECT
+ROUND(a1) AS r1,
+ROUND(a2) AS r2,
+TRUNCATE(a1,0) AS t1,
+TRUNCATE(a2,0) AS t2
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `r1` time DEFAULT NULL,
+ `r2` time NOT NULL,
+ `t1` time DEFAULT NULL,
+ `t2` time NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a TIME(6));
+INSERT INTO t1 VALUES
+('-838:59:59.999999'),
+('-837:59:59.999999'),
+('-23:59:59.999999'),
+('-00:59:59.999999'),
+('-00:00:59.999999'),
+('00:00:00.999999'),
+('00:00:59.999999'),
+('00:59:59.999999'),
+('23:59:59.999999'),
+('837:59:59.999999'),
+('838:59:59.999999');
+SELECT a, TRUNCATE(a,0) FROM t1;
+a TRUNCATE(a,0)
+-838:59:59.999999 -838:59:59
+-837:59:59.999999 -837:59:59
+-23:59:59.999999 -23:59:59
+-00:59:59.999999 -00:59:59
+-00:00:59.999999 -00:00:59
+00:00:00.999999 00:00:00
+00:00:59.999999 00:00:59
+00:59:59.999999 00:59:59
+23:59:59.999999 23:59:59
+837:59:59.999999 837:59:59
+838:59:59.999999 838:59:59
+SELECT a, TRUNCATE(a,1) FROM t1;
+a TRUNCATE(a,1)
+-838:59:59.999999 -838:59:59.9
+-837:59:59.999999 -837:59:59.9
+-23:59:59.999999 -23:59:59.9
+-00:59:59.999999 -00:59:59.9
+-00:00:59.999999 -00:00:59.9
+00:00:00.999999 00:00:00.9
+00:00:59.999999 00:00:59.9
+00:59:59.999999 00:59:59.9
+23:59:59.999999 23:59:59.9
+837:59:59.999999 837:59:59.9
+838:59:59.999999 838:59:59.9
+SELECT a, TRUNCATE(a,2) FROM t1;
+a TRUNCATE(a,2)
+-838:59:59.999999 -838:59:59.99
+-837:59:59.999999 -837:59:59.99
+-23:59:59.999999 -23:59:59.99
+-00:59:59.999999 -00:59:59.99
+-00:00:59.999999 -00:00:59.99
+00:00:00.999999 00:00:00.99
+00:00:59.999999 00:00:59.99
+00:59:59.999999 00:59:59.99
+23:59:59.999999 23:59:59.99
+837:59:59.999999 837:59:59.99
+838:59:59.999999 838:59:59.99
+SELECT a, TRUNCATE(a,3) FROM t1;
+a TRUNCATE(a,3)
+-838:59:59.999999 -838:59:59.999
+-837:59:59.999999 -837:59:59.999
+-23:59:59.999999 -23:59:59.999
+-00:59:59.999999 -00:59:59.999
+-00:00:59.999999 -00:00:59.999
+00:00:00.999999 00:00:00.999
+00:00:59.999999 00:00:59.999
+00:59:59.999999 00:59:59.999
+23:59:59.999999 23:59:59.999
+837:59:59.999999 837:59:59.999
+838:59:59.999999 838:59:59.999
+SELECT a, TRUNCATE(a,4) FROM t1;
+a TRUNCATE(a,4)
+-838:59:59.999999 -838:59:59.9999
+-837:59:59.999999 -837:59:59.9999
+-23:59:59.999999 -23:59:59.9999
+-00:59:59.999999 -00:59:59.9999
+-00:00:59.999999 -00:00:59.9999
+00:00:00.999999 00:00:00.9999
+00:00:59.999999 00:00:59.9999
+00:59:59.999999 00:59:59.9999
+23:59:59.999999 23:59:59.9999
+837:59:59.999999 837:59:59.9999
+838:59:59.999999 838:59:59.9999
+SELECT a, TRUNCATE(a,5) FROM t1;
+a TRUNCATE(a,5)
+-838:59:59.999999 -838:59:59.99999
+-837:59:59.999999 -837:59:59.99999
+-23:59:59.999999 -23:59:59.99999
+-00:59:59.999999 -00:59:59.99999
+-00:00:59.999999 -00:00:59.99999
+00:00:00.999999 00:00:00.99999
+00:00:59.999999 00:00:59.99999
+00:59:59.999999 00:59:59.99999
+23:59:59.999999 23:59:59.99999
+837:59:59.999999 837:59:59.99999
+838:59:59.999999 838:59:59.99999
+SELECT a, TRUNCATE(a,6) FROM t1;
+a TRUNCATE(a,6)
+-838:59:59.999999 -838:59:59.999999
+-837:59:59.999999 -837:59:59.999999
+-23:59:59.999999 -23:59:59.999999
+-00:59:59.999999 -00:59:59.999999
+-00:00:59.999999 -00:00:59.999999
+00:00:00.999999 00:00:00.999999
+00:00:59.999999 00:00:59.999999
+00:59:59.999999 00:59:59.999999
+23:59:59.999999 23:59:59.999999
+837:59:59.999999 837:59:59.999999
+838:59:59.999999 838:59:59.999999
+SELECT a, TRUNCATE(a,7) FROM t1;
+a TRUNCATE(a,7)
+-838:59:59.999999 -838:59:59.999999
+-837:59:59.999999 -837:59:59.999999
+-23:59:59.999999 -23:59:59.999999
+-00:59:59.999999 -00:59:59.999999
+-00:00:59.999999 -00:00:59.999999
+00:00:00.999999 00:00:00.999999
+00:00:59.999999 00:00:59.999999
+00:59:59.999999 00:59:59.999999
+23:59:59.999999 23:59:59.999999
+837:59:59.999999 837:59:59.999999
+838:59:59.999999 838:59:59.999999
+SELECT a, TRUNCATE(a,-1) FROM t1;
+a TRUNCATE(a,-1)
+-838:59:59.999999 -838:59:59
+-837:59:59.999999 -837:59:59
+-23:59:59.999999 -23:59:59
+-00:59:59.999999 -00:59:59
+-00:00:59.999999 -00:00:59
+00:00:00.999999 00:00:00
+00:00:59.999999 00:00:59
+00:59:59.999999 00:59:59
+23:59:59.999999 23:59:59
+837:59:59.999999 837:59:59
+838:59:59.999999 838:59:59
+SELECT a, TRUNCATE(a,-6) FROM t1;
+a TRUNCATE(a,-6)
+-838:59:59.999999 -838:59:59
+-837:59:59.999999 -837:59:59
+-23:59:59.999999 -23:59:59
+-00:59:59.999999 -00:59:59
+-00:00:59.999999 -00:00:59
+00:00:00.999999 00:00:00
+00:00:59.999999 00:00:59
+00:59:59.999999 00:59:59
+23:59:59.999999 23:59:59
+837:59:59.999999 837:59:59
+838:59:59.999999 838:59:59
+SELECT a, ROUND(a) FROM t1;
+a ROUND(a)
+-838:59:59.999999 -838:59:59
+-837:59:59.999999 -838:00:00
+-23:59:59.999999 -24:00:00
+-00:59:59.999999 -01:00:00
+-00:00:59.999999 -00:01:00
+00:00:00.999999 00:00:01
+00:00:59.999999 00:01:00
+00:59:59.999999 01:00:00
+23:59:59.999999 24:00:00
+837:59:59.999999 838:00:00
+838:59:59.999999 838:59:59
+SELECT a, ROUND(a,0) FROM t1;
+a ROUND(a,0)
+-838:59:59.999999 -838:59:59
+-837:59:59.999999 -838:00:00
+-23:59:59.999999 -24:00:00
+-00:59:59.999999 -01:00:00
+-00:00:59.999999 -00:01:00
+00:00:00.999999 00:00:01
+00:00:59.999999 00:01:00
+00:59:59.999999 01:00:00
+23:59:59.999999 24:00:00
+837:59:59.999999 838:00:00
+838:59:59.999999 838:59:59
+SELECT a, ROUND(a,1) FROM t1;
+a ROUND(a,1)
+-838:59:59.999999 -838:59:59.9
+-837:59:59.999999 -838:00:00.0
+-23:59:59.999999 -24:00:00.0
+-00:59:59.999999 -01:00:00.0
+-00:00:59.999999 -00:01:00.0
+00:00:00.999999 00:00:01.0
+00:00:59.999999 00:01:00.0
+00:59:59.999999 01:00:00.0
+23:59:59.999999 24:00:00.0
+837:59:59.999999 838:00:00.0
+838:59:59.999999 838:59:59.9
+SELECT a, ROUND(a,2) FROM t1;
+a ROUND(a,2)
+-838:59:59.999999 -838:59:59.99
+-837:59:59.999999 -838:00:00.00
+-23:59:59.999999 -24:00:00.00
+-00:59:59.999999 -01:00:00.00
+-00:00:59.999999 -00:01:00.00
+00:00:00.999999 00:00:01.00
+00:00:59.999999 00:01:00.00
+00:59:59.999999 01:00:00.00
+23:59:59.999999 24:00:00.00
+837:59:59.999999 838:00:00.00
+838:59:59.999999 838:59:59.99
+SELECT a, ROUND(a,3) FROM t1;
+a ROUND(a,3)
+-838:59:59.999999 -838:59:59.999
+-837:59:59.999999 -838:00:00.000
+-23:59:59.999999 -24:00:00.000
+-00:59:59.999999 -01:00:00.000
+-00:00:59.999999 -00:01:00.000
+00:00:00.999999 00:00:01.000
+00:00:59.999999 00:01:00.000
+00:59:59.999999 01:00:00.000
+23:59:59.999999 24:00:00.000
+837:59:59.999999 838:00:00.000
+838:59:59.999999 838:59:59.999
+SELECT a, ROUND(a,4) FROM t1;
+a ROUND(a,4)
+-838:59:59.999999 -838:59:59.9999
+-837:59:59.999999 -838:00:00.0000
+-23:59:59.999999 -24:00:00.0000
+-00:59:59.999999 -01:00:00.0000
+-00:00:59.999999 -00:01:00.0000
+00:00:00.999999 00:00:01.0000
+00:00:59.999999 00:01:00.0000
+00:59:59.999999 01:00:00.0000
+23:59:59.999999 24:00:00.0000
+837:59:59.999999 838:00:00.0000
+838:59:59.999999 838:59:59.9999
+SELECT a, ROUND(a,5) FROM t1;
+a ROUND(a,5)
+-838:59:59.999999 -838:59:59.99999
+-837:59:59.999999 -838:00:00.00000
+-23:59:59.999999 -24:00:00.00000
+-00:59:59.999999 -01:00:00.00000
+-00:00:59.999999 -00:01:00.00000
+00:00:00.999999 00:00:01.00000
+00:00:59.999999 00:01:00.00000
+00:59:59.999999 01:00:00.00000
+23:59:59.999999 24:00:00.00000
+837:59:59.999999 838:00:00.00000
+838:59:59.999999 838:59:59.99999
+SELECT a, ROUND(a,6) FROM t1;
+a ROUND(a,6)
+-838:59:59.999999 -838:59:59.999999
+-837:59:59.999999 -837:59:59.999999
+-23:59:59.999999 -23:59:59.999999
+-00:59:59.999999 -00:59:59.999999
+-00:00:59.999999 -00:00:59.999999
+00:00:00.999999 00:00:00.999999
+00:00:59.999999 00:00:59.999999
+00:59:59.999999 00:59:59.999999
+23:59:59.999999 23:59:59.999999
+837:59:59.999999 837:59:59.999999
+838:59:59.999999 838:59:59.999999
+SELECT a, ROUND(a,7) FROM t1;
+a ROUND(a,7)
+-838:59:59.999999 -838:59:59.999999
+-837:59:59.999999 -837:59:59.999999
+-23:59:59.999999 -23:59:59.999999
+-00:59:59.999999 -00:59:59.999999
+-00:00:59.999999 -00:00:59.999999
+00:00:00.999999 00:00:00.999999
+00:00:59.999999 00:00:59.999999
+00:59:59.999999 00:59:59.999999
+23:59:59.999999 23:59:59.999999
+837:59:59.999999 837:59:59.999999
+838:59:59.999999 838:59:59.999999
+SELECT a, ROUND(a,-1) FROM t1;
+a ROUND(a,-1)
+-838:59:59.999999 -838:59:59
+-837:59:59.999999 -838:00:00
+-23:59:59.999999 -24:00:00
+-00:59:59.999999 -01:00:00
+-00:00:59.999999 -00:01:00
+00:00:00.999999 00:00:01
+00:00:59.999999 00:01:00
+00:59:59.999999 01:00:00
+23:59:59.999999 24:00:00
+837:59:59.999999 838:00:00
+838:59:59.999999 838:59:59
+SELECT a, ROUND(a,-6) FROM t1;
+a ROUND(a,-6)
+-838:59:59.999999 -838:59:59
+-837:59:59.999999 -838:00:00
+-23:59:59.999999 -24:00:00
+-00:59:59.999999 -01:00:00
+-00:00:59.999999 -00:01:00
+00:00:00.999999 00:00:01
+00:00:59.999999 00:01:00
+00:59:59.999999 01:00:00
+23:59:59.999999 24:00:00
+837:59:59.999999 838:00:00
+838:59:59.999999 838:59:59
+DROP TABLE t1;
+SET time_zone=DEFAULT;
diff --git a/mysql-test/main/type_time_hires.test b/mysql-test/main/type_time_hires.test
index 3785a23f1eb..0949738e949 100644
--- a/mysql-test/main/type_time_hires.test
+++ b/mysql-test/main/type_time_hires.test
@@ -10,3 +10,66 @@ select min(a - interval 1 hour), max(a - interval 1 hour) from t1 where a < 0;
drop table t1;
select cast(1e-6 as time(6));
+
+
+--echo #
+--echo # Start of 10.4 tests
+--echo #
+
+--echo #
+--echo # MDEV-20397 Support TIMESTAMP, DATETIME, TIME in ROUND() and TRUNCATE()
+--echo #
+
+CREATE TABLE t1 (a1 TIME(6), a2 TIME(6) NOT NULL);
+CREATE TABLE t2 AS SELECT
+ ROUND(a1) AS r1,
+ ROUND(a2) AS r2,
+ TRUNCATE(a1,0) AS t1,
+ TRUNCATE(a2,0) AS t2
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a TIME(6));
+INSERT INTO t1 VALUES
+('-838:59:59.999999'),
+('-837:59:59.999999'),
+('-23:59:59.999999'),
+('-00:59:59.999999'),
+('-00:00:59.999999'),
+('00:00:00.999999'),
+('00:00:59.999999'),
+('00:59:59.999999'),
+('23:59:59.999999'),
+('837:59:59.999999'),
+('838:59:59.999999');
+
+
+SELECT a, TRUNCATE(a,0) FROM t1;
+SELECT a, TRUNCATE(a,1) FROM t1;
+SELECT a, TRUNCATE(a,2) FROM t1;
+SELECT a, TRUNCATE(a,3) FROM t1;
+SELECT a, TRUNCATE(a,4) FROM t1;
+SELECT a, TRUNCATE(a,5) FROM t1;
+SELECT a, TRUNCATE(a,6) FROM t1;
+SELECT a, TRUNCATE(a,7) FROM t1;
+SELECT a, TRUNCATE(a,-1) FROM t1;
+SELECT a, TRUNCATE(a,-6) FROM t1;
+
+SELECT a, ROUND(a) FROM t1;
+SELECT a, ROUND(a,0) FROM t1;
+SELECT a, ROUND(a,1) FROM t1;
+SELECT a, ROUND(a,2) FROM t1;
+SELECT a, ROUND(a,3) FROM t1;
+SELECT a, ROUND(a,4) FROM t1;
+SELECT a, ROUND(a,5) FROM t1;
+SELECT a, ROUND(a,6) FROM t1;
+SELECT a, ROUND(a,7) FROM t1;
+SELECT a, ROUND(a,-1) FROM t1;
+SELECT a, ROUND(a,-6) FROM t1;
+
+DROP TABLE t1;
+
+SET time_zone=DEFAULT;
diff --git a/mysql-test/main/type_timestamp.result b/mysql-test/main/type_timestamp.result
index 97a70d042eb..d8c74f15c57 100644
--- a/mysql-test/main/type_timestamp.result
+++ b/mysql-test/main/type_timestamp.result
@@ -1267,5 +1267,35 @@ f
DROP TABLE t1;
SET sql_mode=DEFAULT;
#
+# MDEV-20417 Assertion `(m_ptr == __null) == item->null_value' failed in VDec::VDec(Item*)
+#
+CREATE TABLE t1 (a TIMESTAMP(4), b TIMESTAMP DEFAULT 0) ENGINE=MyISAM;
+INSERT IGNORE INTO t1 VALUES ('2001-01-01','2002-01-01'),('2003-01-01','2004-01-01');
+SELECT * FROM t1 WHERE DEFAULT(b) - a;
+a b
+Warnings:
+Warning 1916 Got overflow when converting '-20010101000000' to UNSIGNED INT. Value truncated
+Warning 1916 Got overflow when converting '-20030101000000' to UNSIGNED INT. Value truncated
+SELECT LEFT('', DEFAULT(b)-a) FROM t1;
+LEFT('', DEFAULT(b)-a)
+
+
+Warnings:
+Warning 1916 Got overflow when converting '-20010101000000' to UNSIGNED INT. Value truncated
+Warning 1916 Got overflow when converting '-20030101000000' to UNSIGNED INT. Value truncated
+DROP TABLE t1;
+CREATE TABLE t1 (a TIMESTAMP(4), b TIMESTAMP DEFAULT 0) ENGINE=MyISAM;
+INSERT IGNORE INTO t1 (a) VALUES ('2001-01-01'),('2003-01-01');
+SELECT * FROM t1 WHERE (SELECT MIN(b) FROM t1) - a;
+a b
+Warnings:
+Warning 1916 Got overflow when converting '-20010101000000' to UNSIGNED INT. Value truncated
+Warning 1916 Got overflow when converting '-20030101000000' to UNSIGNED INT. Value truncated
+SELECT (SELECT MIN(b) FROM t1) - a FROM t1;
+(SELECT MIN(b) FROM t1) - a
+-20010101000000.0000
+-20030101000000.0000
+DROP TABLE t1;
+#
# End of 10.4 tests
#
diff --git a/mysql-test/main/type_timestamp.test b/mysql-test/main/type_timestamp.test
index ce932b7720c..7b2311eaac3 100644
--- a/mysql-test/main/type_timestamp.test
+++ b/mysql-test/main/type_timestamp.test
@@ -837,6 +837,24 @@ SELECT GREATEST(a,b) AS f FROM t1 ORDER BY 1 DESC;
DROP TABLE t1;
SET sql_mode=DEFAULT;
+
+--echo #
+--echo # MDEV-20417 Assertion `(m_ptr == __null) == item->null_value' failed in VDec::VDec(Item*)
+--echo #
+
+CREATE TABLE t1 (a TIMESTAMP(4), b TIMESTAMP DEFAULT 0) ENGINE=MyISAM;
+INSERT IGNORE INTO t1 VALUES ('2001-01-01','2002-01-01'),('2003-01-01','2004-01-01');
+SELECT * FROM t1 WHERE DEFAULT(b) - a;
+SELECT LEFT('', DEFAULT(b)-a) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TIMESTAMP(4), b TIMESTAMP DEFAULT 0) ENGINE=MyISAM;
+INSERT IGNORE INTO t1 (a) VALUES ('2001-01-01'),('2003-01-01');
+SELECT * FROM t1 WHERE (SELECT MIN(b) FROM t1) - a;
+SELECT (SELECT MIN(b) FROM t1) - a FROM t1;
+DROP TABLE t1;
+
+
--echo #
--echo # End of 10.4 tests
--echo #
diff --git a/mysql-test/main/type_timestamp_hires.result b/mysql-test/main/type_timestamp_hires.result
index fa6adc075ed..dc69aa36b0f 100644
--- a/mysql-test/main/type_timestamp_hires.result
+++ b/mysql-test/main/type_timestamp_hires.result
@@ -17,8 +17,8 @@ a
2010-12-11 01:02:03.456
2010-12-11 03:04:05.789
2010-12-11 15:47:11.123
-select truncate(a, 6) from t1;
-truncate(a, 6)
+select cast(a AS double(30,6)) from t1;
+cast(a AS double(30,6))
0.000000
20101211002003.120000
20101211010203.457031
@@ -333,3 +333,298 @@ t1 CREATE TABLE `t1` (
`a` timestamp(5) NOT NULL DEFAULT '0000-00-00 00:00:00.00000' ON UPDATE current_timestamp(5)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
+#
+# Start of 10.4 tests
+#
+#
+# MDEV-20397 Support TIMESTAMP, DATETIME, TIME in ROUND() and TRUNCATE()
+#
+# ROUND(timestamp) and TRUNCATE(timestamp) currently return DATETIME.
+# This may change in the future to return TIMESTAMP.
+CREATE TABLE t1 (a1 TIMESTAMP(6) NULL DEFAULT '2001-01-01 00:00:00', a2 TIMESTAMP(6) NOT NULL);
+CREATE TABLE t2 AS SELECT
+ROUND(a1) AS r1,
+ROUND(a2) AS r2,
+TRUNCATE(a1,0) AS t1,
+TRUNCATE(a2,0) AS t2
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `r1` datetime DEFAULT NULL,
+ `r2` datetime DEFAULT NULL,
+ `t1` datetime DEFAULT NULL,
+ `t2` datetime NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+SET time_zone='+00:00';
+CREATE TABLE t1 (a TIMESTAMP(6));
+INSERT INTO t1 VALUES
+('1970-01-01 00:00:01.999999'),
+('2000-01-01 00:00:00.999999'),
+('2000-01-01 23:59:59.999999'),
+('2000-02-29 23:59:59.999999'),
+('2000-12-31 23:59:59.999999'),
+('2001-01-01 00:00:00.999999'),
+('2001-01-01 23:59:59.999999'),
+('2001-02-28 23:59:59.999999'),
+('2001-12-31 23:59:59.999999'),
+('2038-01-19 03:14:07.999999');
+SELECT a, TRUNCATE(a,0) FROM t1;
+a TRUNCATE(a,0)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:01
+2000-01-01 00:00:00.999999 2000-01-01 00:00:00
+2000-01-01 23:59:59.999999 2000-01-01 23:59:59
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59
+2001-01-01 00:00:00.999999 2001-01-01 00:00:00
+2001-01-01 23:59:59.999999 2001-01-01 23:59:59
+2001-02-28 23:59:59.999999 2001-02-28 23:59:59
+2001-12-31 23:59:59.999999 2001-12-31 23:59:59
+2038-01-19 03:14:07.999999 2038-01-19 03:14:07
+SELECT a, TRUNCATE(a,1) FROM t1;
+a TRUNCATE(a,1)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:01.9
+2000-01-01 00:00:00.999999 2000-01-01 00:00:00.9
+2000-01-01 23:59:59.999999 2000-01-01 23:59:59.9
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.9
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.9
+2001-01-01 00:00:00.999999 2001-01-01 00:00:00.9
+2001-01-01 23:59:59.999999 2001-01-01 23:59:59.9
+2001-02-28 23:59:59.999999 2001-02-28 23:59:59.9
+2001-12-31 23:59:59.999999 2001-12-31 23:59:59.9
+2038-01-19 03:14:07.999999 2038-01-19 03:14:07.9
+SELECT a, TRUNCATE(a,2) FROM t1;
+a TRUNCATE(a,2)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:01.99
+2000-01-01 00:00:00.999999 2000-01-01 00:00:00.99
+2000-01-01 23:59:59.999999 2000-01-01 23:59:59.99
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.99
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.99
+2001-01-01 00:00:00.999999 2001-01-01 00:00:00.99
+2001-01-01 23:59:59.999999 2001-01-01 23:59:59.99
+2001-02-28 23:59:59.999999 2001-02-28 23:59:59.99
+2001-12-31 23:59:59.999999 2001-12-31 23:59:59.99
+2038-01-19 03:14:07.999999 2038-01-19 03:14:07.99
+SELECT a, TRUNCATE(a,3) FROM t1;
+a TRUNCATE(a,3)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:01.999
+2000-01-01 00:00:00.999999 2000-01-01 00:00:00.999
+2000-01-01 23:59:59.999999 2000-01-01 23:59:59.999
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.999
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.999
+2001-01-01 00:00:00.999999 2001-01-01 00:00:00.999
+2001-01-01 23:59:59.999999 2001-01-01 23:59:59.999
+2001-02-28 23:59:59.999999 2001-02-28 23:59:59.999
+2001-12-31 23:59:59.999999 2001-12-31 23:59:59.999
+2038-01-19 03:14:07.999999 2038-01-19 03:14:07.999
+SELECT a, TRUNCATE(a,4) FROM t1;
+a TRUNCATE(a,4)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:01.9999
+2000-01-01 00:00:00.999999 2000-01-01 00:00:00.9999
+2000-01-01 23:59:59.999999 2000-01-01 23:59:59.9999
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.9999
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.9999
+2001-01-01 00:00:00.999999 2001-01-01 00:00:00.9999
+2001-01-01 23:59:59.999999 2001-01-01 23:59:59.9999
+2001-02-28 23:59:59.999999 2001-02-28 23:59:59.9999
+2001-12-31 23:59:59.999999 2001-12-31 23:59:59.9999
+2038-01-19 03:14:07.999999 2038-01-19 03:14:07.9999
+SELECT a, TRUNCATE(a,5) FROM t1;
+a TRUNCATE(a,5)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:01.99999
+2000-01-01 00:00:00.999999 2000-01-01 00:00:00.99999
+2000-01-01 23:59:59.999999 2000-01-01 23:59:59.99999
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.99999
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.99999
+2001-01-01 00:00:00.999999 2001-01-01 00:00:00.99999
+2001-01-01 23:59:59.999999 2001-01-01 23:59:59.99999
+2001-02-28 23:59:59.999999 2001-02-28 23:59:59.99999
+2001-12-31 23:59:59.999999 2001-12-31 23:59:59.99999
+2038-01-19 03:14:07.999999 2038-01-19 03:14:07.99999
+SELECT a, TRUNCATE(a,6) FROM t1;
+a TRUNCATE(a,6)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:01.999999
+2000-01-01 00:00:00.999999 2000-01-01 00:00:00.999999
+2000-01-01 23:59:59.999999 2000-01-01 23:59:59.999999
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.999999
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.999999
+2001-01-01 00:00:00.999999 2001-01-01 00:00:00.999999
+2001-01-01 23:59:59.999999 2001-01-01 23:59:59.999999
+2001-02-28 23:59:59.999999 2001-02-28 23:59:59.999999
+2001-12-31 23:59:59.999999 2001-12-31 23:59:59.999999
+2038-01-19 03:14:07.999999 2038-01-19 03:14:07.999999
+SELECT a, TRUNCATE(a,7) FROM t1;
+a TRUNCATE(a,7)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:01.999999
+2000-01-01 00:00:00.999999 2000-01-01 00:00:00.999999
+2000-01-01 23:59:59.999999 2000-01-01 23:59:59.999999
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.999999
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.999999
+2001-01-01 00:00:00.999999 2001-01-01 00:00:00.999999
+2001-01-01 23:59:59.999999 2001-01-01 23:59:59.999999
+2001-02-28 23:59:59.999999 2001-02-28 23:59:59.999999
+2001-12-31 23:59:59.999999 2001-12-31 23:59:59.999999
+2038-01-19 03:14:07.999999 2038-01-19 03:14:07.999999
+SELECT a, TRUNCATE(a,-1) FROM t1;
+a TRUNCATE(a,-1)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:01
+2000-01-01 00:00:00.999999 2000-01-01 00:00:00
+2000-01-01 23:59:59.999999 2000-01-01 23:59:59
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59
+2001-01-01 00:00:00.999999 2001-01-01 00:00:00
+2001-01-01 23:59:59.999999 2001-01-01 23:59:59
+2001-02-28 23:59:59.999999 2001-02-28 23:59:59
+2001-12-31 23:59:59.999999 2001-12-31 23:59:59
+2038-01-19 03:14:07.999999 2038-01-19 03:14:07
+SELECT a, TRUNCATE(a,-6) FROM t1;
+a TRUNCATE(a,-6)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:01
+2000-01-01 00:00:00.999999 2000-01-01 00:00:00
+2000-01-01 23:59:59.999999 2000-01-01 23:59:59
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59
+2001-01-01 00:00:00.999999 2001-01-01 00:00:00
+2001-01-01 23:59:59.999999 2001-01-01 23:59:59
+2001-02-28 23:59:59.999999 2001-02-28 23:59:59
+2001-12-31 23:59:59.999999 2001-12-31 23:59:59
+2038-01-19 03:14:07.999999 2038-01-19 03:14:07
+SELECT a, ROUND(a) FROM t1;
+a ROUND(a)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:02
+2000-01-01 00:00:00.999999 2000-01-01 00:00:01
+2000-01-01 23:59:59.999999 2000-01-02 00:00:00
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00
+2001-01-01 00:00:00.999999 2001-01-01 00:00:01
+2001-01-01 23:59:59.999999 2001-01-02 00:00:00
+2001-02-28 23:59:59.999999 2001-03-01 00:00:00
+2001-12-31 23:59:59.999999 2002-01-01 00:00:00
+2038-01-19 03:14:07.999999 2038-01-19 03:14:08
+SELECT a, ROUND(a,0) FROM t1;
+a ROUND(a,0)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:02
+2000-01-01 00:00:00.999999 2000-01-01 00:00:01
+2000-01-01 23:59:59.999999 2000-01-02 00:00:00
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00
+2001-01-01 00:00:00.999999 2001-01-01 00:00:01
+2001-01-01 23:59:59.999999 2001-01-02 00:00:00
+2001-02-28 23:59:59.999999 2001-03-01 00:00:00
+2001-12-31 23:59:59.999999 2002-01-01 00:00:00
+2038-01-19 03:14:07.999999 2038-01-19 03:14:08
+SELECT a, ROUND(a,1) FROM t1;
+a ROUND(a,1)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:02.0
+2000-01-01 00:00:00.999999 2000-01-01 00:00:01.0
+2000-01-01 23:59:59.999999 2000-01-02 00:00:00.0
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00.0
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00.0
+2001-01-01 00:00:00.999999 2001-01-01 00:00:01.0
+2001-01-01 23:59:59.999999 2001-01-02 00:00:00.0
+2001-02-28 23:59:59.999999 2001-03-01 00:00:00.0
+2001-12-31 23:59:59.999999 2002-01-01 00:00:00.0
+2038-01-19 03:14:07.999999 2038-01-19 03:14:08.0
+SELECT a, ROUND(a,2) FROM t1;
+a ROUND(a,2)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:02.00
+2000-01-01 00:00:00.999999 2000-01-01 00:00:01.00
+2000-01-01 23:59:59.999999 2000-01-02 00:00:00.00
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00.00
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00.00
+2001-01-01 00:00:00.999999 2001-01-01 00:00:01.00
+2001-01-01 23:59:59.999999 2001-01-02 00:00:00.00
+2001-02-28 23:59:59.999999 2001-03-01 00:00:00.00
+2001-12-31 23:59:59.999999 2002-01-01 00:00:00.00
+2038-01-19 03:14:07.999999 2038-01-19 03:14:08.00
+SELECT a, ROUND(a,3) FROM t1;
+a ROUND(a,3)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:02.000
+2000-01-01 00:00:00.999999 2000-01-01 00:00:01.000
+2000-01-01 23:59:59.999999 2000-01-02 00:00:00.000
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00.000
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00.000
+2001-01-01 00:00:00.999999 2001-01-01 00:00:01.000
+2001-01-01 23:59:59.999999 2001-01-02 00:00:00.000
+2001-02-28 23:59:59.999999 2001-03-01 00:00:00.000
+2001-12-31 23:59:59.999999 2002-01-01 00:00:00.000
+2038-01-19 03:14:07.999999 2038-01-19 03:14:08.000
+SELECT a, ROUND(a,4) FROM t1;
+a ROUND(a,4)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:02.0000
+2000-01-01 00:00:00.999999 2000-01-01 00:00:01.0000
+2000-01-01 23:59:59.999999 2000-01-02 00:00:00.0000
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00.0000
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00.0000
+2001-01-01 00:00:00.999999 2001-01-01 00:00:01.0000
+2001-01-01 23:59:59.999999 2001-01-02 00:00:00.0000
+2001-02-28 23:59:59.999999 2001-03-01 00:00:00.0000
+2001-12-31 23:59:59.999999 2002-01-01 00:00:00.0000
+2038-01-19 03:14:07.999999 2038-01-19 03:14:08.0000
+SELECT a, ROUND(a,5) FROM t1;
+a ROUND(a,5)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:02.00000
+2000-01-01 00:00:00.999999 2000-01-01 00:00:01.00000
+2000-01-01 23:59:59.999999 2000-01-02 00:00:00.00000
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00.00000
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00.00000
+2001-01-01 00:00:00.999999 2001-01-01 00:00:01.00000
+2001-01-01 23:59:59.999999 2001-01-02 00:00:00.00000
+2001-02-28 23:59:59.999999 2001-03-01 00:00:00.00000
+2001-12-31 23:59:59.999999 2002-01-01 00:00:00.00000
+2038-01-19 03:14:07.999999 2038-01-19 03:14:08.00000
+SELECT a, ROUND(a,6) FROM t1;
+a ROUND(a,6)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:01.999999
+2000-01-01 00:00:00.999999 2000-01-01 00:00:00.999999
+2000-01-01 23:59:59.999999 2000-01-01 23:59:59.999999
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.999999
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.999999
+2001-01-01 00:00:00.999999 2001-01-01 00:00:00.999999
+2001-01-01 23:59:59.999999 2001-01-01 23:59:59.999999
+2001-02-28 23:59:59.999999 2001-02-28 23:59:59.999999
+2001-12-31 23:59:59.999999 2001-12-31 23:59:59.999999
+2038-01-19 03:14:07.999999 2038-01-19 03:14:07.999999
+SELECT a, ROUND(a,7) FROM t1;
+a ROUND(a,7)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:01.999999
+2000-01-01 00:00:00.999999 2000-01-01 00:00:00.999999
+2000-01-01 23:59:59.999999 2000-01-01 23:59:59.999999
+2000-02-29 23:59:59.999999 2000-02-29 23:59:59.999999
+2000-12-31 23:59:59.999999 2000-12-31 23:59:59.999999
+2001-01-01 00:00:00.999999 2001-01-01 00:00:00.999999
+2001-01-01 23:59:59.999999 2001-01-01 23:59:59.999999
+2001-02-28 23:59:59.999999 2001-02-28 23:59:59.999999
+2001-12-31 23:59:59.999999 2001-12-31 23:59:59.999999
+2038-01-19 03:14:07.999999 2038-01-19 03:14:07.999999
+SELECT a, ROUND(a,-1) FROM t1;
+a ROUND(a,-1)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:02
+2000-01-01 00:00:00.999999 2000-01-01 00:00:01
+2000-01-01 23:59:59.999999 2000-01-02 00:00:00
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00
+2001-01-01 00:00:00.999999 2001-01-01 00:00:01
+2001-01-01 23:59:59.999999 2001-01-02 00:00:00
+2001-02-28 23:59:59.999999 2001-03-01 00:00:00
+2001-12-31 23:59:59.999999 2002-01-01 00:00:00
+2038-01-19 03:14:07.999999 2038-01-19 03:14:08
+SELECT a, ROUND(a,-6) FROM t1;
+a ROUND(a,-6)
+1970-01-01 00:00:01.999999 1970-01-01 00:00:02
+2000-01-01 00:00:00.999999 2000-01-01 00:00:01
+2000-01-01 23:59:59.999999 2000-01-02 00:00:00
+2000-02-29 23:59:59.999999 2000-03-01 00:00:00
+2000-12-31 23:59:59.999999 2001-01-01 00:00:00
+2001-01-01 00:00:00.999999 2001-01-01 00:00:01
+2001-01-01 23:59:59.999999 2001-01-02 00:00:00
+2001-02-28 23:59:59.999999 2001-03-01 00:00:00
+2001-12-31 23:59:59.999999 2002-01-01 00:00:00
+2038-01-19 03:14:07.999999 2038-01-19 03:14:08
+DROP TABLE t1;
+SET time_zone=DEFAULT;
+#
+# End of 10.4 tests
+#
diff --git a/mysql-test/main/type_timestamp_hires.test b/mysql-test/main/type_timestamp_hires.test
index 0b05f81ef42..f2e765d09fe 100644
--- a/mysql-test/main/type_timestamp_hires.test
+++ b/mysql-test/main/type_timestamp_hires.test
@@ -40,3 +40,73 @@ show create table t1;
create or replace table t1 (a timestamp(5) on update current_timestamp(6));
show create table t1;
drop table t1;
+
+
+--echo #
+--echo # Start of 10.4 tests
+--echo #
+
+--echo #
+--echo # MDEV-20397 Support TIMESTAMP, DATETIME, TIME in ROUND() and TRUNCATE()
+--echo #
+
+--echo # ROUND(timestamp) and TRUNCATE(timestamp) currently return DATETIME.
+--echo # This may change in the future to return TIMESTAMP.
+
+CREATE TABLE t1 (a1 TIMESTAMP(6) NULL DEFAULT '2001-01-01 00:00:00', a2 TIMESTAMP(6) NOT NULL);
+CREATE TABLE t2 AS SELECT
+ ROUND(a1) AS r1,
+ ROUND(a2) AS r2,
+ TRUNCATE(a1,0) AS t1,
+ TRUNCATE(a2,0) AS t2
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+
+SET time_zone='+00:00';
+
+CREATE TABLE t1 (a TIMESTAMP(6));
+INSERT INTO t1 VALUES
+('1970-01-01 00:00:01.999999'),
+('2000-01-01 00:00:00.999999'),
+('2000-01-01 23:59:59.999999'),
+('2000-02-29 23:59:59.999999'),
+('2000-12-31 23:59:59.999999'),
+('2001-01-01 00:00:00.999999'),
+('2001-01-01 23:59:59.999999'),
+('2001-02-28 23:59:59.999999'),
+('2001-12-31 23:59:59.999999'),
+('2038-01-19 03:14:07.999999');
+
+SELECT a, TRUNCATE(a,0) FROM t1;
+SELECT a, TRUNCATE(a,1) FROM t1;
+SELECT a, TRUNCATE(a,2) FROM t1;
+SELECT a, TRUNCATE(a,3) FROM t1;
+SELECT a, TRUNCATE(a,4) FROM t1;
+SELECT a, TRUNCATE(a,5) FROM t1;
+SELECT a, TRUNCATE(a,6) FROM t1;
+SELECT a, TRUNCATE(a,7) FROM t1;
+SELECT a, TRUNCATE(a,-1) FROM t1;
+SELECT a, TRUNCATE(a,-6) FROM t1;
+
+SELECT a, ROUND(a) FROM t1;
+SELECT a, ROUND(a,0) FROM t1;
+SELECT a, ROUND(a,1) FROM t1;
+SELECT a, ROUND(a,2) FROM t1;
+SELECT a, ROUND(a,3) FROM t1;
+SELECT a, ROUND(a,4) FROM t1;
+SELECT a, ROUND(a,5) FROM t1;
+SELECT a, ROUND(a,6) FROM t1;
+SELECT a, ROUND(a,7) FROM t1;
+SELECT a, ROUND(a,-1) FROM t1;
+SELECT a, ROUND(a,-6) FROM t1;
+
+DROP TABLE t1;
+
+SET time_zone=DEFAULT;
+
+--echo #
+--echo # End of 10.4 tests
+--echo #
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 214a6126f71..6cd7acbe36c 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -449,26 +449,36 @@ sub check_wsrep_support() {
# ADD scripts to $PATH to that wsrep_sst_* can be found
my ($spath) = grep { -f "$_/wsrep_sst_rsync"; } "$bindir/scripts", $path_client_bindir;
mtr_error("No SST scripts") unless $spath;
- $ENV{PATH}="$spath:$ENV{PATH}";
+ my $separator= (IS_WINDOWS) ? ';' : ':';
+ $ENV{PATH}="$spath$separator$ENV{PATH}";
# ADD mysql client library path to path so that wsrep_notify_cmd can find mysql
# client for loading the tables. (Don't assume each machine has mysql install)
my ($cpath) = grep { -f "$_/mysql"; } "$bindir/scripts", $path_client_bindir;
mtr_error("No scritps") unless $cpath;
- $ENV{PATH}="$cpath:$ENV{PATH}" unless $cpath eq $spath;
+ $ENV{PATH}="$cpath$separator$ENV{PATH}" unless $cpath eq $spath;
# ADD my_print_defaults script path to path so that SST scripts can find it
- my ($epath) = grep { -f "$_/my_print_defaults"; } "$bindir/extra", $path_client_bindir;
+ my $my_print_defaults_exe=
+ mtr_exe_maybe_exists(
+ "$bindir/extra/my_print_defaults",
+ "$path_client_bindir/my_print_defaults");
+ my $epath= "";
+ if ($my_print_defaults_exe ne "") {
+ $epath= dirname($my_print_defaults_exe);
+ }
mtr_error("No my_print_defaults") unless $epath;
- $ENV{PATH}="$epath:$ENV{PATH}" unless ($epath eq $spath) or
- ($epath eq $cpath);
+ $ENV{PATH}="$epath$separator$ENV{PATH}" unless ($epath eq $spath) or
+ ($epath eq $cpath);
$extra_path= $epath;
- if (which("socat")) {
- $ENV{MTR_GALERA_TFMT}="socat";
- } elsif (which("nc")) {
- $ENV{MTR_GALERA_TFMT}="nc";
+ if (!IS_WINDOWS) {
+ if (which("socat")) {
+ $ENV{MTR_GALERA_TFMT}="socat";
+ } elsif (which("nc")) {
+ $ENV{MTR_GALERA_TFMT}="nc";
+ }
}
# Check whether WSREP_PROVIDER environment variable is set.
@@ -515,8 +525,9 @@ sub check_mariabackup_support() {
"$bindir/extra/mariabackup$opt_vs_config/mariabackup",
"$path_client_bindir/mariabackup");
if ($mariabackup_exe ne "") {
- my ($bpath) = grep { -f "$_/mariabackup"; } "$bindir/extra/mariabackup$opt_vs_config", $path_client_bindir;
- $ENV{PATH}="$bpath:$ENV{PATH}" unless $bpath eq $extra_path;
+ my $bpath= dirname($mariabackup_exe);
+ my $separator= (IS_WINDOWS) ? ';' : ':';
+ $ENV{PATH}="$bpath$separator$ENV{PATH}" unless $bpath eq $extra_path;
$mariabackup_path= $bpath;
diff --git a/mysql-test/suite.pm b/mysql-test/suite.pm
index cf030dc8827..e21db289445 100644
--- a/mysql-test/suite.pm
+++ b/mysql-test/suite.pm
@@ -50,11 +50,11 @@ sub skip_combinations {
$skip{'include/have_mariabackup.inc'} = 'Need mariabackup'
unless ::have_mariabackup();
- $skip{'include/have_mariabackup.inc'} = 'Need ss'
- unless ::which("ss");
+ $skip{'include/have_mariabackup.inc'} = 'Need socket statistics utility'
+ unless IS_WINDOWS || ::which("ss");
$skip{'include/have_mariabackup.inc'} = 'Need socat or nc'
- unless $ENV{MTR_GALERA_TFMT};
+ unless IS_WINDOWS || $ENV{MTR_GALERA_TFMT};
$skip{'include/have_garbd.inc'} = 'Need garbd'
unless ::have_garbd();
diff --git a/mysql-test/suite/binlog/include/drop_temp_table.test b/mysql-test/suite/binlog/include/drop_temp_table.test
index 9139ac76017..7c95195eadc 100644
--- a/mysql-test/suite/binlog/include/drop_temp_table.test
+++ b/mysql-test/suite/binlog/include/drop_temp_table.test
@@ -150,16 +150,16 @@ RESET MASTER;
--echo # Test case for DROP query.
--connection default
-CREATE TABLE t1 (a INT) ENGINE=INNODB;
+CREATE TABLE t2 (a INT) ENGINE=INNODB;
--connection con1
-CREATE TEMPORARY TABLE t1 (b BLOB) ENGINE=INNODB;
+CREATE TEMPORARY TABLE t2 (b BLOB) ENGINE=INNODB;
--connection default
-DROP TABLE t1;
+DROP TABLE t2;
--connection con1
-DROP TABLE t1;
+DROP TABLE t2;
--connection default
--exec $MYSQL_BINLOG --force-if-open $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/bug28642318.sql
diff --git a/mysql-test/suite/binlog/r/binlog_row_drop_tmp_tbl.result b/mysql-test/suite/binlog/r/binlog_row_drop_tmp_tbl.result
index 60596be480f..10744956995 100644
--- a/mysql-test/suite/binlog/r/binlog_row_drop_tmp_tbl.result
+++ b/mysql-test/suite/binlog/r/binlog_row_drop_tmp_tbl.result
@@ -88,13 +88,13 @@ DROP TABLE IF EXISTS t1;
RESET MASTER;
# Test case for DROP query.
connection default;
-CREATE TABLE t1 (a INT) ENGINE=INNODB;
+CREATE TABLE t2 (a INT) ENGINE=INNODB;
connection con1;
-CREATE TEMPORARY TABLE t1 (b BLOB) ENGINE=INNODB;
+CREATE TEMPORARY TABLE t2 (b BLOB) ENGINE=INNODB;
connection default;
-DROP TABLE t1;
+DROP TABLE t2;
connection con1;
-DROP TABLE t1;
+DROP TABLE t2;
connection default;
# DROP table query fails with unknown table error without patch.
# Clean up
diff --git a/mysql-test/suite/binlog/r/binlog_stm_drop_tmp_tbl.result b/mysql-test/suite/binlog/r/binlog_stm_drop_tmp_tbl.result
index ae7852be9e3..99305abf175 100644
--- a/mysql-test/suite/binlog/r/binlog_stm_drop_tmp_tbl.result
+++ b/mysql-test/suite/binlog/r/binlog_stm_drop_tmp_tbl.result
@@ -116,13 +116,13 @@ DROP TABLE IF EXISTS t1;
RESET MASTER;
# Test case for DROP query.
connection default;
-CREATE TABLE t1 (a INT) ENGINE=INNODB;
+CREATE TABLE t2 (a INT) ENGINE=INNODB;
connection con1;
-CREATE TEMPORARY TABLE t1 (b BLOB) ENGINE=INNODB;
+CREATE TEMPORARY TABLE t2 (b BLOB) ENGINE=INNODB;
connection default;
-DROP TABLE t1;
+DROP TABLE t2;
connection con1;
-DROP TABLE t1;
+DROP TABLE t2;
connection default;
# DROP table query fails with unknown table error without patch.
# Clean up
diff --git a/mysql-test/suite/compat/oracle/r/table_value_constr.result b/mysql-test/suite/compat/oracle/r/table_value_constr.result
index fe09512f635..3621006d7dc 100644
--- a/mysql-test/suite/compat/oracle/r/table_value_constr.result
+++ b/mysql-test/suite/compat/oracle/r/table_value_constr.result
@@ -741,21 +741,21 @@ a b
explain extended select * from t1
where a in (values (1));
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery3> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery3> eq_ref distinct_key distinct_key 4 func 1 100.00
3 MATERIALIZED <derived2> ALL NULL NULL NULL NULL 2 100.00
2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1" semi join ((values (1)) "tvc_0") where "test"."t1"."a" = "tvc_0"."1"
+Note 1003 select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1" semi join ((values (1)) "tvc_0") where 1
explain extended select * from t1
where a in (select * from (values (1)) as tvc_0);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 2 100.00
3 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 /* select#1 */ select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1" semi join ((values (1)) "tvc_0") where "test"."t1"."a" = "tvc_0"."1"
+Note 1003 /* select#1 */ select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1" semi join ((values (1)) "tvc_0") where 1
# IN-subquery with VALUES structure(s) : UNION with VALUES on the first place
select * from t1
where a in (values (1) union select 2);
@@ -976,21 +976,21 @@ a b
explain extended select * from t1
where a = any (values (1),(2));
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery3> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery3> eq_ref distinct_key distinct_key 4 func 1 100.00
3 MATERIALIZED <derived2> ALL NULL NULL NULL NULL 2 100.00
2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1" semi join ((values (1),(2)) "tvc_0") where "test"."t1"."a" = "tvc_0"."1"
+Note 1003 select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1" semi join ((values (1),(2)) "tvc_0") where 1
explain extended select * from t1
where a = any (select * from (values (1),(2)) as tvc_0);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2 100.00
-1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 2 100.00
3 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 /* select#1 */ select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1" semi join ((values (1),(2)) "tvc_0") where "test"."t1"."a" = "tvc_0"."1"
+Note 1003 /* select#1 */ select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1" semi join ((values (1),(2)) "tvc_0") where 1
# ANY-subquery with VALUES structure(s) : UNION with VALUES on the first place
select * from t1
where a = any (values (1) union select 2);
diff --git a/mysql-test/suite/encryption/r/file_creation.result b/mysql-test/suite/encryption/r/file_creation.result
new file mode 100644
index 00000000000..22fe271145c
--- /dev/null
+++ b/mysql-test/suite/encryption/r/file_creation.result
@@ -0,0 +1,26 @@
+SET GLOBAL innodb_encrypt_tables = ON;
+SET GLOBAL innodb_encryption_threads = 1;
+SET GLOBAL innodb_max_dirty_pages_pct = 99;
+SHOW VARIABLES LIKE 'innodb_encrypt%';
+Variable_name Value
+innodb_encrypt_log OFF
+innodb_encrypt_tables ON
+innodb_encrypt_temporary_tables OFF
+innodb_encryption_rotate_key_age 1
+innodb_encryption_rotation_iops 100
+innodb_encryption_threads 1
+CREATE TABLE t1(f1 INT NOT NULL, f2 CHAR(255), f3 CHAR(255),
+f4 CHAR(255), f5 CHAR(255))ENGINE=INNODB;
+INSERT INTO t1 VALUES(1, "mysql", "mariadb", "batman", "superman");
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+# Wait max 10 min for key encryption threads to encrypt all spaces
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
+test.t1 optimize status OK
+ALTER TABLE t1 FORCE;
+# Kill the server
+DROP TABLE t1;
diff --git a/mysql-test/suite/encryption/t/file_creation.opt b/mysql-test/suite/encryption/t/file_creation.opt
new file mode 100644
index 00000000000..7d3f2da7971
--- /dev/null
+++ b/mysql-test/suite/encryption/t/file_creation.opt
@@ -0,0 +1 @@
+--innodb-tablespaces-encryption
diff --git a/mysql-test/suite/encryption/t/file_creation.test b/mysql-test/suite/encryption/t/file_creation.test
new file mode 100644
index 00000000000..6b0126831a4
--- /dev/null
+++ b/mysql-test/suite/encryption/t/file_creation.test
@@ -0,0 +1,41 @@
+--source include/have_innodb.inc
+--source include/have_example_key_management_plugin.inc
+let $restart_noprint=2;
+# embedded does not support restart
+-- source include/not_embedded.inc
+
+#
+# MDEV-19348 MariaBackup prepare fails with InnoDB: Database page corruption
+# on disk or a failed file read
+#
+
+SET GLOBAL innodb_encrypt_tables = ON;
+SET GLOBAL innodb_encryption_threads = 1;
+SET GLOBAL innodb_max_dirty_pages_pct = 99;
+SHOW VARIABLES LIKE 'innodb_encrypt%';
+
+CREATE TABLE t1(f1 INT NOT NULL, f2 CHAR(255), f3 CHAR(255),
+ f4 CHAR(255), f5 CHAR(255))ENGINE=INNODB;
+
+INSERT INTO t1 VALUES(1, "mysql", "mariadb", "batman", "superman");
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+
+--let $tables_count= `select count(*) + 1 from information_schema.tables where engine = 'InnoDB'`
+
+--echo # Wait max 10 min for key encryption threads to encrypt all spaces
+--let $wait_timeout= 600
+--let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0;
+--source include/wait_condition.inc
+
+OPTIMIZE TABLE t1;
+
+--source ../../suite/innodb/include/no_checkpoint_start.inc
+ALTER TABLE t1 FORCE;
+--let CLEANUP_IF_CHECKPOINT=DROP TABLE t1;
+--source ../../suite/innodb/include/no_checkpoint_end.inc
+
+--source include/start_mysqld.inc
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_performance_schema.result b/mysql-test/suite/galera/r/galera_performance_schema.result
index 86d773bb1ef..ea0b6ad9ef4 100644
--- a/mysql-test/suite/galera/r/galera_performance_schema.result
+++ b/mysql-test/suite/galera/r/galera_performance_schema.result
@@ -7,7 +7,6 @@ WHERE name LIKE 'thread/sql/wsrep%'
ORDER BY name;
name thread/sql/wsrep_applier_thread
name thread/sql/wsrep_rollbacker_thread
-name thread/sql/wsrep_rollbacker_thread
use test;
create table t1 (a int not null primary key) engine=innodb;
insert into t1 values (1),(2);
diff --git a/mysql-test/suite/galera/t/galera_load_data.test b/mysql-test/suite/galera/t/galera_load_data.test
index f1dfd1af7fc..66526bea5e1 100644
--- a/mysql-test/suite/galera/t/galera_load_data.test
+++ b/mysql-test/suite/galera/t/galera_load_data.test
@@ -1,6 +1,5 @@
--source include/galera_cluster.inc
-
--connection node_1
create database cardtest02;
@@ -45,16 +44,30 @@ let $table_rows1 = `SELECT table_rows from information_schema.tables WHERE TABLE
let $avg_row_length1 = `SELECT avg_row_length from information_schema.tables WHERE TABLE_NAME = 'cardtest_tbl'`;
let $data_length1 = `SELECT data_length from information_schema.tables WHERE TABLE_NAME = 'cardtest_tbl'`;
+--let $wait_timeout=600
+--let $wait_condition = SELECT table_rows = 301 from information_schema.tables WHERE TABLE_NAME = 'cardtest_tbl';
+--source include/wait_condition.inc
+
select count(*) from cardtest_tbl;
+let $cardinality1 = `SELECT cardinality from information_schema.statistics WHERE TABLE_NAME = 'cardtest_tbl'`;
+let $table_rows1 = `SELECT table_rows from information_schema.tables WHERE TABLE_NAME = 'cardtest_tbl'`;
+let $avg_row_length1 = `SELECT avg_row_length from information_schema.tables WHERE TABLE_NAME = 'cardtest_tbl'`;
+let $data_length1 = `SELECT data_length from information_schema.tables WHERE TABLE_NAME = 'cardtest_tbl'`;
+
--connection node_2
set session wsrep_sync_wait=15;
use cardtest02;
+
+--let $wait_timeout=600
+--let $wait_condition = SELECT table_rows = 301 from information_schema.tables WHERE TABLE_NAME = 'cardtest_tbl';
+--source include/wait_condition.inc
+
select count(*) from cardtest_tbl;
if (`SELECT cardinality <> $cardinality1 from information_schema.statistics WHERE TABLE_NAME = 'cardtest_tbl'`)
{
-SELECT cardinality from from information_schema.statistics WHERE TABLE_NAME = 'cardtest_tbl';
+SELECT cardinality from information_schema.statistics WHERE TABLE_NAME = 'cardtest_tbl';
}
if (`SELECT table_rows <> $table_rows1 from information_schema.tables WHERE TABLE_NAME = 'cardtest_tbl'`)
{
diff --git a/mysql-test/suite/gcol/r/gcol_select_innodb.result b/mysql-test/suite/gcol/r/gcol_select_innodb.result
index f933fe22bdc..6c5b6d8c47e 100644
--- a/mysql-test/suite/gcol/r/gcol_select_innodb.result
+++ b/mysql-test/suite/gcol/r/gcol_select_innodb.result
@@ -699,8 +699,8 @@ WHERE t4.c1 < 'o'
)
AND t1.i1 <= t3.i2_key;
id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4
1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join)
1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t4.i1 1 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join)
2 MATERIALIZED t4 ALL NULL NULL NULL NULL 3 Using where
@@ -754,8 +754,8 @@ WHERE t4.c1 < 'o'
)
AND t1.i1 <= t3.i2_key;
id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4
1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join)
1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t4.i1 1 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join)
2 MATERIALIZED t4 ALL NULL NULL NULL NULL 3 Using where
@@ -810,8 +810,8 @@ WHERE t4.c1 < 'o'
)
AND t1.i1 <= t3.i2_key;
id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4
1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join)
1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t4.i1 1 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join)
2 MATERIALIZED t4 ALL NULL NULL NULL NULL 3 Using where
@@ -874,8 +874,8 @@ WHERE t4.c1 < 'o'
)
AND t1.i1 <= t3.i2_key;
id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4
1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join)
1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t4.i1 1 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join)
2 MATERIALIZED t4 ALL NULL NULL NULL NULL 3 Using where
diff --git a/mysql-test/suite/gcol/r/gcol_select_myisam.result b/mysql-test/suite/gcol/r/gcol_select_myisam.result
index 45c3f73ed8e..c19ea3207ca 100644
--- a/mysql-test/suite/gcol/r/gcol_select_myisam.result
+++ b/mysql-test/suite/gcol/r/gcol_select_myisam.result
@@ -1325,8 +1325,8 @@ WHERE t4.c1 < 'o'
)
AND t1.i1 <= t3.i2_key;
id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4
1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join)
1 PRIMARY t3 eq_ref PRIMARY,v_idx PRIMARY 4 test.t4.i1 1 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join)
2 MATERIALIZED t4 ALL NULL NULL NULL NULL 3 Using where
@@ -1381,8 +1381,8 @@ WHERE t4.c1 < 'o'
)
AND t1.i1 <= t3.i2_key;
id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4
1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join)
1 PRIMARY t3 eq_ref PRIMARY,v_idx,v_idx2 PRIMARY 4 test.t4.i1 1 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join)
2 MATERIALIZED t4 ALL NULL NULL NULL NULL 3 Using where
@@ -1439,8 +1439,8 @@ WHERE t4.c1 < 'o'
)
AND t1.i1 <= t3.i2_key;
id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4
1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join)
1 PRIMARY t3 eq_ref PRIMARY,v_idx2 PRIMARY 4 test.t4.i1 1 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join)
2 MATERIALIZED t4 ALL NULL NULL NULL NULL 3 Using where
@@ -1506,8 +1506,8 @@ WHERE t4.c1 < 'o'
)
AND t1.i1 <= t3.i2_key;
id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4
1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2
-1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using join buffer (flat, BNL join)
1 PRIMARY t3 eq_ref PRIMARY,v_idx PRIMARY 4 test.t4.i1 1 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join)
2 MATERIALIZED t4 ALL NULL NULL NULL NULL 3 Using where
diff --git a/mysql-test/suite/innodb/r/foreign-keys.result b/mysql-test/suite/innodb/r/foreign-keys.result
index f64e84fe429..62b4d37a979 100644
--- a/mysql-test/suite/innodb/r/foreign-keys.result
+++ b/mysql-test/suite/innodb/r/foreign-keys.result
@@ -161,3 +161,62 @@ c d
6 30
drop table t2, t1;
drop user foo;
+#
+# MDEV-17187 table doesn't exist in engine after ALTER other tables
+# with CONSTRAINTs
+#
+set foreign_key_checks=on;
+create table t1 (id int not null primary key) engine=innodb;
+create table t2 (id int not null primary key, fid int not null,
+CONSTRAINT fk_fid FOREIGN KEY (fid) REFERENCES t1 (id))engine=innodb;
+insert into t1 values (1), (2), (3);
+insert into t2 values (1, 1), (2, 1), (3, 2);
+set foreign_key_checks=off;
+alter table t2 drop index fk_fid;
+set foreign_key_checks=on;
+delete from t1 where id=2;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `fk_fid` FOREIGN KEY (`fid`) REFERENCES `t1` (`id`))
+insert into t2 values(4, 99);
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `fk_fid` FOREIGN KEY (`fid`) REFERENCES `t1` (`id`))
+select * from t1;
+id
+1
+2
+3
+select * from t2;
+id fid
+1 1
+2 1
+3 2
+set foreign_key_checks=off;
+delete from t1 where id=2;
+insert into t2 values(4, 99);
+set foreign_key_checks=on;
+select * from t1;
+id
+1
+3
+select * from t2;
+id fid
+1 1
+2 1
+3 2
+4 99
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `id` int(11) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `id` int(11) NOT NULL,
+ `fid` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `fk_fid` FOREIGN KEY (`fid`) REFERENCES `t1` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+drop table t1,t2;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails
+drop table t1,t2;
+ERROR 42S02: Unknown table 'test.t2'
diff --git a/mysql-test/suite/innodb/r/innodb-fk-warnings.result b/mysql-test/suite/innodb/r/innodb-fk-warnings.result
index 0832e6ae9ff..21e7c23d249 100644
--- a/mysql-test/suite/innodb/r/innodb-fk-warnings.result
+++ b/mysql-test/suite/innodb/r/innodb-fk-warnings.result
@@ -25,7 +25,7 @@ create table t2(a int, constraint a foreign key a (a) references t1(a)) engine=i
ERROR HY000: Can't create table `test`.`t2` (errno: 150 "Foreign key constraint is incorrectly formed")
show warnings;
Level Code Message
-Warning 150 Create table '`test`.`t2`' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns near ' foreign key a (a) references t1(a)) engine=innodb'.
+Warning 150 Create table `test`.`t2` with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns near ' foreign key a (a) references t1(a)) engine=innodb'.
Error 1005 Can't create table `test`.`t2` (errno: 150 "Foreign key constraint is incorrectly formed")
Warning 1215 Cannot add foreign key constraint for `t2`
drop table t1;
@@ -42,7 +42,7 @@ alter table t2 add constraint b foreign key (b) references t2(b);
ERROR HY000: Can't create table `test`.`t2` (errno: 150 "Foreign key constraint is incorrectly formed")
show warnings;
Level Code Message
-Warning 150 Alter table '`test`.`t2`' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns near ' foreign key (b) references t2(b)'.
+Warning 150 Alter table `test`.`t2` with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns near ' foreign key (b) references t2(b)'.
Error 1005 Can't create table `test`.`t2` (errno: 150 "Foreign key constraint is incorrectly formed")
Warning 1215 Cannot add foreign key constraint for `t2`
drop table t2, t1;
diff --git a/mysql-test/suite/innodb/r/innodb-read-view.result b/mysql-test/suite/innodb/r/innodb-read-view.result
new file mode 100644
index 00000000000..e01d8a110e6
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb-read-view.result
@@ -0,0 +1,222 @@
+CREATE TABLE t1 (c1 INT , c2 CHAR(10), PRIMARY KEY (c1)) ENGINE = InnoDB;
+INSERT INTO t1 VALUES(0, "0");
+INSERT INTO t1 VALUES(1, "1");
+INSERT INTO t1 VALUES(2, "2");
+INSERT INTO t1 VALUES(3, "3");
+CREATE TABLE t2 (c1 INT , c2 CHAR(10), PRIMARY KEY (c1)) ENGINE = InnoDB;
+INSERT INTO t2 VALUES(0, "a");
+INSERT INTO t2 VALUES(1, "b");
+INSERT INTO t2 VALUES(2, "c");
+INSERT INTO t2 VALUES(3, "d");
+connect con1,localhost,root,,;
+connect con2,localhost,root,,;
+connection con1;
+'T1'
+SET AUTOCOMMIT=0;
+BEGIN;
+SELECT * FROM t2;
+c1 c2
+0 a
+1 b
+2 c
+3 d
+connection default;
+'T2'
+SET AUTOCOMMIT=0;
+BEGIN;
+SELECT * FROM t1;
+c1 c2
+0 0
+1 1
+2 2
+3 3
+connection con2;
+'T3'
+SET AUTOCOMMIT=0;
+SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+BEGIN;
+SELECT * FROM t1;
+c1 c2
+0 0
+1 1
+2 2
+3 3
+SELECT * FROM t2;
+c1 c2
+0 a
+1 b
+2 c
+3 d
+connection con1;
+'T1'
+UPDATE t2 SET c1 = c1 + 100;
+SELECT * FROM t2;
+c1 c2
+100 a
+101 b
+102 c
+103 d
+COMMIT;
+connection default;
+'T2'
+UPDATE t1 SET c1 = c1 + 100;
+SELECT * FROM t1;
+c1 c2
+100 0
+101 1
+102 2
+103 3
+COMMIT;
+connection con2;
+'T3'
+SET DEBUG_SYNC='row_search_for_mysql_before_return WAIT_FOR waiting1';
+SELECT * FROM t1;;
+connection default;
+'T2'
+SET DEBUG_SYNC='now SIGNAL waiting1';
+'Signalled T3'
+connection con2;
+'T3'
+c1 c2
+0 0
+1 1
+2 2
+3 3
+connection con2;
+'T3'
+SET DEBUG_SYNC='row_search_for_mysql_before_return WAIT_FOR waiting1';
+SELECT * FROM t2;;
+connection default;
+'T2'
+SET DEBUG_SYNC='now SIGNAL waiting1';
+'Signalled T3'
+connection con2;
+'T3'
+c1 c2
+0 a
+1 b
+2 c
+3 d
+connection default;
+disconnect con1;
+disconnect con2;
+connect con1,localhost,root,,;
+connect con2,localhost,root,,;
+connection con1;
+'T1'
+SET AUTOCOMMIT=0;
+BEGIN;
+SELECT * FROM t1;
+c1 c2
+100 0
+101 1
+102 2
+103 3
+connection default;
+'T2'
+SET AUTOCOMMIT=0;
+BEGIN;
+SELECT * FROM t2;
+c1 c2
+100 a
+101 b
+102 c
+103 d
+UPDATE t2 SET c1 = c1 + 100;
+SELECT * FROM t2;
+c1 c2
+200 a
+201 b
+202 c
+203 d
+COMMIT;
+connection con2;
+'T3'
+SET AUTOCOMMIT=0;
+SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+BEGIN;
+SELECT * FROM t1;
+c1 c2
+100 0
+101 1
+102 2
+103 3
+SELECT * FROM t2;
+c1 c2
+200 a
+201 b
+202 c
+203 d
+connection con1;
+'T1'
+UPDATE t1 SET c1 = c1 + 100;
+SELECT * FROM t1;
+c1 c2
+200 0
+201 1
+202 2
+203 3
+COMMIT;
+connection con2;
+'T3'
+SET DEBUG_SYNC='row_select_wait WAIT_FOR waiting1';
+SELECT * FROM t1;;
+connection con1;
+'T2'
+SET DEBUG_SYNC='now SIGNAL waiting1';
+'Signalled T3'
+connection con2;
+'T3'
+c1 c2
+100 0
+101 1
+102 2
+103 3
+connection con2;
+'T3'
+SET DEBUG_SYNC='row_select_wait WAIT_FOR waiting1';
+SELECT * FROM t2;;
+connection default;
+'T2'
+SET DEBUG_SYNC='now SIGNAL waiting1';
+'Signalled T3'
+connection con2;
+'T3'
+c1 c2
+200 a
+201 b
+202 c
+203 d
+connection default;
+disconnect con1;
+disconnect con2;
+DROP TABLE t1;
+DROP TABLE t2;
+#
+# Bug 21433768: NON-REPEATABLE READ WITH REPEATABLE READ ISOLATION
+#
+connect con1,localhost,root,,;
+CREATE TABLE t1(col1 INT PRIMARY KEY, col2 INT) ENGINE = InnoDB;
+INSERT INTO t1 values (1, 0), (2, 0);
+SELECT * FROM t1 ORDER BY col1;
+col1 col2
+1 0
+2 0
+START TRANSACTION;
+UPDATE t1 SET col2 = 100;
+SET DEBUG_SYNC = 'after_trx_committed_in_memory SIGNAL s1 WAIT_FOR s2';
+COMMIT;;
+connection default;
+SET DEBUG_SYNC = 'now WAIT_FOR s1';
+UPDATE t1 SET col2 = col2 + 10 where col1 = 1;
+COMMIT;
+SELECT * FROM t1 ORDER BY col1;
+col1 col2
+1 110
+2 100
+SET DEBUG_SYNC = 'now SIGNAL s2';
+connection con1;
+disconnect con1;
+connection default;
+DROP TABLE t1;
+SET DEBUG_SYNC= 'RESET';
diff --git a/mysql-test/suite/innodb/r/innodb-system-table-view.result b/mysql-test/suite/innodb/r/innodb-system-table-view.result
index 7685cd121e2..11fc1ae8cf9 100644
--- a/mysql-test/suite/innodb/r/innodb-system-table-view.result
+++ b/mysql-test/suite/innodb/r/innodb-system-table-view.result
@@ -1,3 +1,5 @@
+SET @save_frequency=@@GLOBAL.innodb_purge_rseg_truncate_frequency;
+SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
SELECT table_id INTO @table_stats_id FROM information_schema.innodb_sys_tables
WHERE name = 'mysql/innodb_table_stats';
SELECT table_id INTO @index_stats_id FROM information_schema.innodb_sys_tables
@@ -108,6 +110,7 @@ SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
ID FOR_COL_NAME REF_COL_NAME POS
test/constraint_test parent_id id 0
INSERT INTO parent VALUES(1);
+InnoDB 0 transactions not purged
SELECT name, num_rows, ref_count
FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS
WHERE name LIKE "%parent";
@@ -169,6 +172,7 @@ INSERT INTO parent VALUES(1, 9);
SELECT * FROM parent WHERE id IN (SELECT id FROM parent);
id newid
1 9
+InnoDB 0 transactions not purged
SELECT name, num_rows, ref_count
FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS
WHERE name LIKE "%parent";
@@ -176,3 +180,4 @@ name num_rows ref_count
test/parent 1 2
DROP TABLE child;
DROP TABLE parent;
+SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency;
diff --git a/mysql-test/suite/innodb/r/innodb_bug68148.result b/mysql-test/suite/innodb/r/innodb_bug68148.result
index ee6c1d62f53..7206bccd50f 100644
--- a/mysql-test/suite/innodb/r/innodb_bug68148.result
+++ b/mysql-test/suite/innodb/r/innodb_bug68148.result
@@ -18,9 +18,7 @@ Tables_in_test
main
ref_table1
ref_table2
-# restart and see if we can still access the main table
# restart
-SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE `main` ADD INDEX `idx_1` (`ref_id1`);
SHOW CREATE TABLE `main`;
Table Create Table
diff --git a/mysql-test/suite/innodb/r/innodb_bug84958.result b/mysql-test/suite/innodb/r/innodb_bug84958.result
index 1a59a10eb2f..b721c73a0fc 100644
--- a/mysql-test/suite/innodb/r/innodb_bug84958.result
+++ b/mysql-test/suite/innodb/r/innodb_bug84958.result
@@ -4,13 +4,17 @@
#
# Set up the test with a procedure and a function.
#
+SET @saved_frequency= @@GLOBAL.innodb_purge_rseg_truncate_frequency;
+SET GLOBAL innodb_purge_rseg_truncate_frequency= 1;
CREATE PROCEDURE insert_n(start int, end int)
BEGIN
DECLARE i INT DEFAULT start;
+START TRANSACTION;
WHILE i <= end do
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = i;
SET i = i + 1;
END WHILE;
+COMMIT;
END~~
CREATE FUNCTION num_pages_get()
RETURNS INT
@@ -47,13 +51,14 @@ connection default;
# Connect to default and record how many pages were accessed
# when selecting the record using the secondary key.
#
+InnoDB 4 transactions not purged
SET @num_pages_1 = num_pages_get();
SELECT * FROM t1 force index (b);
a b c
SET @num_pages_2= num_pages_get();
-SELECT @num_pages_2 - @num_pages_1 < 500;
-@num_pages_2 - @num_pages_1 < 500
-1
+SELECT IF(@num_pages_2 - @num_pages_1 < 5000, 'OK', @num_pages_2 - @num_pages_1) num_pages_diff;
+num_pages_diff
+OK
#
# Commit and show the final record.
#
@@ -76,6 +81,7 @@ test.t1 check status OK
#
disconnect con2;
disconnect con3;
+SET GLOBAL innodb_purge_rseg_truncate_frequency= @saved_frequency;
DROP TABLE t1;
DROP PROCEDURE insert_n;
DROP FUNCTION num_pages_get;
diff --git a/mysql-test/suite/innodb/r/innodb_mysql.result b/mysql-test/suite/innodb/r/innodb_mysql.result
index b78988e08a8..b83dba5345e 100644
--- a/mysql-test/suite/innodb/r/innodb_mysql.result
+++ b/mysql-test/suite/innodb/r/innodb_mysql.result
@@ -383,6 +383,17 @@ INSERT INTO t1(id, dept, age, name) VALUES
(3996, 'cs4', 20, 'rs2'), (4003, 'cs5', 10, 'rs3'), (4004, 'cs6', 20, 'rs3'),
(4011, 'cs7', 10, 'rs4'), (4012, 'cs8', 20, 'rs4'), (4019, 'cs9', 10, 'rs5'),
(4020, 'cs10', 20, 'rs5'),(4027, 'cs11', 10, 'rs6'),(4028, 'cs12', 20, 'rs6');
+set
+@tmp_uss=@@use_stat_tables,
+@tmp_occ=@@optimizer_use_condition_selectivity;
+set
+use_stat_tables='preferably',
+optimizer_use_condition_selectivity=4;
+analyze table t1 persistent for all;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+flush tables;
EXPLAIN SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref name name 22 const 2 Using where; Using index
@@ -398,6 +409,9 @@ id select_type table type possible_keys key key_len ref rows Extra
SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5';
name dept
DROP TABLE t1;
+set
+use_stat_tables=@tmp_uss,
+optimizer_use_condition_selectivity=@tmp_occ;
drop table if exists t1;
show variables like 'innodb_rollback_on_timeout';
Variable_name Value
@@ -3166,8 +3180,8 @@ SELECT COUNT(*) FROM
(SELECT * FROM t1 FORCE INDEX (idx,PRIMARY)
WHERE a BETWEEN 2 AND 7 OR pk=1000000) AS t;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <derived2> ALL NULL NULL NULL NULL 1537
-2 DERIVED t1 index_merge PRIMARY,idx idx,PRIMARY 5,4 NULL 1537 Using sort_union(idx,PRIMARY); Using where
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL #
+2 DERIVED t1 index_merge PRIMARY,idx idx,PRIMARY 5,4 NULL # Using sort_union(idx,PRIMARY); Using where
SELECT COUNT(*) FROM
(SELECT * FROM t1 FORCE INDEX (idx,PRIMARY)
WHERE a BETWEEN 2 AND 7 OR pk=1000000) AS t;
diff --git a/mysql-test/suite/innodb/r/instant_alter.result b/mysql-test/suite/innodb/r/instant_alter.result
index 3122c15fae0..3139bbd152c 100644
--- a/mysql-test/suite/innodb/r/instant_alter.result
+++ b/mysql-test/suite/innodb/r/instant_alter.result
@@ -498,6 +498,29 @@ DELETE FROM t1;
COMMIT;
InnoDB 0 transactions not purged
DROP TABLE t1;
+CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB ROW_FORMAT=REDUNDANT;
+INSERT INTO t1 VALUES (7);
+ALTER TABLE t1 ADD COLUMN c INT NOT NULL DEFAULT 0;
+ALTER TABLE t1 ADD INDEX (c);
+BEGIN;
+DELETE FROM t1;
+INSERT INTO t1 VALUES (4,0),(7,77);
+COMMIT;
+BEGIN;
+DELETE FROM t1 WHERE a=7;
+UPDATE t1 SET a=7;
+COMMIT;
+SELECT * FROM t1 FORCE INDEX(PRIMARY);
+a c
+7 0
+SELECT * FROM t1 FORCE INDEX(c);
+a c
+7 0
+DELETE FROM t1;
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
CREATE TABLE t1 (a INT, b INT UNIQUE) ENGINE=InnoDB ROW_FORMAT=REDUNDANT;
INSERT INTO t1 (a) VALUES (NULL), (NULL);
ALTER TABLE t1 DROP a, ADD COLUMN a INT;
@@ -1326,6 +1349,29 @@ DELETE FROM t1;
COMMIT;
InnoDB 0 transactions not purged
DROP TABLE t1;
+CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB ROW_FORMAT=COMPACT;
+INSERT INTO t1 VALUES (7);
+ALTER TABLE t1 ADD COLUMN c INT NOT NULL DEFAULT 0;
+ALTER TABLE t1 ADD INDEX (c);
+BEGIN;
+DELETE FROM t1;
+INSERT INTO t1 VALUES (4,0),(7,77);
+COMMIT;
+BEGIN;
+DELETE FROM t1 WHERE a=7;
+UPDATE t1 SET a=7;
+COMMIT;
+SELECT * FROM t1 FORCE INDEX(PRIMARY);
+a c
+7 0
+SELECT * FROM t1 FORCE INDEX(c);
+a c
+7 0
+DELETE FROM t1;
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
CREATE TABLE t1 (a INT, b INT UNIQUE) ENGINE=InnoDB ROW_FORMAT=COMPACT;
INSERT INTO t1 (a) VALUES (NULL), (NULL);
ALTER TABLE t1 DROP a, ADD COLUMN a INT;
@@ -2154,6 +2200,29 @@ DELETE FROM t1;
COMMIT;
InnoDB 0 transactions not purged
DROP TABLE t1;
+CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
+INSERT INTO t1 VALUES (7);
+ALTER TABLE t1 ADD COLUMN c INT NOT NULL DEFAULT 0;
+ALTER TABLE t1 ADD INDEX (c);
+BEGIN;
+DELETE FROM t1;
+INSERT INTO t1 VALUES (4,0),(7,77);
+COMMIT;
+BEGIN;
+DELETE FROM t1 WHERE a=7;
+UPDATE t1 SET a=7;
+COMMIT;
+SELECT * FROM t1 FORCE INDEX(PRIMARY);
+a c
+7 0
+SELECT * FROM t1 FORCE INDEX(c);
+a c
+7 0
+DELETE FROM t1;
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
CREATE TABLE t1 (a INT, b INT UNIQUE) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
INSERT INTO t1 (a) VALUES (NULL), (NULL);
ALTER TABLE t1 DROP a, ADD COLUMN a INT;
@@ -2544,7 +2613,7 @@ SELECT variable_value-@old_instant instants
FROM information_schema.global_status
WHERE variable_name = 'innodb_instant_alter_column';
instants
-181
+184
SET GLOBAL innodb_purge_rseg_truncate_frequency= @saved_frequency;
#
# MDEV-18266: Changing an index comment unnecessarily rebuilds index
diff --git a/mysql-test/suite/innodb/r/instant_alter_bugs.result b/mysql-test/suite/innodb/r/instant_alter_bugs.result
index 5e3c2f87bf1..109cbffe871 100644
--- a/mysql-test/suite/innodb/r/instant_alter_bugs.result
+++ b/mysql-test/suite/innodb/r/instant_alter_bugs.result
@@ -261,3 +261,11 @@ a
1
3
DROP TABLE t1;
+#
+# MDEV-20479: assertion failure in dict_table_get_nth_col() after INSTANT DROP COLUMN
+#
+CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
+ALTER TABLE t1 ADD COLUMN (b INT, c INT, d INT, e INT NOT NULL DEFAULT 0);
+ALTER TABLE t1 ADD UNIQUE INDEX(e);
+ALTER TABLE t1 DROP b, DROP c, DROP d, DROP e;
+DROP TABLE t1;
diff --git a/mysql-test/suite/innodb/t/foreign-keys.test b/mysql-test/suite/innodb/t/foreign-keys.test
index d16ae9ed826..aec6bb54e72 100644
--- a/mysql-test/suite/innodb/t/foreign-keys.test
+++ b/mysql-test/suite/innodb/t/foreign-keys.test
@@ -203,3 +203,49 @@ connection default;
select * from t2;
drop table t2, t1;
drop user foo;
+
+--echo #
+--echo # MDEV-17187 table doesn't exist in engine after ALTER other tables
+--echo # with CONSTRAINTs
+--echo #
+
+set foreign_key_checks=on;
+create table t1 (id int not null primary key) engine=innodb;
+create table t2 (id int not null primary key, fid int not null,
+CONSTRAINT fk_fid FOREIGN KEY (fid) REFERENCES t1 (id))engine=innodb;
+
+insert into t1 values (1), (2), (3);
+insert into t2 values (1, 1), (2, 1), (3, 2);
+
+set foreign_key_checks=off;
+alter table t2 drop index fk_fid;
+set foreign_key_checks=on;
+
+--error ER_ROW_IS_REFERENCED_2
+delete from t1 where id=2;
+--error ER_NO_REFERENCED_ROW_2
+insert into t2 values(4, 99);
+
+select * from t1;
+select * from t2;
+
+set foreign_key_checks=off;
+delete from t1 where id=2;
+insert into t2 values(4, 99);
+set foreign_key_checks=on;
+
+select * from t1;
+select * from t2;
+
+show create table t1;
+show create table t2;
+
+# Optional: test DROP TABLE without any prior ha_innobase::open().
+# This was tested manually, but it would cause --embedded to skip the test,
+# and the restart would significantly increase the running time.
+# --source include/restart_mysqld.inc
+
+--error ER_ROW_IS_REFERENCED_2
+drop table t1,t2;
+--error ER_BAD_TABLE_ERROR
+drop table t1,t2;
diff --git a/mysql-test/suite/innodb/t/innodb-read-view.test b/mysql-test/suite/innodb/t/innodb-read-view.test
new file mode 100644
index 00000000000..425cbeb08c8
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb-read-view.test
@@ -0,0 +1,208 @@
+# DEBUG_SYNC must be compiled in.
+--source include/have_debug_sync.inc
+--source include/have_debug.inc
+
+# We need to test the use case:
+# a. Create a transaction T1 that will be promoted to RW.
+# b. Create a transaction T2 that will be promoted to RW.
+# a. Create a RO transaction T3
+# d. T3 does a select - creates a read view that doesn't include T1 and T2
+# e. T1 & T2 do some updates - this promotes T1 & T2 to RW transactions
+# f. T1 & T2 Commit
+# g. T3 Does a select - it should not see the changes of T1 & T2
+
+--source include/have_innodb.inc
+--source include/count_sessions.inc
+
+CREATE TABLE t1 (c1 INT , c2 CHAR(10), PRIMARY KEY (c1)) ENGINE = InnoDB;
+INSERT INTO t1 VALUES(0, "0");
+INSERT INTO t1 VALUES(1, "1");
+INSERT INTO t1 VALUES(2, "2");
+INSERT INTO t1 VALUES(3, "3");
+
+CREATE TABLE t2 (c1 INT , c2 CHAR(10), PRIMARY KEY (c1)) ENGINE = InnoDB;
+INSERT INTO t2 VALUES(0, "a");
+INSERT INTO t2 VALUES(1, "b");
+INSERT INTO t2 VALUES(2, "c");
+INSERT INTO t2 VALUES(3, "d");
+
+--connect (con1,localhost,root,,)
+--connect (con2,localhost,root,,)
+
+connection con1;
+--echo 'T1'
+SET AUTOCOMMIT=0;
+BEGIN;
+SELECT * FROM t2;
+
+connection default;
+--echo 'T2'
+SET AUTOCOMMIT=0;
+BEGIN;
+SELECT * FROM t1;
+
+connection con2;
+--echo 'T3'
+SET AUTOCOMMIT=0;
+SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+BEGIN;
+SELECT * FROM t1;
+SELECT * FROM t2;
+
+connection con1;
+--echo 'T1'
+UPDATE t2 SET c1 = c1 + 100;
+SELECT * FROM t2;
+COMMIT;
+
+connection default;
+--echo 'T2'
+UPDATE t1 SET c1 = c1 + 100;
+SELECT * FROM t1;
+COMMIT;
+
+connection con2;
+--echo 'T3'
+SET DEBUG_SYNC='row_search_for_mysql_before_return WAIT_FOR waiting1';
+--send SELECT * FROM t1;
+
+connection default;
+--echo 'T2'
+SET DEBUG_SYNC='now SIGNAL waiting1';
+--echo 'Signalled T3'
+
+connection con2;
+--echo 'T3'
+reap;
+
+connection con2;
+--echo 'T3'
+SET DEBUG_SYNC='row_search_for_mysql_before_return WAIT_FOR waiting1';
+--send SELECT * FROM t2;
+
+connection default;
+--echo 'T2'
+SET DEBUG_SYNC='now SIGNAL waiting1';
+--echo 'Signalled T3'
+
+connection con2;
+--echo 'T3'
+reap;
+
+connection default;
+disconnect con1;
+disconnect con2;
+
+# We need to test the use case:
+# a. Create a transaction T1 that will be promoted to RW.
+# b. Create a transaction T2 that will be promoted to RW.
+# c. T2 does some updates - this promotes T2 to RW transactions
+# d. T2 Commits
+# e. Create a RO transaction T3
+# f. T3 does a select - creates a read view that doesn't include T1
+# g. T1 does some updates - this promotes T1 to RW transactions
+# h. T1 Commits
+# i. T3 Does a select - it should not see the changes made by T1 but should
+# see the changes by T2
+
+--connect (con1,localhost,root,,)
+--connect (con2,localhost,root,,)
+
+connection con1;
+--echo 'T1'
+SET AUTOCOMMIT=0;
+BEGIN;
+SELECT * FROM t1;
+
+connection default;
+--echo 'T2'
+SET AUTOCOMMIT=0;
+BEGIN;
+SELECT * FROM t2;
+UPDATE t2 SET c1 = c1 + 100;
+SELECT * FROM t2;
+COMMIT;
+
+connection con2;
+--echo 'T3'
+SET AUTOCOMMIT=0;
+SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+BEGIN;
+SELECT * FROM t1;
+SELECT * FROM t2;
+
+connection con1;
+--echo 'T1'
+UPDATE t1 SET c1 = c1 + 100;
+SELECT * FROM t1;
+COMMIT;
+
+connection con2;
+--echo 'T3'
+SET DEBUG_SYNC='row_select_wait WAIT_FOR waiting1';
+--send SELECT * FROM t1;
+
+connection con1;
+--echo 'T2'
+SET DEBUG_SYNC='now SIGNAL waiting1';
+--echo 'Signalled T3'
+
+connection con2;
+--echo 'T3'
+reap;
+
+connection con2;
+--echo 'T3'
+SET DEBUG_SYNC='row_select_wait WAIT_FOR waiting1';
+--send SELECT * FROM t2;
+
+connection default;
+--echo 'T2'
+SET DEBUG_SYNC='now SIGNAL waiting1';
+--echo 'Signalled T3'
+
+connection con2;
+--echo 'T3'
+reap;
+
+connection default;
+disconnect con1;
+disconnect con2;
+
+DROP TABLE t1;
+DROP TABLE t2;
+
+--echo #
+--echo # Bug 21433768: NON-REPEATABLE READ WITH REPEATABLE READ ISOLATION
+--echo #
+
+--connect (con1,localhost,root,,)
+
+CREATE TABLE t1(col1 INT PRIMARY KEY, col2 INT) ENGINE = InnoDB;
+INSERT INTO t1 values (1, 0), (2, 0);
+SELECT * FROM t1 ORDER BY col1;
+
+START TRANSACTION;
+UPDATE t1 SET col2 = 100;
+SET DEBUG_SYNC = 'after_trx_committed_in_memory SIGNAL s1 WAIT_FOR s2';
+--send COMMIT;
+
+connection default;
+SET DEBUG_SYNC = 'now WAIT_FOR s1';
+UPDATE t1 SET col2 = col2 + 10 where col1 = 1;
+COMMIT;
+
+SELECT * FROM t1 ORDER BY col1;
+SET DEBUG_SYNC = 'now SIGNAL s2';
+
+connection con1;
+reap;
+disconnect con1;
+
+connection default;
+
+DROP TABLE t1;
+
+# Clean up resources used in this test case.
+SET DEBUG_SYNC= 'RESET';
+--source include/wait_until_count_sessions.inc
diff --git a/mysql-test/suite/innodb/t/innodb-system-table-view.test b/mysql-test/suite/innodb/t/innodb-system-table-view.test
index 087c0a22eca..4f5111eafbc 100644
--- a/mysql-test/suite/innodb/t/innodb-system-table-view.test
+++ b/mysql-test/suite/innodb/t/innodb-system-table-view.test
@@ -4,6 +4,8 @@
--source include/innodb_page_size_small.inc
+SET @save_frequency=@@GLOBAL.innodb_purge_rseg_truncate_frequency;
+SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
LET $MYSQLD_DATADIR = `select @@datadir`;
LET $INNODB_PAGE_SIZE = `select @@innodb_page_size`;
@@ -70,6 +72,8 @@ SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
# INNODB_SYS_TABLESTATS
INSERT INTO parent VALUES(1);
+--source include/wait_all_purged.inc
+
--sorted_result
SELECT name, num_rows, ref_count
FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS
@@ -126,6 +130,8 @@ INSERT INTO parent VALUES(1, 9);
--sorted_result
SELECT * FROM parent WHERE id IN (SELECT id FROM parent);
+--source include/wait_all_purged.inc
+
--sorted_result
SELECT name, num_rows, ref_count
FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS
@@ -134,3 +140,4 @@ WHERE name LIKE "%parent";
DROP TABLE child;
DROP TABLE parent;
+SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency;
diff --git a/mysql-test/suite/innodb/t/innodb_bug68148.test b/mysql-test/suite/innodb/t/innodb_bug68148.test
index 531baa30e48..ab4e0311656 100644
--- a/mysql-test/suite/innodb/t/innodb_bug68148.test
+++ b/mysql-test/suite/innodb/t/innodb_bug68148.test
@@ -28,11 +28,8 @@ SET FOREIGN_KEY_CHECKS=0;
DROP INDEX `idx_1` ON `main`;
SHOW TABLES;
---echo # restart and see if we can still access the main table
--source include/restart_mysqld.inc
-# This is required to access the table
-SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE `main` ADD INDEX `idx_1` (`ref_id1`);
SHOW CREATE TABLE `main`;
diff --git a/mysql-test/suite/innodb/t/innodb_bug84958.test b/mysql-test/suite/innodb/t/innodb_bug84958.test
index 4456df21cb9..cbcc5d1abc6 100644
--- a/mysql-test/suite/innodb/t/innodb_bug84958.test
+++ b/mysql-test/suite/innodb/t/innodb_bug84958.test
@@ -6,15 +6,19 @@
--echo #
--source include/have_innodb.inc
+SET @saved_frequency= @@GLOBAL.innodb_purge_rseg_truncate_frequency;
+SET GLOBAL innodb_purge_rseg_truncate_frequency= 1;
DELIMITER ~~;
CREATE PROCEDURE insert_n(start int, end int)
BEGIN
DECLARE i INT DEFAULT start;
+ START TRANSACTION;
WHILE i <= end do
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = i;
SET i = i + 1;
END WHILE;
+ COMMIT;
END~~
CREATE FUNCTION num_pages_get()
@@ -60,11 +64,13 @@ connection default;
--echo # Connect to default and record how many pages were accessed
--echo # when selecting the record using the secondary key.
--echo #
+--let $wait_all_purged=4
+--source include/wait_all_purged.inc
SET @num_pages_1 = num_pages_get();
SELECT * FROM t1 force index (b);
SET @num_pages_2= num_pages_get();
-SELECT @num_pages_2 - @num_pages_1 < 500;
+SELECT IF(@num_pages_2 - @num_pages_1 < 5000, 'OK', @num_pages_2 - @num_pages_1) num_pages_diff;
--echo #
--echo # Commit and show the final record.
@@ -81,6 +87,7 @@ CHECK TABLE t1;
--echo #
disconnect con2;
disconnect con3;
+SET GLOBAL innodb_purge_rseg_truncate_frequency= @saved_frequency;
DROP TABLE t1;
DROP PROCEDURE insert_n;
DROP FUNCTION num_pages_get;
diff --git a/mysql-test/suite/innodb/t/innodb_mysql.test b/mysql-test/suite/innodb/t/innodb_mysql.test
index 23bba81c6bd..d495186db25 100644
--- a/mysql-test/suite/innodb/t/innodb_mysql.test
+++ b/mysql-test/suite/innodb/t/innodb_mysql.test
@@ -850,6 +850,7 @@ set @optimizer_switch_saved=@@optimizer_switch;
SET SESSION optimizer_switch='derived_merge=off';
SET SESSION sort_buffer_size = 1024*36;
+--replace_column 9 #
EXPLAIN
SELECT COUNT(*) FROM
(SELECT * FROM t1 FORCE INDEX (idx,PRIMARY)
diff --git a/mysql-test/suite/innodb/t/instant_alter.test b/mysql-test/suite/innodb/t/instant_alter.test
index dc6fe45fa69..c4be8c19f5c 100644
--- a/mysql-test/suite/innodb/t/instant_alter.test
+++ b/mysql-test/suite/innodb/t/instant_alter.test
@@ -365,6 +365,30 @@ COMMIT;
--source include/wait_all_purged.inc
DROP TABLE t1;
+#
+# MDEV-20066 Wrong value on instantly added column after DELETE and UPDATE
+#
+
+eval CREATE TABLE t1(a INT PRIMARY KEY) $engine;
+INSERT INTO t1 VALUES (7);
+
+ALTER TABLE t1 ADD COLUMN c INT NOT NULL DEFAULT 0;
+ALTER TABLE t1 ADD INDEX (c);
+
+BEGIN;
+DELETE FROM t1;
+INSERT INTO t1 VALUES (4,0),(7,77);
+COMMIT;
+BEGIN;
+DELETE FROM t1 WHERE a=7;
+UPDATE t1 SET a=7;
+COMMIT;
+SELECT * FROM t1 FORCE INDEX(PRIMARY);
+SELECT * FROM t1 FORCE INDEX(c);
+DELETE FROM t1;
+CHECK TABLE t1;
+DROP TABLE t1;
+
# MDEV-15562 Instant DROP/ADD/reorder columns
eval CREATE TABLE t1 (a INT, b INT UNIQUE) $engine;
diff --git a/mysql-test/suite/innodb/t/instant_alter_bugs.test b/mysql-test/suite/innodb/t/instant_alter_bugs.test
index 3cf3de54ba5..fc5e3ca56e4 100644
--- a/mysql-test/suite/innodb/t/instant_alter_bugs.test
+++ b/mysql-test/suite/innodb/t/instant_alter_bugs.test
@@ -266,3 +266,14 @@ ROLLBACK;
SELECT * FROM t1;
DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-20479: assertion failure in dict_table_get_nth_col() after INSTANT DROP COLUMN
+--echo #
+
+CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
+ALTER TABLE t1 ADD COLUMN (b INT, c INT, d INT, e INT NOT NULL DEFAULT 0);
+ALTER TABLE t1 ADD UNIQUE INDEX(e);
+ALTER TABLE t1 DROP b, DROP c, DROP d, DROP e;
+DROP TABLE t1;
diff --git a/mysql-test/suite/innodb_gis/r/point_basic.result b/mysql-test/suite/innodb_gis/r/point_basic.result
index d88b01d514b..f24ddfeb761 100644
--- a/mysql-test/suite/innodb_gis/r/point_basic.result
+++ b/mysql-test/suite/innodb_gis/r/point_basic.result
@@ -1524,7 +1524,7 @@ ALTER TABLE child ADD FOREIGN KEY(p) REFERENCES parent(p);
ERROR HY000: Can't create table `test`.`child` (errno: 150 "Foreign key constraint is incorrectly formed")
show warnings;
Level Code Message
-Warning 150 Alter table '`test`.`child`' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns near 'FOREIGN KEY(p) REFERENCES parent(p)'.
+Warning 150 Alter table `test`.`child` with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns near 'FOREIGN KEY(p) REFERENCES parent(p)'.
Error 1005 Can't create table `test`.`child` (errno: 150 "Foreign key constraint is incorrectly formed")
Warning 1215 Cannot add foreign key constraint for `child`
ALTER TABLE parent DROP INDEX idx1;
@@ -1532,7 +1532,7 @@ ALTER TABLE child ADD FOREIGN KEY(p) REFERENCES parent(p);
Got one of the listed errors
show warnings;
Level Code Message
-Warning 150 Alter table '`test`.`child`' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns near 'FOREIGN KEY(p) REFERENCES parent(p)'.
+Warning 150 Alter table `test`.`child` with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns near 'FOREIGN KEY(p) REFERENCES parent(p)'.
Error 1005 Can't create table `test`.`child` (errno: 150 "Foreign key constraint is incorrectly formed")
Warning 1215 Cannot add foreign key constraint for `child`
ALTER TABLE child DROP INDEX idx2;
@@ -1540,7 +1540,7 @@ ALTER TABLE child ADD FOREIGN KEY(p) REFERENCES parent(p);
Got one of the listed errors
show warnings;
Level Code Message
-Warning 150 Alter table '`test`.`child`' with foreign key constraint failed. There is only prefix index in the referenced table where the referenced columns appear as the first columns near 'FOREIGN KEY(p) REFERENCES parent(p)'.
+Warning 150 Alter table `test`.`child` with foreign key constraint failed. There is only prefix index in the referenced table where the referenced columns appear as the first columns near 'FOREIGN KEY(p) REFERENCES parent(p)'.
Error 1005 Can't create table `test`.`child` (errno: 150 "Foreign key constraint is incorrectly formed")
Warning 1215 Cannot add foreign key constraint for `child`
DROP TABLE child, parent;
diff --git a/mysql-test/suite/maria/partition.result b/mysql-test/suite/maria/partition.result
new file mode 100644
index 00000000000..929c6bab22e
--- /dev/null
+++ b/mysql-test/suite/maria/partition.result
@@ -0,0 +1,4 @@
+CREATE TABLE t (a INT, KEY(a)) ENGINE=Aria PARTITION BY KEY(a) PARTITIONS 2;
+SELECT * FROM t PARTITION (p1);
+a
+DROP TABLE t;
diff --git a/mysql-test/suite/maria/partition.test b/mysql-test/suite/maria/partition.test
new file mode 100644
index 00000000000..86f976a05e7
--- /dev/null
+++ b/mysql-test/suite/maria/partition.test
@@ -0,0 +1,11 @@
+--source include/have_partition.inc
+
+#
+# MDEV-19254
+# Server crashes in maria_status / ha_maria::info upon SELECT with partition
+# pruning
+#
+
+CREATE TABLE t (a INT, KEY(a)) ENGINE=Aria PARTITION BY KEY(a) PARTITIONS 2;
+SELECT * FROM t PARTITION (p1);
+DROP TABLE t;
diff --git a/mysql-test/suite/mariabackup/compress_qpress.result b/mysql-test/suite/mariabackup/compress_qpress.result
index 457cb2f10f9..ff940813440 100644
--- a/mysql-test/suite/mariabackup/compress_qpress.result
+++ b/mysql-test/suite/mariabackup/compress_qpress.result
@@ -10,7 +10,6 @@ t.ibd.qp
# remove datadir
# xtrabackup move back
# restart
-# restart
SELECT * FROM t;
i
1
diff --git a/mysql-test/suite/mariabackup/disabled.def b/mysql-test/suite/mariabackup/disabled.def
new file mode 100644
index 00000000000..88a66df052d
--- /dev/null
+++ b/mysql-test/suite/mariabackup/disabled.def
@@ -0,0 +1,12 @@
+##############################################################################
+#
+# List the test cases that are to be disabled temporarily.
+#
+# Separate the test case name and the comment with ':'.
+#
+# <testcasename> : BUG#<xxxx> <date disabled> <disabler> <comment>
+#
+# Do not use any TAB characters for whitespace.
+#
+##############################################################################
+big_innodb_log : MDEV-20421 2019-08-26 wlad Always fails on Windows buildbot \ No newline at end of file
diff --git a/mysql-test/suite/rpl/r/rpl_extra_col_master_innodb.result b/mysql-test/suite/rpl/r/rpl_extra_col_master_innodb.result
index 968d469fc8d..5865b75550f 100644
--- a/mysql-test/suite/rpl/r/rpl_extra_col_master_innodb.result
+++ b/mysql-test/suite/rpl/r/rpl_extra_col_master_innodb.result
@@ -468,7 +468,7 @@ INSERT INTO t10 () VALUES(1,@b1,DEFAULT,'Kyle',DEFAULT),
connection slave;
include/wait_for_slave_sql_error_and_skip.inc [errno=1677]
-Last_SQL_Error = 'Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5)''
+Last_SQL_Error = 'Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5 octets) character set latin1''
*** Drop t10 ***
connection master;
@@ -510,7 +510,7 @@ INSERT INTO t11 () VALUES(1,@b1,'Testing is fun','Kyle',DEFAULT),
connection slave;
include/wait_for_slave_sql_error_and_skip.inc [errno=1677]
-Last_SQL_Error = 'Column 2 of table 'test.t11' cannot be converted from type 'blob' to type 'varchar(254)''
+Last_SQL_Error = 'Column 2 of table 'test.t11' cannot be converted from type 'blob' to type 'varchar(254 octets) character set latin1''
*** Drop t11 ***
connection master;
diff --git a/mysql-test/suite/rpl/r/rpl_extra_col_master_myisam.result b/mysql-test/suite/rpl/r/rpl_extra_col_master_myisam.result
index 9be792a41fc..f47d79b5b86 100644
--- a/mysql-test/suite/rpl/r/rpl_extra_col_master_myisam.result
+++ b/mysql-test/suite/rpl/r/rpl_extra_col_master_myisam.result
@@ -468,7 +468,7 @@ INSERT INTO t10 () VALUES(1,@b1,DEFAULT,'Kyle',DEFAULT),
connection slave;
include/wait_for_slave_sql_error_and_skip.inc [errno=1677]
-Last_SQL_Error = 'Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5)''
+Last_SQL_Error = 'Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5 octets) character set latin1''
*** Drop t10 ***
connection master;
@@ -510,7 +510,7 @@ INSERT INTO t11 () VALUES(1,@b1,'Testing is fun','Kyle',DEFAULT),
connection slave;
include/wait_for_slave_sql_error_and_skip.inc [errno=1677]
-Last_SQL_Error = 'Column 2 of table 'test.t11' cannot be converted from type 'blob' to type 'varchar(254)''
+Last_SQL_Error = 'Column 2 of table 'test.t11' cannot be converted from type 'blob' to type 'varchar(254 octets) character set latin1''
*** Drop t11 ***
connection master;
diff --git a/mysql-test/suite/rpl/r/rpl_extra_col_slave_innodb.result b/mysql-test/suite/rpl/r/rpl_extra_col_slave_innodb.result
index 0017b8f7f99..a9cbbd9fafe 100644
--- a/mysql-test/suite/rpl/r/rpl_extra_col_slave_innodb.result
+++ b/mysql-test/suite/rpl/r/rpl_extra_col_slave_innodb.result
@@ -64,7 +64,7 @@ a b c
connection slave;
START SLAVE;
include/wait_for_slave_sql_error.inc [errno=1677]
-Last_SQL_Error = 'Column 2 of table 'test.t2' cannot be converted from type 'char(10)' to type 'char(5)''
+Last_SQL_Error = 'Column 2 of table 'test.t2' cannot be converted from type 'char(10 octets)' to type 'char(5 octets) character set latin1''
STOP SLAVE;
RESET SLAVE;
SELECT * FROM t2 ORDER BY a;
@@ -160,7 +160,7 @@ INSERT INTO t5 () VALUES(1,'Kyle',200.23,1,'b1b1',23.00098),
********************************************
connection slave;
include/wait_for_slave_sql_error_and_skip.inc [errno=1677]
-Last_SQL_Error = 'Column 1 of table 'test.t5' cannot be converted from type 'varchar(6)' to type 'char(5)''
+Last_SQL_Error = 'Column 1 of table 'test.t5' cannot be converted from type 'varchar(6 octets)' to type 'char(5 octets) character set latin1''
*** Drop t5 ***
connection master;
DROP TABLE t5;
@@ -188,7 +188,7 @@ INSERT INTO t6 () VALUES(1,'Kyle',200.23,1),
********************************************
connection slave;
include/wait_for_slave_sql_error.inc [errno=1677]
-Last_SQL_Error = 'Column 1 of table 'test.t6' cannot be converted from type 'varchar(6)' to type 'char(5)''
+Last_SQL_Error = 'Column 1 of table 'test.t6' cannot be converted from type 'varchar(6 octets)' to type 'char(5 octets) character set latin1''
*** Drop t6 ***
include/rpl_reset.inc
connection master;
@@ -310,7 +310,7 @@ INSERT INTO t10 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
********************************************
connection slave;
include/wait_for_slave_sql_error_and_skip.inc [errno=1677]
-Last_SQL_Error = 'Column 2 of table 'test.t10' cannot be converted from type 'char(5)' to type 'double''
+Last_SQL_Error = 'Column 2 of table 'test.t10' cannot be converted from type 'char(5 octets)' to type 'double''
*** Drop t10 ***
connection master;
DROP TABLE t10;
@@ -338,7 +338,7 @@ INSERT INTO t11 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
********************************************
connection slave;
include/wait_for_slave_sql_error_and_skip.inc [errno=1677]
-Last_SQL_Error = 'Column 2 of table 'test.t11' cannot be converted from type 'varchar(254)' to type 'int(11)''
+Last_SQL_Error = 'Column 2 of table 'test.t11' cannot be converted from type 'varchar(254 octets)' to type 'int(11)''
*** Drop t11 ***
connection master;
DROP TABLE t11;
diff --git a/mysql-test/suite/rpl/r/rpl_extra_col_slave_myisam.result b/mysql-test/suite/rpl/r/rpl_extra_col_slave_myisam.result
index 487c2c88b18..11a716f22b6 100644
--- a/mysql-test/suite/rpl/r/rpl_extra_col_slave_myisam.result
+++ b/mysql-test/suite/rpl/r/rpl_extra_col_slave_myisam.result
@@ -64,7 +64,7 @@ a b c
connection slave;
START SLAVE;
include/wait_for_slave_sql_error.inc [errno=1677]
-Last_SQL_Error = 'Column 2 of table 'test.t2' cannot be converted from type 'char(10)' to type 'char(5)''
+Last_SQL_Error = 'Column 2 of table 'test.t2' cannot be converted from type 'char(10 octets)' to type 'char(5 octets) character set latin1''
STOP SLAVE;
RESET SLAVE;
SELECT * FROM t2 ORDER BY a;
@@ -160,7 +160,7 @@ INSERT INTO t5 () VALUES(1,'Kyle',200.23,1,'b1b1',23.00098),
********************************************
connection slave;
include/wait_for_slave_sql_error_and_skip.inc [errno=1677]
-Last_SQL_Error = 'Column 1 of table 'test.t5' cannot be converted from type 'varchar(6)' to type 'char(5)''
+Last_SQL_Error = 'Column 1 of table 'test.t5' cannot be converted from type 'varchar(6 octets)' to type 'char(5 octets) character set latin1''
*** Drop t5 ***
connection master;
DROP TABLE t5;
@@ -188,7 +188,7 @@ INSERT INTO t6 () VALUES(1,'Kyle',200.23,1),
********************************************
connection slave;
include/wait_for_slave_sql_error.inc [errno=1677]
-Last_SQL_Error = 'Column 1 of table 'test.t6' cannot be converted from type 'varchar(6)' to type 'char(5)''
+Last_SQL_Error = 'Column 1 of table 'test.t6' cannot be converted from type 'varchar(6 octets)' to type 'char(5 octets) character set latin1''
*** Drop t6 ***
include/rpl_reset.inc
connection master;
@@ -310,7 +310,7 @@ INSERT INTO t10 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
********************************************
connection slave;
include/wait_for_slave_sql_error_and_skip.inc [errno=1677]
-Last_SQL_Error = 'Column 2 of table 'test.t10' cannot be converted from type 'char(5)' to type 'double''
+Last_SQL_Error = 'Column 2 of table 'test.t10' cannot be converted from type 'char(5 octets)' to type 'double''
*** Drop t10 ***
connection master;
DROP TABLE t10;
@@ -338,7 +338,7 @@ INSERT INTO t11 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
********************************************
connection slave;
include/wait_for_slave_sql_error_and_skip.inc [errno=1677]
-Last_SQL_Error = 'Column 2 of table 'test.t11' cannot be converted from type 'varchar(254)' to type 'int(11)''
+Last_SQL_Error = 'Column 2 of table 'test.t11' cannot be converted from type 'varchar(254 octets)' to type 'int(11)''
*** Drop t11 ***
connection master;
DROP TABLE t11;
diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result b/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result
index 1d4b31a4a87..98e95e8cc77 100644
--- a/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result
+++ b/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result
@@ -560,7 +560,7 @@ INSERT INTO t5 VALUES (1, "", 1);
INSERT INTO t5 VALUES (2, repeat(_utf8'a', 255), 2);
connection slave;
include/wait_for_slave_sql_error.inc [errno=1677]
-Last_SQL_Error = 'Column 1 of table 'test.t5' cannot be converted from type 'char(255)' to type 'char(16)''
+Last_SQL_Error = 'Column 1 of table 'test.t5' cannot be converted from type 'char(765 octets)' to type 'char(48 octets) character set utf8''
include/rpl_reset.inc
[expecting slave to stop]
connection master;
@@ -568,7 +568,7 @@ INSERT INTO t6 VALUES (1, "", 1);
INSERT INTO t6 VALUES (2, repeat(_utf8'a', 255), 2);
connection slave;
include/wait_for_slave_sql_error.inc [errno=1677]
-Last_SQL_Error = 'Column 1 of table 'test.t6' cannot be converted from type 'char(255)' to type 'char(128)''
+Last_SQL_Error = 'Column 1 of table 'test.t6' cannot be converted from type 'char(765 octets)' to type 'char(384 octets) character set utf8''
include/rpl_reset.inc
[expecting slave to replicate correctly]
connection master;
diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result b/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result
index 1e3ddd4f289..3203d5394df 100644
--- a/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result
+++ b/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result
@@ -565,7 +565,7 @@ INSERT INTO t5 VALUES (1, "", 1);
INSERT INTO t5 VALUES (2, repeat(_utf8'a', 255), 2);
connection slave;
include/wait_for_slave_sql_error.inc [errno=1677]
-Last_SQL_Error = 'Column 1 of table 'test.t5' cannot be converted from type 'char(255)' to type 'char(16)''
+Last_SQL_Error = 'Column 1 of table 'test.t5' cannot be converted from type 'char(765 octets)' to type 'char(48 octets) character set utf8''
include/rpl_reset.inc
[expecting slave to stop]
connection master;
@@ -573,7 +573,7 @@ INSERT INTO t6 VALUES (1, "", 1);
INSERT INTO t6 VALUES (2, repeat(_utf8'a', 255), 2);
connection slave;
include/wait_for_slave_sql_error.inc [errno=1677]
-Last_SQL_Error = 'Column 1 of table 'test.t6' cannot be converted from type 'char(255)' to type 'char(128)''
+Last_SQL_Error = 'Column 1 of table 'test.t6' cannot be converted from type 'char(765 octets)' to type 'char(384 octets) character set utf8''
include/rpl_reset.inc
[expecting slave to replicate correctly]
connection master;
diff --git a/mysql-test/suite/rpl/r/rpl_row_colSize.result b/mysql-test/suite/rpl/r/rpl_row_colSize.result
index d36f1964334..748d83a7f8e 100644
--- a/mysql-test/suite/rpl/r/rpl_row_colSize.result
+++ b/mysql-test/suite/rpl/r/rpl_row_colSize.result
@@ -185,7 +185,7 @@ INSERT INTO t1 VALUES ('This is a test.');
connection slave;
START SLAVE;
include/wait_for_slave_sql_error.inc [errno=1677]
-Last_SQL_Error = 'Column 0 of table 'test.t1' cannot be converted from type 'char(20)' to type 'char(10)''
+Last_SQL_Error = 'Column 0 of table 'test.t1' cannot be converted from type 'char(20 octets)' to type 'char(10 octets) character set latin1''
SELECT COUNT(*) FROM t1;
COUNT(*)
0
@@ -264,7 +264,7 @@ INSERT INTO t1 VALUES ('This is a test.');
connection slave;
START SLAVE;
include/wait_for_slave_sql_error.inc [errno=1677]
-Last_SQL_Error = 'Column 0 of table 'test.t1' cannot be converted from type 'varchar(2000)' to type 'varchar(100)''
+Last_SQL_Error = 'Column 0 of table 'test.t1' cannot be converted from type 'varchar(2000 octets)' to type 'varchar(100 octets) character set latin1''
SELECT COUNT(*) FROM t1;
COUNT(*)
0
@@ -287,7 +287,7 @@ INSERT INTO t1 VALUES ('This is a test.');
connection slave;
START SLAVE;
include/wait_for_slave_sql_error.inc [errno=1677]
-Last_SQL_Error = 'Column 0 of table 'test.t1' cannot be converted from type 'varchar(200)' to type 'varchar(10)''
+Last_SQL_Error = 'Column 0 of table 'test.t1' cannot be converted from type 'varchar(200 octets)' to type 'varchar(10 octets) character set latin1''
SELECT COUNT(*) FROM t1;
COUNT(*)
0
@@ -310,7 +310,7 @@ INSERT INTO t1 VALUES ('This is a test.');
connection slave;
START SLAVE;
include/wait_for_slave_sql_error.inc [errno=1677]
-Last_SQL_Error = 'Column 0 of table 'test.t1' cannot be converted from type 'varchar(2000)' to type 'varchar(1000)''
+Last_SQL_Error = 'Column 0 of table 'test.t1' cannot be converted from type 'varchar(2000 octets)' to type 'varchar(1000 octets) character set latin1''
SELECT COUNT(*) FROM t1;
COUNT(*)
0
diff --git a/mysql-test/suite/rpl/r/rpl_row_type_conv_err_msg.result b/mysql-test/suite/rpl/r/rpl_row_type_conv_err_msg.result
new file mode 100644
index 00000000000..4b348425877
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_row_type_conv_err_msg.result
@@ -0,0 +1,164 @@
+include/master-slave.inc
+[connection master]
+####################################################################
+# Test Case1: Improved error message with charset information
+####################################################################
+connection master;
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 VARCHAR(1) CHARACTER SET 'utf8mb3');
+SET SQL_LOG_BIN=1;
+connection slave;
+CREATE TABLE t1 (c1 VARCHAR(1) CHARACTER SET 'utf8mb4');
+connection master;
+INSERT INTO t1 VALUES ('a');
+connection slave;
+include/wait_for_slave_sql_error.inc [errno=1677]
+FOUND 1 /\'varchar\(3 octets\)\' to type \'varchar\(4 octets\) character set utf8mb4\'/ in mysqld.2.err
+connection master;
+DROP TABLE t1;
+connection slave;
+DROP TABLE t1;
+include/rpl_reset.inc
+####################################################################
+# Test Case2: Improved error message with charset information for CHAR
+# type
+####################################################################
+connection master;
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 CHAR(1) CHARACTER SET 'utf8mb3');
+SET SQL_LOG_BIN=1;
+connection slave;
+CREATE TABLE t1 (c1 CHAR(1) CHARACTER SET 'utf8mb4');
+connection master;
+INSERT INTO t1 VALUES ('a');
+connection slave;
+include/wait_for_slave_sql_error.inc [errno=1677]
+FOUND 1 /\'char\(3 octets\)\' to type \'char\(4 octets\) character set utf8mb4\'/ in mysqld.2.err
+connection master;
+DROP TABLE t1;
+connection slave;
+DROP TABLE t1;
+include/rpl_reset.inc
+####################################################################
+# Test Case3: For BLOB type fileds, when type conversion failed on
+# slave, the errormessage had incorrect type names.
+####################################################################
+connection master;
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 LONGBLOB);
+SET SQL_LOG_BIN=1;
+connection slave;
+CREATE TABLE t1 (c1 TINYBLOB);
+connection master;
+INSERT INTO t1 VALUES ('a');
+connection slave;
+include/wait_for_slave_sql_error.inc [errno=1677]
+FOUND 1 /\'longblob\' to type \'tinyblob\'/ in mysqld.2.err
+connection master;
+DROP TABLE t1;
+connection slave;
+DROP TABLE t1;
+include/rpl_reset.inc
+####################################################################
+# Test Case4: Verifies varbinary to binary type conversion failure
+# specific error message.
+####################################################################
+connection master;
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 VARBINARY(10));
+SET SQL_LOG_BIN=1;
+connection slave;
+CREATE TABLE t1 (c1 BINARY(10));
+connection master;
+INSERT INTO t1 VALUES ('a');
+connection slave;
+include/wait_for_slave_sql_error.inc [errno=1677]
+FOUND 1 /\'varbinary\(10\)\' to type \'binary\(10\)\'/ in mysqld.2.err
+connection master;
+DROP TABLE t1;
+connection slave;
+DROP TABLE t1;
+include/rpl_reset.inc
+####################################################################
+# Test Case5: Verifies binary to varbinary type conversion failure
+# specific error message.
+####################################################################
+connection master;
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 BINARY(10));
+SET SQL_LOG_BIN=1;
+connection slave;
+CREATE TABLE t1 (c1 VARBINARY(10));
+connection master;
+INSERT INTO t1 VALUES ('a');
+connection slave;
+include/wait_for_slave_sql_error.inc [errno=1677]
+FOUND 1 /\'binary\(10\)\' to type \'varbinary\(10\)\'/ in mysqld.2.err
+connection master;
+DROP TABLE t1;
+connection slave;
+DROP TABLE t1;
+include/rpl_reset.inc
+####################################################################
+# Test Case6: Verifies binary to binary type conversion failure
+# specific error message.
+####################################################################
+connection master;
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 BINARY(1));
+SET SQL_LOG_BIN=1;
+connection slave;
+CREATE TABLE t1 (c1 BINARY(10));
+connection master;
+INSERT INTO t1 VALUES ('a');
+connection slave;
+include/wait_for_slave_sql_error.inc [errno=1677]
+FOUND 1 /\'binary\(1\)\' to type \'binary\(10\)\'/ in mysqld.2.err
+connection master;
+DROP TABLE t1;
+connection slave;
+DROP TABLE t1;
+include/rpl_reset.inc
+####################################################################
+# Test Case7: Verifies char to blob type conversion failure
+# specific error message. BLOB field on slave has no
+# associated character set hence the master side field
+# is also considered as binary.
+####################################################################
+connection master;
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 CHAR(1));
+SET SQL_LOG_BIN=1;
+connection slave;
+CREATE TABLE t1 (c1 BLOB);
+connection master;
+INSERT INTO t1 VALUES ('a');
+connection slave;
+include/wait_for_slave_sql_error.inc [errno=1677]
+FOUND 1 /\'binary\(1\)\' to type \'blob\'/ in mysqld.2.err
+connection master;
+DROP TABLE t1;
+connection slave;
+DROP TABLE t1;
+include/rpl_reset.inc
+####################################################################
+# Test Case8: Verifies char to text type conversion failure
+# specific error message.
+####################################################################
+connection master;
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 CHAR(1));
+SET SQL_LOG_BIN=1;
+connection slave;
+CREATE TABLE t1 (c1 TEXT);
+connection master;
+INSERT INTO t1 VALUES ('a');
+connection slave;
+include/wait_for_slave_sql_error.inc [errno=1677]
+FOUND 1 /\'char\(1 octets\)\' to type \'text\'/ in mysqld.2.err
+connection master;
+DROP TABLE t1;
+connection slave;
+DROP TABLE t1;
+include/rpl_reset.inc
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_row_type_conv_err_msg.test b/mysql-test/suite/rpl/t/rpl_row_type_conv_err_msg.test
new file mode 100644
index 00000000000..2442f869abc
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_row_type_conv_err_msg.test
@@ -0,0 +1,356 @@
+# ==== Purpose ====
+#
+# Test verifies that when slave side type conversion fails in row based
+# replication, more informative error message is displayed. It also verifies
+# that in the case of blob fields appropriate type name is displayed in error
+# message.
+#
+# ==== Implementation ====
+#
+# Steps:
+# Test case1:
+# 1. Create a table on master with VARCHAR filed and charset
+# 'utf8mb3'.
+# 2. Create a table on slave with VARCHAR field and charset
+# 'utf8mb4'.
+# 3. Insert a tuple on master.
+# 4. Verify that slave provides more informative error message with
+# respect to difference in charsets.
+# Test case2: Repeat same steps as above for CHAR field
+# Test case3:
+# 1. Create a table on master with LONGBLOB field.
+# 2. Create a table on slave with TINYBLOB field.
+# 3. Insert a tuple on master.
+# 4. Verify that error message displayed on slave clearly states type
+# conversion failure from 'longblob' to 'tinyblob'.
+# 5. Also verify that error message doesn't show additional details
+# of charset when not required.
+# Test Case4: Verifies varbinary to binary type conversion failure specific
+# error message.
+# Test Case5: Verifies binary to varbinary type conversion failure specific
+# error message.
+# Test Case6: Verifies binary to binary type conversion failure specific
+# error message.
+# Test Case7: Verifies char to blob type conversion failure specific
+# error message.
+# Test Case8: Verifies char to text type conversion failure specific
+# error message.
+# ==== References ====
+#
+# MDEV-19925: Column ... cannot be converted from type 'varchar(20)' to type
+# 'varchar(20)'
+#
+
+--source include/have_binlog_format_row.inc
+# Inorder to grep a specific error pattern in error log a fresh error log
+# needs to be generated.
+--source include/force_restart.inc
+--source include/master-slave.inc
+
+--echo ####################################################################
+--echo # Test Case1: Improved error message with charset information
+--echo ####################################################################
+--connection master
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 VARCHAR(1) CHARACTER SET 'utf8mb3');
+SET SQL_LOG_BIN=1;
+
+--connection slave
+CREATE TABLE t1 (c1 VARCHAR(1) CHARACTER SET 'utf8mb4');
+
+--connection master
+INSERT INTO t1 VALUES ('a');
+
+--connection slave
+--let $slave_sql_errno= 1677
+--source include/wait_for_slave_sql_error.inc
+
+# Check error log for correct messages.
+let $log_error_= `SELECT @@GLOBAL.log_error`;
+if(!$log_error_)
+{
+ # MySQL Server on windows is started with --console and thus
+ # does not know the location of its .err log, use default location
+ let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err;
+}
+
+# Error msg before: Column 0 of table 'test.t1' cannot be converted from type 'varchar(3)' to type 'varchar(1)'
+# Error msg after : Column 0 of table 'test.t1' cannot be converted from type 'varchar(3 octets)' to type 'varchar(4 octets) character set utf8mb4'
+--let SEARCH_FILE=$log_error_
+--let SEARCH_PATTERN=\'varchar\(3 octets\)\' to type \'varchar\(4 octets\) character set utf8mb4\'
+--source include/search_pattern_in_file.inc
+
+--connection master
+DROP TABLE t1;
+--connection slave
+DROP TABLE t1;
+--let $rpl_only_running_threads= 1
+--source include/rpl_reset.inc
+
+--echo ####################################################################
+--echo # Test Case2: Improved error message with charset information for CHAR
+--echo # type
+--echo ####################################################################
+--connection master
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 CHAR(1) CHARACTER SET 'utf8mb3');
+SET SQL_LOG_BIN=1;
+
+--connection slave
+CREATE TABLE t1 (c1 CHAR(1) CHARACTER SET 'utf8mb4');
+
+--connection master
+INSERT INTO t1 VALUES ('a');
+
+--connection slave
+--let $slave_sql_errno= 1677
+--source include/wait_for_slave_sql_error.inc
+
+# Error msg before: Column 0 of table 'test.t1' cannot be converted from type 'char(0)' to type 'char(1)'
+# Error msg after : Column 0 of table 'test.t1' cannot be converted from type 'char(3 octets)' to type 'char(4 octets) character set utf8mb4)'
+--let SEARCH_FILE=$log_error_
+--let SEARCH_PATTERN=\'char\(3 octets\)\' to type \'char\(4 octets\) character set utf8mb4\'
+--source include/search_pattern_in_file.inc
+
+--connection master
+DROP TABLE t1;
+--connection slave
+DROP TABLE t1;
+--let $rpl_only_running_threads= 1
+--source include/rpl_reset.inc
+
+--echo ####################################################################
+--echo # Test Case3: For BLOB type fileds, when type conversion failed on
+--echo # slave, the errormessage had incorrect type names.
+--echo ####################################################################
+--connection master
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 LONGBLOB);
+SET SQL_LOG_BIN=1;
+
+--connection slave
+CREATE TABLE t1 (c1 TINYBLOB);
+
+--connection master
+INSERT INTO t1 VALUES ('a');
+
+--connection slave
+--let $slave_sql_errno= 1677
+--source include/wait_for_slave_sql_error.inc
+
+# Error msg before: Column 0 of table 'test.t1' cannot be converted from type 'tinyblob' to type 'tinyblob'
+# Error msg after : Column 0 of table 'test.t1' cannot be converted from type 'longblob' to type 'tinyblob'
+--let SEARCH_FILE=$log_error_
+--let SEARCH_PATTERN=\'longblob\' to type \'tinyblob\'
+--source include/search_pattern_in_file.inc
+
+--connection master
+DROP TABLE t1;
+--connection slave
+DROP TABLE t1;
+--let $rpl_only_running_threads= 1
+--source include/rpl_reset.inc
+
+--echo ####################################################################
+--echo # Test Case4: Verifies varbinary to binary type conversion failure
+--echo # specific error message.
+--echo ####################################################################
+--connection master
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 VARBINARY(10));
+SET SQL_LOG_BIN=1;
+
+--connection slave
+CREATE TABLE t1 (c1 BINARY(10));
+
+--connection master
+INSERT INTO t1 VALUES ('a');
+
+--connection slave
+--let $slave_sql_errno= 1677
+--source include/wait_for_slave_sql_error.inc
+
+# Check error log for correct messages.
+let $log_error_= `SELECT @@GLOBAL.log_error`;
+if(!$log_error_)
+{
+ # MySQL Server on windows is started with --console and thus
+ # does not know the location of its .err log, use default location
+ let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err;
+}
+
+# Expected Error : Column 0 of table 'test.t1' cannot be converted from type 'varbinary(10)' to type 'binary(10)'
+--let SEARCH_FILE=$log_error_
+--let SEARCH_PATTERN=\'varbinary\(10\)\' to type \'binary\(10\)\'
+--source include/search_pattern_in_file.inc
+
+--connection master
+DROP TABLE t1;
+--connection slave
+DROP TABLE t1;
+--let $rpl_only_running_threads= 1
+--source include/rpl_reset.inc
+
+--echo ####################################################################
+--echo # Test Case5: Verifies binary to varbinary type conversion failure
+--echo # specific error message.
+--echo ####################################################################
+--connection master
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 BINARY(10));
+SET SQL_LOG_BIN=1;
+
+--connection slave
+CREATE TABLE t1 (c1 VARBINARY(10));
+
+--connection master
+INSERT INTO t1 VALUES ('a');
+
+--connection slave
+--let $slave_sql_errno= 1677
+--source include/wait_for_slave_sql_error.inc
+
+# Check error log for correct messages.
+let $log_error_= `SELECT @@GLOBAL.log_error`;
+if(!$log_error_)
+{
+ # MySQL Server on windows is started with --console and thus
+ # does not know the location of its .err log, use default location
+ let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err;
+}
+
+# Expected Error : Column 0 of table 'test.t1' cannot be converted from type 'binary(10)' to type 'varbinary(10)'
+--let SEARCH_FILE=$log_error_
+--let SEARCH_PATTERN=\'binary\(10\)\' to type \'varbinary\(10\)\'
+--source include/search_pattern_in_file.inc
+
+--connection master
+DROP TABLE t1;
+--connection slave
+DROP TABLE t1;
+--let $rpl_only_running_threads= 1
+--source include/rpl_reset.inc
+
+--echo ####################################################################
+--echo # Test Case6: Verifies binary to binary type conversion failure
+--echo # specific error message.
+--echo ####################################################################
+--connection master
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 BINARY(1));
+SET SQL_LOG_BIN=1;
+
+--connection slave
+CREATE TABLE t1 (c1 BINARY(10));
+
+--connection master
+INSERT INTO t1 VALUES ('a');
+
+--connection slave
+--let $slave_sql_errno= 1677
+--source include/wait_for_slave_sql_error.inc
+
+# Check error log for correct messages.
+let $log_error_= `SELECT @@GLOBAL.log_error`;
+if(!$log_error_)
+{
+ # MySQL Server on windows is started with --console and thus
+ # does not know the location of its .err log, use default location
+ let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err;
+}
+
+# Expected Error : Column 0 of table 'test.t1' cannot be converted from type 'binary(1)' to type 'binary(10)'
+--let SEARCH_FILE=$log_error_
+--let SEARCH_PATTERN=\'binary\(1\)\' to type \'binary\(10\)\'
+--source include/search_pattern_in_file.inc
+
+--connection master
+DROP TABLE t1;
+--connection slave
+DROP TABLE t1;
+--let $rpl_only_running_threads= 1
+--source include/rpl_reset.inc
+
+--echo ####################################################################
+--echo # Test Case7: Verifies char to blob type conversion failure
+--echo # specific error message. BLOB field on slave has no
+--echo # associated character set hence the master side field
+--echo # is also considered as binary.
+--echo ####################################################################
+--connection master
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 CHAR(1));
+SET SQL_LOG_BIN=1;
+
+--connection slave
+CREATE TABLE t1 (c1 BLOB);
+
+--connection master
+INSERT INTO t1 VALUES ('a');
+
+--connection slave
+--let $slave_sql_errno= 1677
+--source include/wait_for_slave_sql_error.inc
+
+# Check error log for correct messages.
+let $log_error_= `SELECT @@GLOBAL.log_error`;
+if(!$log_error_)
+{
+ # MySQL Server on windows is started with --console and thus
+ # does not know the location of its .err log, use default location
+ let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err;
+}
+
+# Expected Error : Column 0 of table 'test.t1' cannot be converted from type 'binary(1)' to type 'binary(10)'
+--let SEARCH_FILE=$log_error_
+--let SEARCH_PATTERN=\'binary\(1\)\' to type \'blob\'
+--source include/search_pattern_in_file.inc
+
+--connection master
+DROP TABLE t1;
+--connection slave
+DROP TABLE t1;
+--let $rpl_only_running_threads= 1
+--source include/rpl_reset.inc
+
+--echo ####################################################################
+--echo # Test Case8: Verifies char to text type conversion failure
+--echo # specific error message.
+--echo ####################################################################
+--connection master
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 CHAR(1));
+SET SQL_LOG_BIN=1;
+
+--connection slave
+CREATE TABLE t1 (c1 TEXT);
+
+--connection master
+INSERT INTO t1 VALUES ('a');
+
+--connection slave
+--let $slave_sql_errno= 1677
+--source include/wait_for_slave_sql_error.inc
+
+# Check error log for correct messages.
+let $log_error_= `SELECT @@GLOBAL.log_error`;
+if(!$log_error_)
+{
+ # MySQL Server on windows is started with --console and thus
+ # does not know the location of its .err log, use default location
+ let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err;
+}
+
+# Expected Error : Column 0 of table 'test.t1' cannot be converted from type 'binary(1)' to type 'binary(10)'
+--let SEARCH_FILE=$log_error_
+--let SEARCH_PATTERN=\'char\(1 octets\)\' to type \'text\'
+--source include/search_pattern_in_file.inc
+
+--connection master
+DROP TABLE t1;
+--connection slave
+DROP TABLE t1;
+--let $rpl_only_running_threads= 1
+--source include/rpl_reset.inc
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result
index 9d6eee28a96..e9caa8844f8 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result
@@ -5,6 +5,7 @@ variable_name not in (
'innodb_disallow_writes', # only available WITH_WSREP
'innodb_numa_interleave', # only available WITH_NUMA
'innodb_sched_priority_cleaner', # linux only
+'innodb_evict_tables_on_commit_debug', # one may want to override this
'innodb_use_native_aio', # default value depends on OS
'innodb_buffer_pool_load_pages_abort') # debug build only, and is only for testing
order by variable_name;
diff --git a/mysql-test/suite/sys_vars/t/sysvars_innodb.test b/mysql-test/suite/sys_vars/t/sysvars_innodb.test
index 9be60723f85..c573c5592b2 100644
--- a/mysql-test/suite/sys_vars/t/sysvars_innodb.test
+++ b/mysql-test/suite/sys_vars/t/sysvars_innodb.test
@@ -12,6 +12,7 @@ select * from information_schema.system_variables
'innodb_disallow_writes', # only available WITH_WSREP
'innodb_numa_interleave', # only available WITH_NUMA
'innodb_sched_priority_cleaner', # linux only
+ 'innodb_evict_tables_on_commit_debug', # one may want to override this
'innodb_use_native_aio', # default value depends on OS
'innodb_buffer_pool_load_pages_abort') # debug build only, and is only for testing
order by variable_name;
diff --git a/mysql-test/suite/versioning/r/cte.result b/mysql-test/suite/versioning/r/cte.result
index 44135a83eb6..30003146da7 100644
--- a/mysql-test/suite/versioning/r/cte.result
+++ b/mysql-test/suite/versioning/r/cte.result
@@ -137,15 +137,15 @@ where e.mgr = a.emp_id
)
select name from emp where emp_id in (select emp_id from ancestors for system_time as of timestamp @ts_1);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <subquery4> ALL distinct_key NULL NULL NULL 4 100.00
-1 PRIMARY emp ALL PRIMARY NULL NULL NULL 4 100.00 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY emp ALL PRIMARY NULL NULL NULL 4 100.00 Using where
+1 PRIMARY <subquery4> eq_ref distinct_key distinct_key 4 func 1 100.00
4 MATERIALIZED <derived2> ALL NULL NULL NULL NULL 4 100.00
2 DERIVED e ALL NULL NULL NULL NULL 4 100.00 Using where
3 RECURSIVE UNION e ALL mgr-fk NULL NULL NULL 4 100.00 Using where
3 RECURSIVE UNION <derived2> ref key0 key0 5 test.e.mgr 2 100.00
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL NULL
Warnings:
-Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME ALL `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME ALL `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `test`.`emp`.`name` AS `name` from `test`.`emp` FOR SYSTEM_TIME ALL semi join (`ancestors`) where `test`.`emp`.`emp_id` = `ancestors`.`emp_id` and `test`.`emp`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999'
+Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME ALL `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME ALL `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `test`.`emp`.`name` AS `name` from `test`.`emp` FOR SYSTEM_TIME ALL semi join (`ancestors`) where `test`.`emp`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999'
with recursive
ancestors
as
diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result
index 9e532824414..aa651452108 100644
--- a/mysql-test/suite/versioning/r/partition.result
+++ b/mysql-test/suite/versioning/r/partition.result
@@ -555,17 +555,6 @@ t1 CREATE TABLE `t1` (
create or replace table t1 (f int) with system versioning partition by hash(f);
insert delayed into t1 values (1);
#
-# MDEV-17613 MIN/MAX Optimization (Select tables optimized away) does not work
-#
-create or replace table t1 (pk int primary key) with system versioning
-partition by system_time (
-partition p1 history,
-partition pn current);
-insert into t1 values (1), (2);
-explain select max(pk) from t1;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
-#
# MDEV-20068 History partition rotation is not done under LOCK TABLES
#
create or replace table t1 (x int) with system versioning partition by system_time limit 1
diff --git a/mysql-test/suite/versioning/r/partition_rotation.result b/mysql-test/suite/versioning/r/partition_rotation.result
index 69b30a56bd6..82558085c02 100644
--- a/mysql-test/suite/versioning/r/partition_rotation.result
+++ b/mysql-test/suite/versioning/r/partition_rotation.result
@@ -44,10 +44,10 @@ i
6
explain partitions select * from t1;
id select_type table partitions type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 pn_pnsp0,pn_pnsp1 ALL NULL NULL NULL NULL 2
+1 SIMPLE t1 pn_pnsp0,pn_pnsp1 ALL NULL NULL NULL NULL 2 Using where
explain partitions select * from t1 for system_time as of '2001-02-04 10:20:30';
id select_type table partitions type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 p1_p1sp0,p1_p1sp1,p0_p0sp0,p0_p0sp1,p2_p2sp0,p2_p2sp1,pn_pnsp0,pn_pnsp1 ALL NULL NULL NULL NULL # Using where
+1 SIMPLE t1 p0_p0sp0,p0_p0sp1,p2_p2sp0,p2_p2sp1,pn_pnsp0,pn_pnsp1 ALL NULL NULL NULL NULL # Using where
set @ts=(select row_end from t1 for system_time all where i=1);
select * from t1 for system_time all where row_end = @ts;
i
diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test
index ac9b0de690a..73df539d965 100644
--- a/mysql-test/suite/versioning/t/partition.test
+++ b/mysql-test/suite/versioning/t/partition.test
@@ -489,27 +489,6 @@ create or replace table t1 (f int) with system versioning partition by hash(f);
insert delayed into t1 values (1);
--echo #
---echo # MDEV-17613 MIN/MAX Optimization (Select tables optimized away) does not work
---echo #
---disable_query_log
-set @saved_storage_engine= @@default_storage_engine;
-if ($MTR_COMBINATION_HEAP)
-{
- # This case does not work with HEAP
- set default_storage_engine= myisam;
-}
---enable_query_log
-create or replace table t1 (pk int primary key) with system versioning
-partition by system_time (
- partition p1 history,
- partition pn current);
-insert into t1 values (1), (2);
-explain select max(pk) from t1;
---disable_query_log
-set default_storage_engine= @saved_storage_engine;
---enable_query_log
-
---echo #
--echo # MDEV-20068 History partition rotation is not done under LOCK TABLES
--echo #
create or replace table t1 (x int) with system versioning partition by system_time limit 1
diff --git a/mysys/my_static.c b/mysys/my_static.c
index 7b367756c11..fc4c60bc237 100644
--- a/mysys/my_static.c
+++ b/mysys/my_static.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- Copyright (c) 2009, 2012, Monty Program Ab.
+ Copyright (c) 2009, 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
@@ -36,6 +36,9 @@ ulong my_file_total_opened= 0;
int my_umask=0664, my_umask_dir=0777;
myf my_global_flags= 0;
+#ifndef DBUG_OFF
+my_bool my_assert= 1;
+#endif
my_bool my_assert_on_error= 0;
struct st_my_file_info my_file_info_default[MY_NFILE];
uint my_file_limit= MY_NFILE;
diff --git a/plugin/auth_pam/testing/pam_mariadb_mtr.c b/plugin/auth_pam/testing/pam_mariadb_mtr.c
index 0a6b56091d1..c0e07232027 100644
--- a/plugin/auth_pam/testing/pam_mariadb_mtr.c
+++ b/plugin/auth_pam/testing/pam_mariadb_mtr.c
@@ -56,7 +56,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags,
if (strcmp(r1, "crash pam module") == 0 && atoi(r2) == 616)
abort();
- if (strlen(r1) == (uint)atoi(r2) % 100)
+ if (strlen(r1) == (size_t)atoi(r2) % 100)
retval = PAM_SUCCESS;
else
retval = PAM_AUTH_ERR;
diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh
index 7add8541d7a..b8730e2624a 100644
--- a/scripts/mysqld_multi.sh
+++ b/scripts/mysqld_multi.sh
@@ -308,7 +308,9 @@ sub report_mysqlds
sub start_mysqlds()
{
- my (@groups, $com, $tmp, $i, @options, $j, $mysqld_found, $info_sent);
+ my (@groups, $com, $tmp, $i, @options, $j, $mysqld_found, $suffix_found, $info_sent);
+
+ $suffix_found= 0;
if (!$opt_no_log)
{
@@ -347,6 +349,10 @@ sub start_mysqlds()
$options[$j]= quote_shell_word($options[$j]);
$tmp.= " $options[$j]";
}
+ elseif ("--defaults-group-suffix=" eq substr($options[$j], 0, 24))
+ {
+ $suffix_found= 1;
+ }
else
{
$options[$j]= quote_shell_word($options[$j]);
@@ -364,6 +370,12 @@ sub start_mysqlds()
}
$com.= $tmp;
+ if (!$suffix_found)
+ {
+ $com.= " --defaults-group-suffix=";
+ $com.= $groups[$i];
+ }
+
if ($opt_wsrep_new_cluster) {
$com.= " --wsrep-new-cluster";
}
diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh
index 41c6f3370f8..16607470f2c 100755
--- a/scripts/wsrep_sst_common.sh
+++ b/scripts/wsrep_sst_common.sh
@@ -28,7 +28,12 @@ WSREP_SST_OPT_PSWD=${WSREP_SST_OPT_PSWD:-}
WSREP_SST_OPT_DEFAULT=""
WSREP_SST_OPT_EXTRA_DEFAULT=""
WSREP_SST_OPT_SUFFIX_DEFAULT=""
+WSREP_SST_OPT_SUFFIX_VALUE=""
+WSREP_SST_OPT_MYSQLD=""
INNODB_DATA_HOME_DIR_ARG=""
+INNODB_LOG_GROUP_HOME_ARG=""
+INNODB_UNDO_DIR_ARG=""
+LOG_BIN_ARG=""
while [ $# -gt 0 ]; do
case "$1" in
@@ -83,6 +88,18 @@ case "$1" in
readonly INNODB_DATA_HOME_DIR_ARG="$2"
shift
;;
+ '--innodb-log-group-home-dir')
+ readonly INNODB_LOG_GROUP_HOME_ARG="$2"
+ shift
+ ;;
+ '--innodb-undo-directory')
+ readonly INNODB_UNDO_DIR_ARG="$2"
+ shift
+ ;;
+ '--log-bin')
+ readonly LOG_BIN_ARG="$2"
+ shift
+ ;;
'--defaults-file')
readonly WSREP_SST_OPT_DEFAULT="$1=$2"
shift
@@ -93,6 +110,7 @@ case "$1" in
;;
'--defaults-group-suffix')
readonly WSREP_SST_OPT_SUFFIX_DEFAULT="$1=$2"
+ readonly WSREP_SST_OPT_SUFFIX_VALUE="$2"
shift
;;
'--host')
@@ -143,6 +161,50 @@ case "$1" in
readonly WSREP_SST_OPT_GTID_DOMAIN_ID="$2"
shift
;;
+ '--mysqld-args')
+ original_cmd=""
+ shift
+ while [ $# -gt 0 ]; do
+ option=${1%%=*}
+ if [[ "$option" != "--defaults-file" && \
+ "$option" != "--defaults-extra-file" && \
+ "$option" != "--defaults-group-suffix" && \
+ "$option" != "--port" && \
+ "$option" != "--socket" ]]; then
+ value=${1#*=}
+ case "$option" in
+ '--innodb-data-home-dir')
+ if [ -z "$INNODB_DATA_HOME_DIR_ARG" ]; then
+ readonly INNODB_DATA_HOME_DIR_ARG="$value"
+ fi
+ ;;
+ '--innodb-log-group-home-dir')
+ if [ -z "$INNODB_LOG_GROUP_HOME_ARG" ]; then
+ readonly INNODB_LOG_GROUP_HOME_ARG="$value"
+ fi
+ ;;
+ '--innodb-undo-directory')
+ if [ -z "$INNODB_UNDO_DIR_ARG" ]; then
+ readonly INNODB_UNDO_DIR_ARG="$value"
+ fi
+ ;;
+ '--log-bin')
+ if [ -z "$LOG_BIN_ARG" ]; then
+ readonly LOG_BIN_ARG="$value"
+ fi
+ ;;
+ esac
+ if [ -z "$original_cmd" ]; then
+ original_cmd="$1"
+ else
+ original_cmd="$original_cmd $1"
+ fi
+ fi
+ shift
+ done
+ readonly WSREP_SST_OPT_MYSQLD="$original_cmd"
+ break
+ ;;
*) # must be command
# usage
# exit 1
@@ -191,7 +253,15 @@ else
MY_PRINT_DEFAULTS=my_print_defaults
fi
-readonly WSREP_SST_OPT_CONF="$WSREP_SST_OPT_DEFAULT $WSREP_SST_OPT_EXTRA_DEFAULT $WSREP_SST_OPT_SUFFIX_DEFAULT"
+wsrep_defaults="$WSREP_SST_OPT_DEFAULT"
+if [ -n "$wsrep_defaults" ]; then
+ wsrep_defaults="$wsrep_defaults "
+fi
+wsrep_defaults="$wsrep_defaults$WSREP_SST_OPT_EXTRA_DEFAULT"
+if [ -n "$wsrep_defaults" ]; then
+ wsrep_defaults="$wsrep_defaults "
+fi
+readonly WSREP_SST_OPT_CONF="$wsrep_defaults$WSREP_SST_OPT_SUFFIX_DEFAULT"
readonly MY_PRINT_DEFAULTS="$MY_PRINT_DEFAULTS $WSREP_SST_OPT_CONF"
wsrep_auth_not_set()
diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh
index 6c3206a03e1..36deeff779d 100644
--- a/scripts/wsrep_sst_mariabackup.sh
+++ b/scripts/wsrep_sst_mariabackup.sh
@@ -60,7 +60,7 @@ rebuild=0
rebuildcmd=""
payload=0
pvformat="-F '%N => Rate:%r Avg:%a Elapsed:%t %e Bytes: %b %p' "
-pvopts="-f -i 10 -N $WSREP_SST_OPT_ROLE "
+pvopts="-f -i 10 -N $WSREP_SST_OPT_ROLE "
STATDIR=""
uextra=0
disver=""
@@ -130,7 +130,7 @@ get_keys()
if [[ $encrypt -eq 0 ]];then
if $MY_PRINT_DEFAULTS xtrabackup | grep -q encrypt;then
- wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html "
+ wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html"
fi
return
fi
@@ -464,7 +464,7 @@ cleanup_donor()
if [[ -n ${XTRABACKUP_PID:-} ]];then
if check_pid $XTRABACKUP_PID
then
- wsrep_log_error "xtrabackup process is still running. Killing... "
+ wsrep_log_error "xtrabackup process is still running. Killing..."
kill_xtrabackup
fi
@@ -566,7 +566,7 @@ check_extra()
# Xtrabackup works only locally.
# Hence, setting host to 127.0.0.1 unconditionally.
wsrep_log_info "SST through extra_port $eport"
- INNOEXTRA+=" --host=127.0.0.1 --port=$eport "
+ INNOEXTRA+=" --host=127.0.0.1 --port=$eport"
use_socket=0
else
wsrep_log_error "Extra port $eport null, failing"
@@ -576,8 +576,8 @@ check_extra()
wsrep_log_info "Thread pool not set, ignore the option use_extra"
fi
fi
- if [[ $use_socket -eq 1 ]] && [[ -n "${WSREP_SST_OPT_SOCKET}" ]];then
- INNOEXTRA+=" --socket=${WSREP_SST_OPT_SOCKET}"
+ if [[ $use_socket -eq 1 ]] && [[ -n "$WSREP_SST_OPT_SOCKET" ]];then
+ INNOEXTRA+=" --socket=$WSREP_SST_OPT_SOCKET"
fi
}
@@ -697,8 +697,7 @@ if [[ ${FORCE_FTWRL:-0} -eq 1 ]];then
iopts+=" --no-backup-locks "
fi
-
-INNOEXTRA=""
+INNOEXTRA=$WSREP_SST_OPT_MYSQLD
INNODB_DATA_HOME_DIR=${INNODB_DATA_HOME_DIR:-""}
# Try to set INNODB_DATA_HOME_DIR from the command line:
@@ -707,6 +706,9 @@ if [ ! -z "$INNODB_DATA_HOME_DIR_ARG" ]; then
fi
# if INNODB_DATA_HOME_DIR env. variable is not set, try to get it from my.cnf
if [ -z "$INNODB_DATA_HOME_DIR" ]; then
+ INNODB_DATA_HOME_DIR=$(parse_cnf mysqld$WSREP_SST_OPT_SUFFIX_VALUE innodb-data-home-dir '')
+fi
+if [ -z "$INNODB_DATA_HOME_DIR" ]; then
INNODB_DATA_HOME_DIR=$(parse_cnf --mysqld innodb-data-home-dir '')
fi
if [ ! -z "$INNODB_DATA_HOME_DIR" ]; then
@@ -741,8 +743,8 @@ if [[ $ssyslog -eq 1 ]];then
logger -p daemon.info -t ${ssystag}wsrep-sst-$WSREP_SST_OPT_ROLE "$@"
}
- INNOAPPLY="${INNOBACKUPEX_BIN} --innobackupex $disver $iapts \$INNOEXTRA --apply-log \$rebuildcmd \${DATA} 2>&1 | logger -p daemon.err -t ${ssystag}innobackupex-apply "
- INNOMOVE="${INNOBACKUPEX_BIN} --innobackupex ${WSREP_SST_OPT_CONF} $disver $impts --move-back --force-non-empty-directories \${DATA} 2>&1 | logger -p daemon.err -t ${ssystag}innobackupex-move "
+ INNOAPPLY="${INNOBACKUPEX_BIN} --innobackupex $disver $iapts \$INNOEXTRA --apply-log \$rebuildcmd \${DATA} 2>&1 | logger -p daemon.err -t ${ssystag}innobackupex-apply"
+ INNOMOVE="${INNOBACKUPEX_BIN} --innobackupex ${WSREP_SST_OPT_CONF} $disver $impts --move-back --force-non-empty-directories \${DATA} 2>&1 | logger -p daemon.err -t ${ssystag}innobackupex-move"
INNOBACKUP="${INNOBACKUPEX_BIN} --innobackupex ${WSREP_SST_OPT_CONF} $disver $iopts \$tmpopts \$INNOEXTRA --galera-info --stream=\$sfmt \$itmpdir 2> >(logger -p daemon.err -t ${ssystag}innobackupex-backup)"
fi
@@ -826,9 +828,11 @@ then
exit 93
fi
- if [[ -z $(parse_cnf --mysqld tmpdir "") && -z $(parse_cnf xtrabackup tmpdir "") ]];then
+ if [[ -z $(parse_cnf mysqld$WSREP_SST_OPT_SUFFIX_VALUE tmpdir "") && \
+ -z $(parse_cnf --mysqld tmpdir "") && \
+ -z $(parse_cnf xtrabackup tmpdir "") ]]; then
xtmpdir=$(mktemp -d)
- tmpopts=" --tmpdir=$xtmpdir "
+ tmpopts=" --tmpdir=$xtmpdir"
wsrep_log_info "Using $xtmpdir as xtrabackup temporary directory"
fi
@@ -850,13 +854,12 @@ then
get_keys
if [[ $encrypt -eq 1 ]];then
if [[ -n $ekey ]];then
- INNOEXTRA+=" --encrypt=$ealgo --encrypt-key=$ekey "
+ INNOEXTRA+=" --encrypt=$ealgo --encrypt-key=$ekey"
else
- INNOEXTRA+=" --encrypt=$ealgo --encrypt-key-file=$ekeyfile "
+ INNOEXTRA+=" --encrypt=$ealgo --encrypt-key-file=$ekeyfile"
fi
fi
-
check_extra
wsrep_log_info "Streaming GTID file before SST"
@@ -877,7 +880,6 @@ then
tcmd=" $scomp | $tcmd "
fi
-
send_donor $DATA "${stagemsg}-gtid"
tcmd="$ttcmd"
@@ -949,8 +951,24 @@ then
[[ -n $SST_PROGRESS_FILE ]] && touch $SST_PROGRESS_FILE
ib_home_dir=$INNODB_DATA_HOME_DIR
- ib_log_dir=$(parse_cnf --mysqld innodb-log-group-home-dir "")
- ib_undo_dir=$(parse_cnf --mysqld innodb-undo-directory "")
+
+ # Try to set ib_log_dir from the command line:
+ ib_log_dir=$INNODB_LOG_GROUP_HOME_ARG
+ if [ -z "$ib_log_dir" ]; then
+ ib_log_dir=$(parse_cnf mysqld$WSREP_SST_OPT_SUFFIX_VALUE innodb-log-group-home-dir "")
+ fi
+ if [ -z "$ib_log_dir" ]; then
+ ib_log_dir=$(parse_cnf --mysqld innodb-log-group-home-dir "")
+ fi
+
+ # Try to set ib_undo_dir from the command line:
+ ib_undo_dir=$INNODB_UNDO_DIR_ARG
+ if [ -z "$ib_undo_dir" ]; then
+ ib_undo_dir=$(parse_cnf mysqld$WSREP_SST_OPT_SUFFIX_VALUE innodb-undo-directory "")
+ fi
+ if [ -z "$ib_undo_dir" ]; then
+ ib_undo_dir=$(parse_cnf --mysqld innodb-undo-directory "")
+ fi
stagemsg="Joiner-Recv"
@@ -1027,7 +1045,13 @@ then
find $ib_home_dir $ib_log_dir $ib_undo_dir $DATA -mindepth 1 -prune -regex $cpat -o -exec rm -rfv {} 1>&2 \+
fi
- tempdir=$(parse_cnf --mysqld log-bin "")
+ tempdir=$LOG_BIN_ARG
+ if [ -z "$tempdir" ]; then
+ tempdir=$(parse_cnf mysqld$WSREP_SST_OPT_SUFFIX_VALUE log-bin "")
+ fi
+ if [ -z "$tempdir" ]; then
+ tempdir=$(parse_cnf --mysqld log-bin "")
+ fi
if [[ -n ${tempdir:-} ]];then
binlog_dir=$(dirname $tempdir)
binlog_file=$(basename $tempdir)
diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh
index 0fb7509d387..5403b9e8505 100644
--- a/scripts/wsrep_sst_rsync.sh
+++ b/scripts/wsrep_sst_rsync.sh
@@ -151,8 +151,15 @@ then
fi
WSREP_LOG_DIR=${WSREP_LOG_DIR:-""}
+# Try to set WSREP_LOG_DIR from the command line:
+if [ -z "$WSREP_LOG_DIR" ]; then
+ WSREP_LOG_DIR=$INNODB_LOG_GROUP_HOME_ARG
+fi
# if WSREP_LOG_DIR env. variable is not set, try to get it from my.cnf
if [ -z "$WSREP_LOG_DIR" ]; then
+ WSREP_LOG_DIR=$(parse_cnf mysqld$WSREP_SST_OPT_SUFFIX_VALUE innodb-log-group-home-dir '')
+fi
+if [ -z "$WSREP_LOG_DIR" ]; then
WSREP_LOG_DIR=$(parse_cnf --mysqld innodb-log-group-home-dir '')
fi
@@ -171,6 +178,9 @@ if [ ! -z "$INNODB_DATA_HOME_DIR_ARG" ]; then
fi
# if INNODB_DATA_HOME_DIR env. variable is not set, try to get it from my.cnf
if [ -z "$INNODB_DATA_HOME_DIR" ]; then
+ INNODB_DATA_HOME_DIR=$(parse_cnf mysqld$WSREP_SST_OPT_SUFFIX_VALUE innodb-data-home-dir '')
+fi
+if [ -z "$INNODB_DATA_HOME_DIR" ]; then
INNODB_DATA_HOME_DIR=$(parse_cnf --mysqld innodb-data-home-dir '')
fi
diff --git a/sql-common/my_time.c b/sql-common/my_time.c
index 22ea32e5076..5c14b8071a3 100644
--- a/sql-common/my_time.c
+++ b/sql-common/my_time.c
@@ -201,7 +201,7 @@ static int get_date_time_separator(uint *number_of_fields,
do
{
s++;
- } while (my_isspace(&my_charset_latin1, *s));
+ } while (s < end && my_isspace(&my_charset_latin1, *s));
*str= s;
return 0;
}
diff --git a/sql/create_options.cc b/sql/create_options.cc
index 5adcb2f1e9e..a8d997efaf4 100644
--- a/sql/create_options.cc
+++ b/sql/create_options.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010, 2017, MariaDB Corporation Ab
+/* 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
@@ -132,7 +132,8 @@ static bool set_one_value(ha_create_table_option *opt,
switch (opt->type)
{
case HA_OPTION_TYPE_SYSVAR:
- DBUG_ASSERT(0); // HA_OPTION_TYPE_SYSVAR's are replaced in resolve_sysvars()
+ // HA_OPTION_TYPE_SYSVAR's are replaced in resolve_sysvars()
+ break; // to DBUG_ASSERT(0)
case HA_OPTION_TYPE_ULL:
{
ulonglong *val= (ulonglong*)value_ptr(base, opt);
diff --git a/sql/field.cc b/sql/field.cc
index dbd9a30b244..be97ceeb227 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -7314,6 +7314,28 @@ void Field_string::sql_type(String &res) const
res.append(STRING_WITH_LEN(" binary"));
}
+/**
+ For fields which are associated with character sets their length is provided
+ in octets and their character set information is also provided as part of
+ type information.
+
+ @param res String which contains filed type and length.
+*/
+void Field_string::sql_rpl_type(String *res) const
+{
+ CHARSET_INFO *cs=charset();
+ if (Field_string::has_charset())
+ {
+ size_t length= cs->cset->snprintf(cs, (char*) res->ptr(),
+ res->alloced_length(),
+ "char(%u octets) character set %s",
+ field_length,
+ charset()->csname);
+ res->length(length);
+ }
+ else
+ Field_string::sql_type(*res);
+ }
uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length)
{
@@ -7754,6 +7776,29 @@ void Field_varstring::sql_type(String &res) const
res.append(STRING_WITH_LEN(" binary"));
}
+/**
+ For fields which are associated with character sets their length is provided
+ in octets and their character set information is also provided as part of
+ type information.
+
+ @param res String which contains filed type and length.
+*/
+void Field_varstring::sql_rpl_type(String *res) const
+{
+ CHARSET_INFO *cs=charset();
+ if (Field_varstring::has_charset())
+ {
+ size_t length= cs->cset->snprintf(cs, (char*) res->ptr(),
+ res->alloced_length(),
+ "varchar(%u octets) character set %s",
+ field_length,
+ charset()->csname);
+ res->length(length);
+ }
+ else
+ Field_varstring::sql_type(*res);
+}
+
uint32 Field_varstring::data_length()
{
diff --git a/sql/field.h b/sql/field.h
index 58bac152ea2..5ae8838c303 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, 2017, MariaDB Corporation.
+ Copyright (c) 2008, 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
@@ -579,6 +579,7 @@ public:
/* Flag indicating that the field is physically stored in the database */
bool stored_in_db;
bool utf8; /* Already in utf8 */
+ bool automatic_name;
Item *expr;
Lex_ident name; /* Name of constraint */
/* see VCOL_* (VCOL_FIELD_REF, ...) */
@@ -588,7 +589,7 @@ public:
:Type_handler_hybrid_field_type(&type_handler_null),
vcol_type((enum_vcol_info_type)VCOL_TYPE_NONE),
in_partitioning_expr(FALSE), stored_in_db(FALSE),
- utf8(TRUE), expr(NULL), flags(0)
+ utf8(TRUE), automatic_name(FALSE), expr(NULL), flags(0)
{
name.str= NULL;
name.length= 0;
@@ -1198,6 +1199,7 @@ public:
in str and restore it with set() if needed
*/
virtual void sql_type(String &str) const =0;
+ virtual void sql_rpl_type(String *str) const { sql_type(*str); }
virtual uint size_of() const =0; // For new field
inline bool is_null(my_ptrdiff_t row_offset= 0) const
{
@@ -3700,6 +3702,7 @@ public:
st->m_fixed_string_total_length+= pack_length();
}
void sql_type(String &str) const;
+ void sql_rpl_type(String*) const;
bool is_equal(const Column_definition &new_field) const;
bool can_be_converted_by_engine(const Column_definition &new_type) const
{
@@ -3822,6 +3825,7 @@ public:
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);
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index b19e86c27a6..45ea9eb1552 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -8303,6 +8303,7 @@ int ha_partition::info(uint flag)
ulonglong max_records= 0;
uint32 i= 0;
uint32 handler_instance= 0;
+ bool handler_instance_set= 0;
file_array= m_file;
do
@@ -8315,8 +8316,9 @@ int ha_partition::info(uint flag)
!bitmap_is_set(&(m_part_info->read_partitions),
(uint) (file_array - m_file)))
file->info(HA_STATUS_VARIABLE | no_lock_flag | extra_var_flag);
- if (file->stats.records > max_records)
+ if (file->stats.records > max_records || !handler_instance_set)
{
+ handler_instance_set= 1;
max_records= file->stats.records;
handler_instance= i;
}
diff --git a/sql/handler.cc b/sql/handler.cc
index 5f2a1a573ba..5f0c8e0b5ec 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -2026,9 +2026,9 @@ static char* xid_to_str(char *buf, XID *xid)
}
#endif
-#ifdef WITH_WSREP
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();
long long cur_seqno= cur_position.seqno().get();
@@ -2046,8 +2046,10 @@ static my_xid wsrep_order_and_check_continuity(XID *list, int len)
}
WSREP_INFO("Last wsrep seqno to be recovered %lld", cur_seqno);
return (cur_seqno < 0 ? 0 : cur_seqno);
-}
+#else
+ return 0;
#endif /* WITH_WSREP */
+}
/**
recover() step of xa.
@@ -2085,7 +2087,6 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
{
sql_print_information("Found %d prepared transaction(s) in %s",
got, hton_name(hton)->str);
-#ifdef WITH_WSREP
/* If wsrep_on=ON, XIDs are first ordered and then the range of
recovered XIDs is checked for continuity. All the XIDs which
are in continuous range can be safely committed if binlog
@@ -2101,12 +2102,10 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
crashes after T2 finishes prepare step but before T1 starts
the prepare.
*/
- my_xid wsrep_limit= 0;
+ my_xid wsrep_limit __attribute__((unused))= 0;
if (WSREP_ON)
- {
wsrep_limit= wsrep_order_and_check_continuity(info->list, got);
- }
-#endif /* WITH_WSREP */
+
for (int i=0; i < got; i ++)
{
my_xid x= IF_WSREP(WSREP_ON && wsrep_is_wsrep_xid(&info->list[i]) ?
@@ -2115,10 +2114,10 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
info->list[i].get_my_xid());
if (!x) // not "mine" - that is generated by external TM
{
-#ifndef DBUG_OFF
- char buf[XIDDATASIZE*4+6]; // see xid_to_str
- DBUG_PRINT("info", ("ignore xid %s", xid_to_str(buf, info->list+i)));
-#endif
+ DBUG_EXECUTE("info",{
+ char buf[XIDDATASIZE*4+6];
+ _db_doprnt_("ignore xid %s", xid_to_str(buf, info->list+i));
+ });
xid_cache_insert(info->list + i);
info->found_foreign_xids++;
continue;
@@ -2139,32 +2138,25 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
my_hash_search(info->commit_list, (uchar *)&x, sizeof(x)) != 0 :
tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT))
{
-#ifndef DBUG_OFF
- int rc=
-#endif
- hton->commit_by_xid(hton, info->list+i);
-#ifndef DBUG_OFF
+ int rc= hton->commit_by_xid(hton, info->list+i);
if (rc == 0)
{
- char buf[XIDDATASIZE*4+6]; // see xid_to_str
- DBUG_PRINT("info", ("commit xid %s", xid_to_str(buf, info->list+i)));
+ DBUG_EXECUTE("info",{
+ char buf[XIDDATASIZE*4+6];
+ _db_doprnt_("commit xid %s", xid_to_str(buf, info->list+i));
+ });
}
-#endif
}
else
{
-#ifndef DBUG_OFF
- int rc=
-#endif
- hton->rollback_by_xid(hton, info->list+i);
-#ifndef DBUG_OFF
+ int rc= hton->rollback_by_xid(hton, info->list+i);
if (rc == 0)
{
- char buf[XIDDATASIZE*4+6]; // see xid_to_str
- DBUG_PRINT("info", ("rollback xid %s",
- xid_to_str(buf, info->list+i)));
+ DBUG_EXECUTE("info",{
+ char buf[XIDDATASIZE*4+6];
+ _db_doprnt_("rollback xid %s", xid_to_str(buf, info->list+i));
+ });
}
-#endif
}
}
if (got < info->len)
diff --git a/sql/item.cc b/sql/item.cc
index 98bc56c9025..7d1c71901f2 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -3782,6 +3782,20 @@ my_decimal *Item_null::val_decimal(my_decimal *decimal_value)
}
+longlong Item_null::val_datetime_packed(THD *)
+{
+ null_value= true;
+ return 0;
+}
+
+
+longlong Item_null::val_time_packed(THD *)
+{
+ null_value= true;
+ return 0;
+}
+
+
bool Item_null::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
@@ -8223,6 +8237,24 @@ bool Item_ref::val_native(THD *thd, Native *to)
}
+longlong Item_ref::val_datetime_packed(THD *thd)
+{
+ DBUG_ASSERT(fixed);
+ longlong tmp= (*ref)->val_datetime_packed(thd);
+ null_value= (*ref)->null_value;
+ return tmp;
+}
+
+
+longlong Item_ref::val_time_packed(THD *thd)
+{
+ DBUG_ASSERT(fixed);
+ longlong tmp= (*ref)->val_time_packed(thd);
+ null_value= (*ref)->null_value;
+ return tmp;
+}
+
+
my_decimal *Item_ref::val_decimal(my_decimal *decimal_value)
{
my_decimal *val= (*ref)->val_decimal_result(decimal_value);
diff --git a/sql/item.h b/sql/item.h
index 6e1f1e3891e..b9a0287482e 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -767,7 +767,7 @@ public:
/* Cache of the result of is_expensive(). */
int8 is_expensive_cache;
- /* Reuse size, only used by SP local variable assignment, otherwize 0 */
+ /* Reuse size, only used by SP local variable assignment, otherwise 0 */
uint rsize;
protected:
@@ -3556,6 +3556,8 @@ public:
String *val_str(String *str);
my_decimal *val_decimal(my_decimal *);
bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ longlong val_datetime_packed(THD *);
+ longlong val_time_packed(THD *);
int save_in_field(Field *field, bool no_conversions);
int save_safe_in_field(Field *field);
bool send(Protocol *protocol, st_value *buffer);
@@ -5140,6 +5142,8 @@ public:
bool val_native(THD *thd, Native *to);
bool is_null();
bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ longlong val_datetime_packed(THD *);
+ longlong val_time_packed(THD *);
double val_result();
longlong val_int_result();
String *str_result(String* tmp);
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index c9f4d731318..a311c32c5a6 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -132,6 +132,9 @@ public:
int compare_e_json_str();
int compare_e_str_json();
+ void min_max_update_field_native(THD *thd, Field *field, Item *item,
+ int cmp_sign);
+
Item** cache_converted_constant(THD *thd, Item **value, Item **cache,
const Type_handler *type);
inline bool is_owner_equal_func()
diff --git a/sql/item_func.cc b/sql/item_func.cc
index af908d9d553..eaf6113e10e 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2350,6 +2350,42 @@ void Item_func_round::fix_arg_double()
}
+void Item_func_round::fix_arg_temporal(const Type_handler *h,
+ uint int_part_length)
+{
+ set_handler(h);
+ if (args[1]->const_item() && !args[1]->is_expensive())
+ {
+ Longlong_hybrid_null dec= args[1]->to_longlong_hybrid_null();
+ fix_attributes_temporal(int_part_length,
+ dec.is_null() ? args[0]->decimals :
+ dec.to_uint(TIME_SECOND_PART_DIGITS));
+ }
+ else
+ fix_attributes_temporal(int_part_length, args[0]->decimals);
+}
+
+
+void Item_func_round::fix_arg_time()
+{
+ fix_arg_temporal(&type_handler_time2, MIN_TIME_WIDTH);
+}
+
+
+void Item_func_round::fix_arg_datetime()
+{
+ /*
+ Day increment operations are not supported for '0000-00-00',
+ see get_date_from_daynr() for details. Therefore, expressions like
+ ROUND('0000-00-00 23:59:59.999999')
+ return NULL.
+ */
+ if (!truncate)
+ maybe_null= true;
+ fix_arg_temporal(&type_handler_datetime2, MAX_DATETIME_WIDTH);
+}
+
+
void Item_func_round::fix_arg_int()
{
if (args[1]->const_item())
@@ -2489,6 +2525,36 @@ my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value)
}
+bool Item_func_round::time_op(THD *thd, MYSQL_TIME *to)
+{
+ DBUG_ASSERT(args[0]->type_handler()->mysql_timestamp_type() ==
+ MYSQL_TIMESTAMP_TIME);
+ Time::Options opt(Time::default_flags_for_get_date(),
+ truncate ? TIME_FRAC_TRUNCATE : TIME_FRAC_ROUND,
+ Time::DATETIME_TO_TIME_DISALLOW);
+ Longlong_hybrid_null dec= args[1]->to_longlong_hybrid_null();
+ Time *tm= new (to) Time(thd, args[0], opt,
+ dec.to_uint(TIME_SECOND_PART_DIGITS));
+ null_value= !tm->is_valid_time() || dec.is_null();
+ DBUG_ASSERT(maybe_null || !null_value);
+ return null_value;
+}
+
+
+bool Item_func_round::date_op(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate)
+{
+ DBUG_ASSERT(args[0]->type_handler()->mysql_timestamp_type() ==
+ MYSQL_TIMESTAMP_DATETIME);
+ Datetime::Options opt(thd, truncate ? TIME_FRAC_TRUNCATE : TIME_FRAC_ROUND);
+ Longlong_hybrid_null dec= args[1]->to_longlong_hybrid_null();
+ Datetime *tm= new (to) Datetime(thd, args[0], opt,
+ dec.to_uint(TIME_SECOND_PART_DIGITS));
+ null_value= !tm->is_valid_datetime() || dec.is_null();
+ DBUG_ASSERT(maybe_null || !null_value);
+ return null_value;
+}
+
+
void Item_func_rand::seed_random(Item *arg)
{
/*
diff --git a/sql/item_func.h b/sql/item_func.h
index 22832543242..f1212033b6c 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1715,21 +1715,36 @@ public:
/* This handles round and truncate */
-class Item_func_round :public Item_func_numhybrid
+class Item_func_round :public Item_func_hybrid_field_type
{
bool truncate;
void fix_length_and_dec_decimal(uint decimals_to_set);
void fix_length_and_dec_double(uint decimals_to_set);
public:
Item_func_round(THD *thd, Item *a, Item *b, bool trunc_arg)
- :Item_func_numhybrid(thd, a, b), truncate(trunc_arg) {}
+ :Item_func_hybrid_field_type(thd, a, b), truncate(trunc_arg) {}
const char *func_name() const { return truncate ? "truncate" : "round"; }
double real_op();
longlong int_op();
my_decimal *decimal_op(my_decimal *);
+ bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool time_op(THD *thd, MYSQL_TIME *ltime);
+ bool native_op(THD *thd, Native *to)
+ {
+ DBUG_ASSERT(0);
+ return true;
+ }
+ String *str_op(String *str)
+ {
+ DBUG_ASSERT(0);
+ return NULL;
+ }
void fix_arg_decimal();
void fix_arg_int();
void fix_arg_double();
+ void fix_arg_time();
+ void fix_arg_datetime();
+ void fix_arg_temporal(const Type_handler *h, uint int_part_length);
bool fix_length_and_dec()
{
return args[0]->type_handler()->Item_func_round_fix_length_and_dec(this);
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 87f3e1d3345..5ff31898a0d 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -3089,18 +3089,32 @@ void Item_sum_min_max::update_field()
tmp_item= args[0];
args[0]= direct_item;
}
- switch (result_type()) {
- case STRING_RESULT:
- min_max_update_str_field();
- break;
- case INT_RESULT:
- min_max_update_int_field();
- break;
- case DECIMAL_RESULT:
- min_max_update_decimal_field();
- break;
- default:
- min_max_update_real_field();
+ if (Item_sum_min_max::type_handler()->is_val_native_ready())
+ {
+ /*
+ TODO-10.5: change Item_sum_min_max to use val_native() for all data types
+ - make all type handlers val_native() ready
+ - use min_max_update_native_field() for all data types
+ - remove Item_sum_min_max::min_max_update_{str|real|int|decimal}_field()
+ */
+ min_max_update_native_field();
+ }
+ else
+ {
+ switch (Item_sum_min_max::type_handler()->cmp_type()) {
+ case STRING_RESULT:
+ case TIME_RESULT:
+ min_max_update_str_field();
+ break;
+ case INT_RESULT:
+ min_max_update_int_field();
+ break;
+ case DECIMAL_RESULT:
+ min_max_update_decimal_field();
+ break;
+ default:
+ min_max_update_real_field();
+ }
}
if (unlikely(direct_added))
{
@@ -3111,6 +3125,40 @@ void Item_sum_min_max::update_field()
}
+void Arg_comparator::min_max_update_field_native(THD *thd,
+ Field *field,
+ Item *item,
+ int cmp_sign)
+{
+ DBUG_ENTER("Arg_comparator::min_max_update_field_native");
+ if (!item->val_native(current_thd, &m_native2))
+ {
+ if (field->is_null())
+ field->store_native(m_native2); // The first non-null value
+ else
+ {
+ field->val_native(&m_native1);
+ if ((cmp_sign * m_compare_handler->cmp_native(m_native2, m_native1)) < 0)
+ field->store_native(m_native2);
+ }
+ field->set_notnull();
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+void
+Item_sum_min_max::min_max_update_native_field()
+{
+ DBUG_ENTER("Item_sum_min_max::min_max_update_native_field");
+ DBUG_ASSERT(cmp);
+ DBUG_ASSERT(type_handler_for_comparison() == cmp->compare_type_handler());
+ THD *thd= current_thd;
+ cmp->min_max_update_field_native(thd, result_field, args[0], cmp_sign);
+ DBUG_VOID_RETURN;
+}
+
+
void
Item_sum_min_max::min_max_update_str_field()
{
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 16cc8d131b8..50c7b524d6c 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -1117,6 +1117,7 @@ public:
void min_max_update_real_field();
void min_max_update_int_field();
void min_max_update_decimal_field();
+ void min_max_update_native_field();
void cleanup();
bool any_value() { return was_values; }
void no_rows_in_result();
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 689258158a1..d621a3be1cd 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1590,7 +1590,7 @@ static my_bool kill_thread_phase_2(THD *thd, void *)
/* associated with the kill thread phase 1 */
static my_bool warn_threads_active_after_phase_1(THD *thd, void *)
{
- if (!thd->is_binlog_dump_thread())
+ if (!thd->is_binlog_dump_thread() && thd->vio_ok())
sql_print_warning("%s: Thread %llu (user : '%s') did not exit\n", my_progname,
(ulonglong) thd->thread_id,
(thd->main_security_ctx.user ?
@@ -6493,6 +6493,10 @@ struct my_option my_long_options[]=
0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif /* HAVE_REPLICATION */
#ifndef DBUG_OFF
+ {"debug-assert", 0,
+ "Allow DBUG_ASSERT() to invoke assert()",
+ &my_assert, &my_assert,
+ 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
{"debug-assert-on-error", 0,
"Do an assert in various functions if we get a fatal error",
&my_assert_on_error, &my_assert_on_error,
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index f00d0ed019d..de999559b8c 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -2192,12 +2192,15 @@ int pull_out_semijoin_tables(JOIN *join)
TABLE_LIST *sj_nest;
DBUG_ENTER("pull_out_semijoin_tables");
List_iterator<TABLE_LIST> sj_list_it(join->select_lex->sj_nests);
-
+
/* Try pulling out of the each of the semi-joins */
while ((sj_nest= sj_list_it++))
{
List_iterator<TABLE_LIST> child_li(sj_nest->nested_join->join_list);
TABLE_LIST *tbl;
+ Json_writer_object trace_wrapper(join->thd);
+ Json_writer_object trace(join->thd, "semijoin_table_pullout");
+ Json_writer_array trace_arr(join->thd, "pulled_out_tables");
/*
Don't do table pull-out for nested joins (if we get nested joins here, it
@@ -2296,7 +2299,8 @@ int pull_out_semijoin_tables(JOIN *join)
pulled_a_table= TRUE;
pulled_tables |= tbl->table->map;
DBUG_PRINT("info", ("Table %s pulled out (reason: func dep)",
- tbl->table->alias.c_ptr()));
+ tbl->table->alias.c_ptr_safe()));
+ trace_arr.add(tbl->table->alias.c_ptr_safe());
/*
Pulling a table out of uncorrelated subquery in general makes
makes it correlated. See the NOTE to this funtion.
@@ -2456,7 +2460,7 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
&subjoin_out_rows);
sjm->materialization_cost.convert_from_cost(subjoin_read_time);
- sjm->rows= subjoin_out_rows;
+ sjm->rows_with_duplicates= sjm->rows= subjoin_out_rows;
// Don't use the following list because it has "stale" items. use
// ref_pointer_array instead:
@@ -2778,27 +2782,30 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx,
{
POSITION *pos= join->positions + idx;
const JOIN_TAB *new_join_tab= pos->table;
- Semi_join_strategy_picker *pickers[]=
- {
- &pos->firstmatch_picker,
- &pos->loosescan_picker,
- &pos->sjmat_picker,
- &pos->dups_weedout_picker,
- NULL,
- };
-
- if (join->emb_sjm_nest)
+ if (join->emb_sjm_nest || //(1)
+ !join->select_lex->have_merged_subqueries) //(2)
{
/*
- We're performing optimization inside SJ-Materialization nest:
+ (1): We're performing optimization inside SJ-Materialization nest:
- there are no other semi-joins inside semi-join nests
- attempts to build semi-join strategies here will confuse
the optimizer, so bail out.
+ (2): Don't waste time on semi-join optimizations if we don't have any
+ semi-joins
*/
pos->sj_strategy= SJ_OPT_NONE;
return;
}
+ Semi_join_strategy_picker *pickers[]=
+ {
+ &pos->firstmatch_picker,
+ &pos->loosescan_picker,
+ &pos->sjmat_picker,
+ &pos->dups_weedout_picker,
+ NULL,
+ };
+ Json_writer_array trace_steps(join->thd, "semijoin_strategy_choice");
/*
Update join->cur_sj_inner_tables (Used by FirstMatch in this function and
LooseScan detector in best_access_path)
@@ -2897,6 +2904,7 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx,
*current_read_time= read_time;
*current_record_count= rec_count;
dups_producing_tables &= ~handled_fanout;
+
//TODO: update bitmap of semi-joins that were handled together with
// others.
if (is_multiple_semi_joins(join, join->positions, idx,
@@ -2924,6 +2932,33 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx,
}
}
}
+
+ if (unlikely(join->thd->trace_started() && pos->sj_strategy != SJ_OPT_NONE))
+ {
+ Json_writer_object tr(join->thd);
+ const char *sname;
+ switch (pos->sj_strategy) {
+ case SJ_OPT_MATERIALIZE:
+ sname= "SJ-Materialize";
+ break;
+ case SJ_OPT_MATERIALIZE_SCAN:
+ sname= "SJ-Materialize-Scan";
+ break;
+ case SJ_OPT_FIRST_MATCH:
+ sname= "FirstMatch";
+ break;
+ case SJ_OPT_DUPS_WEEDOUT:
+ sname= "DuplicateWeedout";
+ break;
+ case SJ_OPT_LOOSE_SCAN:
+ sname= "LooseScan";
+ break;
+ default:
+ DBUG_ASSERT(0);
+ sname="Invalid";
+ }
+ tr.add("chosen_strategy", sname);
+ }
}
if ((emb_sj_nest= new_join_tab->emb_sj_nest))
@@ -3000,6 +3035,8 @@ bool Sj_materialization_picker::check_qep(JOIN *join,
}
else
{
+ Json_writer_object trace(join->thd);
+ trace.add("strategy", "SJ-Materialization");
/* This is SJ-Materialization with lookups */
Cost_estimate prefix_cost;
signed int first_tab= (int)idx - mat_info->tables;
@@ -3032,6 +3069,11 @@ bool Sj_materialization_picker::check_qep(JOIN *join,
*record_count= prefix_rec_count;
*handled_fanout= new_join_tab->emb_sj_nest->sj_inner_tables;
*strategy= SJ_OPT_MATERIALIZE;
+ if (unlikely(join->thd->trace_started()))
+ {
+ trace.add("records", *record_count);
+ trace.add("read_time", *read_time);
+ }
return TRUE;
}
}
@@ -3040,6 +3082,8 @@ bool Sj_materialization_picker::check_qep(JOIN *join,
if (sjm_scan_need_tables && /* Have SJM-Scan prefix */
!(sjm_scan_need_tables & remaining_tables))
{
+ Json_writer_object trace(join->thd);
+ trace.add("strategy", "SJ-Materialization-Scan");
TABLE_LIST *mat_nest=
join->positions[sjm_scan_last_inner].table->emb_sj_nest;
SJ_MATERIALIZATION_INFO *mat_info= mat_nest->sj_mat_info;
@@ -3082,12 +3126,20 @@ bool Sj_materialization_picker::check_qep(JOIN *join,
disable_jbuf, prefix_rec_count, &curpos, &dummy);
prefix_rec_count= COST_MULT(prefix_rec_count, curpos.records_read);
prefix_cost= COST_ADD(prefix_cost, curpos.read_time);
+ prefix_cost= COST_ADD(prefix_cost,
+ prefix_rec_count / (double) TIME_FOR_COMPARE);
+ //TODO: take into account join condition selectivity here
}
*strategy= SJ_OPT_MATERIALIZE_SCAN;
*read_time= prefix_cost;
- *record_count= prefix_rec_count;
+ *record_count= prefix_rec_count / mat_info->rows_with_duplicates;
*handled_fanout= mat_nest->sj_inner_tables;
+ if (unlikely(join->thd->trace_started()))
+ {
+ trace.add("records", *record_count);
+ trace.add("read_time", *read_time);
+ }
return TRUE;
}
return FALSE;
@@ -3151,6 +3203,8 @@ bool LooseScan_picker::check_qep(JOIN *join,
!(remaining_tables & loosescan_need_tables) &&
(new_join_tab->table->map & loosescan_need_tables))
{
+ Json_writer_object trace(join->thd);
+ trace.add("strategy", "SJ-Materialization-Scan");
/*
Ok we have LooseScan plan and also have all LooseScan sj-nest's
inner tables and outer correlated tables into the prefix.
@@ -3181,6 +3235,11 @@ bool LooseScan_picker::check_qep(JOIN *join,
*/
*strategy= SJ_OPT_LOOSE_SCAN;
*handled_fanout= first->table->emb_sj_nest->sj_inner_tables;
+ if (unlikely(join->thd->trace_started()))
+ {
+ trace.add("records", *record_count);
+ trace.add("read_time", *read_time);
+ }
return TRUE;
}
return FALSE;
@@ -3260,6 +3319,8 @@ bool Firstmatch_picker::check_qep(JOIN *join,
if (in_firstmatch_prefix() &&
!(firstmatch_need_tables & remaining_tables))
{
+ Json_writer_object trace(join->thd);
+ trace.add("strategy", "FirstMatch");
/*
Got a complete FirstMatch range. Calculate correct costs and fanout
*/
@@ -3292,6 +3353,11 @@ bool Firstmatch_picker::check_qep(JOIN *join,
*handled_fanout= firstmatch_need_tables;
/* *record_count and *read_time were set by the above call */
*strategy= SJ_OPT_FIRST_MATCH;
+ if (unlikely(join->thd->trace_started()))
+ {
+ trace.add("records", *record_count);
+ trace.add("read_time", *read_time);
+ }
return TRUE;
}
}
@@ -3370,6 +3436,8 @@ bool Duplicate_weedout_picker::check_qep(JOIN *join,
double sj_inner_fanout= 1.0;
double sj_outer_fanout= 1.0;
uint temptable_rec_size;
+ Json_writer_object trace(join->thd);
+ trace.add("strategy", "DuplicateWeedout");
if (first_tab == join->const_tables)
{
prefix_rec_count= 1.0;
@@ -3430,6 +3498,11 @@ bool Duplicate_weedout_picker::check_qep(JOIN *join,
*record_count= prefix_rec_count * sj_outer_fanout;
*handled_fanout= dups_removed_fanout;
*strategy= SJ_OPT_DUPS_WEEDOUT;
+ if (unlikely(join->thd->trace_started()))
+ {
+ trace.add("records", *record_count);
+ trace.add("read_time", *read_time);
+ }
return TRUE;
}
return FALSE;
@@ -3660,7 +3733,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
join->best_positions[first].n_sj_tables= sjm->tables;
join->best_positions[first].sj_strategy= SJ_OPT_MATERIALIZE;
Json_writer_object semijoin_strategy(thd);
- semijoin_strategy.add("semi_join_strategy","sj_materialize");
+ semijoin_strategy.add("semi_join_strategy","SJ-Materialization");
Json_writer_array semijoin_plan(thd, "join_order");
for (uint i= first; i < first+ sjm->tables; i++)
{
@@ -3709,7 +3782,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
POSITION dummy;
join->cur_sj_inner_tables= 0;
Json_writer_object semijoin_strategy(thd);
- semijoin_strategy.add("semi_join_strategy","sj_materialize_scan");
+ semijoin_strategy.add("semi_join_strategy","SJ-Materialization-Scan");
Json_writer_array semijoin_plan(thd, "join_order");
for (i= first + sjm->tables; i <= tablenr; i++)
{
@@ -3747,7 +3820,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
*/
join->cur_sj_inner_tables= 0;
Json_writer_object semijoin_strategy(thd);
- semijoin_strategy.add("semi_join_strategy","firstmatch");
+ semijoin_strategy.add("semi_join_strategy","FirstMatch");
Json_writer_array semijoin_plan(thd, "join_order");
for (idx= first; idx <= tablenr; idx++)
{
@@ -3785,7 +3858,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
*/
join->cur_sj_inner_tables= 0;
Json_writer_object semijoin_strategy(thd);
- semijoin_strategy.add("semi_join_strategy","sj_materialize");
+ semijoin_strategy.add("semi_join_strategy","LooseScan");
Json_writer_array semijoin_plan(thd, "join_order");
for (idx= first; idx <= tablenr; idx++)
{
diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h
index 65131f6bc89..6210fc972c8 100644
--- a/sql/opt_subselect.h
+++ b/sql/opt_subselect.h
@@ -96,15 +96,14 @@ public:
Loose_scan_opt():
try_loosescan(FALSE),
bound_sj_equalities(0),
- quick_uses_applicable_index(FALSE)
+ quick_uses_applicable_index(0),
+ quick_max_loose_keypart(0),
+ best_loose_scan_key(0),
+ best_loose_scan_cost(0),
+ best_loose_scan_records(0),
+ best_loose_scan_start_key(NULL),
+ best_max_loose_keypart(0)
{
- /* Protected by quick_uses_applicable_index */
- LINT_INIT(quick_max_loose_keypart);
- /* The following are protected by best_loose_scan_cost!= DBL_MAX */
- LINT_INIT(best_loose_scan_key);
- LINT_INIT(best_loose_scan_records);
- LINT_INIT(best_max_loose_keypart);
- LINT_INIT(best_loose_scan_start_key);
}
void init(JOIN *join, JOIN_TAB *s, table_map remaining_tables)
diff --git a/sql/partition_element.h b/sql/partition_element.h
index a3eb6953be1..ff0d0d59fc4 100644
--- a/sql/partition_element.h
+++ b/sql/partition_element.h
@@ -98,7 +98,7 @@ enum stat_trx_field
class partition_element :public Sql_alloc
{
public:
- enum elem_type
+ enum elem_type_enum
{
CONVENTIONAL= 0,
CURRENT,
@@ -125,19 +125,7 @@ public:
bool max_value; // MAXVALUE range
uint32 id;
bool empty;
-
- // TODO: subclass partition_element by partitioning type to avoid such semantic
- // mixup
- elem_type type()
- {
- return (elem_type)(int(signed_flag) << 1 | int(max_value));
- }
-
- void type(elem_type val)
- {
- max_value= (bool)(val & 1);
- signed_flag= (bool)(val & 2);
- }
+ elem_type_enum type;
partition_element()
: part_max_rows(0), part_min_rows(0), range_value(0),
@@ -148,7 +136,8 @@ public:
nodegroup_id(UNDEF_NODEGROUP), has_null_value(FALSE),
signed_flag(FALSE), max_value(FALSE),
id(UINT_MAX32),
- empty(true)
+ empty(true),
+ type(CONVENTIONAL)
{}
partition_element(partition_element *part_elem)
: part_max_rows(part_elem->part_max_rows),
@@ -164,13 +153,13 @@ public:
nodegroup_id(part_elem->nodegroup_id),
has_null_value(FALSE),
id(part_elem->id),
- empty(part_elem->empty)
+ empty(part_elem->empty),
+ type(CONVENTIONAL)
{}
~partition_element() {}
part_column_list_val& get_col_val(uint idx)
{
- DBUG_ASSERT(type() == CONVENTIONAL || list_val_list.elements == 1);
part_elem_value *ev= list_val_list.head();
DBUG_ASSERT(ev);
DBUG_ASSERT(ev->col_val_array);
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index 66216493de8..38e085b3be9 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -894,15 +894,16 @@ bool partition_info::vers_setup_expression(THD * thd, uint32 alter_add)
DBUG_ASSERT(part_type == VERSIONING_PARTITION);
DBUG_ASSERT(table->versioned(VERS_TIMESTAMP));
- DBUG_ASSERT(num_columns == 1);
if (!alter_add)
{
Field *row_end= table->vers_end_field();
- part_field_list.push_back(row_end->field_name.str, thd->mem_root);
- DBUG_ASSERT(part_field_list.elements == 1);
// 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)
@@ -911,12 +912,12 @@ bool partition_info::vers_setup_expression(THD * thd, uint32 alter_add)
partition_element *el;
for(uint32 id= 0; ((el= it++)); id++)
{
- DBUG_ASSERT(el->type() != partition_element::CONVENTIONAL);
+ 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)
+ if (el->id == UINT_MAX32 || el->type == partition_element::CURRENT)
{
el->id= id;
- if (el->type() == partition_element::CURRENT)
+ if (el->type == partition_element::CURRENT)
break;
}
}
@@ -1343,13 +1344,13 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
}
if (part_type == VERSIONING_PARTITION)
{
- if (part_elem->type() == partition_element::HISTORY)
+ if (part_elem->type == partition_element::HISTORY)
{
hist_parts++;
}
else
{
- DBUG_ASSERT(part_elem->type() == partition_element::CURRENT);
+ DBUG_ASSERT(part_elem->type == partition_element::CURRENT);
now_parts++;
}
}
@@ -1473,15 +1474,8 @@ void partition_info::print_no_partition_found(TABLE *table_arg, myf errflag)
FALSE Success
*/
-bool partition_info::set_part_expr(THD *thd, char *start_token, Item *item_ptr,
- char *end_token, bool is_subpart)
+bool partition_info::set_part_expr(THD *thd, Item *item_ptr, bool is_subpart)
{
- size_t expr_len= end_token - start_token;
- char *func_string= (char*) thd->memdup(start_token, expr_len);
-
- if (unlikely(!func_string))
- return TRUE;
-
if (is_subpart)
{
list_of_subpart_fields= FALSE;
@@ -2650,12 +2644,9 @@ part_column_list_val *partition_info::add_column_value(THD *thd)
return NULL;
}
-bool partition_info::set_part_expr(THD *thd, char *start_token, Item *item_ptr,
- char *end_token, bool is_subpart)
+bool partition_info::set_part_expr(THD *thd, Item *item_ptr, bool is_subpart)
{
- (void)start_token;
(void)item_ptr;
- (void)end_token;
(void)is_subpart;
return FALSE;
}
@@ -2693,9 +2684,8 @@ bool check_partition_dirs(partition_info *part_info)
bool partition_info::vers_init_info(THD * thd)
{
part_type= VERSIONING_PARTITION;
- list_of_part_fields= TRUE;
- column_list= TRUE;
- num_columns= 1;
+ list_of_part_fields= true;
+ column_list= false;
vers_info= new (thd->mem_root) Vers_part_info;
if (unlikely(!vers_info))
return true;
diff --git a/sql/partition_info.h b/sql/partition_info.h
index a2320c34048..00ef815ce09 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -55,11 +55,11 @@ struct Vers_part_info : public Sql_alloc
if (now_part)
{
DBUG_ASSERT(now_part->id != UINT_MAX32);
- DBUG_ASSERT(now_part->type() == partition_element::CURRENT);
+ DBUG_ASSERT(now_part->type == partition_element::CURRENT);
if (hist_part)
{
DBUG_ASSERT(hist_part->id != UINT_MAX32);
- DBUG_ASSERT(hist_part->type() == partition_element::HISTORY);
+ DBUG_ASSERT(hist_part->type == partition_element::HISTORY);
}
return true;
}
@@ -366,8 +366,7 @@ public:
void init_col_val(part_column_list_val *col_val, Item *item);
int reorganize_into_single_field_col_val(THD *thd);
part_column_list_val *add_column_value(THD *thd);
- bool set_part_expr(THD *thd, char *start_token, Item *item_ptr,
- char *end_token, bool is_subpart);
+ bool set_part_expr(THD *thd, Item *item_ptr, bool is_subpart);
bool set_up_charset_field_preps(THD *thd);
bool check_partition_field_length();
bool init_column_part(THD *thd);
diff --git a/sql/rpl_utility_server.cc b/sql/rpl_utility_server.cc
index de088be6434..e58c9cf018e 100644
--- a/sql/rpl_utility_server.cc
+++ b/sql/rpl_utility_server.cc
@@ -266,48 +266,55 @@ Type_handler_olddecimal::max_display_length_for_field(const Conv_source &src)
}
-void Type_handler::show_binlog_type(const Conv_source &src, String *str) const
+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(),
- "varchar(%u)",
- src.metadata() / src.mbmaxlen());
+ 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(),
- "varchar(%u)",
- src.metadata() / src.mbmaxlen());
+ 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(),
- "varchar(%u) compressed",
- src.metadata() / src.mbmaxlen());
+ fmt, src.metadata());
str->length(length);
}
-void Type_handler_bit::show_binlog_type(const Conv_source &src,
+void Type_handler_bit::show_binlog_type(const Conv_source &src, const Field &,
String *str) const
{
CHARSET_INFO *cs= str->charset();
@@ -320,6 +327,7 @@ void Type_handler_bit::show_binlog_type(const Conv_source &src,
void Type_handler_olddecimal::show_binlog_type(const Conv_source &src,
+ const Field &,
String *str) const
{
CHARSET_INFO *cs= str->charset();
@@ -332,6 +340,7 @@ void Type_handler_olddecimal::show_binlog_type(const Conv_source &src,
void Type_handler_newdecimal::show_binlog_type(const Conv_source &src,
+ const Field &,
String *str) const
{
CHARSET_INFO *cs= str->charset();
@@ -344,6 +353,7 @@ void Type_handler_newdecimal::show_binlog_type(const Conv_source &src,
void Type_handler_blob_compressed::show_binlog_type(const Conv_source &src,
+ const Field &,
String *str) const
{
/*
@@ -371,6 +381,7 @@ void Type_handler_blob_compressed::show_binlog_type(const Conv_source &src,
void Type_handler_string::show_binlog_type(const Conv_source &src,
+ const Field &dst,
String *str) const
{
/*
@@ -379,9 +390,11 @@ void Type_handler_string::show_binlog_type(const Conv_source &src,
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(),
- "char(%d)", bytes / src.mbmaxlen());
+ fmt, bytes);
str->length(length);
}
@@ -743,13 +756,14 @@ Field_null::rpl_conv_type_from(const Conv_source &source,
/**
*/
-void show_sql_type(const Conv_source &src, String *str)
+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, str);
+ src.type_handler()->show_binlog_type(src, dst, str);
DBUG_VOID_RETURN;
}
@@ -979,8 +993,8 @@ table_def::compatible_with(THD *thd, rpl_group_info *rgi,
StringBuffer<MAX_FIELD_WIDTH> target_type(&my_charset_latin1);
THD *thd= table->in_use;
- show_sql_type(source, &source_type);
- field->sql_type(target_type);
+ 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(),
diff --git a/sql/select_handler.cc b/sql/select_handler.cc
index f020d2f6b80..b364cb12341 100644
--- a/sql/select_handler.cc
+++ b/sql/select_handler.cc
@@ -45,6 +45,8 @@ Pushdown_select::Pushdown_select(SELECT_LEX *sel, select_handler *h)
Pushdown_select::~Pushdown_select()
{
+ if (handler->table)
+ free_tmp_table(handler->thd, handler->table);
delete handler;
select->select_h= NULL;
}
diff --git a/sql/service_wsrep.cc b/sql/service_wsrep.cc
index c47ba9d9d37..b365b393e0b 100644
--- a/sql/service_wsrep.cc
+++ b/sql/service_wsrep.cc
@@ -146,11 +146,10 @@ extern "C" void wsrep_handle_SR_rollback(THD *bf_thd,
victim_thd->wsrep_trx_id(),
victim_thd->wsrep_sr().fragments_certified(),
wsrep_thd_transaction_state_str(victim_thd));
- if (bf_thd && bf_thd != victim_thd)
- {
- victim_thd->store_globals();
- }
- else
+
+ /* Note: do not store/reset globals before wsrep_bf_abort() call
+ to avoid losing BF thd context. */
+ if (!(bf_thd && bf_thd != victim_thd))
{
DEBUG_SYNC(victim_thd, "wsrep_before_SR_rollback");
}
@@ -162,21 +161,24 @@ extern "C" void wsrep_handle_SR_rollback(THD *bf_thd,
{
wsrep_thd_self_abort(victim_thd);
}
- if (bf_thd && bf_thd != victim_thd)
+ if (bf_thd)
{
- bf_thd->store_globals();
+ wsrep_store_threadvars(bf_thd);
}
}
extern "C" my_bool wsrep_thd_bf_abort(const THD *bf_thd, THD *victim_thd,
my_bool signal)
{
+ /* Note: do not store/reset globals before wsrep_bf_abort() call
+ to avoid losing BF thd context. */
if (WSREP(victim_thd) && !victim_thd->wsrep_trx().active())
{
WSREP_DEBUG("BF abort for non active transaction");
wsrep_start_transaction(victim_thd, victim_thd->wsrep_next_trx_id());
}
my_bool ret= wsrep_bf_abort(bf_thd, victim_thd);
+ wsrep_store_threadvars((THD*)bf_thd);
/*
Send awake signal if victim was BF aborted or does not
have wsrep on. Note that this should never interrupt RSU
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 0f68c726747..4cb8750ccf8 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -6461,7 +6461,7 @@ ER_MESSAGE_AND_STATEMENT
eng "%s Statement: %s"
ER_SLAVE_CONVERSION_FAILED
- eng "Column %d of table '%-.192s.%-.192s' cannot be converted from type '%-.32s' to type '%-.32s'"
+ eng "Column %d of table '%-.192s.%-.192s' cannot be converted from type '%-.50s' to type '%-.50s'"
ER_SLAVE_CANT_CREATE_CONVERSION
eng "Can't create conversion table for table '%-.192s.%-.192s'"
ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 7ac0dcad596..562c70be914 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2663,9 +2663,16 @@ Locked_tables_list::reopen_tables(THD *thd, bool need_reopen)
{
if (!table_list->table || !table_list->table->needs_reopen())
continue;
- /* no need to remove the table from the TDC here, thus (TABLE*)1 */
- close_all_tables_for_name(thd, table_list->table->s,
- HA_EXTRA_NOT_USED, (TABLE*)1);
+ for (TABLE **prev= &thd->open_tables; *prev; prev= &(*prev)->next)
+ {
+ if (*prev == table_list->table)
+ {
+ thd->locked_tables_list.unlink_from_list(thd, table_list, false);
+ mysql_lock_remove(thd, thd->lock, *prev);
+ close_thread_table(thd, prev);
+ break;
+ }
+ }
DBUG_ASSERT(table_list->table == NULL);
}
else
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 54d6541efbf..a8f3de4cb1a 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -6162,7 +6162,10 @@ public:
uint tables; /* Number of tables in the sj-nest */
- /* Expected #rows in the materialized table */
+ /* Number of rows in the materialized table, before the de-duplication */
+ double rows_with_duplicates;
+
+ /* Expected #rows in the materialized table, after de-duplication */
double rows;
/*
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 37c4c27c08b..0add71b7b11 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -1188,6 +1188,16 @@ void end_connection(THD *thd)
{
NET *net= &thd->net;
+#ifdef WITH_WSREP
+ if (thd->wsrep_cs().state() == wsrep::client_state::s_exec)
+ {
+ /* Error happened after the thread acquired ownership to wsrep
+ client state, but before command was processed. Clean up the
+ state before wsrep_close(). */
+ wsrep_after_command_ignore_result(thd);
+ }
+ wsrep_close(thd);
+#endif /* WITH_WSREP */
if (thd->user_connect)
{
/*
@@ -1330,6 +1340,7 @@ bool thd_prepare_connection(THD *thd)
prepare_new_connection_state(thd);
#ifdef WITH_WSREP
thd->wsrep_client_thread= true;
+ wsrep_open(thd);
#endif /* WITH_WSREP */
return FALSE;
}
@@ -1403,9 +1414,6 @@ void do_handle_one_connection(CONNECT *connect, bool put_in_cache)
create_user= FALSE;
goto end_thread;
}
-#ifdef WITH_WSREP
- wsrep_open(thd);
-#endif /* WITH_WSREP */
while (thd_is_connection_alive(thd))
{
@@ -1416,10 +1424,6 @@ void do_handle_one_connection(CONNECT *connect, bool put_in_cache)
}
end_connection(thd);
-#ifdef WITH_WSREP
- wsrep_close(thd);
-#endif /* WITH_WSREP */
-
end_thread:
close_connection(thd);
diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc
index 2b46a385ba1..d3b85638898 100644
--- a/sql/sql_explain.cc
+++ b/sql/sql_explain.cc
@@ -460,6 +460,8 @@ uint Explain_union::make_union_table_name(char *buf)
break;
default:
DBUG_ASSERT(0);
+ type.str= NULL;
+ type.length= 0;
}
memcpy(buf, type.str, (len= (uint)type.length));
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index e8e320e8439..dcffc0662dd 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -2076,7 +2076,7 @@ before_trg_err:
/******************************************************************************
- Check that all fields with arn't null_fields are used
+ Check that there aren't any null_fields
******************************************************************************/
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index e77f17394b6..2e163a9d464 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -2998,6 +2998,7 @@ void st_select_lex_unit::print(String *str, enum_query_type query_type)
{
default:
DBUG_ASSERT(0);
+ /* fall through */
case UNION_TYPE:
str->append(STRING_WITH_LEN(" union "));
break;
@@ -8770,11 +8771,9 @@ bool LEX::part_values_current(THD *thd)
create_last_non_select_table->table_name.str);
return true;
}
- elem->type(partition_element::CURRENT);
+ elem->type= partition_element::CURRENT;
DBUG_ASSERT(part_info->vers_info);
part_info->vers_info->now_part= elem;
- if (unlikely(part_info->init_column_part(thd)))
- return true;
return false;
}
@@ -8804,9 +8803,7 @@ bool LEX::part_values_history(THD *thd)
create_last_non_select_table->table_name.str);
return true;
}
- elem->type(partition_element::HISTORY);
- if (unlikely(part_info->init_column_part(thd)))
- return true;
+ elem->type= partition_element::HISTORY;
return false;
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 813f3fb3d57..9b1cb836867 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3629,6 +3629,7 @@ mysql_execute_command(THD *thd)
case GET_NO_ARG:
case GET_DISABLED:
DBUG_ASSERT(0);
+ /* fall through */
case 0:
case GET_FLAGSET:
case GET_ENUM:
@@ -8350,9 +8351,9 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
DBUG_ENTER("nest_last_join");
TABLE_LIST *head= join_list->head();
- if (head->nested_join && head->nested_join->nest_type & REBALANCED_NEST)
+ if (head->nested_join && (head->nested_join->nest_type & REBALANCED_NEST))
{
- join_list->empty();
+ head= join_list->pop();
DBUG_RETURN(head);
}
@@ -8436,13 +8437,13 @@ void st_select_lex::add_joined_table(TABLE_LIST *table)
context and right-associative in another context.
In this query
- SELECT * FROM t1 JOIN t2 LEFT JOIN t3 ON t2.a=t3.a (Q1)
+ SELECT * FROM t1 JOIN t2 LEFT JOIN t3 ON t2.a=t3.a (Q1)
JOIN is left-associative and the query Q1 is interpreted as
- SELECT * FROM (t1 JOIN t2) LEFT JOIN t3 ON t2.a=t3.a.
+ SELECT * FROM (t1 JOIN t2) LEFT JOIN t3 ON t2.a=t3.a.
While in this query
- SELECT * FROM t1 JOIN t2 LEFT JOIN t3 ON t2.a=t3.a ON t1.b=t2.b (Q2)
+ SELECT * FROM t1 JOIN t2 LEFT JOIN t3 ON t2.a=t3.a ON t1.b=t2.b (Q2)
JOIN is right-associative and the query Q2 is interpreted as
- SELECT * FROM t1 JOIN (t2 LEFT JOIN t3 ON t2.a=t3.a) ON t1.b=t2.b
+ SELECT * FROM t1 JOIN (t2 LEFT JOIN t3 ON t2.a=t3.a) ON t1.b=t2.b
JOIN is right-associative if it is used with ON clause or with USING clause.
Otherwise it is left-associative.
@@ -8488,9 +8489,9 @@ void st_select_lex::add_joined_table(TABLE_LIST *table)
J LJ - ON
/ \ / \
- t1 LJ - ON (TQ3*) => J t2
- / \ / \
- t3 t2 t1 t3
+ t1 LJ - ON (TQ3*) => t3 J
+ / \ / \
+ t3 t2 t1 t2
With several left associative JOINs
SELECT * FROM t1 JOIN t2 JOIN t3 LEFT JOIN t4 ON t3.a=t4.a (Q4)
@@ -8498,15 +8499,15 @@ void st_select_lex::add_joined_table(TABLE_LIST *table)
J1 LJ - ON
/ \ / \
- t1 LJ - ON J2 t4
+ t1 J2 J2 t4
/ \ => / \
- J2 t4 J1 t3
- / \ / \
- t2 t3 t1 t2
+ t2 LJ - ON J1 t3
+ / \ / \
+ t3 t4 t1 t2
- Here's another example:
- SELECT *
- FROM t1 JOIN t2 LEFT JOIN t3 JOIN t4 ON t3.a=t4.a ON t2.b=t3.b (Q5)
+ Here's another example:
+ SELECT *
+ FROM t1 JOIN t2 LEFT JOIN t3 JOIN t4 ON t3.a=t4.a ON t2.b=t3.b (Q5)
J LJ - ON
/ \ / \
@@ -8516,15 +8517,58 @@ void st_select_lex::add_joined_table(TABLE_LIST *table)
/ \
t3 t4
- If the transformed nested join node node is a natural join node like in
- the following query
- SELECT * FROM t1 JOIN t2 LEFT JOIN t3 USING(a) (Q6)
- the transformation additionally has to take care about setting proper
- references in the field natural_join for both operands of the natural
- join operation.
- The function also has to change the name resolution context for ON
- expressions used in the transformed join expression to take into
- account the tables of the left_op node.
+ If the transformed nested join node node is a natural join node like in
+ the following query
+ SELECT * FROM t1 JOIN t2 LEFT JOIN t3 USING(a) (Q6)
+ the transformation additionally has to take care about setting proper
+ references in the field natural_join for both operands of the natural
+ join operation.
+
+ The queries that combine comma syntax for join operation with
+ JOIN expression require a special care. Consider the query
+ SELECT * FROM t1, t2 JOIN t3 LEFT JOIN t4 ON t3.a=t4.a (Q7)
+ This query is equivalent to the query
+ SELECT * FROM (t1, t2) JOIN t3 LEFT JOIN t4 ON t3.a=t4.a
+ The latter is transformed in the same way as query Q1
+
+ J LJ - ON
+ / \ / \
+ (t1,t2) LJ - ON => J t4
+ / \ / \
+ t3 t4 (t1,t2) t3
+
+ A transformation similar to the transformation for Q3 is done for
+ the following query with RIGHT JOIN
+ SELECT * FROM t1, t2 JOIN t3 RIGHT JOIN t4 ON t3.a=t4.a (Q8)
+
+ J LJ - ON
+ / \ / \
+ t3 LJ - ON => t4 J
+ / \ / \
+ t4 (t1,t2) (t1,t2) t3
+
+ The function also has to change the name resolution context for ON
+ expressions used in the transformed join expression to take into
+ account the tables of the left_op node.
+
+ TODO:
+ A more elegant solution would be to implement the transformation that
+ eliminates nests for cross join operations. For Q7 it would work like this:
+
+ J LJ - ON
+ / \ / \
+ (t1,t2) LJ - ON => (t1,t2,t3) t4
+ / \
+ t3 t4
+
+ For Q8 with RIGHT JOIN the transformation would work similarly:
+
+ J LJ - ON
+ / \ / \
+ t3 LJ - ON => t4 (t1,t2,t3)
+ / \
+ t4 (t1,t2)
+
*/
bool st_select_lex::add_cross_joined_table(TABLE_LIST *left_op,
@@ -8549,11 +8593,9 @@ bool st_select_lex::add_cross_joined_table(TABLE_LIST *left_op,
}
TABLE_LIST *tbl;
- List<TABLE_LIST> *jl= &right_op->nested_join->join_list;
+ List<TABLE_LIST> *right_op_jl= right_op->join_list;
TABLE_LIST *cj_nest;
- add_joined_table(right_op);
-
/*
Create the node NJ for a new nested join for the future inclusion
of left_op in it. Initially the nest is empty.
@@ -8568,6 +8610,8 @@ bool st_select_lex::add_cross_joined_table(TABLE_LIST *left_op,
List<TABLE_LIST> *cjl= &cj_nest->nested_join->join_list;
cjl->empty();
+ List<TABLE_LIST> *jl= &right_op->nested_join->join_list;
+ DBUG_ASSERT(jl->elements == 2);
/* Look for the left most node tbl of the right_op tree */
for ( ; ; )
{
@@ -8640,6 +8684,8 @@ bool st_select_lex::add_cross_joined_table(TABLE_LIST *left_op,
create a new top level nested join node.
*/
right_op->nested_join->nest_type|= REBALANCED_NEST;
+ if (unlikely(right_op_jl->push_front(right_op)))
+ DBUG_RETURN(true);
DBUG_RETURN(false);
}
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index e24a8962dcd..a0fd64c72ad 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -1559,7 +1559,7 @@ static bool check_vers_constants(THD *thd, partition_info *part_info)
return 0;
part_info->range_int_array=
- (longlong*) thd->alloc(hist_parts * sizeof(longlong));
+ (longlong*) thd->alloc(part_info->num_parts * sizeof(longlong));
MYSQL_TIME ltime;
List_iterator<partition_element> it(part_info->partitions);
@@ -1578,6 +1578,9 @@ static bool check_vers_constants(THD *thd, partition_info *part_info)
if (vers_info->hist_part->range_value <= thd->query_start())
vers_info->hist_part= el;
}
+ DBUG_ASSERT(el == vers_info->now_part);
+ el->max_value= true;
+ part_info->range_int_array[el->id]= el->range_value= LONGLONG_MAX;
return 0;
err:
my_error(ER_DATA_OUT_OF_RANGE, MYF(0), "TIMESTAMP", "INTERVAL");
@@ -1971,7 +1974,6 @@ bool fix_partition_func(THD *thd, TABLE *table, bool is_create_table_ind)
}
}
DBUG_ASSERT(part_info->part_type != NOT_A_PARTITION);
- DBUG_ASSERT(part_info->part_type != VERSIONING_PARTITION || part_info->column_list);
/*
Partition is defined. We need to verify that partitioning
function is correct.
@@ -2004,15 +2006,15 @@ bool fix_partition_func(THD *thd, TABLE *table, bool is_create_table_ind)
{
if (part_info->column_list)
{
- if (part_info->part_type == VERSIONING_PARTITION &&
- part_info->vers_setup_expression(thd))
- goto end;
List_iterator<const char> it(part_info->part_field_list);
if (unlikely(handle_list_of_fields(thd, it, table, part_info, FALSE)))
goto end;
}
else
{
+ if (part_info->part_type == VERSIONING_PARTITION &&
+ part_info->vers_setup_expression(thd))
+ goto end;
if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
table, FALSE, is_create_table_ind)))
goto end;
@@ -2028,7 +2030,8 @@ bool fix_partition_func(THD *thd, TABLE *table, bool is_create_table_ind)
goto end;
}
if (unlikely(!part_info->column_list &&
- part_info->part_expr->result_type() != INT_RESULT))
+ part_info->part_expr->result_type() != INT_RESULT &&
+ part_info->part_expr->result_type() != DECIMAL_RESULT))
{
part_info->report_part_expr_error(FALSE);
goto end;
@@ -2537,7 +2540,7 @@ static int add_partition_values(String *str, partition_info *part_info,
}
else if (part_info->part_type == VERSIONING_PARTITION)
{
- switch (p_elem->type())
+ switch (p_elem->type)
{
case partition_element::CURRENT:
err+= str->append(STRING_WITH_LEN(" CURRENT"));
@@ -5315,7 +5318,7 @@ that are reorganised.
partition_element *el;
while ((el= it++))
{
- if (el->type() == partition_element::CURRENT)
+ if (el->type == partition_element::CURRENT)
{
it.remove();
now_part= el;
@@ -5411,7 +5414,7 @@ that are reorganised.
{
if (tab_part_info->part_type == VERSIONING_PARTITION)
{
- if (part_elem->type() == partition_element::CURRENT)
+ if (part_elem->type == partition_element::CURRENT)
{
my_error(ER_VERS_WRONG_PARTS, MYF(0), table->s->table_name.str);
goto err;
@@ -7665,6 +7668,10 @@ static void set_up_range_analysis_info(partition_info *part_info)
partitioning
*/
switch (part_info->part_type) {
+ case VERSIONING_PARTITION:
+ if (!part_info->vers_info->interval.is_set())
+ break;
+ /* Fall through */
case RANGE_PARTITION:
case LIST_PARTITION:
if (!part_info->column_list)
@@ -8101,7 +8108,8 @@ static int get_part_iter_for_interval_via_mapping(partition_info *part_info,
part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE;
part_iter->ret_default_part= part_iter->ret_default_part_orig= FALSE;
- if (part_info->part_type == RANGE_PARTITION)
+ if (part_info->part_type == RANGE_PARTITION ||
+ part_info->part_type == VERSIONING_PARTITION)
{
if (part_info->part_charset_field_array)
get_endpoint= get_partition_id_range_for_endpoint_charset;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 46c68d7cd4d..1361930b65d 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -924,19 +924,6 @@ Item* SELECT_LEX::period_setup_conds(THD *thd, TABLE_LIST *tables, Item *where)
DBUG_RETURN(result);
}
-/**
- Setup System Versioning conditions
-
- Add WHERE condition according to FOR SYSTEM_TIME clause.
-
- If the table is partitioned by SYSTEM_TIME and there is no FOR SYSTEM_TIME
- clause, then select now-partition instead of modifying WHERE condition.
-
- @retval
- -1 on error
- @retval
- 0 on success
-*/
int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
{
DBUG_ENTER("SELECT_LEX::vers_setup_conds");
@@ -994,13 +981,12 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
vers_select_conds_t &vers_conditions= table->vers_conditions;
#ifdef WITH_PARTITION_STORAGE_ENGINE
- Vers_part_info *vers_info;
- if (table->table->part_info && (vers_info= table->table->part_info->vers_info))
- {
- if (table->partition_names)
+ /*
+ if the history is stored in partitions, then partitions
+ themselves are not versioned
+ */
+ if (table->partition_names && table->table->part_info->vers_info)
{
- /* If the history is stored in partitions, then partitions
- themselves are not versioned. */
if (vers_conditions.is_set())
{
my_error(ER_VERS_QUERY_IN_PARTITION, MYF(0), table->alias.str);
@@ -1009,19 +995,6 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
else
vers_conditions.init(SYSTEM_TIME_ALL);
}
- else if (!vers_conditions.is_set() &&
- /* We cannot optimize REPLACE .. SELECT because it may need
- to call vers_set_hist_part() to update history. */
- thd->lex->sql_command != SQLCOM_REPLACE_SELECT)
- {
- table->partition_names= newx List<String>;
- String *s= newx String(vers_info->now_part->partition_name,
- system_charset_info);
- table->partition_names->push_back(s);
- table->table->file->change_partitions_to_open(table->partition_names);
- vers_conditions.init(SYSTEM_TIME_ALL);
- }
- }
#endif
if (outer_table && !vers_conditions.is_set())
@@ -1076,7 +1049,6 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
DBUG_RETURN(0);
}
-#undef newx
/*****************************************************************************
Check fields, find best join, do the select and output fields.
@@ -8831,6 +8803,7 @@ void JOIN::get_prefix_cost_and_fanout(uint n_tables,
record_count= COST_MULT(record_count, best_positions[i].records_read);
read_time= COST_ADD(read_time, best_positions[i].read_time);
}
+ /* TODO: Take into account condition selectivities here */
}
*read_time_arg= read_time;// + record_count / TIME_FOR_COMPARE;
*record_count_arg= record_count;
@@ -9071,6 +9044,7 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
KEYUSE *keyuse= pos->key;
KEYUSE *prev_ref_keyuse= keyuse;
uint key= keyuse->key;
+ bool used_range_selectivity= false;
/*
Check if we have a prefix of key=const that matches a quick select.
@@ -9096,6 +9070,7 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
keyparts++;
}
sel /= (double)table->quick_rows[key] / (double) table->stat_records();
+ used_range_selectivity= true;
}
}
@@ -9131,13 +9106,14 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
if (keyparts > keyuse->keypart)
{
/* Ok this is the keyuse that will be used for ref access */
- uint fldno;
- if (is_hash_join_key_no(key))
- fldno= keyuse->keypart;
- else
- fldno= table->key_info[key].key_part[keyparts-1].fieldnr - 1;
- if (keyuse->val->const_item())
+ if (!used_range_selectivity && keyuse->val->const_item())
{
+ uint fldno;
+ if (is_hash_join_key_no(key))
+ fldno= keyuse->keypart;
+ else
+ fldno= table->key_info[key].key_part[keyparts-1].fieldnr - 1;
+
if (table->field[fldno]->cond_selectivity > 0)
{
sel /= table->field[fldno]->cond_selectivity;
@@ -16718,10 +16694,20 @@ void optimize_wo_join_buffering(JOIN *join, uint first_tab, uint last_tab,
reopt_remaining_tables &= ~rs->table->map;
rec_count= COST_MULT(rec_count, pos.records_read);
cost= COST_ADD(cost, pos.read_time);
-
-
+ cost= COST_ADD(cost, rec_count / (double) TIME_FOR_COMPARE);
+ //TODO: take into account join condition selectivity here
+ double pushdown_cond_selectivity= 1.0;
+ table_map real_table_bit= rs->table->map;
+ if (join->thd->variables.optimizer_use_condition_selectivity > 1)
+ {
+ pushdown_cond_selectivity= table_cond_selectivity(join, i, rs,
+ reopt_remaining_tables &
+ ~real_table_bit);
+ }
+ (*outer_rec_count) *= pushdown_cond_selectivity;
if (!rs->emb_sj_nest)
*outer_rec_count= COST_MULT(*outer_rec_count, pos.records_read);
+
}
join->cur_sj_inner_tables= save_cur_sj_inner_tables;
@@ -28676,7 +28662,7 @@ select_handler *SELECT_LEX::find_select_handler(THD *thd)
return 0;
if (master_unit()->outer_select())
return 0;
- for (TABLE_LIST *tbl= join->tables_list; tbl; tbl= tbl->next_local)
+ for (TABLE_LIST *tbl= join->tables_list; tbl; tbl= tbl->next_global)
{
if (!tbl->table)
continue;
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 0c226e54706..2fafdd74ad9 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -882,7 +882,7 @@ public:
void set_empty()
{
sjm_scan_need_tables= 0;
- LINT_INIT_STRUCT(sjm_scan_last_inner);
+ sjm_scan_last_inner= 0;
is_used= FALSE;
}
void set_from_prev(struct st_position *prev);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 34c0e0abc6c..cc977ddca4b 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2158,6 +2158,10 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(STRING_WITH_LEN(" STORED"));
else
packet->append(STRING_WITH_LEN(" VIRTUAL"));
+ if (field->invisible == INVISIBLE_USER)
+ {
+ packet->append(STRING_WITH_LEN(" INVISIBLE"));
+ }
}
else
{
@@ -2478,6 +2482,7 @@ static const LEX_CSTRING *view_algorithm(TABLE_LIST *table)
return &merge;
default:
DBUG_ASSERT(0); // never should happen
+ /* fall through */
case VIEW_ALGORITHM_UNDEFINED:
return &undefined;
}
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index a91d3a03ed1..438a9248a31 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -1820,16 +1820,13 @@ public:
bool is_partial_fields_present;
Index_prefix_calc(THD *thd, TABLE *table, KEY *key_info)
- : index_table(table), index_info(key_info)
+ : index_table(table), index_info(key_info), prefixes(0), empty(true),
+ calc_state(NULL), is_single_comp_pk(false), is_partial_fields_present(false)
{
uint i;
Prefix_calc_state *state;
uint key_parts= table->actual_n_key_parts(key_info);
- empty= TRUE;
- prefixes= 0;
- LINT_INIT_STRUCT(calc_state);
- is_partial_fields_present= is_single_comp_pk= FALSE;
uint pk= table->s->primary_key;
if ((uint) (table->key_info - key_info) == pk &&
table->key_info[pk].user_defined_key_parts == 1)
@@ -2133,6 +2130,7 @@ int alloc_statistics_for_table(THD* thd, TABLE *table)
if ((histogram= (uchar *) alloc_root(&table->mem_root,
hist_size * columns)))
bzero(histogram, hist_size * columns);
+
}
if (!table_stats || !column_stats || !index_stats || !idx_avg_frequency ||
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index a4050c579d0..483eb4fcbec 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -1204,6 +1204,8 @@ size_t convert_to_printable_required_length(uint len)
bool String::append_semi_hex(const char *s, uint len, CHARSET_INFO *cs)
{
+ if (!len)
+ return false;
size_t dst_len= convert_to_printable_required_length(len);
if (reserve(dst_len))
return true;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 9bb1d98152b..0785276ecd8 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -64,7 +64,7 @@ const char *primary_key_name="PRIMARY";
static int check_if_keyname_exists(const char *name,KEY *start, KEY *end);
static char *make_unique_key_name(THD *, const char *, KEY *, KEY *);
-static void make_unique_constraint_name(THD *, LEX_CSTRING *, const char *,
+static bool make_unique_constraint_name(THD *, LEX_CSTRING *, const char *,
List<Virtual_column_info> *, uint *);
static const char *make_unique_invisible_field_name(THD *, const char *,
List<Create_field> *);
@@ -76,6 +76,9 @@ static int copy_data_between_tables(THD *, TABLE *,TABLE *,
static int mysql_prepare_create_table(THD *, HA_CREATE_INFO *, Alter_info *,
uint *, handler *, KEY **, uint *, int);
static uint blob_length_by_type(enum_field_types type);
+static bool fix_constraints_names(THD *thd, List<Virtual_column_info>
+ *check_constraint_list,
+ const HA_CREATE_INFO *create_info);
/**
@brief Helper function for explain_filename
@@ -4326,20 +4329,13 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
/* Check table level constraints */
create_info->check_constraint_list= &alter_info->check_constraint_list;
{
- uint nr= 1;
List_iterator_fast<Virtual_column_info> c_it(alter_info->check_constraint_list);
Virtual_column_info *check;
while ((check= c_it++))
{
- if (!check->name.length)
- {
- const char *own_name_base= create_info->period_info.constr == check
- ? create_info->period_info.name.str : NULL;
+ if (!check->name.length || check->automatic_name)
+ continue;
- make_unique_constraint_name(thd, &check->name, own_name_base,
- &alter_info->check_constraint_list,
- &nr);
- }
{
/* Check that there's no repeating constraint names. */
List_iterator_fast<Virtual_column_info>
@@ -4884,6 +4880,10 @@ int create_table_impl(THD *thd, const LEX_CSTRING &orig_db,
DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d path: %s",
db.str, table_name.str, internal_tmp_table, path));
+ if (fix_constraints_names(thd, &alter_info->check_constraint_list,
+ create_info))
+ DBUG_RETURN(1);
+
if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)
{
if (create_info->data_file_name)
@@ -5382,7 +5382,7 @@ make_unique_key_name(THD *thd, const char *field_name,KEY *start,KEY *end)
Make an unique name for constraints without a name
*/
-static void make_unique_constraint_name(THD *thd, LEX_CSTRING *name,
+static bool make_unique_constraint_name(THD *thd, LEX_CSTRING *name,
const char *own_name_base,
List<Virtual_column_info> *vcol,
uint *nr)
@@ -5410,9 +5410,10 @@ static void make_unique_constraint_name(THD *thd, LEX_CSTRING *name,
{
name->length= (size_t) (real_end - buff);
name->str= thd->strmake(buff, name->length);
- return;
+ return (name->str == NULL);
}
}
+ return FALSE;
}
/**
@@ -6035,10 +6036,11 @@ static bool is_candidate_key(KEY *key)
from the list if existing found.
RETURN VALUES
- NONE
+ TRUE error
+ FALSE OK
*/
-static void
+static bool
handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info,
Table_period_info *period_info)
{
@@ -6484,6 +6486,7 @@ remove_key:
Virtual_column_info *check;
TABLE_SHARE *share= table->s;
uint c;
+
while ((check=it++))
{
if (!(check->flags & Alter_info::CHECK_CONSTRAINT_IF_NOT_EXISTS) &&
@@ -6531,7 +6534,48 @@ remove_key:
*period_info= {};
}
- DBUG_VOID_RETURN;
+ DBUG_RETURN(false);
+}
+
+
+static bool fix_constraints_names(THD *thd, List<Virtual_column_info>
+ *check_constraint_list,
+ const HA_CREATE_INFO *create_info)
+{
+ List_iterator<Virtual_column_info> it((*check_constraint_list));
+ Virtual_column_info *check;
+ uint nr= 1;
+ DBUG_ENTER("fix_constraints_names");
+ if (!check_constraint_list)
+ DBUG_RETURN(FALSE);
+ // Prevent accessing freed memory during generating unique names
+ while ((check=it++))
+ {
+ if (check->automatic_name)
+ {
+ check->name.str= NULL;
+ check->name.length= 0;
+ }
+ }
+ it.rewind();
+ // Generate unique names if needed
+ while ((check=it++))
+ {
+ if (!check->name.length)
+ {
+ check->automatic_name= TRUE;
+
+ const char *own_name_base= create_info->period_info.constr == check
+ ? create_info->period_info.name.str : NULL;
+
+ if (make_unique_constraint_name(thd, &check->name,
+ own_name_base,
+ check_constraint_list,
+ &nr))
+ DBUG_RETURN(TRUE);
+ }
+ }
+ DBUG_RETURN(FALSE);
}
@@ -7959,7 +8003,6 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
Create_field *def;
Field **f_ptr,*field;
MY_BITMAP *dropped_fields= NULL; // if it's NULL - no dropped fields
- bool save_reopen= table->m_needs_reopen;
bool drop_period= false;
DBUG_ENTER("mysql_prepare_alter_table");
@@ -8707,9 +8750,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
alter_info->create_list.swap(new_create_list);
alter_info->key_list.swap(new_key_list);
alter_info->check_constraint_list.swap(new_constraint_list);
- DBUG_RETURN(rc);
err:
- table->m_needs_reopen= save_reopen;
DBUG_RETURN(rc);
}
@@ -9675,7 +9716,11 @@ do_continue:;
}
}
- handle_if_exists_options(thd, table, alter_info, &create_info->period_info);
+ if (handle_if_exists_options(thd, table, alter_info,
+ &create_info->period_info) ||
+ fix_constraints_names(thd, &alter_info->check_constraint_list,
+ create_info))
+ DBUG_RETURN(true);
/*
Look if we have to do anything at all.
@@ -11153,10 +11198,9 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
{
DBUG_ENTER("Sql_cmd_create_table::execute");
LEX *lex= thd->lex;
- TABLE_LIST *all_tables= lex->query_tables;
SELECT_LEX *select_lex= lex->first_select_lex();
TABLE_LIST *first_table= select_lex->table_list.first;
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ DBUG_ASSERT(first_table == lex->query_tables && first_table != 0);
bool link_to_local;
TABLE_LIST *create_table= first_table;
TABLE_LIST *select_tables= lex->create_last_non_select_table->next_global;
diff --git a/sql/sql_time.cc b/sql/sql_time.cc
index c64995fa3d6..b128a7f7291 100644
--- a/sql/sql_time.cc
+++ b/sql/sql_time.cc
@@ -914,7 +914,7 @@ void make_truncated_value_warning(THD *thd,
#define GET_PART(X, N) X % N ## LL; X/= N ## LL
bool date_add_interval(THD *thd, MYSQL_TIME *ltime, interval_type int_type,
- const INTERVAL &interval)
+ const INTERVAL &interval, bool push_warn)
{
long period, sign;
@@ -1027,6 +1027,7 @@ bool date_add_interval(THD *thd, MYSQL_TIME *ltime, interval_type int_type,
return 0; // Ok
invalid_date:
+ if (push_warn)
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_DATETIME_FUNCTION_OVERFLOW,
diff --git a/sql/sql_time.h b/sql/sql_time.h
index 25980d6417c..fe9697adf67 100644
--- a/sql/sql_time.h
+++ b/sql/sql_time.h
@@ -92,7 +92,7 @@ bool my_TIME_to_str(const MYSQL_TIME *ltime, String *str, uint dec);
/* MYSQL_TIME operations */
bool date_add_interval(THD *thd, MYSQL_TIME *ltime, interval_type int_type,
- const INTERVAL &interval);
+ const INTERVAL &interval, bool push_warn= true);
bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
int l_sign, ulonglong *seconds_out, ulong *microseconds_out);
int append_interval(String *str, interval_type int_type,
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index 905676ee604..2ac1516082a 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -1029,10 +1029,21 @@ bool Temporal::datetime_add_nanoseconds_or_invalidate(THD *thd, int *warn, ulong
INTERVAL interval;
memset(&interval, 0, sizeof(interval));
interval.hour= 1;
- /* date_add_interval cannot handle bad dates */
- if (check_date(TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE, warn) ||
- date_add_interval(thd, this, INTERVAL_HOUR, interval))
+ /*
+ date_add_interval cannot handle bad dates with zero YYYY or MM.
+ Note, check_date(NO_ZERO_XX) does not check YYYY against zero,
+ so let's additionally check it.
+ */
+ if (year == 0 ||
+ check_date(TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE, warn) ||
+ date_add_interval(thd, this, INTERVAL_HOUR, interval, false/*no warn*/))
{
+ char buf[MAX_DATE_STRING_REP_LENGTH];
+ my_date_to_str(this, buf);
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WRONG_VALUE_FOR_TYPE,
+ ER_THD(thd, ER_WRONG_VALUE_FOR_TYPE),
+ "date", buf, "round(datetime)");
make_from_out_of_range(warn);
return true;
}
@@ -6073,6 +6084,30 @@ bool Type_handler_temporal_result::
}
+bool Type_handler_time_common::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ item->fix_arg_time();
+ return false;
+}
+
+
+bool Type_handler_datetime_common::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ item->fix_arg_datetime();
+ return false;
+}
+
+
+bool Type_handler_timestamp_common::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ item->fix_arg_datetime();
+ return false;
+}
+
+
bool Type_handler_string_result::
Item_func_round_fix_length_and_dec(Item_func_round *item) const
{
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 62ba43acc81..64b5a9d252b 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -2524,7 +2524,7 @@ public:
Datetime to_datetime(THD *thd) const
{
if (is_zero_datetime())
- return Datetime();
+ return Datetime::zero();
return Timestamp::to_datetime(thd);
}
bool is_zero_datetime() const { return m_is_zero_datetime; }
@@ -2572,7 +2572,7 @@ public:
Datetime to_datetime(THD *thd) const
{
return is_zero_datetime() ?
- Datetime() :
+ Datetime::zero() :
Datetime(thd, Timestamp(*this).tv());
}
bool is_zero_datetime() const
@@ -3344,6 +3344,16 @@ public:
{
return MYSQL_TIMESTAMP_ERROR;
}
+ /*
+ Return true if the native format is fully implemented for a data type:
+ - Field_xxx::val_native()
+ - Item_xxx::val_native() for all classes supporting this data type
+ - Type_handler_xxx::cmp_native()
+ */
+ virtual bool is_val_native_ready() const
+ {
+ return false;
+ }
virtual bool is_timestamp_type() const
{
return false;
@@ -3495,7 +3505,8 @@ public:
TABLE *table,
uint metadata,
const Field *target) const= 0;
- virtual void show_binlog_type(const Conv_source &src, String *str) const;
+ 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,
@@ -4746,13 +4757,14 @@ public:
class Type_handler_general_purpose_int: public Type_handler_int_result
{
public:
- bool type_can_have_auto_increment_attribute() const { return true; }
+ 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
+ uint32 max_display_length(const Item *item) const override
{
return type_limits_int()->char_length();
}
- bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p) const;
+ bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p)
+ const override;
};
@@ -4762,68 +4774,71 @@ 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;
+ Sort_param *param) const override;
void sortlength(THD *thd,
const Type_std_attributes *item,
- SORT_FIELD_ATTR *attr) const;
+ 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;
+ const st_value *value) const override;
+ uint32 max_display_length(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;
+ bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p)
+ const override;
};
@@ -4981,8 +4996,9 @@ public:
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; }
+ bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p)
+ const override;
};
@@ -5407,7 +5423,8 @@ public:
{
return print_item_value_csstr(thd, item, str);
}
- void show_binlog_type(const Conv_source &src, String *str) 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;
@@ -5652,6 +5669,7 @@ public:
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;
@@ -5935,6 +5953,7 @@ public:
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 *,
@@ -6037,6 +6056,10 @@ public:
{
return MYSQL_TIMESTAMP_DATETIME;
}
+ bool is_val_native_ready() const override
+ {
+ return true;
+ }
bool is_timestamp_type() const override
{
return true;
@@ -6052,6 +6075,7 @@ public:
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;
@@ -6178,7 +6202,8 @@ public:
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, String *str) 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;
@@ -6211,7 +6236,8 @@ public:
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;
- void show_binlog_type(const Conv_source &src, String *str) 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;
@@ -6326,7 +6352,8 @@ public:
{
return varstring_type_handler(item);
}
- void show_binlog_type(const Conv_source &src, String *str) const override;
+ 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;
@@ -6369,7 +6396,8 @@ public:
return varstring_type_handler(item);
}
uint32 max_display_length_for_field(const Conv_source &src) const override;
- void show_binlog_type(const Conv_source &src, String *str) 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,
@@ -6408,7 +6436,8 @@ public:
return varstring_type_handler(item);
}
bool is_param_long_data_type() const override { return true; }
- void show_binlog_type(const Conv_source &src, String *str) const override;
+ 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;
@@ -6458,7 +6487,8 @@ public:
return MYSQL_TYPE_VARCHAR_COMPRESSED;
}
uint32 max_display_length_for_field(const Conv_source &src) const override;
- void show_binlog_type(const Conv_source &src, String *str) const override;
+ 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;
@@ -6626,7 +6656,8 @@ public:
return MYSQL_TYPE_BLOB_COMPRESSED;
}
uint32 max_display_length_for_field(const Conv_source &src) const override;
- void show_binlog_type(const Conv_source &src, String *str) 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;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index a09af1237e1..49ca047e89b 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -5478,10 +5478,10 @@ part_column_list:
part_func:
- '(' remember_name part_func_expr remember_end ')'
+ '(' part_func_expr ')'
{
partition_info *part_info= Lex->part_info;
- if (unlikely(part_info->set_part_expr(thd, $2 + 1, $3, $4, FALSE)))
+ if (unlikely(part_info->set_part_expr(thd, $2, FALSE)))
MYSQL_YYABORT;
part_info->num_columns= 1;
part_info->column_list= FALSE;
@@ -5489,9 +5489,9 @@ part_func:
;
sub_part_func:
- '(' remember_name part_func_expr remember_end ')'
+ '(' part_func_expr ')'
{
- if (unlikely(Lex->part_info->set_part_expr(thd, $2 + 1, $3, $4, TRUE)))
+ if (unlikely(Lex->part_info->set_part_expr(thd, $2, TRUE)))
MYSQL_YYABORT;
}
;
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index f938bcfd9d5..cff3a5be47c 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -5477,10 +5477,10 @@ part_column_list:
part_func:
- '(' remember_name part_func_expr remember_end ')'
+ '(' part_func_expr ')'
{
partition_info *part_info= Lex->part_info;
- if (unlikely(part_info->set_part_expr(thd, $2 + 1, $3, $4, FALSE)))
+ if (unlikely(part_info->set_part_expr(thd, $2, FALSE)))
MYSQL_YYABORT;
part_info->num_columns= 1;
part_info->column_list= FALSE;
@@ -5488,9 +5488,9 @@ part_func:
;
sub_part_func:
- '(' remember_name part_func_expr remember_end ')'
+ '(' part_func_expr ')'
{
- if (unlikely(Lex->part_info->set_part_expr(thd, $2 + 1, $3, $4, TRUE)))
+ if (unlikely(Lex->part_info->set_part_expr(thd, $2, TRUE)))
MYSQL_YYABORT;
}
;
diff --git a/sql/table.cc b/sql/table.cc
index 3b3a1fa6fb0..61bc015269c 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -801,7 +801,8 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end,
{
if (strpos + (new_frm_ver >= 1 ? 9 : 7) >= frm_image_end)
return 1;
- *rec_per_key++=0;
+ if (!(keyinfo->algorithm == HA_KEY_ALG_LONG_HASH))
+ *rec_per_key++=0;
key_part->fieldnr= (uint16) (uint2korr(strpos) & FIELD_NR_MASK);
key_part->offset= (uint) uint2korr(strpos+2)-1;
key_part->key_type= (uint) uint2korr(strpos+5);
@@ -829,6 +830,7 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end,
{
keyinfo->key_length= HA_HASH_KEY_LENGTH_WITHOUT_NULL;
key_part++; // reserved for the hash value
+ *rec_per_key++=0;
}
/*
@@ -9523,8 +9525,7 @@ bool vers_select_conds_t::eq(const vers_select_conds_t &conds) const
case SYSTEM_TIME_ALL:
return true;
case SYSTEM_TIME_BEFORE:
- DBUG_ASSERT(0);
- return false;
+ break;
case SYSTEM_TIME_AS_OF:
return start.eq(conds.start);
case SYSTEM_TIME_FROM_TO:
diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc
index ec889851b78..6ed80c8de76 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
@@ -25,6 +25,10 @@
#include <threadpool.h>
#include <my_counter.h>
+#ifdef WITH_WSREP
+#include "wsrep_trans_observer.h"
+#endif /* WITH_WSREP */
+
/* Threadpool parameters */
uint threadpool_min_threads;
@@ -139,6 +143,11 @@ static inline void set_thd_idle(THD *thd)
*/
static void thread_attach(THD* thd)
{
+#ifdef WITH_WSREP
+ /* Wait until possible background rollback has finished before
+ attaching the thd. */
+ wsrep_wait_rollback_complete_and_acquire_ownership(thd);
+#endif /* WITH_WSREP */
pthread_setspecific(THR_KEY_mysys,thd->mysys_var);
thd->thread_stack=(char*)&thd;
thd->store_globals();
diff --git a/sql/wsrep_client_service.cc b/sql/wsrep_client_service.cc
index 0fa10c1c9ea..8d58f62bd03 100644
--- a/sql/wsrep_client_service.cc
+++ b/sql/wsrep_client_service.cc
@@ -29,9 +29,9 @@
#include "slave.h" /* opt_log_slave_updates */
#include "transaction.h" /* trans_commit()... */
#include "log.h" /* stmt_has_updated_trans_table() */
-//#include "debug_sync.h"
#include "mysql/service_debug_sync.h"
#include "mysql/psi/mysql_thread.h" /* mysql_mutex_assert_owner() */
+
namespace
{
@@ -56,16 +56,12 @@ Wsrep_client_service::Wsrep_client_service(THD* thd,
void Wsrep_client_service::store_globals()
{
- DBUG_ENTER("Wsrep_client_service::store_globals");
- m_thd->store_globals();
- DBUG_VOID_RETURN;
+ wsrep_store_threadvars(m_thd);
}
void Wsrep_client_service::reset_globals()
{
- DBUG_ENTER("Wsrep_client_service::reset_globals");
- m_thd->reset_globals();
- DBUG_VOID_RETURN;
+ wsrep_reset_threadvars(m_thd);
}
bool Wsrep_client_service::interrupted(
diff --git a/sql/wsrep_high_priority_service.cc b/sql/wsrep_high_priority_service.cc
index 581ecfc8d34..02ab3b50388 100644
--- a/sql/wsrep_high_priority_service.cc
+++ b/sql/wsrep_high_priority_service.cc
@@ -398,20 +398,13 @@ int Wsrep_high_priority_service::apply_toi(const wsrep::ws_meta& ws_meta,
void Wsrep_high_priority_service::store_globals()
{
- DBUG_ENTER("Wsrep_high_priority_service::store_globals");
- /* In addition to calling THD::store_globals(), call
- wsrep::client_state::store_globals() to gain ownership of
- the client state */
- m_thd->store_globals();
- m_thd->wsrep_cs().store_globals();
- DBUG_VOID_RETURN;
+ wsrep_store_threadvars(m_thd);
+ m_thd->wsrep_cs().acquire_ownership();
}
void Wsrep_high_priority_service::reset_globals()
{
- DBUG_ENTER("Wsrep_high_priority_service::reset_globals");
- m_thd->reset_globals();
- DBUG_VOID_RETURN;
+ wsrep_reset_threadvars(m_thd);
}
void Wsrep_high_priority_service::switch_execution_context(wsrep::high_priority_service& orig_high_priority_service)
@@ -590,11 +583,14 @@ Wsrep_replayer_service::Wsrep_replayer_service(THD* replayer_thd, THD* orig_thd)
thd_proc_info(orig_thd, "wsrep replaying trx");
/*
- Swith execution context to replayer_thd and prepare it for
+ Switch execution context to replayer_thd and prepare it for
replay execution.
*/
- orig_thd->reset_globals();
- replayer_thd->store_globals();
+ /* Copy thd vars from orig_thd before reset, otherwise reset
+ for orig thd clears thread local storage before copy. */
+ wsrep_assign_from_threadvars(replayer_thd);
+ wsrep_reset_threadvars(orig_thd);
+ wsrep_store_threadvars(replayer_thd);
wsrep_open(replayer_thd);
wsrep_before_command(replayer_thd);
replayer_thd->wsrep_cs().clone_transaction_for_replay(orig_thd->wsrep_trx());
@@ -611,8 +607,8 @@ Wsrep_replayer_service::~Wsrep_replayer_service()
wsrep_after_apply(replayer_thd);
wsrep_after_command_ignore_result(replayer_thd);
wsrep_close(replayer_thd);
- replayer_thd->reset_globals();
- orig_thd->store_globals();
+ wsrep_reset_threadvars(replayer_thd);
+ wsrep_store_threadvars(orig_thd);
DBUG_ASSERT(!orig_thd->get_stmt_da()->is_sent());
DBUG_ASSERT(!orig_thd->get_stmt_da()->is_set());
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index ad4203490f2..22b274bef1b 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -2251,6 +2251,7 @@ static void wsrep_close_thread(THD *thd)
{
thd->set_killed(KILL_CONNECTION);
MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (thd));
+ mysql_mutex_lock(&thd->LOCK_thd_kill);
if (thd->mysys_var)
{
thd->mysys_var->abort=1;
@@ -2263,6 +2264,7 @@ static void wsrep_close_thread(THD *thd)
}
mysql_mutex_unlock(&thd->mysys_var->mutex);
}
+ mysql_mutex_unlock(&thd->LOCK_thd_kill);
}
static my_bool have_committing_connections(THD *thd, void *)
@@ -2659,7 +2661,8 @@ void* start_wsrep_THD(void *arg)
/* now that we've called my_thread_init(), it is safe to call DBUG_* */
thd->thread_stack= (char*) &thd;
- if (thd->store_globals())
+ wsrep_assign_from_threadvars(thd);
+ if (wsrep_store_threadvars(thd))
{
close_connection(thd, ER_OUT_OF_RESOURCES);
statistic_increment(aborted_connects,&LOCK_status);
@@ -2697,19 +2700,17 @@ void* start_wsrep_THD(void *arg)
WSREP_DEBUG("wsrep system thread %llu, %p starting",
thd->thread_id, thd);
- thd_args->fun()(thd, thd_args->args());
+ thd_args->fun()(thd, static_cast<void *>(thd_args));
WSREP_DEBUG("wsrep system thread: %llu, %p closing",
thd->thread_id, thd);
/* Wsrep may reset globals during thread context switches, store globals
before cleanup. */
- thd->store_globals();
+ wsrep_store_threadvars(thd);
close_connection(thd, 0);
- delete thd_args;
-
mysql_mutex_lock(&LOCK_wsrep_slave_threads);
DBUG_ASSERT(wsrep_running_threads > 0);
wsrep_running_threads--;
@@ -2728,6 +2729,7 @@ void* start_wsrep_THD(void *arg)
break;
}
+ delete thd_args;
WSREP_DEBUG("wsrep running threads now: %lu", wsrep_running_threads);
mysql_cond_broadcast(&COND_wsrep_slave_threads);
mysql_mutex_unlock(&LOCK_wsrep_slave_threads);
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
index 42808aa66c0..497e5f7a086 100644
--- a/sql/wsrep_mysqld.h
+++ b/sql/wsrep_mysqld.h
@@ -411,18 +411,17 @@ typedef void (*wsrep_thd_processor_fun)(THD*, void *);
class Wsrep_thd_args
{
public:
- Wsrep_thd_args(wsrep_thd_processor_fun fun, void* args,
- wsrep_thread_type thread_type)
+ Wsrep_thd_args(wsrep_thd_processor_fun fun,
+ wsrep_thread_type thread_type,
+ pthread_t thread_id)
:
fun_ (fun),
- args_ (args),
- thread_type_ (thread_type)
+ thread_type_ (thread_type),
+ thread_id_ (thread_id)
{ }
wsrep_thd_processor_fun fun() { return fun_; }
-
- void* args() { return args_; }
-
+ pthread_t* thread_id() {return &thread_id_; }
enum wsrep_thread_type thread_type() {return thread_type_;}
private:
@@ -431,8 +430,8 @@ class Wsrep_thd_args
Wsrep_thd_args& operator=(const Wsrep_thd_args&);
wsrep_thd_processor_fun fun_;
- void* args_;
enum wsrep_thread_type thread_type_;
+ pthread_t thread_id_;
};
void* start_wsrep_THD(void*);
diff --git a/sql/wsrep_schema.cc b/sql/wsrep_schema.cc
index ee0fc8f12cc..c7ea378d4fb 100644
--- a/sql/wsrep_schema.cc
+++ b/sql/wsrep_schema.cc
@@ -29,6 +29,7 @@
#include "wsrep_binlog.h"
#include "wsrep_high_priority_service.h"
#include "wsrep_storage_service.h"
+#include "wsrep_thd.h"
#include <string>
#include <sstream>
@@ -145,13 +146,13 @@ public:
: m_orig_thd(orig_thd)
, m_cur_thd(cur_thd)
{
- m_orig_thd->reset_globals();
- m_cur_thd->store_globals();
+ wsrep_reset_threadvars(m_orig_thd);
+ wsrep_store_threadvars(m_cur_thd);
}
~thd_context_switch()
{
- m_cur_thd->reset_globals();
- m_orig_thd->store_globals();
+ wsrep_reset_threadvars(m_cur_thd);
+ wsrep_store_threadvars(m_orig_thd);
}
private:
THD *m_orig_thd;
@@ -474,7 +475,9 @@ static int scan(TABLE* table, uint field, char* strbuf, uint strbuf_len)
{
String str;
(void)table->field[field]->val_str(&str);
- strncpy(strbuf, str.ptr(), std::min(str.length(), strbuf_len));
+ LEX_CSTRING tmp= str.lex_cstring();
+ uint len = tmp.length;
+ strncpy(strbuf, tmp.str, std::min(len, strbuf_len));
strbuf[strbuf_len - 1]= '\0';
return 0;
}
@@ -593,7 +596,8 @@ static void wsrep_init_thd_for_schema(THD *thd)
thd->variables.option_bits |= OPTION_LOG_OFF;
/* Read committed isolation to avoid gap locking */
thd->variables.tx_isolation= ISO_READ_COMMITTED;
- thd->store_globals();
+ wsrep_assign_from_threadvars(thd);
+ wsrep_store_threadvars(thd);
}
int Wsrep_schema::init()
@@ -1121,6 +1125,7 @@ int Wsrep_schema::replay_transaction(THD* orig_thd,
THD thd(next_thread_id(), true);
thd.thread_stack= (orig_thd ? orig_thd->thread_stack :
(char*) &thd);
+ wsrep_assign_from_threadvars(&thd);
Wsrep_schema_impl::wsrep_off wsrep_off(&thd);
Wsrep_schema_impl::binlog_off binlog_off(&thd);
@@ -1226,6 +1231,7 @@ int Wsrep_schema::recover_sr_transactions(THD *orig_thd)
THD storage_thd(next_thread_id(), true);
storage_thd.thread_stack= (orig_thd ? orig_thd->thread_stack :
(char*) &storage_thd);
+ wsrep_assign_from_threadvars(&storage_thd);
TABLE* frag_table= 0;
TABLE* cluster_table= 0;
Wsrep_storage_service storage_service(&storage_thd);
@@ -1331,12 +1337,7 @@ int Wsrep_schema::recover_sr_transactions(THD *orig_thd)
transaction_id)))
{
DBUG_ASSERT(wsrep::starts_transaction(flags));
- THD* thd= new THD(next_thread_id(), true);
- thd->thread_stack= (char*)&storage_thd;
-
- thd->real_id= pthread_self();
-
- applier= new Wsrep_applier_service(thd);
+ applier = wsrep_create_streaming_applier(&storage_thd, "recovery");
server_state.start_streaming_applier(server_id, transaction_id,
applier);
applier->start_transaction(wsrep::ws_handle(transaction_id, 0),
@@ -1366,6 +1367,7 @@ int Wsrep_schema::recover_sr_transactions(THD *orig_thd)
Wsrep_schema_impl::end_scan(frag_table);
Wsrep_schema_impl::finish_stmt(&storage_thd);
trans_commit(&storage_thd);
+ storage_thd.set_mysys_var(0);
out:
DBUG_RETURN(ret);
}
diff --git a/sql/wsrep_server_service.cc b/sql/wsrep_server_service.cc
index 42856862db3..bfb85e3d0ab 100644
--- a/sql/wsrep_server_service.cc
+++ b/sql/wsrep_server_service.cc
@@ -26,6 +26,7 @@
#include "wsrep_mysqld.h"
#include "wsrep_schema.h"
#include "wsrep_utils.h"
+#include "wsrep_thd.h"
#include "log.h" /* sql_print_xxx() */
#include "sql_class.h" /* system variables */
@@ -50,6 +51,10 @@ wsrep::storage_service* Wsrep_server_service::storage_service(
init_service_thd(thd, cs.m_thd->thread_stack);
WSREP_DEBUG("Created storage service with thread id %llu",
thd->thread_id);
+ /* Use variables from the current thd attached to client_service.
+ This is because we need to be able to BF abort storage access
+ operations. */
+ wsrep_assign_from_threadvars(thd);
return new Wsrep_storage_service(thd);
}
@@ -62,6 +67,7 @@ wsrep::storage_service* Wsrep_server_service::storage_service(
init_service_thd(thd, hps.m_thd->thread_stack);
WSREP_DEBUG("Created high priority storage service with thread id %llu",
thd->thread_id);
+ wsrep_assign_from_threadvars(thd);
return new Wsrep_storage_service(thd);
}
@@ -71,21 +77,48 @@ void Wsrep_server_service::release_storage_service(
Wsrep_storage_service* ss=
static_cast<Wsrep_storage_service*>(storage_service);
THD* thd= ss->m_thd;
+ wsrep_reset_threadvars(thd);
delete ss;
delete thd;
}
+Wsrep_applier_service*
+wsrep_create_streaming_applier(THD *orig_thd, const char *ctx)
+{
+ /* Reset variables to allow creating new variables in thread local
+ storage for new THD if needed. Note that reset must be done for
+ current_thd, as orig_thd may not be in effect. This may be the case when
+ streaming transaction is BF aborted and streaming applier
+ is created from BF aborter context. */
+ Wsrep_threadvars saved_threadvars(wsrep_save_threadvars());
+ wsrep_reset_threadvars(saved_threadvars.cur_thd);
+ THD *thd= 0;
+ Wsrep_applier_service *ret= 0;
+ if (!wsrep_create_threadvars() &&
+ (thd= new THD(next_thread_id(), true)))
+ {
+ init_service_thd(thd, orig_thd->thread_stack);
+ wsrep_assign_from_threadvars(thd);
+ WSREP_DEBUG("Created streaming applier service in %s context with "
+ "thread id %llu", ctx, thd->thread_id);
+ if (!(ret= new (std::nothrow) Wsrep_applier_service(thd)))
+ {
+ delete thd;
+ }
+ }
+ /* Restore original thread local storage state before returning. */
+ wsrep_restore_threadvars(saved_threadvars);
+ wsrep_store_threadvars(saved_threadvars.cur_thd);
+ return ret;
+}
+
wsrep::high_priority_service*
Wsrep_server_service::streaming_applier_service(
wsrep::client_service& orig_client_service)
{
Wsrep_client_service& orig_cs=
static_cast<Wsrep_client_service&>(orig_client_service);
- THD* thd= new THD(next_thread_id(), true);
- init_service_thd(thd, orig_cs.m_thd->thread_stack);
- WSREP_DEBUG("Created streaming applier service in local context with "
- "thread id %llu", thd->thread_id);
- return new Wsrep_applier_service(thd);
+ return wsrep_create_streaming_applier(orig_cs.m_thd, "local");
}
wsrep::high_priority_service*
@@ -94,11 +127,7 @@ Wsrep_server_service::streaming_applier_service(
{
Wsrep_high_priority_service&
orig_hps(static_cast<Wsrep_high_priority_service&>(orig_high_priority_service));
- THD* thd= new THD(next_thread_id(), true);
- init_service_thd(thd, orig_hps.m_thd->thread_stack);
- WSREP_DEBUG("Created streaming applier service in high priority "
- "context with thread id %llu", thd->thread_id);
- return new Wsrep_applier_service(thd);
+ return wsrep_create_streaming_applier(orig_hps.m_thd, "high priority");
}
void Wsrep_server_service::release_high_priority_service(wsrep::high_priority_service* high_priority_service)
@@ -107,7 +136,9 @@ void Wsrep_server_service::release_high_priority_service(wsrep::high_priority_se
static_cast<Wsrep_high_priority_service*>(high_priority_service);
THD* thd= hps->m_thd;
delete hps;
+ wsrep_store_threadvars(thd);
delete thd;
+ wsrep_delete_threadvars();
}
void Wsrep_server_service::background_rollback(wsrep::client_state& client_state)
diff --git a/sql/wsrep_server_service.h b/sql/wsrep_server_service.h
index b8f1f009cde..6336fe2c473 100644
--- a/sql/wsrep_server_service.h
+++ b/sql/wsrep_server_service.h
@@ -77,5 +77,14 @@ private:
Wsrep_server_state& m_server_state;
};
+/**
+ Helper method to create new streaming applier.
+
+ @param orig_thd Original thd context to copy operation context from.
+ @param ctx Context string for debug logging.
+ */
+class Wsrep_applier_service;
+Wsrep_applier_service*
+wsrep_create_streaming_applier(THD *orig_thd, const char *ctx);
#endif /* WSREP_SERVER_SERVICE */
diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc
index 85d5aca342d..74a8b9dff05 100644
--- a/sql/wsrep_sst.cc
+++ b/sql/wsrep_sst.cc
@@ -16,6 +16,7 @@
#include "mariadb.h"
#include "wsrep_sst.h"
#include <inttypes.h>
+#include <ctype.h>
#include <mysqld.h>
#include <m_ctype.h>
#include <strfunc.h>
@@ -27,6 +28,8 @@
#include "wsrep_priv.h"
#include "wsrep_utils.h"
#include "wsrep_xid.h"
+#include "wsrep_thd.h"
+
#include <cstdio>
#include <cstdlib>
@@ -237,7 +240,7 @@ void wsrep_sst_received (THD* thd,
wsrep thread pool. Restore original thd context before returning.
*/
if (thd) {
- thd->store_globals();
+ wsrep_store_threadvars(thd);
}
else {
my_pthread_setspecific_ptr(THR_THD, NULL);
@@ -307,7 +310,31 @@ static char* my_fgets (char* buf, size_t buf_len, FILE* stream)
}
/*
- Generate opt_binlog_opt_val for sst_donate_other(), sst_prepare_other().
+ Generate "name 'value'" string.
+*/
+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));
+ if (buf)
+ {
+ char* ref= buf;
+ *ref++ = ' ';
+ memcpy(ref, name, name_len * sizeof(char));
+ ref += name_len;
+ *ref++ = ' ';
+ *ref++ = '\'';
+ memcpy(ref, value, value_len * sizeof(char));
+ ref += value_len;
+ *ref++ = '\'';
+ *ref = 0;
+ }
+ return buf;
+}
+/*
+ Generate binlog option string for sst_donate_other(), sst_prepare_other().
Returns zero on success, negative error code otherwise.
@@ -323,7 +350,9 @@ static int generate_binlog_opt_val(char** ret)
{
assert(opt_bin_logname);
*ret= strcmp(opt_bin_logname, "0") ?
- my_strdup(opt_bin_logname, MYF(0)) : my_strdup("", MYF(0));
+ generate_name_value(WSREP_SST_OPT_BINLOG,
+ opt_bin_logname) :
+ my_strdup("", MYF(0));
}
else
{
@@ -340,7 +369,9 @@ static int generate_binlog_index_opt_val(char** ret)
if (opt_binlog_index_name)
{
*ret= strcmp(opt_binlog_index_name, "0") ?
- my_strdup(opt_binlog_index_name, MYF(0)) : my_strdup("", MYF(0));
+ generate_name_value(WSREP_SST_OPT_BINLOG_INDEX,
+ opt_binlog_index_name) :
+ my_strdup("", MYF(0));
}
else
{
@@ -509,7 +540,8 @@ err:
thd->system_thread= SYSTEM_THREAD_GENERIC;
thd->real_id= pthread_self();
- thd->store_globals();
+ wsrep_assign_from_threadvars(thd);
+ wsrep_store_threadvars(thd);
/* */
thd->variables.wsrep_on = 0;
@@ -576,23 +608,320 @@ static int sst_append_data_dir(wsp::env& env, const char* data_dir)
return -env.error();
}
+static size_t estimate_cmd_len (bool* extra_args)
+{
+ /*
+ The length of the area reserved for the control parameters
+ of the SST script (excluding the copying of the original
+ mysqld arguments):
+ */
+ size_t cmd_len= 4096;
+ bool extra= false;
+ /*
+ If mysqld was started with arguments, add them all:
+ */
+ if (orig_argc > 1)
+ {
+ for (int i = 1; i < orig_argc; i++)
+ {
+ const char* arg= orig_argv[i];
+ size_t n= strlen(arg);
+ if (n == 0) continue;
+ cmd_len += n;
+ bool quotation= false;
+ char c;
+ while ((c = *arg++) != 0)
+ {
+ /* A whitespace or a single quote requires double quotation marks: */
+ if (isspace(c) || c == '\'')
+ {
+ quotation= true;
+ }
+ /*
+ If the equals symbol is encountered, then we need to separately
+ process the right side:
+ */
+ else if (c == '=')
+ {
+ /* Perhaps we need to quote the left part of the argument: */
+ if (quotation)
+ {
+ cmd_len += 2;
+ /*
+ Reset the quotation flag, since now the status for
+ the right side of the expression will be saved here:
+ */
+ quotation= false;
+ }
+ while ((c = *arg++) != 0)
+ {
+ /*
+ A whitespace or a single quote requires double
+ quotation marks:
+ */
+ if (isspace(c) || c == '\'')
+ {
+ quotation= true;
+ }
+ /*
+ Double quotation mark or backslash symbol requires backslash
+ prefixing:
+ */
+#ifdef __WIN__
+ else if (c == '"' || c == '\\')
+#else
+ /*
+ The dollar symbol is used to substitute a variable, therefore
+ it also requires escaping:
+ */
+ else if (c == '"' || c == '\\' || c == '$')
+#endif
+ {
+ cmd_len++;
+ }
+ }
+ break;
+ }
+ /*
+ Double quotation mark or backslash symbol requires backslash
+ prefixing:
+ */
+#ifdef __WIN__
+ else if (c == '"' || c == '\\')
+#else
+ /*
+ The dollar symbol is used to substitute a variable, therefore
+ it also requires escaping:
+ */
+ else if (c == '"' || c == '\\' || c == '$')
+#endif
+ {
+ cmd_len++;
+ }
+ }
+ /* Perhaps we need to quote the entire argument or its right part: */
+ if (quotation)
+ {
+ cmd_len += 2;
+ }
+ }
+ extra = true;
+ cmd_len += strlen(WSREP_SST_OPT_MYSQLD);
+ /*
+ Add the separating spaces between arguments,
+ and one additional space before "--mysqld-args":
+ */
+ cmd_len += orig_argc;
+ }
+ *extra_args= extra;
+ return cmd_len;
+}
+
+static void copy_orig_argv (char* cmd_str)
+{
+ /*
+ If mysqld was started with arguments, copy them all:
+ */
+ if (orig_argc > 1)
+ {
+ size_t n = strlen(WSREP_SST_OPT_MYSQLD);
+ *cmd_str++ = ' ';
+ memcpy(cmd_str, WSREP_SST_OPT_MYSQLD, n * sizeof(char));
+ cmd_str += n;
+ for (int i = 1; i < orig_argc; i++)
+ {
+ char* arg= orig_argv[i];
+ n = strlen(arg);
+ if (n == 0) continue;
+ *cmd_str++ = ' ';
+ bool quotation= false;
+ bool plain= true;
+ char *arg_scan= arg;
+ char c;
+ while ((c = *arg_scan++) != 0)
+ {
+ /* A whitespace or a single quote requires double quotation marks: */
+ if (isspace(c) || c == '\'')
+ {
+ quotation= true;
+ }
+ /*
+ If the equals symbol is encountered, then we need to separately
+ process the right side:
+ */
+ else if (c == '=')
+ {
+ /* Calculate length of the Left part of the argument: */
+ size_t m = (size_t) (arg_scan - arg) - 1;
+ if (m)
+ {
+ /* Perhaps we need to quote the left part of the argument: */
+ if (quotation)
+ {
+ *cmd_str++ = '"';
+ }
+ /*
+ If there were special characters inside, then we can use
+ the fast memcpy function:
+ */
+ if (plain)
+ {
+ memcpy(cmd_str, arg, m * sizeof(char));
+ cmd_str += m;
+ /* Left part of the argument has already been processed: */
+ n -= m;
+ arg += m;
+ }
+ /* Otherwise we need to prefix individual characters: */
+ else
+ {
+ n -= m;
+ while (m)
+ {
+ c = *arg++;
+#ifdef __WIN__
+ if (c == '"' || c == '\\')
+#else
+ if (c == '"' || c == '\\' || c == '$')
+#endif
+ {
+ *cmd_str++ = '\\';
+ }
+ *cmd_str++ = c;
+ m--;
+ }
+ /*
+ Reset the plain string flag, since now the status for
+ the right side of the expression will be saved here:
+ */
+ plain= true;
+ }
+ /* Perhaps we need to quote the left part of the argument: */
+ if (quotation)
+ {
+ *cmd_str++ = '"';
+ /*
+ Reset the quotation flag, since now the status for
+ the right side of the expression will be saved here:
+ */
+ quotation= false;
+ }
+ }
+ /* Copy equals symbol: */
+ *cmd_str++ = '=';
+ arg++;
+ n--;
+ /* Let's deal with the left side of the expression: */
+ while ((c = *arg_scan++) != 0)
+ {
+ /*
+ A whitespace or a single quote requires double
+ quotation marks:
+ */
+ if (isspace(c) || c == '\'')
+ {
+ quotation= true;
+ }
+ /*
+ Double quotation mark or backslash symbol requires backslash
+ prefixing:
+ */
+#ifdef __WIN__
+ else if (c == '"' || c == '\\')
+#else
+ /*
+ The dollar symbol is used to substitute a variable, therefore
+ it also requires escaping:
+ */
+ else if (c == '"' || c == '\\' || c == '$')
+#endif
+ {
+ plain= false;
+ }
+ }
+ break;
+ }
+ /*
+ Double quotation mark or backslash symbol requires backslash
+ prefixing:
+ */
+#ifdef __WIN__
+ else if (c == '"' || c == '\\')
+#else
+ /*
+ The dollar symbol is used to substitute a variable, therefore
+ it also requires escaping:
+ */
+ else if (c == '"' || c == '\\' || c == '$')
+#endif
+ {
+ plain= false;
+ }
+ }
+ if (n)
+ {
+ /* Perhaps we need to quote the entire argument or its right part: */
+ if (quotation)
+ {
+ *cmd_str++ = '"';
+ }
+ /*
+ If there were no special characters inside, then we can use
+ the fast memcpy function:
+ */
+ if (plain)
+ {
+ memcpy(cmd_str, arg, n * sizeof(char));
+ cmd_str += n;
+ }
+ /* Otherwise we need to prefix individual characters: */
+ else
+ {
+ while ((c = *arg++) != 0)
+ {
+#ifdef __WIN__
+ if (c == '"' || c == '\\')
+#else
+ if (c == '"' || c == '\\' || c == '$')
+#endif
+ {
+ *cmd_str++ = '\\';
+ }
+ *cmd_str++ = c;
+ }
+ }
+ /* Perhaps we need to quote the entire argument or its right part: */
+ if (quotation)
+ {
+ *cmd_str++ = '"';
+ }
+ }
+ }
+ /*
+ Add a terminating null character (not counted in the length,
+ since we've overwritten the original null character which
+ was previously added by snprintf:
+ */
+ *cmd_str = 0;
+ }
+}
+
static ssize_t sst_prepare_other (const char* method,
const char* sst_auth,
const char* addr_in,
const char** addr_out)
{
- int const cmd_len= 4096;
+ bool extra_args;
+ size_t const cmd_len= estimate_cmd_len(&extra_args);
wsp::string cmd_str(cmd_len);
if (!cmd_str())
{
- WSREP_ERROR("sst_prepare_other(): could not allocate cmd buffer of %d bytes",
+ WSREP_ERROR("sst_prepare_other(): could not allocate cmd buffer of %zd bytes",
cmd_len);
return -ENOMEM;
}
- const char* binlog_opt= "";
- const char* binlog_index_opt= "";
char* binlog_opt_val= NULL;
char* binlog_index_opt_val= NULL;
@@ -610,9 +939,6 @@ static ssize_t sst_prepare_other (const char* method,
ret);
}
- if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG;
- if (strlen(binlog_index_opt_val)) binlog_index_opt= WSREP_SST_OPT_BINLOG_INDEX;
-
make_wsrep_defaults_file();
ret= snprintf (cmd_str(), cmd_len,
@@ -620,23 +946,26 @@ static ssize_t sst_prepare_other (const char* method,
WSREP_SST_OPT_ROLE " 'joiner' "
WSREP_SST_OPT_ADDR " '%s' "
WSREP_SST_OPT_DATA " '%s' "
- " %s "
+ "%s"
WSREP_SST_OPT_PARENT " '%d'"
- " %s '%s'"
- " %s '%s'",
+ "%s"
+ "%s",
method, addr_in, mysql_real_data_home,
wsrep_defaults_file,
- (int)getpid(), binlog_opt, binlog_opt_val,
- binlog_index_opt, binlog_index_opt_val);
+ (int)getpid(),
+ binlog_opt_val, binlog_index_opt_val);
my_free(binlog_opt_val);
my_free(binlog_index_opt_val);
- if (ret < 0 || ret >= cmd_len)
+ if (ret < 0 || size_t(ret) >= cmd_len)
{
WSREP_ERROR("sst_prepare_other(): snprintf() failed: %d", ret);
return (ret < 0 ? ret : -EMSGSIZE);
}
+ if (extra_args)
+ copy_orig_argv(cmd_str() + ret);
+
wsp::env env(NULL);
if (env.error())
{
@@ -890,13 +1219,14 @@ static int sst_donate_mysqldump (const char* addr,
}
memcpy(host, address.get_address(), address.get_address_len());
int port= address.get_port();
- int const cmd_len= 4096;
- wsp::string cmd_str(cmd_len);
+ bool extra_args;
+ size_t const cmd_len= estimate_cmd_len(&extra_args);
+ wsp::string cmd_str(cmd_len);
if (!cmd_str())
{
WSREP_ERROR("sst_donate_mysqldump(): "
- "could not allocate cmd buffer of %d bytes", cmd_len);
+ "could not allocate cmd buffer of %zd bytes", cmd_len);
return -ENOMEM;
}
@@ -917,7 +1247,7 @@ static int sst_donate_mysqldump (const char* addr,
WSREP_SST_OPT_PORT " '%u' "
WSREP_SST_OPT_LPORT " '%u' "
WSREP_SST_OPT_SOCKET " '%s' "
- " %s "
+ "%s"
WSREP_SST_OPT_GTID " '%s:%lld' "
WSREP_SST_OPT_GTID_DOMAIN_ID " '%d'"
"%s",
@@ -927,12 +1257,15 @@ static int sst_donate_mysqldump (const char* addr,
wsrep_gtid_domain_id,
bypass ? " " WSREP_SST_OPT_BYPASS : "");
- if (ret < 0 || ret >= cmd_len)
+ if (ret < 0 || size_t(ret) >= cmd_len)
{
WSREP_ERROR("sst_donate_mysqldump(): snprintf() failed: %d", ret);
return (ret < 0 ? ret : -EMSGSIZE);
}
+ if (extra_args)
+ copy_orig_argv(cmd_str() + ret);
+
WSREP_DEBUG("Running: '%s'", cmd_str());
ret= sst_run_shell (cmd_str(), env, 3);
@@ -1283,18 +1616,17 @@ static int sst_donate_other (const char* method,
bool bypass,
char** env) // carries auth info
{
- int const cmd_len= 4096;
- wsp::string cmd_str(cmd_len);
+ bool extra_args;
+ size_t const cmd_len= estimate_cmd_len(&extra_args);
+ wsp::string cmd_str(cmd_len);
if (!cmd_str())
{
WSREP_ERROR("sst_donate_other(): "
- "could not allocate cmd buffer of %d bytes", cmd_len);
+ "could not allocate cmd buffer of %zd bytes", cmd_len);
return -ENOMEM;
}
- const char* binlog_opt= "";
- const char* binlog_index_opt= "";
char* binlog_opt_val= NULL;
char* binlog_index_opt_val= NULL;
@@ -1311,9 +1643,6 @@ static int sst_donate_other (const char* method,
ret);
}
- if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG;
- if (strlen(binlog_index_opt_val)) binlog_index_opt= WSREP_SST_OPT_BINLOG_INDEX;
-
make_wsrep_defaults_file();
std::ostringstream uuid_oss;
@@ -1324,27 +1653,30 @@ static int sst_donate_other (const char* method,
WSREP_SST_OPT_ADDR " '%s' "
WSREP_SST_OPT_SOCKET " '%s' "
WSREP_SST_OPT_DATA " '%s' "
- " %s "
- " %s '%s' "
- " %s '%s' "
+ "%s"
WSREP_SST_OPT_GTID " '%s:%lld' "
WSREP_SST_OPT_GTID_DOMAIN_ID " '%d'"
+ "%s"
+ "%s"
"%s",
method, addr, mysqld_unix_port, mysql_real_data_home,
wsrep_defaults_file,
- binlog_opt, binlog_opt_val,
- binlog_index_opt, binlog_index_opt_val,
uuid_oss.str().c_str(), gtid.seqno().get(), wsrep_gtid_domain_id,
+ binlog_opt_val, binlog_index_opt_val,
bypass ? " " WSREP_SST_OPT_BYPASS : "");
+
my_free(binlog_opt_val);
my_free(binlog_index_opt_val);
- if (ret < 0 || ret >= cmd_len)
+ if (ret < 0 || size_t(ret) >= cmd_len)
{
WSREP_ERROR("sst_donate_other(): snprintf() failed: %d", ret);
return (ret < 0 ? ret : -EMSGSIZE);
}
+ if (extra_args)
+ copy_orig_argv(cmd_str() + ret);
+
if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(FALSE);
pthread_t tmp;
diff --git a/sql/wsrep_sst.h b/sql/wsrep_sst.h
index eb218647bc0..2389db4abe7 100644
--- a/sql/wsrep_sst.h
+++ b/sql/wsrep_sst.h
@@ -32,6 +32,7 @@
#define WSREP_SST_OPT_PARENT "--parent"
#define WSREP_SST_OPT_BINLOG "--binlog"
#define WSREP_SST_OPT_BINLOG_INDEX "--binlog-index"
+#define WSREP_SST_OPT_MYSQLD "--mysqld-args"
// mysqldump-specific options
#define WSREP_SST_OPT_USER "--user"
diff --git a/sql/wsrep_storage_service.cc b/sql/wsrep_storage_service.cc
index e164114b733..6dfe3eee448 100644
--- a/sql/wsrep_storage_service.cc
+++ b/sql/wsrep_storage_service.cc
@@ -196,18 +196,10 @@ int Wsrep_storage_service::rollback(const wsrep::ws_handle& ws_handle,
void Wsrep_storage_service::store_globals()
{
- DBUG_ENTER("Wsrep_storage_service::store_globals");
- DBUG_PRINT("info", ("Wsrep_storage_service::store_globals(%llu, %p)",
- m_thd->thread_id, m_thd));
- m_thd->store_globals();
- DBUG_VOID_RETURN;
+ wsrep_store_threadvars(m_thd);
}
void Wsrep_storage_service::reset_globals()
{
- DBUG_ENTER("Wsrep_storage_service::reset_globals");
- DBUG_PRINT("info", ("Wsrep_storage_service::reset_globals(%llu, %p)",
- m_thd->thread_id, m_thd));
- m_thd->reset_globals();
- DBUG_VOID_RETURN;
+ wsrep_reset_threadvars(m_thd);
}
diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc
index 5907d495ee9..50f0376f674 100644
--- a/sql/wsrep_thd.cc
+++ b/sql/wsrep_thd.cc
@@ -31,8 +31,9 @@
#include "rpl_rli.h"
#include "rpl_mi.h"
+extern "C" pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
+
static Wsrep_thd_queue* wsrep_rollback_queue= 0;
-static Wsrep_thd_queue* wsrep_post_rollback_queue= 0;
static Atomic_counter<uint64_t> wsrep_bf_aborts_counter;
@@ -86,7 +87,7 @@ static void wsrep_replication_process(THD *thd,
static bool create_wsrep_THD(Wsrep_thd_args* args)
{
ulong old_wsrep_running_threads= wsrep_running_threads;
- pthread_t unused;
+
#ifdef HAVE_PSI_THREAD_INTERFACE
PSI_thread_key key;
@@ -100,10 +101,11 @@ static bool create_wsrep_THD(Wsrep_thd_args* args)
break;
default:
assert(0);
+ key= 0;
break;
}
#endif
- bool res= mysql_thread_create(key, &unused, &connection_attrib,
+ bool res= mysql_thread_create(key, args->thread_id(), &connection_attrib,
start_wsrep_THD, (void*)args);
/*
if starting a thread on server startup, wait until the this thread's THD
@@ -123,9 +125,9 @@ void wsrep_create_appliers(long threads)
/* Dont' start slave threads if wsrep-provider or wsrep-cluster-address
is not set.
*/
- if (!WSREP_PROVIDER_EXISTS)
+ if (!WSREP_PROVIDER_EXISTS)
{
- return;
+ return;
}
if (!wsrep_cluster_address || wsrep_cluster_address[0]== 0)
@@ -135,11 +137,12 @@ void wsrep_create_appliers(long threads)
}
long wsrep_threads=0;
-
+
while (wsrep_threads++ < threads)
{
- Wsrep_thd_args* args(new Wsrep_thd_args(wsrep_replication_process, 0,
- WSREP_APPLIER_THREAD));
+ Wsrep_thd_args* args(new Wsrep_thd_args(wsrep_replication_process,
+ WSREP_APPLIER_THREAD,
+ pthread_self()));
if (create_wsrep_THD(args))
{
WSREP_WARN("Can't create thread to manage wsrep replication");
@@ -147,6 +150,122 @@ void wsrep_create_appliers(long threads)
}
}
+static void wsrep_rollback_streaming_aborted_by_toi(THD *thd)
+{
+ WSREP_INFO("wsrep_rollback_streaming_aborted_by_toi");
+ /* Set thd->event_scheduler.data temporarily to NULL to avoid
+ callbacks to threadpool wait_begin() during rollback. */
+ auto saved_esd= thd->event_scheduler.data;
+ thd->event_scheduler.data= 0;
+ if (thd->wsrep_cs().mode() == wsrep::client_state::m_high_priority)
+ {
+ DBUG_ASSERT(!saved_esd);
+ DBUG_ASSERT(thd->wsrep_applier_service);
+ thd->wsrep_applier_service->rollback(wsrep::ws_handle(),
+ wsrep::ws_meta());
+ thd->wsrep_applier_service->after_apply();
+ /* Will free THD */
+ Wsrep_server_state::instance().server_service().
+ release_high_priority_service(thd->wsrep_applier_service);
+ }
+ else
+ {
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+ /* prepare THD for rollback processing */
+ thd->reset_for_next_command(true);
+ thd->lex->sql_command= SQLCOM_ROLLBACK;
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+ /* Perform a client rollback, restore globals and signal
+ the victim only when all the resources have been
+ released */
+ thd->wsrep_cs().client_service().bf_rollback();
+ wsrep_reset_threadvars(thd);
+ /* Assign saved event_scheduler.data back before letting
+ client to continue. */
+ thd->event_scheduler.data= saved_esd;
+ thd->wsrep_cs().sync_rollback_complete();
+ }
+}
+
+static void wsrep_rollback_high_priority(THD *thd)
+{
+ WSREP_INFO("rollbacker aborting SR thd: (%lld %llu)",
+ thd->thread_id, (long long)thd->real_id);
+ DBUG_ASSERT(thd->wsrep_cs().mode() == Wsrep_client_state::m_high_priority);
+ /* Must be streaming and must have been removed from the
+ server state streaming appliers map. */
+ DBUG_ASSERT(thd->wsrep_trx().is_streaming());
+ DBUG_ASSERT(!Wsrep_server_state::instance().find_streaming_applier(
+ thd->wsrep_trx().server_id(),
+ thd->wsrep_trx().id()));
+ DBUG_ASSERT(thd->wsrep_applier_service);
+
+ /* Fragment removal should happen before rollback to make
+ the transaction non-observable in SR table after the rollback
+ completes. For correctness the order does not matter here,
+ but currently it is mandated by checks in some MTR tests. */
+ wsrep::transaction_id transaction_id(thd->wsrep_trx().id());
+ Wsrep_storage_service* storage_service=
+ static_cast<Wsrep_storage_service*>(
+ Wsrep_server_state::instance().server_service().storage_service(
+ *thd->wsrep_applier_service));
+ storage_service->store_globals();
+ storage_service->adopt_transaction(thd->wsrep_trx());
+ storage_service->remove_fragments();
+ storage_service->commit(wsrep::ws_handle(transaction_id, 0),
+ wsrep::ws_meta());
+ Wsrep_server_state::instance().server_service().release_storage_service(storage_service);
+ wsrep_store_threadvars(thd);
+ thd->wsrep_applier_service->rollback(wsrep::ws_handle(),
+ wsrep::ws_meta());
+ thd->wsrep_applier_service->after_apply();
+ /* Will free THD */
+ Wsrep_server_state::instance().server_service()
+ .release_high_priority_service(thd->wsrep_applier_service);
+}
+
+static void wsrep_rollback_local(THD *thd)
+{
+ WSREP_INFO("Wsrep_rollback_local");
+ if (thd->wsrep_trx().is_streaming())
+ {
+ wsrep::transaction_id transaction_id(thd->wsrep_trx().id());
+ Wsrep_storage_service* storage_service=
+ static_cast<Wsrep_storage_service*>(
+ Wsrep_server_state::instance().server_service().
+ storage_service(thd->wsrep_cs().client_service()));
+
+ storage_service->store_globals();
+ storage_service->adopt_transaction(thd->wsrep_trx());
+ storage_service->remove_fragments();
+ storage_service->commit(wsrep::ws_handle(transaction_id, 0),
+ wsrep::ws_meta());
+ Wsrep_server_state::instance().server_service().
+ release_storage_service(storage_service);
+ wsrep_store_threadvars(thd);
+ }
+ /* Set thd->event_scheduler.data temporarily to NULL to avoid
+ callbacks to threadpool wait_begin() during rollback. */
+ auto saved_esd= thd->event_scheduler.data;
+ thd->event_scheduler.data= 0;
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+ /* prepare THD for rollback processing */
+ thd->reset_for_next_command();
+ thd->lex->sql_command= SQLCOM_ROLLBACK;
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+ /* Perform a client rollback, restore globals and signal
+ the victim only when all the resources have been
+ released */
+ thd->wsrep_cs().client_service().bf_rollback();
+ wsrep_reset_threadvars(thd);
+ /* Assign saved event_scheduler.data back before letting
+ client to continue. */
+ thd->event_scheduler.data= saved_esd;
+ thd->wsrep_cs().sync_rollback_complete();
+ WSREP_DEBUG("rollbacker aborted thd: (%llu %llu)",
+ thd->thread_id, (long long)thd->real_id);
+}
+
static void wsrep_rollback_process(THD *rollbacker,
void *arg __attribute__((unused)))
{
@@ -168,119 +287,36 @@ static void wsrep_rollback_process(THD *rollbacker,
WSREP_DEBUG("rollbacker thd already aborted: %llu state: %d",
(long long)thd->real_id,
tx.state());
-
mysql_mutex_unlock(&thd->LOCK_thd_data);
continue;
}
mysql_mutex_unlock(&thd->LOCK_thd_data);
+ wsrep_reset_threadvars(rollbacker);
+ wsrep_store_threadvars(thd);
+ thd->wsrep_cs().acquire_ownership();
+
thd_proc_info(rollbacker, "wsrep aborter active");
- wsrep::transaction_id transaction_id(thd->wsrep_trx().id());
+ /* Rollback methods below may free thd pointer. Do not try
+ to access it after method returns. */
if (thd->wsrep_trx().is_streaming() &&
thd->wsrep_trx().bf_aborted_in_total_order())
{
- thd->store_globals();
- thd->wsrep_cs().store_globals();
- if (thd->wsrep_cs().mode() == wsrep::client_state::m_high_priority)
- {
- DBUG_ASSERT(thd->wsrep_applier_service);
- thd->wsrep_applier_service->rollback(wsrep::ws_handle(),
- wsrep::ws_meta());
- thd->wsrep_applier_service->after_apply();
- /* Will free THD */
- Wsrep_server_state::instance().server_service().
- release_high_priority_service(thd->wsrep_applier_service);
- }
- else
- {
- mysql_mutex_lock(&thd->LOCK_thd_data);
- /* prepare THD for rollback processing */
- thd->reset_for_next_command(true);
- thd->lex->sql_command= SQLCOM_ROLLBACK;
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- /* Perform a client rollback, restore globals and signal
- the victim only when all the resources have been
- released */
- thd->wsrep_cs().client_service().bf_rollback();
- thd->reset_globals();
- thd->wsrep_cs().sync_rollback_complete();
- }
+ wsrep_rollback_streaming_aborted_by_toi(thd);
}
else if (wsrep_thd_is_applying(thd))
{
- WSREP_DEBUG("rollbacker aborting SR thd: (%lld %llu)",
- thd->thread_id, (long long)thd->real_id);
- DBUG_ASSERT(thd->wsrep_cs().mode() == Wsrep_client_state::m_high_priority);
- /* Must be streaming and must have been removed from the
- server state streaming appliers map. */
- DBUG_ASSERT(thd->wsrep_trx().is_streaming());
- DBUG_ASSERT(!Wsrep_server_state::instance().find_streaming_applier(
- thd->wsrep_trx().server_id(),
- thd->wsrep_trx().id()));
- DBUG_ASSERT(thd->wsrep_applier_service);
-
- /* Fragment removal should happen before rollback to make
- the transaction non-observable in SR table after the rollback
- completes. For correctness the order does not matter here,
- but currently it is mandated by checks in some MTR tests. */
- Wsrep_storage_service* storage_service=
- static_cast<Wsrep_storage_service*>(
- Wsrep_server_state::instance().server_service().storage_service(
- *thd->wsrep_applier_service));
- storage_service->store_globals();
- storage_service->adopt_transaction(thd->wsrep_trx());
- storage_service->remove_fragments();
- storage_service->commit(wsrep::ws_handle(transaction_id, 0),
- wsrep::ws_meta());
- Wsrep_server_state::instance().server_service().release_storage_service(storage_service);
- thd->store_globals();
- thd->wsrep_cs().store_globals();
- thd->wsrep_applier_service->rollback(wsrep::ws_handle(),
- wsrep::ws_meta());
- thd->wsrep_applier_service->after_apply();
- /* Will free THD */
- Wsrep_server_state::instance().server_service()
- .release_high_priority_service(thd->wsrep_applier_service);
-
+ wsrep_rollback_high_priority(thd);
}
else
{
- if (thd->wsrep_trx().is_streaming())
- {
- Wsrep_storage_service* storage_service=
- static_cast<Wsrep_storage_service*>(
- Wsrep_server_state::instance().server_service().
- storage_service(thd->wsrep_cs().client_service()));
-
- storage_service->store_globals();
- storage_service->adopt_transaction(thd->wsrep_trx());
- storage_service->remove_fragments();
- storage_service->commit(wsrep::ws_handle(transaction_id, 0),
- wsrep::ws_meta());
- Wsrep_server_state::instance().server_service().
- release_storage_service(storage_service);
- }
- thd->store_globals();
- thd->wsrep_cs().store_globals();
- mysql_mutex_lock(&thd->LOCK_thd_data);
- /* prepare THD for rollback processing */
- thd->reset_for_next_command();
- thd->lex->sql_command= SQLCOM_ROLLBACK;
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- /* Perform a client rollback, restore globals and signal
- the victim only when all the resources have been
- released */
- thd->wsrep_cs().client_service().bf_rollback();
- thd->reset_globals();
- thd->wsrep_cs().sync_rollback_complete();
- WSREP_DEBUG("rollbacker aborted thd: (%llu %llu)",
- thd->thread_id, (long long)thd->real_id);
+ wsrep_rollback_local(thd);
}
-
+ wsrep_store_threadvars(rollbacker);
thd_proc_info(rollbacker, "wsrep aborter idle");
}
-
+
delete wsrep_rollback_queue;
wsrep_rollback_queue= NULL;
@@ -291,55 +327,17 @@ static void wsrep_rollback_process(THD *rollbacker,
DBUG_VOID_RETURN;
}
-static void wsrep_post_rollback_process(THD *post_rollbacker,
- void *arg __attribute__((unused)))
-{
- DBUG_ENTER("wsrep_post_rollback_process");
- THD* thd= NULL;
-
- WSREP_INFO("Starting post rollbacker thread %llu", post_rollbacker->thread_id);
- DBUG_ASSERT(!wsrep_post_rollback_queue);
- wsrep_post_rollback_queue= new Wsrep_thd_queue(post_rollbacker);
-
- while ((thd= wsrep_post_rollback_queue->pop_front()) != NULL)
- {
- thd->store_globals();
- wsrep::client_state& cs(thd->wsrep_cs());
- mysql_mutex_lock(&thd->LOCK_thd_data);
- DBUG_ASSERT(thd->wsrep_trx().state() == wsrep::transaction::s_aborting);
- WSREP_DEBUG("post rollbacker calling post rollback for thd %llu, conf %s",
- thd->thread_id, wsrep_thd_transaction_state_str(thd));
-
- cs.after_rollback();
- DBUG_ASSERT(thd->wsrep_trx().state() == wsrep::transaction::s_aborted);
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- }
-
- delete wsrep_post_rollback_queue;
- wsrep_post_rollback_queue= NULL;
-
- DBUG_ASSERT(post_rollbacker->killed != NOT_KILLED);
- DBUG_PRINT("wsrep",("wsrep post rollbacker thread exiting"));
- WSREP_INFO("post rollbacker thread exiting %llu", post_rollbacker->thread_id);
- DBUG_VOID_RETURN;
-}
-
void wsrep_create_rollbacker()
{
if (wsrep_cluster_address && wsrep_cluster_address[0] != 0)
{
- Wsrep_thd_args* args= new Wsrep_thd_args(wsrep_rollback_process, 0,
- WSREP_ROLLBACKER_THREAD);
+ Wsrep_thd_args* args(new Wsrep_thd_args(wsrep_rollback_process,
+ WSREP_ROLLBACKER_THREAD,
+ pthread_self()));
/* create rollbacker */
if (create_wsrep_THD(args))
WSREP_WARN("Can't create thread to manage wsrep rollback");
-
- /* create post_rollbacker */
- args= new Wsrep_thd_args(wsrep_post_rollback_process, 0,
- WSREP_ROLLBACKER_THREAD);
- if (create_wsrep_THD(args))
- WSREP_WARN("Can't create thread to manage wsrep post rollback");
}
}
@@ -433,3 +431,84 @@ void wsrep_thd_auto_increment_variables(THD* thd,
*offset= thd->variables.auto_increment_offset;
*increment= thd->variables.auto_increment_increment;
}
+
+int wsrep_create_threadvars()
+{
+ int ret= 0;
+ if (thread_handling == SCHEDULER_TYPES_COUNT)
+ {
+ /* Caller should have called wsrep_reset_threadvars() before this
+ method. */
+ DBUG_ASSERT(!pthread_getspecific(THR_KEY_mysys));
+ pthread_setspecific(THR_KEY_mysys, 0);
+ ret= my_thread_init();
+ }
+ return ret;
+}
+
+void wsrep_delete_threadvars()
+{
+ if (thread_handling == SCHEDULER_TYPES_COUNT)
+ {
+ /* The caller should have called wsrep_store_threadvars() before
+ this method. */
+ DBUG_ASSERT(pthread_getspecific(THR_KEY_mysys));
+ /* Reset psi state to avoid deallocating applier thread
+ psi_thread. */
+ PSI_thread *psi_thread= PSI_CALL_get_thread();
+#ifdef HAVE_PSI_INTERFACE
+ if (PSI_server)
+ {
+ PSI_server->set_thread(0);
+ }
+#endif /* HAVE_PSI_INTERFACE */
+ my_thread_end();
+ PSI_CALL_set_thread(psi_thread);
+ pthread_setspecific(THR_KEY_mysys, 0);
+ }
+}
+
+void wsrep_assign_from_threadvars(THD *thd)
+{
+ if (thread_handling == SCHEDULER_TYPES_COUNT)
+ {
+ st_my_thread_var *mysys_var= (st_my_thread_var *)pthread_getspecific(THR_KEY_mysys);
+ DBUG_ASSERT(mysys_var);
+ thd->set_mysys_var(mysys_var);
+ }
+}
+
+Wsrep_threadvars wsrep_save_threadvars()
+{
+ return Wsrep_threadvars{
+ current_thd,
+ (st_my_thread_var*) pthread_getspecific(THR_KEY_mysys)
+ };
+}
+
+void wsrep_restore_threadvars(const Wsrep_threadvars& globals)
+{
+ set_current_thd(globals.cur_thd);
+ pthread_setspecific(THR_KEY_mysys, globals.mysys_var);
+}
+
+int wsrep_store_threadvars(THD *thd)
+{
+ if (thread_handling == SCHEDULER_TYPES_COUNT)
+ {
+ pthread_setspecific(THR_KEY_mysys, thd->mysys_var);
+ }
+ return thd->store_globals();
+}
+
+void wsrep_reset_threadvars(THD *thd)
+{
+ if (thread_handling == SCHEDULER_TYPES_COUNT)
+ {
+ pthread_setspecific(THR_KEY_mysys, 0);
+ }
+ else
+ {
+ thd->reset_globals();
+ }
+}
diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h
index 2eceb3223a8..872570cd028 100644
--- a/sql/wsrep_thd.h
+++ b/sql/wsrep_thd.h
@@ -82,13 +82,8 @@ private:
mysql_cond_t COND_wsrep_thd_queue;
};
-void wsrep_prepare_bf_thd(THD*, struct wsrep_thd_shadow*);
-void wsrep_return_from_bf_mode(THD*, struct wsrep_thd_shadow*);
-
int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff,
enum enum_var_type scope);
-void wsrep_client_rollback(THD *thd, bool rollbacker = false);
-void wsrep_replay_transaction(THD *thd);
void wsrep_create_appliers(long threads);
void wsrep_create_rollbacker();
@@ -96,8 +91,83 @@ bool wsrep_bf_abort(const THD*, THD*);
int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr,
my_bool signal);
extern void wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe);
-THD* wsrep_start_SR_THD(char *thread_stack);
-void wsrep_end_SR_THD(THD* thd);
+
+/*
+ Helper methods to deal with thread local storage.
+ The purpose of these methods is to hide the details of thread
+ local storage handling when operating with wsrep storage access
+ and streaming applier THDs
+
+ With one-thread-per-connection thread handling thread specific
+ variables are allocated when the thread is started and deallocated
+ before thread exits (my_thread_init(), my_thread_end()). However,
+ with pool-of-threads thread handling new thread specific variables
+ are allocated for each THD separately (see threadpool_add_connection()),
+ and the variables in thread local storage are assigned from
+ currently active thread (see thread_attach()). This must be taken into
+ account when storing/resetting thread local storage and when creating
+ streaming applier THDs.
+*/
+
+/**
+ Create new variables for thread local storage. With
+ one-thread-per-connection thread handling this is a no op,
+ with pool-of-threads new variables are created via my_thread_init().
+ It is assumed that the caller has called wsrep_reset_threadvars() to clear
+ the thread local storage before this call.
+
+ @return Zero in case of success, non-zero otherwise.
+*/
+int wsrep_create_threadvars();
+
+/**
+ Delete variables which were created by wsrep_create_threadvars().
+ The caller must store variables into thread local storage before
+ this call via wsrep_store_threadvars().
+*/
+void wsrep_delete_threadvars();
+
+/**
+ Assign variables from current thread local storage into THD.
+ This should be called for THDs whose lifetime is limited to single
+ thread execution or which may share the operation context with some
+ parent THD (e.g. storage access) and thus don't require separately
+ allocated globals.
+
+ With one-thread-per-connection thread handling this is a no-op,
+ with pool-of-threads the variables which are currently stored into
+ thread local storage are assigned to THD.
+*/
+void wsrep_assign_from_threadvars(THD *);
+
+/**
+ Helper struct to save variables from thread local storage.
+ */
+struct Wsrep_threadvars
+{
+ THD* cur_thd;
+ st_my_thread_var* mysys_var;
+};
+
+/**
+ Save variables from thread local storage into Wsrep_threadvars struct.
+ */
+Wsrep_threadvars wsrep_save_threadvars();
+
+/**
+ Restore variables into thread local storage from Wsrep_threadvars struct.
+*/
+void wsrep_restore_threadvars(const Wsrep_threadvars&);
+
+/**
+ Store variables into thread local storage.
+*/
+int wsrep_store_threadvars(THD *);
+
+/**
+ Reset thread local storage.
+*/
+void wsrep_reset_threadvars(THD *);
/**
Helper functions to override error status
diff --git a/sql/wsrep_trans_observer.h b/sql/wsrep_trans_observer.h
index 118525bb908..b8ce7eb42d0 100644
--- a/sql/wsrep_trans_observer.h
+++ b/sql/wsrep_trans_observer.h
@@ -422,6 +422,17 @@ static inline void wsrep_close(THD* thd)
DBUG_VOID_RETURN;
}
+static inline void
+wsrep_wait_rollback_complete_and_acquire_ownership(THD *thd)
+{
+ DBUG_ENTER("wsrep_wait_rollback_complete_and_acquire_ownership");
+ if (thd->wsrep_cs().state() != wsrep::client_state::s_none)
+ {
+ thd->wsrep_cs().wait_rollback_complete_and_acquire_ownership();
+ }
+ DBUG_VOID_RETURN;
+}
+
static inline int wsrep_before_command(THD* thd)
{
return (thd->wsrep_cs().state() != wsrep::client_state::s_none ?
diff --git a/sql/wsrep_utils.cc b/sql/wsrep_utils.cc
index 52949a95e5d..49ea78a3872 100644
--- a/sql/wsrep_utils.cc
+++ b/sql/wsrep_utils.cc
@@ -25,6 +25,7 @@
#include "wsrep_api.h"
#include "wsrep_utils.h"
#include "wsrep_mysqld.h"
+#include "wsrep_thd.h"
#include <sql_class.h>
@@ -421,7 +422,8 @@ thd::thd (my_bool won) : init(), ptr(new THD(0))
if (ptr)
{
ptr->thread_stack= (char*) &ptr;
- ptr->store_globals();
+ wsrep_assign_from_threadvars(ptr);
+ 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;
diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt
index feef8db70ec..100df891621 100644
--- a/storage/connect/CMakeLists.txt
+++ b/storage/connect/CMakeLists.txt
@@ -73,6 +73,10 @@ ELSE(NOT UNIX)
tabwmi.cpp tabwmi.h tabmac.cpp tabmac.h macutil.cpp macutil.h)
# Add exception handling to the CONNECT project)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
+ SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
+ SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd")
+ SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MD")
+ SET(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MD")
SET(IPHLPAPI_LIBRARY iphlpapi.lib)
IF(MSVC AND (CMAKE_CXX_COMPILER_ID MATCHES Clang))
# Connect does not work with clang-cl
@@ -308,6 +312,30 @@ ENDIF(CONNECT_WITH_MONGO)
#
+# REST
+#
+
+OPTION(CONNECT_WITH_REST "Compile CONNECT storage engine with REST support" ON)
+
+IF(CONNECT_WITH_REST)
+ MESSAGE(STATUS "=====> REST support is ON")
+ FIND_PACKAGE(cpprestsdk)
+ IF (cpprestsdk_FOUND)
+ MESSAGE(STATUS "=====> cpprestsdk found")
+ IF(UNIX)
+# INCLUDE_DIRECTORIES(${CPPRESTSDK_INCLUDE_DIR})
+# If needed edit next line to set the path to libcpprest.so
+ SET(REST_LIBRARY -lcpprest)
+ MESSAGE (STATUS ${REST_LIBRARY})
+ ENDIF(UNIX)
+ SET(CONNECT_SOURCES ${CONNECT_SOURCES} tabrest.cpp restget.cpp tabrest.h)
+ add_definitions(-DREST_SUPPORT)
+ ELSE(NOT cpprestsdk_FOUND)
+ MESSAGE(STATUS "=====> cpprestsdk package not found")
+ ENDIF (cpprestsdk_FOUND)
+ENDIF(CONNECT_WITH_REST)
+
+#
# XMAP
#
@@ -326,7 +354,7 @@ MYSQL_ADD_PLUGIN(connect ${CONNECT_SOURCES}
COMPONENT connect-engine
RECOMPILE_FOR_EMBEDDED
LINK_LIBRARIES ${ZLIB_LIBRARY} ${XML_LIBRARY} ${ICONV_LIBRARY}
- ${ODBC_LIBRARY} ${JDBC_LIBRARY} ${MONGOC_LIBRARY} ${IPHLPAPI_LIBRARY})
+ ${ODBC_LIBRARY} ${JDBC_LIBRARY} ${MONGOC_LIBRARY} ${IPHLPAPI_LIBRARY} ${REST_LIBRARY})
IF(NOT TARGET connect)
RETURN()
@@ -334,7 +362,7 @@ ENDIF()
IF(MSVC AND (CMAKE_CXX_FLAGS MATCHES "/MP"))
# domdoc.cpp uses compiler directive #import which is not compatible
- # with the /MP option, resulting in compiler error C2813.´
+ # with the /MP option, resulting in compiler error C2813.
# Remove /MP for this file.
SET(src_list ${CONNECT_SOURCES})
LIST(FIND src_list domdoc.cpp idx)
@@ -347,8 +375,8 @@ ENDIF()
IF(WIN32)
IF (libmongoc-1.0_FOUND)
- SET_TARGET_PROPERTIES(connect PROPERTIES LINK_FLAGS
- "/DELAYLOAD:libbson-1.0.dll /DELAYLOAD:libmongoc-1.0.dll")
+ SET_TARGET_PROPERTIES(connect PROPERTIES LINK_FLAGS
+ "/DELAYLOAD:libbson-1.0.dll /DELAYLOAD:libmongoc-1.0.dll")
ENDIF(libmongoc-1.0_FOUND)
# Install some extra files that belong to connect engine
@@ -377,3 +405,4 @@ IF(CONNECT_WITH_JDBC AND JAVA_FOUND AND JNI_FOUND)
${CMAKE_CURRENT_BINARY_DIR}/JdbcInterface.jar
DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine)
ENDIF()
+
diff --git a/storage/connect/array.cpp b/storage/connect/array.cpp
index 972a1e72403..3c736941b6f 100644
--- a/storage/connect/array.cpp
+++ b/storage/connect/array.cpp
@@ -1,7 +1,7 @@
/************* Array C++ Functions Source Code File (.CPP) *************/
/* Name: ARRAY.CPP Version 2.3 */
/* */
-/* (C) Copyright to the author Olivier BERTRAND 2005-2017 */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2019 */
/* */
/* This file contains the XOBJECT derived class ARRAY functions. */
/* ARRAY is used for elaborate type of processing, such as sorting */
@@ -67,7 +67,7 @@ PARRAY MakeValueArray(PGLOBAL g, PPARM pp); // avoid gcc warning
/* MakeValueArray: Makes a value array from a value list. */
/***********************************************************************/
PARRAY MakeValueArray(PGLOBAL g, PPARM pp)
- {
+{
int n, valtyp = 0;
size_t len = 0;
PARRAY par;
@@ -82,8 +82,7 @@ PARRAY MakeValueArray(PGLOBAL g, PPARM pp)
if ((valtyp = pp->Type) != TYPE_STRING)
len = 1;
- if (trace(1))
- htrc("valtyp=%d len=%d\n", valtyp, len);
+ xtrc(1, "valtyp=%d len=%d\n", valtyp, len);
/*********************************************************************/
/* Firstly check the list and count the number of values in it. */
@@ -127,13 +126,13 @@ PARRAY MakeValueArray(PGLOBAL g, PPARM pp)
// Integer stored inside pp->Value
par->AddValue(g, parmp->Intval);
break;
- } // endswitch valtyp
+ } // endswitch valtyp
/*********************************************************************/
/* Send back resulting array. */
/*********************************************************************/
return par;
- } // end of MakeValueArray
+} // end of MakeValueArray
/* -------------------------- Class ARRAY ---------------------------- */
@@ -151,6 +150,9 @@ ARRAY::ARRAY(PGLOBAL g, int type, int size, int length, int prec)
Type = type;
Xsize = -1;
Len = 1;
+ X = 0;
+ Inf = 0;
+ Sup = 0;
switch (type) {
case TYPE_STRING:
@@ -281,130 +283,109 @@ void ARRAY::Empty(void)
/* Add a string element to an array. */
/***********************************************************************/
bool ARRAY::AddValue(PGLOBAL g, PSZ strp)
- {
+{
if (Type != TYPE_STRING) {
sprintf(g->Message, MSG(ADD_BAD_TYPE), GetTypeName(Type), "CHAR");
return true;
- } // endif Type
-
- if (trace(1))
- htrc(" adding string(%d): '%s'\n", Nval, strp);
+ } // endif Type
-//Value->SetValue_psz(strp);
-//Vblp->SetValue(valp, Nval++);
+ xtrc(1, " adding string(%d): '%s'\n", Nval, strp);
Vblp->SetValue(strp, Nval++);
return false;
- } // end of AddValue
+} // end of AddValue
/***********************************************************************/
/* Add a char pointer element to an array. */
/***********************************************************************/
bool ARRAY::AddValue(PGLOBAL g, void *p)
- {
+{
if (Type != TYPE_PCHAR) {
sprintf(g->Message, MSG(ADD_BAD_TYPE), GetTypeName(Type), "PCHAR");
return true;
- } // endif Type
-
- if (trace(1))
- htrc(" adding pointer(%d): %p\n", Nval, p);
+ } // endif Type
+ xtrc(1, " adding pointer(%d): %p\n", Nval, p);
Vblp->SetValue((PSZ)p, Nval++);
return false;
- } // end of AddValue
+} // end of AddValue
/***********************************************************************/
/* Add a short integer element to an array. */
/***********************************************************************/
bool ARRAY::AddValue(PGLOBAL g, short n)
- {
+{
if (Type != TYPE_SHORT) {
sprintf(g->Message, MSG(ADD_BAD_TYPE), GetTypeName(Type), "SHORT");
return true;
- } // endif Type
-
- if (trace(1))
- htrc(" adding SHORT(%d): %hd\n", Nval, n);
+ } // endif Type
-//Value->SetValue(n);
-//Vblp->SetValue(valp, Nval++);
+ xtrc(1, " adding SHORT(%d): %hd\n", Nval, n);
Vblp->SetValue(n, Nval++);
return false;
- } // end of AddValue
+} // end of AddValue
/***********************************************************************/
/* Add an integer element to an array. */
/***********************************************************************/
bool ARRAY::AddValue(PGLOBAL g, int n)
- {
+{
if (Type != TYPE_INT) {
sprintf(g->Message, MSG(ADD_BAD_TYPE), GetTypeName(Type), "INTEGER");
return true;
- } // endif Type
+ } // endif Type
- if (trace(1))
- htrc(" adding int(%d): %d\n", Nval, n);
-
-//Value->SetValue(n);
-//Vblp->SetValue(valp, Nval++);
+ xtrc(1, " adding int(%d): %d\n", Nval, n);
Vblp->SetValue(n, Nval++);
return false;
- } // end of AddValue
+} // end of AddValue
/***********************************************************************/
/* Add a double float element to an array. */
/***********************************************************************/
bool ARRAY::AddValue(PGLOBAL g, double d)
- {
+{
if (Type != TYPE_DOUBLE) {
sprintf(g->Message, MSG(ADD_BAD_TYPE), GetTypeName(Type), "DOUBLE");
return true;
- } // endif Type
-
- if (trace(1))
- htrc(" adding float(%d): %lf\n", Nval, d);
+ } // endif Type
+ xtrc(1, " adding float(%d): %lf\n", Nval, d);
Value->SetValue(d);
Vblp->SetValue(Value, Nval++);
return false;
- } // end of AddValue
+} // end of AddValue
/***********************************************************************/
/* Add the value of a XOBJECT block to an array. */
/***********************************************************************/
bool ARRAY::AddValue(PGLOBAL g, PXOB xp)
- {
- if (Type != xp->GetResultType()) {
- sprintf(g->Message, MSG(ADD_BAD_TYPE),
- GetTypeName(xp->GetResultType()), GetTypeName(Type));
- return true;
- } // endif Type
-
- if (trace(1))
- htrc(" adding (%d) from xp=%p\n", Nval, xp);
+{
+ if (Type != xp->GetResultType()) {
+ sprintf(g->Message, MSG(ADD_BAD_TYPE),
+ GetTypeName(xp->GetResultType()), GetTypeName(Type));
+ return true;
+ } // endif Type
-//AddValue(xp->GetValue());
- Vblp->SetValue(xp->GetValue(), Nval++);
- return false;
- } // end of AddValue
+ xtrc(1, " adding (%d) from xp=%p\n", Nval, xp);
+ Vblp->SetValue(xp->GetValue(), Nval++);
+ return false;
+} // end of AddValue
/***********************************************************************/
/* Add a value to an array. */
/***********************************************************************/
bool ARRAY::AddValue(PGLOBAL g, PVAL vp)
- {
+{
if (Type != vp->GetType()) {
sprintf(g->Message, MSG(ADD_BAD_TYPE),
GetTypeName(vp->GetType()), GetTypeName(Type));
return true;
- } // endif Type
-
- if (trace(1))
- htrc(" adding (%d) from vp=%p\n", Nval, vp);
+ } // endif Type
+ xtrc(1, " adding (%d) from vp=%p\n", Nval, vp);
Vblp->SetValue(vp, Nval++);
return false;
- } // end of AddValue
+} // end of AddValue
/***********************************************************************/
/* Retrieve the nth value of the array. */
@@ -975,7 +956,7 @@ int ARRAY::BlockTest(PGLOBAL, int opc, int opm,
/* MakeArrayList: Makes a value list from an SQL IN array (in work). */
/***********************************************************************/
PSZ ARRAY::MakeArrayList(PGLOBAL g)
- {
+{
char *p, *tp;
int i;
size_t z, len = 2;
@@ -990,11 +971,9 @@ PSZ ARRAY::MakeArrayList(PGLOBAL g)
Value->SetValue_pvblk(Vblp, i);
Value->Prints(g, tp, z);
len += strlen(tp);
- } // enfor i
-
- if (trace(1))
- htrc("Arraylist: len=%d\n", len);
+ } // enfor i
+ xtrc(1, "Arraylist: len=%d\n", len);
p = (char *)PlugSubAlloc(g, NULL, len);
strcpy(p, "(");
@@ -1003,19 +982,17 @@ PSZ ARRAY::MakeArrayList(PGLOBAL g)
Value->Prints(g, tp, z);
strcat(p, tp);
strcat(p, (++i == Nval) ? ")" : ",");
- } // enfor i
-
- if (trace(1))
- htrc("Arraylist: newlen=%d\n", strlen(p));
+ } // enfor i
+ xtrc(1, "Arraylist: newlen=%d\n", strlen(p));
return p;
- } // end of MakeArrayList
+} // end of MakeArrayList
/***********************************************************************/
/* Make file output of ARRAY contents. */
/***********************************************************************/
void ARRAY::Printf(PGLOBAL g, FILE *f, uint n)
- {
+{
char m[64];
int lim = MY_MIN(Nval,10);
@@ -1037,19 +1014,19 @@ void ARRAY::Printf(PGLOBAL g, FILE *f, uint n)
} else
fprintf(f, "%sVALLST: numval=%d\n", m, Nval);
- } // end of Printf
+} // end of Printf
/***********************************************************************/
/* Make string output of ARRAY contents. */
/***********************************************************************/
void ARRAY::Prints(PGLOBAL, char *ps, uint z)
- {
+{
if (z < 16)
return;
sprintf(ps, "ARRAY: type=%d\n", Type);
// More to be implemented later
- } // end of Prints
+} // end of Prints
/* -------------------------- Class MULAR ---------------------------- */
diff --git a/storage/connect/block.h b/storage/connect/block.h
index 737c74c1293..2ca9586ee3f 100644
--- a/storage/connect/block.h
+++ b/storage/connect/block.h
@@ -38,9 +38,7 @@ typedef class BLOCK *PBLOCK;
class DllExport BLOCK {
public:
void * operator new(size_t size, PGLOBAL g, void *p = NULL) {
- if (trace(256))
- htrc("New BLOCK: size=%d g=%p p=%p\n", size, g, p);
-
+ xtrc(256, "New BLOCK: size=%d g=%p p=%p\n", size, g, p);
return (PlugSubAlloc(g, p, size));
} // end of new
diff --git a/storage/connect/connect.h b/storage/connect/connect.h
index cf0373ba635..3a60cd40160 100644
--- a/storage/connect/connect.h
+++ b/storage/connect/connect.h
@@ -11,7 +11,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
/**************** Cnt H Declares Source Code File (.H) *****************/
/* Name: CONNECT.H Version 2.4 */
diff --git a/storage/connect/global.h b/storage/connect/global.h
index dc1e149745f..fd26c87b800 100644
--- a/storage/connect/global.h
+++ b/storage/connect/global.h
@@ -224,6 +224,7 @@ DllExport void *PlugSubAlloc(PGLOBAL, void *, size_t);
DllExport char *PlugDup(PGLOBAL g, const char *str);
DllExport void *MakePtr(void *, OFFSET);
DllExport void htrc(char const *fmt, ...);
+DllExport void xtrc(uint, char const* fmt, ...);
DllExport uint GetTraceValue(void);
#if defined(__cplusplus)
diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc
index 2b47162bb34..6939e6948f9 100644
--- a/storage/connect/ha_connect.cc
+++ b/storage/connect/ha_connect.cc
@@ -11,7 +11,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
/**
@file ha_connect.cc
@@ -164,15 +164,15 @@
/***********************************************************************/
/* Initialize the ha_connect static members. */
/***********************************************************************/
-#define SZCONV 8192
+#define SZCONV 1024 // Default converted text size
#define SZWORK 67108864 // Default work area size 64M
#define SZWMIN 4194304 // Minimum work area size 4M
#define JSONMAX 10 // JSON Default max grp size
extern "C" {
- char version[]= "Version 1.06.0009 January 27, 2019";
+ char version[]= "Version 1.06.0010 June 01, 2019";
#if defined(__WIN__)
- char compver[]= "Version 1.06.0009 " __DATE__ " " __TIME__;
+ char compver[]= "Version 1.06.0010 " __DATE__ " " __TIME__;
char slash= '\\';
#else // !__WIN__
char slash= '/';
@@ -211,14 +211,14 @@ char *GetUserVariable(PGLOBAL g, const uchar *varname)
{
char buf[1024];
bool b;
- THD *thd = current_thd;
- CHARSET_INFO *cs = system_charset_info;
- String *str = NULL, tmp(buf, sizeof(buf), cs);
- HASH uvars = thd->user_vars;
- user_var_entry *uvar = (user_var_entry*)my_hash_search(&uvars, varname, 0);
+ THD *thd= current_thd;
+ CHARSET_INFO *cs= system_charset_info;
+ String *str= NULL, tmp(buf, sizeof(buf), cs);
+ HASH uvars= thd->user_vars;
+ user_var_entry *uvar= (user_var_entry*)my_hash_search(&uvars, varname, 0);
if (uvar)
- str = uvar->val_str(&b, &tmp, NOT_FIXED_DEC);
+ str= uvar->val_str(&b, &tmp, NOT_FIXED_DEC);
return str ? PlugDup(g, str->ptr()) : NULL;
}; // end of GetUserVariable
@@ -231,6 +231,9 @@ PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info);
PQRYRES VirColumns(PGLOBAL g, bool info);
PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info);
PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info);
+#if defined(REST_SUPPORT)
+PQRYRES RESTColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info);
+#endif // REST_SUPPORT
#if defined(JAVA_SUPPORT)
PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ url, PTOS topt, bool info);
#endif // JAVA_SUPPORT
@@ -238,7 +241,9 @@ int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v);
void PushWarning(PGLOBAL g, THD *thd, int level);
bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, PCSZ host, PCSZ db,
PCSZ tab, PCSZ src, int port);
+#if defined(ZIP_SUPPORT)
bool ZipLoadFile(PGLOBAL, PCSZ, PCSZ, PCSZ, bool, bool);
+#endif // ZIP_SUPPORT
bool ExactInfo(void);
#if defined(CMGO_SUPPORT)
//void mongo_init(bool);
@@ -350,7 +355,7 @@ static MYSQL_THDVAR_UINT(work_size,
static MYSQL_THDVAR_INT(conv_size,
PLUGIN_VAR_RQCMDARG, // opt
"Size used when converting TEXT columns.",
- NULL, NULL, SZCONV, 0, 65500, 8192);
+ NULL, NULL, SZCONV, 0, 65500, 1);
/**
Type conversion:
@@ -581,7 +586,9 @@ ha_create_table_option connect_table_option_list[]=
HA_TOPTION_STRING("FILTER", filter),
HA_TOPTION_STRING("OPTION_LIST", oplist),
HA_TOPTION_STRING("DATA_CHARSET", data_charset),
- HA_TOPTION_NUMBER("LRECL", lrecl, 0, 0, INT_MAX32, 1),
+ HA_TOPTION_STRING("HTTP", http),
+ HA_TOPTION_STRING("URI", uri),
+ HA_TOPTION_NUMBER("LRECL", lrecl, 0, 0, INT_MAX32, 1),
HA_TOPTION_NUMBER("BLOCK_SIZE", elements, 0, 0, INT_MAX32, 1),
//HA_TOPTION_NUMBER("ESTIMATE", estimate, 0, 0, INT_MAX32, 1),
HA_TOPTION_NUMBER("MULTIPLE", multiple, 0, 0, 3, 1),
@@ -988,11 +995,11 @@ static PCONNECT GetUser(THD *thd, PCONNECT xp)
pthread_mutex_unlock(&usrmut);
if (!xp) {
- xp = new user_connect(thd);
+ xp= new user_connect(thd);
if (xp->user_init()) {
delete xp;
- xp = NULL;
+ xp= NULL;
} // endif user_init
} // endif xp
@@ -1024,6 +1031,19 @@ TABTYPE ha_connect::GetRealType(PTOS pos)
if (type == TAB_UNDEF)
type= pos->srcdef ? TAB_MYSQL : pos->tabname ? TAB_PRX : TAB_DOS;
+#if defined(REST_SUPPORT)
+ else if (pos->http)
+ switch (type) {
+ case TAB_JSON:
+ case TAB_XML:
+ case TAB_CSV:
+ type = TAB_REST;
+ break;
+ case TAB_REST:
+ type = TAB_NIY;
+ break;
+ } // endswitch type
+#endif // REST_SUPPORT
} else
type= TAB_UNDEF;
@@ -1127,48 +1147,48 @@ PCSZ GetListOption(PGLOBAL g, PCSZ opname, PCSZ oplist, PCSZ def)
return (char*)def;
char key[16], val[256];
- char *pv, *pn, *pk = (char*)oplist;
- PCSZ opval = def;
+ char *pv, *pn, *pk= (char*)oplist;
+ PCSZ opval= def;
int n;
while (*pk == ' ')
pk++;
- for (; pk; pk = pn) {
- pn = strchr(pk, ',');
- pv = strchr(pk, '=');
+ for (; pk; pk= pn) {
+ pn= strchr(pk, ',');
+ pv= strchr(pk, '=');
if (pv && (!pn || pv < pn)) {
- n = MY_MIN(static_cast<size_t>(pv - pk), sizeof(key) - 1);
+ n= MY_MIN(static_cast<size_t>(pv - pk), sizeof(key) - 1);
memcpy(key, pk, n);
while (n && key[n - 1] == ' ')
n--;
- key[n] = 0;
+ key[n]= 0;
while (*(++pv) == ' ');
- n = MY_MIN((pn ? pn - pv : strlen(pv)), sizeof(val) - 1);
+ n= MY_MIN((pn ? pn - pv : strlen(pv)), sizeof(val) - 1);
memcpy(val, pv, n);
while (n && val[n - 1] == ' ')
n--;
- val[n] = 0;
+ val[n]= 0;
} else {
- n = MY_MIN((pn ? pn - pk : strlen(pk)), sizeof(key) - 1);
+ n= MY_MIN((pn ? pn - pk : strlen(pk)), sizeof(key) - 1);
memcpy(key, pk, n);
while (n && key[n - 1] == ' ')
n--;
- key[n] = 0;
- val[0] = 0;
+ key[n]= 0;
+ val[0]= 0;
} // endif pv
if (!stricmp(opname, key)) {
- opval = PlugDup(g, val);
+ opval= PlugDup(g, val);
break;
} else if (!pn)
break;
@@ -1216,9 +1236,13 @@ PCSZ GetStringTableOption(PGLOBAL g, PTOS options, PCSZ opname, PCSZ sdef)
else if (!stricmp(opname, "Colist"))
opval= options->colist;
else if (!stricmp(opname, "Filter"))
- opval = options->filter;
+ opval= options->filter;
else if (!stricmp(opname, "Data_charset"))
opval= options->data_charset;
+ else if (!stricmp(opname, "Http") || !stricmp(opname, "URL"))
+ opval = options->http;
+ else if (!stricmp(opname, "Uri"))
+ opval = options->uri;
if (!opval && options->oplist)
opval= GetListOption(g, opname, options->oplist);
@@ -1249,7 +1273,7 @@ bool GetBooleanTableOption(PGLOBAL g, PTOS options, PCSZ opname, bool bdef)
else if (!stricmp(opname, "Header"))
opval= (options->header != 0); // Is Boolean for some table types
else if (!stricmp(opname, "Zipped"))
- opval = options->zipped;
+ opval= options->zipped;
else if (options->oplist)
if ((pv= GetListOption(g, opname, options->oplist)))
opval= (!*pv || *pv == 'y' || *pv == 'Y' || atoi(pv) != 0);
@@ -1314,7 +1338,7 @@ char *ha_connect::GetRealString(PCSZ s)
{
char *sv;
- if (IsPartitioned() && s && partname && *partname) {
+ if (IsPartitioned() && s && *partname) {
sv= (char*)PlugSubAlloc(xp->g, NULL, 0);
sprintf(sv, s, partname);
PlugSubAlloc(xp->g, NULL, strlen(sv) + 1);
@@ -1343,8 +1367,8 @@ PCSZ ha_connect::GetStringOption(PCSZ opname, PCSZ sdef)
} else if (!stricmp(opname, "Query_String")) {
// This escapes everything and returns a wrong query
-// opval = thd_query_string(table->in_use)->str;
- opval = (PCSZ)PlugSubAlloc(xp->g, NULL,
+// opval= thd_query_string(table->in_use)->str;
+ opval= (PCSZ)PlugSubAlloc(xp->g, NULL,
thd_query_string(table->in_use)->length + 1);
strcpy((char*)opval, thd_query_string(table->in_use)->str);
// sprintf((char*)opval, "%s", thd_query_string(table->in_use)->str);
@@ -1365,7 +1389,7 @@ PCSZ ha_connect::GetStringOption(PCSZ opname, PCSZ sdef)
|| !stricmp(opname, "filename")
|| !stricmp(opname, "optname")
|| !stricmp(opname, "entry")))
- opval = GetRealString(opval);
+ opval= GetRealString(opval);
if (!opval) {
if (sdef && !strcmp(sdef, "*")) {
@@ -1494,7 +1518,7 @@ PFOS ha_connect::GetFieldOptionStruct(Field *fdp)
void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf)
{
const char *cp;
- char *chset, v = 0;
+ char *chset, v= 0;
ha_field_option_struct *fop;
Field* fp;
Field* *fldp;
@@ -1546,7 +1570,7 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf)
pcf->Fieldfmt= NULL;
} // endif fop
- chset = (char *)fp->charset()->name;
+ chset= (char *)fp->charset()->name;
switch (fp->type()) {
case MYSQL_TYPE_BLOB:
@@ -1811,7 +1835,7 @@ const char *ha_connect::GetTableName(void)
{
const char *path= tshp ? tshp->path.str : table_share->path.str;
const char *name= strrchr(path, slash);
- return name ? name+1 : path;
+ return name ? name + 1 : path;
} // end of GetTableName
char *ha_connect::GetPartName(void)
@@ -2051,10 +2075,10 @@ bool ha_connect::CheckColumnList(PGLOBAL g)
} catch (int n) {
if (trace(1))
htrc("Exception %d: %s\n", n, g->Message);
- brc = true;
+ brc= true;
} catch (const char *msg) {
strcpy(g->Message, msg);
- brc = true;
+ brc= true;
} // end catch
return brc;
@@ -2180,9 +2204,9 @@ int ha_connect::MakeRecord(char *buf)
rc= fp->store(p, strlen(p), charset, CHECK_FIELD_WARN);
break;
case TYPE_BIN:
- p = value->GetCharValue();
- charset = &my_charset_bin;
- rc = fp->store(p, strlen(p), charset, CHECK_FIELD_WARN);
+ p= value->GetCharValue();
+ charset= &my_charset_bin;
+ rc= fp->store(p, strlen(p), charset, CHECK_FIELD_WARN);
break;
case TYPE_DOUBLE:
rc= fp->store(value->GetFloatValue());
@@ -2431,7 +2455,7 @@ bool ha_connect::MakeKeyWhere(PGLOBAL g, PSTRG qry, OPVAL vop, char q,
kfp= &table->key_info[active_index];
old_map= dbug_tmp_use_all_columns(table, table->write_set);
- for (i = 0; i <= 1; i++) {
+ for (i= 0; i <= 1; i++) {
if (ranges[i] == NULL)
continue;
@@ -2542,7 +2566,7 @@ const char *ha_connect::GetValStr(OPVAL vop, bool neg)
switch (vop) {
case OP_EQ:
- val= " = ";
+ val= "= ";
break;
case OP_NE:
val= " <> ";
@@ -2815,7 +2839,7 @@ PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond)
/***********************************************************************/
PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond)
{
- AMT tty = filp->Type;
+ AMT tty= filp->Type;
char *body= filp->Body;
char *havg= filp->Having;
unsigned int i;
@@ -2832,7 +2856,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond)
if (cond->type() == COND::COND_ITEM) {
char *pb0, *pb1, *pb2, *ph0= 0, *ph1= 0, *ph2= 0;
- bool bb = false, bh = false;
+ bool bb= false, bh= false;
Item_cond *cond_item= (Item_cond *)cond;
if (x)
@@ -2891,13 +2915,13 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond)
bb |= filp->Bd;
bh |= filp->Hv;
- filp->Bd = filp->Hv = false;
+ filp->Bd= filp->Hv= false;
} else
return NULL;
if (bb) {
strcpy(pb1, ")");
- filp->Bd = bb;
+ filp->Bd= bb;
} else
*pb0= 0;
@@ -2905,13 +2929,13 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond)
if (bb && bh && vop == OP_OR) {
// Cannot or'ed a where clause with a having clause
bb= bh= 0;
- *pb0 = 0;
- *ph0 = 0;
+ *pb0= 0;
+ *ph0= 0;
} else if (bh) {
strcpy(ph1, ")");
filp->Hv= bh;
} else
- *ph0 = 0;
+ *ph0= 0;
} // endif havg
@@ -2924,7 +2948,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond)
Item_func *condf= (Item_func *)cond;
Item* *args= condf->arguments();
- filp->Bd = filp->Hv = false;
+ filp->Bd= filp->Hv= false;
if (trace(1))
htrc("Func type=%d argnum=%d\n", condf->functype(),
@@ -2940,10 +2964,10 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond)
case Item_func::GT_FUNC: vop= OP_GT; break;
case Item_func::LIKE_FUNC:
vop= OP_LIKE;
- neg = ((Item_func_opt_neg *)condf)->negated;
+ neg= ((Item_func_opt_neg *)condf)->negated;
break;
case Item_func::ISNOTNULL_FUNC:
- neg = true;
+ neg= true;
// fall through
case Item_func::ISNULL_FUNC: vop= OP_NULL; break;
case Item_func::IN_FUNC: vop= OP_IN; /* fall through */
@@ -3001,12 +3025,12 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond)
} else {
bool h;
- fnm = filp->Chk(pField->field->field_name.str, &h);
+ fnm= filp->Chk(pField->field->field_name.str, &h);
if (h && i && !ishav)
return NULL; // Having should be col VOP arg
else
- ishav = h;
+ ishav= h;
} // endif's
@@ -3053,7 +3077,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond)
if (!x) {
const char *p;
- char *s = (ishav) ? havg : body;
+ char *s= (ishav) ? havg : body;
uint j, k, n;
// Append the value to the filter
@@ -3111,37 +3135,37 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond)
strcat(s, "'}");
break;
default:
- j = strlen(s);
- s[j++] = '\'';
- p = res->ptr();
- n = res->length();
+ j= strlen(s);
+ s[j++]= '\'';
+ p= res->ptr();
+ n= res->length();
- for (k = 0; k < n; k++) {
+ for (k= 0; k < n; k++) {
if (p[k] == '\'')
- s[j++] = '\'';
+ s[j++]= '\'';
- s[j++] = p[k];
+ s[j++]= p[k];
} // endfor k
- s[j++] = '\'';
- s[j] = 0;
+ s[j++]= '\'';
+ s[j]= 0;
} // endswitch field type
} else {
- j = strlen(s);
- s[j++] = '\'';
- p = res->ptr();
- n = res->length();
+ j= strlen(s);
+ s[j++]= '\'';
+ p= res->ptr();
+ n= res->length();
- for (k = 0; k < n; k++) {
+ for (k= 0; k < n; k++) {
if (p[k] == '\'')
- s[j++] = '\'';
+ s[j++]= '\'';
- s[j++] = p[k];
+ s[j++]= p[k];
} // endfor k
- s[j++] = '\'';
- s[j] = 0;
+ s[j++]= '\'';
+ s[j]= 0;
} // endif tty
break;
@@ -3165,7 +3189,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond)
} // endif's Type
if (!x) {
- char *s = (ishav) ? havg : body;
+ char *s= (ishav) ? havg : body;
if (!i)
strcat(s, GetValStr(vop, neg));
@@ -3179,11 +3203,11 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond)
} // endfor i
if (x)
- filp->Op = vop;
+ filp->Op= vop;
else if (ishav)
- filp->Hv = true;
+ filp->Hv= true;
else
- filp->Bd = true;
+ filp->Bd= true;
} else {
if (trace(1))
@@ -3233,21 +3257,21 @@ const COND *ha_connect::cond_push(const COND *cond)
PCFIL filp;
int rc;
- if ((filp = tdbp->GetCondFil()) && tdbp->GetCond() == cond &&
+ if ((filp= tdbp->GetCondFil()) && tdbp->GetCond() == cond &&
filp->Idx == active_index && filp->Type == tty)
goto fin;
- filp = new(g) CONDFIL(active_index, tty);
- rc = filp->Init(g, this);
+ filp= new(g) CONDFIL(active_index, tty);
+ rc= filp->Init(g, this);
if (rc == RC_INFO) {
- filp->Having = (char*)PlugSubAlloc(g, NULL, 256);
- *filp->Having = 0;
+ filp->Having= (char*)PlugSubAlloc(g, NULL, 256);
+ *filp->Having= 0;
} else if (rc == RC_FX)
goto fin;
- filp->Body = (char*)PlugSubAlloc(g, NULL, (x) ? 128 : 0);
- *filp->Body = 0;
+ filp->Body= (char*)PlugSubAlloc(g, NULL, (x) ? 128 : 0);
+ *filp->Body= 0;
if (CheckCond(g, filp, cond)) {
if (filp->Having && strlen(filp->Having) > 255)
@@ -3261,7 +3285,7 @@ const COND *ha_connect::cond_push(const COND *cond)
if (!x)
PlugSubAlloc(g, NULL, strlen(filp->Body) + 1);
else
- cond = NULL; // Does this work?
+ cond= NULL; // Does this work?
tdbp->SetCondFil(filp);
} else if (x && cond)
@@ -3311,8 +3335,8 @@ ha_rows ha_connect::records()
int ha_connect::check(THD* thd, HA_CHECK_OPT* check_opt)
{
- int rc = HA_ADMIN_OK;
- PGLOBAL g = ((table && table->in_use) ? GetPlug(table->in_use, xp) :
+ int rc= HA_ADMIN_OK;
+ PGLOBAL g= ((table && table->in_use) ? GetPlug(table->in_use, xp) :
(xp) ? xp->g : NULL);
DBUG_ENTER("ha_connect::check");
@@ -3322,32 +3346,32 @@ int ha_connect::check(THD* thd, HA_CHECK_OPT* check_opt)
// Do not close the table if it was opened yet (possible?)
if (IsOpened()) {
if (IsPartitioned() && CheckColumnList(g)) // map can have been changed
- rc = HA_ADMIN_CORRUPT;
+ rc= HA_ADMIN_CORRUPT;
else if (tdbp->OpenDB(g)) // Rewind table
- rc = HA_ADMIN_CORRUPT;
+ rc= HA_ADMIN_CORRUPT;
} else if (xp->CheckQuery(valid_query_id)) {
- tdbp = NULL; // Not valid anymore
+ tdbp= NULL; // Not valid anymore
if (OpenTable(g, false))
- rc = HA_ADMIN_CORRUPT;
+ rc= HA_ADMIN_CORRUPT;
} else // possible?
DBUG_RETURN(HA_ADMIN_INTERNAL_ERROR);
if (rc == HA_ADMIN_OK) {
- TABTYPE type = GetTypeID(GetStringOption("Type", "*"));
+ TABTYPE type= GetTypeID(GetStringOption("Type", "*"));
if (IsFileType(type)) {
if (check_opt->flags & T_MEDIUM) {
// TO DO
do {
- if ((rc = CntReadNext(g, tdbp)) == RC_FX)
+ if ((rc= CntReadNext(g, tdbp)) == RC_FX)
break;
} while (rc != RC_EF);
- rc = (rc == RC_EF) ? HA_ADMIN_OK : HA_ADMIN_CORRUPT;
+ rc= (rc == RC_EF) ? HA_ADMIN_OK : HA_ADMIN_CORRUPT;
} else if (check_opt->flags & T_EXTEND) {
// TO DO
} // endif's flags
@@ -3375,7 +3399,7 @@ bool ha_connect::get_error_message(int error, String* buf)
DBUG_ENTER("ha_connect::get_error_message");
if (xp && xp->g) {
- PGLOBAL g = xp->g;
+ PGLOBAL g= xp->g;
if (trace(1))
htrc("GEM(%d): %s\n", error, g->Message);
@@ -3484,32 +3508,32 @@ int ha_connect::optimize(THD* thd, HA_CHECK_OPT*)
try {
// Ignore error on the opt file
dup->Check &= ~CHK_OPT;
- tdbp = GetTDB(g);
+ tdbp= GetTDB(g);
dup->Check |= CHK_OPT;
if (tdbp && !tdbp->IsRemote()) {
- bool dop = IsTypeIndexable(GetRealType(NULL));
- bool dox = (tdbp->GetDef()->Indexable() == 1);
+ bool dop= IsTypeIndexable(GetRealType(NULL));
+ bool dox= (tdbp->GetDef()->Indexable() == 1);
- if ((rc = ((PTDBASE)tdbp)->ResetTableOpt(g, dop, dox))) {
+ if ((rc= ((PTDBASE)tdbp)->ResetTableOpt(g, dop, dox))) {
if (rc == RC_INFO) {
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
- rc = 0;
+ rc= 0;
} else
- rc = HA_ERR_CRASHED_ON_USAGE; // Table must be repaired
+ rc= HA_ERR_CRASHED_ON_USAGE; // Table must be repaired
} // endif rc
} else if (!tdbp)
- rc = HA_ERR_INTERNAL_ERROR;
+ rc= HA_ERR_INTERNAL_ERROR;
} catch (int n) {
if (trace(1))
htrc("Exception %d: %s\n", n, g->Message);
- rc = HA_ERR_INTERNAL_ERROR;
+ rc= HA_ERR_INTERNAL_ERROR;
} catch (const char *msg) {
strcpy(g->Message, msg);
- rc = HA_ERR_INTERNAL_ERROR;
+ rc= HA_ERR_INTERNAL_ERROR;
} // end catch
if (rc)
@@ -4209,7 +4233,7 @@ int ha_connect::rnd_pos(uchar *buf, uchar *pos)
tdbp->SetFilter(NULL);
rc= rnd_next(buf);
} else {
- PGLOBAL g = GetPlug((table) ? table->in_use : NULL, xp);
+ PGLOBAL g= GetPlug((table) ? table->in_use : NULL, xp);
// strcpy(g->Message, "Not supported by this table type");
my_message(ER_ILLEGAL_HA, g->Message, MYF(0));
rc= HA_ERR_INTERNAL_ERROR;
@@ -4291,12 +4315,12 @@ int ha_connect::info(uint flag)
} else
DBUG_RETURN(HA_ERR_INTERNAL_ERROR); // Should never happen
- if (!(tdbp = GetTDB(g))) {
+ if (!(tdbp= GetTDB(g))) {
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
} // endif tdbp
- valid_info = false;
+ valid_info= false;
} // endif tdbp
if (!valid_info) {
@@ -4439,6 +4463,7 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, const char *dbn, bool
case TAB_XML:
case TAB_INI:
case TAB_VEC:
+ case TAB_REST:
case TAB_JSON:
if (options->filename && *options->filename) {
if (!quick) {
@@ -4575,14 +4600,14 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd,
// newmode= MODE_UPDATE; // To be checked
// break;
case SQLCOM_DELETE_MULTI:
- *cras = true;
+ *cras= true;
// fall through
case SQLCOM_DELETE:
case SQLCOM_TRUNCATE:
newmode= MODE_DELETE;
break;
case SQLCOM_UPDATE_MULTI:
- *cras = true;
+ *cras= true;
// fall through
case SQLCOM_UPDATE:
newmode= MODE_UPDATE;
@@ -4612,7 +4637,7 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd,
break;
// } // endif partitioned
case SQLCOM_REPAIR: // TODO implement it
- newmode = MODE_UPDATE;
+ newmode= MODE_UPDATE;
break;
default:
htrc("Unsupported sql_command=%d\n", thd_sql_command(thd));
@@ -4727,15 +4752,15 @@ int ha_connect::start_stmt(THD *thd, thr_lock_type lock_type)
if (CloseTable(g)) {
// Make error a warning to avoid crash
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
- rc = 0;
+ rc= 0;
} // endif Close
- locked = 0;
- xmod = MODE_ANY; // For info commands
+ locked= 0;
+ xmod= MODE_ANY; // For info commands
DBUG_RETURN(rc);
} // endif MODE_ANY
- newmode = CheckMode(g, thd, newmode, &chk, &cras);
+ newmode= CheckMode(g, thd, newmode, &chk, &cras);
if (newmode == MODE_ERROR)
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
@@ -4811,7 +4836,7 @@ int ha_connect::external_lock(THD *thd, int lock_type)
DBUG_RETURN(0);
} else if (g->Xchk) {
if (!tdbp) {
- if (!(tdbp = GetTDB(g))) {
+ if (!(tdbp= GetTDB(g))) {
// DBUG_RETURN(HA_ERR_INTERNAL_ERROR); causes assert error
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
DBUG_RETURN(0);
@@ -4948,7 +4973,7 @@ int ha_connect::external_lock(THD *thd, int lock_type)
int ha_connect::check_stmt(PGLOBAL g, MODE newmode, bool cras)
{
- int rc = 0;
+ int rc= 0;
DBUG_ENTER("ha_connect::check_stmt");
// If this is the start of a new query, cleanup the previous one
@@ -5035,7 +5060,7 @@ THR_LOCK_DATA **ha_connect::store_lock(THD *,
{
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
lock.type=lock_type;
- *to++ = &lock;
+ *to++= &lock;
return to;
}
@@ -5312,7 +5337,7 @@ static bool add_field(String *sql, const char *field_name, int typ, int len,
int dec, char *key, uint tm, const char *rem, char *dft,
char *xtra, char *fmt, int flag, bool dbf, char v)
{
- char var = (len > 255) ? 'V' : v;
+ char var= (len > 255) ? 'V' : v;
bool q, error= false;
const char *type= PLGtoMYSQLtype(typ, dbf, var);
@@ -5356,9 +5381,9 @@ static bool add_field(String *sql, const char *field_name, int typ, int len,
error|= sql->append(" DEFAULT ");
if (typ == TYPE_DATE)
- q = (strspn(dft, "0123456789 -:/") == strlen(dft));
+ q= (strspn(dft, "0123456789 -:/") == strlen(dft));
else
- q = !IsTypeNum(typ);
+ q= !IsTypeNum(typ);
if (q) {
error|= sql->append("'");
@@ -5510,13 +5535,13 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
PCSZ fncn= "?";
PCSZ user, fn, db, host, pwd, sep, tbl, src;
PCSZ col, ocl, rnk, pic, fcl, skc, zfn;
- char *tab, *dsn, *shm, *dpath;
+ char *tab, *dsn, *shm, *dpath, *url;
#if defined(__WIN__)
PCSZ nsp= NULL, cls= NULL;
#endif // __WIN__
//int hdr, mxe;
- int port = 0, mxr __attribute__((unused)) = 0, rc = 0, mul = 0;
-//PCSZ tabtyp = NULL;
+ int port= 0, mxr __attribute__((unused)) = 0, rc= 0, mul= 0;
+//PCSZ tabtyp= NULL;
#if defined(ODBC_SUPPORT)
POPARM sop= NULL;
PCSZ ucnc= NULL;
@@ -5526,7 +5551,6 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
#if defined(JAVA_SUPPORT)
PJPARM sjp= NULL;
PCSZ driver= NULL;
- char *url= NULL;
#endif // JAVA_SUPPORT
uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL);
bool bif, ok= false, dbf= false;
@@ -5544,7 +5568,8 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
String sql(buf, sizeof(buf), system_charset_info);
sql.copy(STRING_WITH_LEN("CREATE TABLE whatever ("), system_charset_info);
- user= host= pwd= tbl= src= col= ocl= pic= fcl= skc= rnk= zfn= dsn= NULL;
+ user = host = pwd = tbl = src = col = ocl = pic = fcl = skc = rnk = zfn = NULL;
+ dsn = url = NULL;
// Get the useful create options
ttp= GetTypeID(topt->type);
@@ -5555,7 +5580,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
fncn= topt->catfunc;
fnc= GetFuncID(fncn);
sep= topt->separator;
- mul = (int)topt->multiple;
+ mul= (int)topt->multiple;
tbl= topt->tablist;
col= topt->colist;
@@ -5578,7 +5603,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
#endif // __WIN__
port= atoi(GetListOption(g, "port", topt->oplist, "0"));
#if defined(ODBC_SUPPORT)
-// tabtyp = GetListOption(g, "Tabtype", topt->oplist, NULL);
+// tabtyp= GetListOption(g, "Tabtype", topt->oplist, NULL);
mxr= atoi(GetListOption(g,"maxres", topt->oplist, "0"));
cto= atoi(GetListOption(g,"ConnectTimeout", topt->oplist, "-1"));
qto= atoi(GetListOption(g,"QueryTimeout", topt->oplist, "-1"));
@@ -5593,7 +5618,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0"));
#endif // PROMPT_OK
#if defined(ZIP_SUPPORT)
- zfn = GetListOption(g, "Zipfile", topt->oplist, NULL);
+ zfn= GetListOption(g, "Zipfile", topt->oplist, NULL);
#endif // ZIP_SUPPORT
} else {
host= "localhost";
@@ -5606,14 +5631,24 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
try {
// Check table type
if (ttp == TAB_UNDEF) {
- topt->type = (src) ? "MYSQL" : (tab) ? "PROXY" : "DOS";
- ttp = GetTypeID(topt->type);
+ topt->type= (src) ? "MYSQL" : (tab) ? "PROXY" : "DOS";
+ ttp= GetTypeID(topt->type);
sprintf(g->Message, "No table_type. Was set to %s", topt->type);
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
} else if (ttp == TAB_NIY) {
sprintf(g->Message, "Unsupported table type %s", topt->type);
- rc = HA_ERR_INTERNAL_ERROR;
+ rc= HA_ERR_INTERNAL_ERROR;
goto err;
+#if defined(REST_SUPPORT)
+ } else if (topt->http) {
+ switch (ttp) {
+ case TAB_JSON:
+ case TAB_XML:
+ case TAB_CSV:
+ ttp = TAB_REST;
+ break;
+ } // endswitch type
+#endif // REST_SUPPORT
} // endif ttp
if (!tab) {
@@ -5623,39 +5658,39 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
if (!tbl) {
strcpy(g->Message, "Missing table list");
- rc = HA_ERR_INTERNAL_ERROR;
+ rc= HA_ERR_INTERNAL_ERROR;
goto err;
} // endif tbl
- tab = PlugDup(g, tbl);
+ tab= PlugDup(g, tbl);
- if ((p = strchr(tab, ',')))
- *p = 0;
+ if ((p= strchr(tab, ',')))
+ *p= 0;
- if ((p = strchr(tab, '.'))) {
- *p = 0;
- db = tab;
- tab = p + 1;
+ if ((p= strchr(tab, '.'))) {
+ *p= 0;
+ db= tab;
+ tab= p + 1;
} // endif p
} else if (ttp != TAB_ODBC || !(fnc & (FNC_TABLE | FNC_COL)))
- tab = (char*)table_s->table_name.str; // Default value
+ tab= (char*)table_s->table_name.str; // Default value
} // endif tab
switch (ttp) {
#if defined(ODBC_SUPPORT)
case TAB_ODBC:
- dsn = strz(g, create_info->connect_string);
+ dsn= strz(g, create_info->connect_string);
if (fnc & (FNC_DSN | FNC_DRIVER)) {
- ok = true;
+ ok= true;
#if defined(PROMPT_OK)
} else if (!stricmp(thd->main_security_ctx.host, "localhost")
&& cop == 1) {
- if ((dsn = ODBCCheckConnection(g, dsn, cop)) != NULL) {
+ if ((dsn= ODBCCheckConnection(g, dsn, cop)) != NULL) {
thd->make_lex_string(&create_info->connect_string, dsn, strlen(dsn));
- ok = true;
+ ok= true;
} // endif dsn
#endif // PROMPT_OK
@@ -5663,13 +5698,13 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
sprintf(g->Message, "Missing %s connection string", topt->type);
} else {
// Store ODBC additional parameters
- sop = (POPARM)PlugSubAlloc(g, NULL, sizeof(ODBCPARM));
- sop->User = (char*)user;
- sop->Pwd = (char*)pwd;
- sop->Cto = cto;
- sop->Qto = qto;
- sop->UseCnc = cnc;
- ok = true;
+ sop= (POPARM)PlugSubAlloc(g, NULL, sizeof(ODBCPARM));
+ sop->User= (char*)user;
+ sop->Pwd= (char*)pwd;
+ sop->Cto= cto;
+ sop->Qto= qto;
+ sop->UseCnc= cnc;
+ ok= true;
} // endif's
supfnc |= (FNC_TABLE | FNC_DSN | FNC_DRIVER);
@@ -5678,13 +5713,13 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
#if defined(JAVA_SUPPORT)
case TAB_JDBC:
if (fnc & FNC_DRIVER) {
- ok = true;
- } else if (!(url = strz(g, create_info->connect_string))) {
+ ok= true;
+ } else if (!(url= strz(g, create_info->connect_string))) {
strcpy(g->Message, "Missing URL");
} else {
// Store JDBC additional parameters
int rc;
- PJDBCDEF jdef = new(g) JDBCDEF();
+ PJDBCDEF jdef= new(g) JDBCDEF();
jdef->SetName(create_info->alias.str);
sjp = (PJPARM)PlugSubAlloc(g, NULL, sizeof(JDBCPARM));
@@ -5700,9 +5735,9 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
ok = true;
} else if (rc == RC_NF) {
if (jdef->GetTabname())
- tab = (char*)jdef->GetTabname();
+ tab= (char*)jdef->GetTabname();
- ok = jdef->SetParms(sjp);
+ ok= jdef->SetParms(sjp);
} // endif rc
} // endif's
@@ -5711,7 +5746,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
break;
#endif // JAVA_SUPPORT
case TAB_DBF:
- dbf = true;
+ dbf= true;
// fall through
case TAB_CSV:
if (!fn && fnc != FNC_NO)
@@ -5719,55 +5754,55 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
else if (sep && strlen(sep) > 1)
sprintf(g->Message, "Invalid separator %s", sep);
else
- ok = true;
+ ok= true;
break;
case TAB_MYSQL:
- ok = true;
+ ok= true;
if (create_info->connect_string.str &&
create_info->connect_string.length) {
- PMYDEF mydef = new(g) MYSQLDEF();
+ PMYDEF mydef= new(g) MYSQLDEF();
- dsn = strz(g, create_info->connect_string);
+ dsn= strz(g, create_info->connect_string);
mydef->SetName(create_info->alias.str);
if (!mydef->ParseURL(g, dsn, false)) {
if (mydef->GetHostname())
- host = mydef->GetHostname();
+ host= mydef->GetHostname();
if (mydef->GetUsername())
- user = mydef->GetUsername();
+ user= mydef->GetUsername();
if (mydef->GetPassword())
- pwd = mydef->GetPassword();
+ pwd= mydef->GetPassword();
if (mydef->GetTabschema())
- db = mydef->GetTabschema();
+ db= mydef->GetTabschema();
if (mydef->GetTabname())
- tab = (char*)mydef->GetTabname();
+ tab= (char*)mydef->GetTabname();
if (mydef->GetPortnumber())
- port = mydef->GetPortnumber();
+ port= mydef->GetPortnumber();
} else
- ok = false;
+ ok= false;
} else if (!user)
- user = "root";
+ user= "root";
if (ok && CheckSelf(g, table_s, host, db, tab, src, port))
- ok = false;
+ ok= false;
break;
#if defined(__WIN__)
case TAB_WMI:
- ok = true;
+ ok= true;
break;
#endif // __WIN__
case TAB_PIVOT:
- supfnc = FNC_NO;
+ supfnc= FNC_NO;
// fall through
case TAB_PRX:
case TAB_TBL:
@@ -5777,12 +5812,12 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
(!db || !stricmp(db, table_s->db.str)))
sprintf(g->Message, "A %s table cannot refer to itself", topt->type);
else
- ok = true;
+ ok= true;
break;
case TAB_OEM:
if (topt->module && topt->subtype)
- ok = true;
+ ok= true;
else
strcpy(g->Message, "Missing OEM module or subtype");
@@ -5791,24 +5826,33 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
case TAB_XML:
#endif // LIBXML2_SUPPORT || DOMDOC_SUPPORT
case TAB_JSON:
- dsn = strz(g, create_info->connect_string);
+ dsn= strz(g, create_info->connect_string);
if (!fn && !zfn && !mul && !dsn)
sprintf(g->Message, "Missing %s file name", topt->type);
else
- ok = true;
+ ok= true;
break;
#if defined(JAVA_SUPPORT)
case TAB_MONGO:
if (!topt->tabname)
- topt->tabname = tab;
+ topt->tabname= tab;
- ok = true;
+ ok= true;
break;
#endif // JAVA_SUPPORT
+#if defined(REST_SUPPORT)
+ case TAB_REST:
+ if (!topt->http)
+ sprintf(g->Message, "Missing %s HTTP address", topt->type);
+ else
+ ok = true;
+
+ break;
+#endif // REST_SUPPORT
case TAB_VIR:
- ok = true;
+ ok= true;
break;
default:
sprintf(g->Message, "Cannot get column info for table type %s", topt->type);
@@ -5819,12 +5863,12 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
if (ok && !(supfnc & fnc)) {
sprintf(g->Message, "Unsupported catalog function %s for table type %s",
fncn, topt->type);
- ok = false;
+ ok= false;
} // endif supfnc
if (src && fnc != FNC_NO) {
strcpy(g->Message, "Cannot make catalog table from srcdef");
- ok = false;
+ ok= false;
} // endif src
if (ok) {
@@ -5832,23 +5876,23 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
char *dft, *xtra, *key, *fmt;
int i, len, prec, dec, typ, flg;
- if (!(dpath = SetPath(g, table_s->db.str))) {
- rc = HA_ERR_INTERNAL_ERROR;
+ if (!(dpath= SetPath(g, table_s->db.str))) {
+ rc= HA_ERR_INTERNAL_ERROR;
goto err;
} // endif dpath
if (src && ttp != TAB_PIVOT && ttp != TAB_ODBC && ttp != TAB_JDBC) {
- qrp = SrcColumns(g, host, db, user, pwd, src, port);
+ qrp= SrcColumns(g, host, db, user, pwd, src, port);
if (qrp && ttp == TAB_OCCUR)
if (OcrSrcCols(g, qrp, col, ocl, rnk)) {
- rc = HA_ERR_INTERNAL_ERROR;
+ rc= HA_ERR_INTERNAL_ERROR;
goto err;
} // endif OcrSrcCols
} else switch (ttp) {
case TAB_DBF:
- qrp = DBFColumns(g, dpath, fn, fnc == FNC_COL);
+ qrp= DBFColumns(g, dpath, fn, fnc == FNC_COL);
break;
#if defined(ODBC_SUPPORT)
case TAB_ODBC:
@@ -5856,21 +5900,21 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
case FNC_NO:
case FNC_COL:
if (src) {
- qrp = ODBCSrcCols(g, dsn, (char*)src, sop);
- src = NULL; // for next tests
+ qrp= ODBCSrcCols(g, dsn, (char*)src, sop);
+ src= NULL; // for next tests
} else
- qrp = ODBCColumns(g, dsn, shm, tab, NULL,
+ qrp= ODBCColumns(g, dsn, shm, tab, NULL,
mxr, fnc == FNC_COL, sop);
break;
case FNC_TABLE:
- qrp = ODBCTables(g, dsn, shm, tab, NULL, mxr, true, sop);
+ qrp= ODBCTables(g, dsn, shm, tab, NULL, mxr, true, sop);
break;
case FNC_DSN:
- qrp = ODBCDataSources(g, mxr, true);
+ qrp= ODBCDataSources(g, mxr, true);
break;
case FNC_DRIVER:
- qrp = ODBCDrivers(g, mxr, true);
+ qrp= ODBCDrivers(g, mxr, true);
break;
default:
sprintf(g->Message, "invalid catfunc %s", fncn);
@@ -5885,23 +5929,23 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
case FNC_NO:
case FNC_COL:
if (src) {
- qrp = JDBCSrcCols(g, (char*)src, sjp);
- src = NULL; // for next tests
+ qrp= JDBCSrcCols(g, (char*)src, sjp);
+ src= NULL; // for next tests
} else
- qrp = JDBCColumns(g, shm, tab, NULL, mxr, fnc == FNC_COL, sjp);
+ qrp= JDBCColumns(g, shm, tab, NULL, mxr, fnc == FNC_COL, sjp);
break;
case FNC_TABLE:
-// qrp = JDBCTables(g, shm, tab, tabtyp, mxr, true, sjp);
- qrp = JDBCTables(g, shm, tab, NULL, mxr, true, sjp);
+// qrp= JDBCTables(g, shm, tab, tabtyp, mxr, true, sjp);
+ qrp= JDBCTables(g, shm, tab, NULL, mxr, true, sjp);
break;
#if 0
case FNC_DSN:
- qrp = JDBCDataSources(g, mxr, true);
+ qrp= JDBCDataSources(g, mxr, true);
break;
#endif // 0
case FNC_DRIVER:
- qrp = JDBCDrivers(g, mxr, true);
+ qrp= JDBCDrivers(g, mxr, true);
break;
default:
sprintf(g->Message, "invalid catfunc %s", fncn);
@@ -5911,56 +5955,61 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
break;
#endif // JAVA_SUPPORT
case TAB_MYSQL:
- qrp = MyColumns(g, thd, host, db, user, pwd, tab,
+ qrp= MyColumns(g, thd, host, db, user, pwd, tab,
NULL, port, fnc == FNC_COL);
break;
case TAB_CSV:
- qrp = CSVColumns(g, dpath, topt, fnc == FNC_COL);
+ qrp= CSVColumns(g, dpath, topt, fnc == FNC_COL);
break;
#if defined(__WIN__)
case TAB_WMI:
- qrp = WMIColumns(g, nsp, cls, fnc == FNC_COL);
+ qrp= WMIColumns(g, nsp, cls, fnc == FNC_COL);
break;
#endif // __WIN__
case TAB_PRX:
case TAB_TBL:
case TAB_XCL:
case TAB_OCCUR:
- bif = fnc == FNC_COL;
- qrp = TabColumns(g, thd, db, tab, bif);
+ bif= fnc == FNC_COL;
+ qrp= TabColumns(g, thd, db, tab, bif);
if (!qrp && bif && fnc != FNC_COL) // tab is a view
- qrp = MyColumns(g, thd, host, db, user, pwd, tab, NULL, port, false);
+ qrp= MyColumns(g, thd, host, db, user, pwd, tab, NULL, port, false);
if (qrp && ttp == TAB_OCCUR && fnc != FNC_COL)
if (OcrColumns(g, qrp, col, ocl, rnk)) {
- rc = HA_ERR_INTERNAL_ERROR;
+ rc= HA_ERR_INTERNAL_ERROR;
goto err;
} // endif OcrColumns
break;
case TAB_PIVOT:
- qrp = PivotColumns(g, tab, src, pic, fcl, skc, host, db, user, pwd, port);
+ qrp= PivotColumns(g, tab, src, pic, fcl, skc, host, db, user, pwd, port);
break;
case TAB_VIR:
- qrp = VirColumns(g, fnc == FNC_COL);
+ qrp= VirColumns(g, fnc == FNC_COL);
break;
case TAB_JSON:
- qrp = JSONColumns(g, db, dsn, topt, fnc == FNC_COL);
+ qrp= JSONColumns(g, db, dsn, topt, fnc == FNC_COL);
break;
#if defined(JAVA_SUPPORT)
case TAB_MONGO:
- url = strz(g, create_info->connect_string);
- qrp = MGOColumns(g, db, url, topt, fnc == FNC_COL);
+ url= strz(g, create_info->connect_string);
+ qrp= MGOColumns(g, db, url, topt, fnc == FNC_COL);
break;
#endif // JAVA_SUPPORT
#if defined(LIBXML2_SUPPORT) || defined(DOMDOC_SUPPORT)
case TAB_XML:
- qrp = XMLColumns(g, (char*)db, tab, topt, fnc == FNC_COL);
+ qrp= XMLColumns(g, (char*)db, tab, topt, fnc == FNC_COL);
break;
#endif // LIBXML2_SUPPORT || DOMDOC_SUPPORT
+#if defined(REST_SUPPORT)
+ case TAB_REST:
+ qrp = RESTColumns(g, topt, tab, (char *)db, fnc == FNC_COL);
+ break;
+#endif // REST_SUPPORT
case TAB_OEM:
- qrp = OEMColumns(g, topt, tab, (char*)db, fnc == FNC_COL);
+ qrp= OEMColumns(g, topt, tab, (char*)db, fnc == FNC_COL);
break;
default:
strcpy(g->Message, "System error during assisted discovery");
@@ -5968,33 +6017,33 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
} // endswitch ttp
if (!qrp) {
- rc = HA_ERR_INTERNAL_ERROR;
+ rc= HA_ERR_INTERNAL_ERROR;
goto err;
} // endif !qrp
if (fnc != FNC_NO || src || ttp == TAB_PIVOT) {
// Catalog like table
- for (crp = qrp->Colresp; !rc && crp; crp = crp->Next) {
- cnm = (ttp == TAB_PIVOT) ? crp->Name : encode(g, crp->Name);
- typ = crp->Type;
- len = crp->Length;
- dec = crp->Prec;
- flg = crp->Flag;
- v = (crp->Kdata->IsUnsigned()) ? 'U' : crp->Var;
- tm = (crp->Kdata->IsNullable()) ? 0 : NOT_NULL_FLAG;
+ for (crp= qrp->Colresp; !rc && crp; crp= crp->Next) {
+ cnm= (ttp == TAB_PIVOT) ? crp->Name : encode(g, crp->Name);
+ typ= crp->Type;
+ len= crp->Length;
+ dec= crp->Prec;
+ flg= crp->Flag;
+ v= (crp->Kdata->IsUnsigned()) ? 'U' : crp->Var;
+ tm= (crp->Kdata->IsNullable()) ? 0 : NOT_NULL_FLAG;
if (!len && typ == TYPE_STRING)
- len = 256; // STRBLK's have 0 length
+ len= 256; // STRBLK's have 0 length
// Now add the field
if (add_field(&sql, cnm, typ, len, dec, NULL, tm,
NULL, NULL, NULL, NULL, flg, dbf, v))
- rc = HA_ERR_OUT_OF_MEM;
+ rc= HA_ERR_OUT_OF_MEM;
} // endfor crp
} else {
char *schem __attribute__((unused)) = NULL;
- char *tn = NULL;
+ char *tn= NULL;
// Not a catalog table
if (!qrp->Nblin) {
@@ -6003,57 +6052,57 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
else
strcpy(g->Message, "Fail to retrieve columns");
- rc = HA_ERR_INTERNAL_ERROR;
+ rc= HA_ERR_INTERNAL_ERROR;
goto err;
} // endif !nblin
- for (i = 0; !rc && i < qrp->Nblin; i++) {
- typ = len = prec = dec = 0;
- tm = NOT_NULL_FLAG;
- cnm = (char*)"noname";
- dft = xtra = key = fmt = tn = NULL;
- v = ' ';
- rem = NULL;
+ for (i= 0; !rc && i < qrp->Nblin; i++) {
+ typ= len= prec= dec= 0;
+ tm= NOT_NULL_FLAG;
+ cnm= (char*)"noname";
+ dft= xtra= key= fmt= tn= NULL;
+ v= ' ';
+ rem= NULL;
- for (crp = qrp->Colresp; crp; crp = crp->Next)
+ for (crp= qrp->Colresp; crp; crp= crp->Next)
switch (crp->Fld) {
case FLD_NAME:
if (ttp == TAB_PRX ||
(ttp == TAB_CSV && topt->data_charset &&
(!stricmp(topt->data_charset, "UTF8") ||
!stricmp(topt->data_charset, "UTF-8"))))
- cnm = crp->Kdata->GetCharValue(i);
+ cnm= crp->Kdata->GetCharValue(i);
else
- cnm = encode(g, crp->Kdata->GetCharValue(i));
+ cnm= encode(g, crp->Kdata->GetCharValue(i));
break;
case FLD_TYPE:
- typ = crp->Kdata->GetIntValue(i);
- v = (crp->Nulls) ? crp->Nulls[i] : 0;
+ typ= crp->Kdata->GetIntValue(i);
+ v= (crp->Nulls) ? crp->Nulls[i] : 0;
break;
case FLD_TYPENAME:
- tn = crp->Kdata->GetCharValue(i);
+ tn= crp->Kdata->GetCharValue(i);
break;
case FLD_PREC:
// PREC must be always before LENGTH
- len = prec = crp->Kdata->GetIntValue(i);
+ len= prec= crp->Kdata->GetIntValue(i);
break;
case FLD_LENGTH:
- len = crp->Kdata->GetIntValue(i);
+ len= crp->Kdata->GetIntValue(i);
break;
case FLD_SCALE:
- dec = (!crp->Kdata->IsNull(i)) ? crp->Kdata->GetIntValue(i) : -1;
+ dec= (!crp->Kdata->IsNull(i)) ? crp->Kdata->GetIntValue(i) : -1;
break;
case FLD_NULL:
if (crp->Kdata->GetIntValue(i))
- tm = 0; // Nullable
+ tm= 0; // Nullable
break;
case FLD_FORMAT:
- fmt = (crp->Kdata) ? crp->Kdata->GetCharValue(i) : NULL;
+ fmt= (crp->Kdata) ? crp->Kdata->GetCharValue(i) : NULL;
break;
case FLD_REM:
- rem = crp->Kdata->GetCharValue(i);
+ rem= crp->Kdata->GetCharValue(i);
break;
// case FLD_CHARSET:
// No good because remote table is already translated
@@ -6062,19 +6111,19 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
// break;
case FLD_DEFAULT:
- dft = crp->Kdata->GetCharValue(i);
+ dft= crp->Kdata->GetCharValue(i);
break;
case FLD_EXTRA:
- xtra = crp->Kdata->GetCharValue(i);
+ xtra= crp->Kdata->GetCharValue(i);
// Auto_increment is not supported yet
if (!stricmp(xtra, "AUTO_INCREMENT"))
- xtra = NULL;
+ xtra= NULL;
break;
case FLD_KEY:
if (ttp == TAB_VIR)
- key = crp->Kdata->GetCharValue(i);
+ key= crp->Kdata->GetCharValue(i);
break;
case FLD_SCHEM:
@@ -6083,10 +6132,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
if (schem && stricmp(schem, crp->Kdata->GetCharValue(i))) {
sprintf(g->Message,
"Several %s tables found, specify DBNAME", tab);
- rc = HA_ERR_INTERNAL_ERROR;
+ rc= HA_ERR_INTERNAL_ERROR;
goto err;
} else if (!schem)
- schem = crp->Kdata->GetCharValue(i);
+ schem= crp->Kdata->GetCharValue(i);
} // endif ttp
#endif // ODBC_SUPPORT || JAVA_SUPPORT
@@ -6097,10 +6146,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
#if defined(ODBC_SUPPORT)
if (ttp == TAB_ODBC) {
int plgtyp;
- bool w = false; // Wide character type
+ bool w= false; // Wide character type
// typ must be PLG type, not SQL type
- if (!(plgtyp = TranslateSQLType(typ, dec, prec, v, w))) {
+ if (!(plgtyp= TranslateSQLType(typ, dec, prec, v, w))) {
if (GetTypeConv() == TPC_SKIP) {
// Skip this column
sprintf(g->Message, "Column %s skipped (unsupported type %d)",
@@ -6109,12 +6158,12 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
continue;
} else {
sprintf(g->Message, "Unsupported SQL type %d", typ);
- rc = HA_ERR_INTERNAL_ERROR;
+ rc= HA_ERR_INTERNAL_ERROR;
goto err;
} // endif type_conv
} else
- typ = plgtyp;
+ typ= plgtyp;
switch (typ) {
case TYPE_STRING:
@@ -6129,10 +6178,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
prec += (dec + 2); // To be safe
break;
case TYPE_DECIM:
- prec = len;
+ prec= len;
break;
default:
- dec = 0;
+ dec= 0;
} // endswitch typ
} else
@@ -6142,7 +6191,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
int plgtyp;
// typ must be PLG type, not SQL type
- if (!(plgtyp = TranslateJDBCType(typ, tn, dec, prec, v))) {
+ if (!(plgtyp= TranslateJDBCType(typ, tn, dec, prec, v))) {
if (GetTypeConv() == TPC_SKIP) {
// Skip this column
sprintf(g->Message, "Column %s skipped (unsupported type %d)",
@@ -6151,12 +6200,12 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
continue;
} else {
sprintf(g->Message, "Unsupported SQL type %d", typ);
- rc = HA_ERR_INTERNAL_ERROR;
+ rc= HA_ERR_INTERNAL_ERROR;
goto err;
} // endif type_conv
} else
- typ = plgtyp;
+ typ= plgtyp;
switch (typ) {
case TYPE_DOUBLE:
@@ -6165,43 +6214,43 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
prec += (dec + 2); // To be safe
break;
default:
- dec = 0;
+ dec= 0;
} // endswitch typ
} else
#endif // ODBC_SUPPORT
// Make the arguments as required by add_fields
if (typ == TYPE_DOUBLE)
- prec = len;
+ prec= len;
if (typ == TYPE_DATE)
- prec = 0;
+ prec= 0;
// Now add the field
if (add_field(&sql, cnm, typ, prec, dec, key, tm, rem, dft, xtra,
fmt, 0, dbf, v))
- rc = HA_ERR_OUT_OF_MEM;
+ rc= HA_ERR_OUT_OF_MEM;
} // endfor i
} // endif fnc
if (!rc)
- rc = init_table_share(thd, table_s, create_info, &sql);
+ rc= init_table_share(thd, table_s, create_info, &sql);
//g->jump_level--;
//PopUser(xp);
//return rc;
} else {
- rc = HA_ERR_UNSUPPORTED;
+ rc= HA_ERR_UNSUPPORTED;
} // endif ok
} catch (int n) {
if (trace(1))
htrc("Exception %d: %s\n", n, g->Message);
- rc = HA_ERR_INTERNAL_ERROR;
+ rc= HA_ERR_INTERNAL_ERROR;
} catch (const char *msg) {
strcpy(g->Message, msg);
- rc = HA_ERR_INTERNAL_ERROR;
+ rc= HA_ERR_INTERNAL_ERROR;
} // end catch
err:
@@ -6270,7 +6319,7 @@ int ha_connect::create(const char *name, TABLE *table_arg,
TABLE *st= table; // Probably unuseful
THD *thd= ha_thd();
LEX_CSTRING cnc = table_arg->s->connect_string;
-#ifdef WITH_PARTITION_STORAGE_ENGINE
+#if defined(WITH_PARTITION_STORAGE_ENGINE)
partition_info *part_info= table_arg->part_info;
#else // !WITH_PARTITION_STORAGE_ENGINE
#define part_info 0
@@ -6396,7 +6445,7 @@ int ha_connect::create(const char *name, TABLE *table_arg,
host= mydef->GetHostname();
if (mydef->GetTabschema())
- db = mydef->GetTabschema();
+ db= mydef->GetTabschema();
if (mydef->GetTabname())
tab= mydef->GetTabname();
@@ -6479,7 +6528,7 @@ int ha_connect::create(const char *name, TABLE *table_arg,
} // endif type JSON
if (type == TAB_CSV) {
- const char *sep = options->separator;
+ const char *sep= options->separator;
if (sep && strlen(sep) > 1) {
sprintf(g->Message, "Invalid separator %s", sep);
@@ -6681,15 +6730,15 @@ int ha_connect::create(const char *name, TABLE *table_arg,
#if defined(ZIP_SUPPORT)
if (options->zipped) {
// Check whether the zip entry must be made from a file
- PCSZ fn = GetListOption(g, "Load", options->oplist, NULL);
+ PCSZ fn= GetListOption(g, "Load", options->oplist, NULL);
if (fn) {
char zbuf[_MAX_PATH], buf[_MAX_PATH], dbpath[_MAX_PATH];
- PCSZ entry = GetListOption(g, "Entry", options->oplist, NULL);
- PCSZ a = GetListOption(g, "Append", options->oplist, "NO");
- bool append = *a == '1' || *a == 'Y' || *a == 'y' || !stricmp(a, "ON");
- PCSZ m = GetListOption(g, "Mulentries", options->oplist, "NO");
- bool mul = *m == '1' || *m == 'Y' || *m == 'y' || !stricmp(m, "ON");
+ PCSZ entry= GetListOption(g, "Entry", options->oplist, NULL);
+ PCSZ a= GetListOption(g, "Append", options->oplist, "NO");
+ bool append= *a == '1' || *a == 'Y' || *a == 'y' || !stricmp(a, "ON");
+ PCSZ m= GetListOption(g, "Mulentries", options->oplist, "NO");
+ bool mul= *m == '1' || *m == 'Y' || *m == 'y' || !stricmp(m, "ON");
if (!entry && !mul) {
my_message(ER_UNKNOWN_ERROR, "Missing entry name", MYF(0));
@@ -6708,7 +6757,7 @@ int ha_connect::create(const char *name, TABLE *table_arg,
} // endif fn
} // endif zipped
-#endif // ZIP_SUPPORT
+#endif // ZIP_SUPPORT
// To check whether indexes have to be made or remade
if (!g->Xchk) {
@@ -6758,7 +6807,7 @@ int ha_connect::create(const char *name, TABLE *table_arg,
if (SetDataPath(g, table_arg->s->db.str)) {
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- rc = HA_ERR_INTERNAL_ERROR;
+ rc= HA_ERR_INTERNAL_ERROR;
} else if (cat) {
if (part_info)
strncpy(partname,
@@ -7102,7 +7151,7 @@ ha_connect::check_if_supported_inplace_alter(TABLE *altered_table,
/*
ALTER TABLE tbl_name CONVERT TO CHARACTER SET .. and
- ALTER TABLE table_name DEFAULT CHARSET = .. most likely
+ ALTER TABLE table_name DEFAULT CHARSET= .. most likely
change column charsets and so not supported in-place through
old API.
@@ -7334,7 +7383,7 @@ maria_declare_plugin(connect)
0x0106, /* version number (1.06) */
NULL, /* status variables */
connect_system_variables, /* system variables */
- "1.06.0009", /* string version */
+ "1.06.0010", /* string version */
MariaDB_PLUGIN_MATURITY_STABLE /* maturity */
}
maria_declare_plugin_end;
diff --git a/storage/connect/ha_connect.h b/storage/connect/ha_connect.h
index 53e666d534d..06de375ef58 100644
--- a/storage/connect/ha_connect.h
+++ b/storage/connect/ha_connect.h
@@ -11,7 +11,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
/** @file ha_connect.h
Author Olivier Bertrand
diff --git a/storage/connect/inihandl.cpp b/storage/connect/inihandl.cpp
index c39c94fb30d..ab6d5db4f0a 100644
--- a/storage/connect/inihandl.cpp
+++ b/storage/connect/inihandl.cpp
@@ -192,7 +192,7 @@ static void PROFILE_Save( FILE *file, PROFILESECTION *section )
}
for (key = section->key; key; key = key->next)
- if (key->name[0]) {
+ if (key->name && key->name[0]) {
fprintf(file, "%s", SVP(key->name));
if (key->value)
diff --git a/storage/connect/jsonudf.cpp b/storage/connect/jsonudf.cpp
index c634d722c31..b1e32394de0 100644
--- a/storage/connect/jsonudf.cpp
+++ b/storage/connect/jsonudf.cpp
@@ -1,6 +1,6 @@
/****************** jsonudf C++ Program Source Code File (.CPP) ******************/
-/* PROGRAM NAME: jsonudf Version 1.7 */
-/* (C) Copyright to the author Olivier BERTRAND 2015-2018 */
+/* PROGRAM NAME: jsonudf Version 1.8 */
+/* (C) Copyright to the author Olivier BERTRAND 2015-2019 */
/* This program are the JSON User Defined Functions . */
/*********************************************************************************/
@@ -1685,7 +1685,7 @@ static PCSZ MakeKey(PGLOBAL g, UDF_ARGS *args, int i)
} // endif *s
if (n < 1)
- return (char*) "Key";
+ return (PCSZ) "Key";
if (!b) {
if ((p = (PSZ)PlgDBSubAlloc(g, NULL, n + 1))) {
@@ -1702,7 +1702,7 @@ static PCSZ MakeKey(PGLOBAL g, UDF_ARGS *args, int i)
return (char*) s;
} // endif count
- return (char*) "Key";
+ return (PCSZ) "Key";
} // end of MakeKey
/*********************************************************************************/
diff --git a/storage/connect/libdoc.cpp b/storage/connect/libdoc.cpp
index 089b1197e58..c1eaa6766cc 100644
--- a/storage/connect/libdoc.cpp
+++ b/storage/connect/libdoc.cpp
@@ -1035,7 +1035,7 @@ PXNODE XML2NODE::AddChildNode(PGLOBAL g, PCSZ name, PXNODE np)
// If name has the format m[n] only m is taken as node name
if ((p = strchr(pn, '[')))
- p = BufAlloc(g, pn, p - pn);
+ p = BufAlloc(g, pn, int(p - pn));
else
p = pn;
diff --git a/storage/connect/mini-global.h b/storage/connect/mini-global.h
new file mode 100644
index 00000000000..f712795827c
--- /dev/null
+++ b/storage/connect/mini-global.h
@@ -0,0 +1,33 @@
+/***********************************************************************/
+/* Definitions needed by the included files. */
+/***********************************************************************/
+#if !defined(MY_GLOBAL_H)
+#define MY_GLOBAL_H
+typedef unsigned int uint;
+typedef unsigned int uint32;
+typedef unsigned short ushort;
+typedef unsigned long ulong;
+typedef unsigned long DWORD;
+typedef char *LPSTR;
+typedef const char *LPCSTR;
+typedef int BOOL;
+#if defined(_WINDOWS)
+typedef void *HANDLE;
+#else
+typedef int HANDLE;
+#endif
+typedef char *PSZ;
+typedef const char *PCSZ;
+typedef unsigned char BYTE;
+typedef unsigned char uchar;
+typedef long long longlong;
+typedef unsigned long long ulonglong;
+typedef char my_bool;
+struct charset_info_st {};
+typedef const charset_info_st CHARSET_INFO;
+#define FALSE 0
+#define TRUE 1
+#define Item char
+#define MY_MAX(a,b) ((a>b)?(a):(b))
+#define MY_MIN(a,b) ((a<b)?(a):(b))
+#endif // MY_GLOBAL_H
diff --git a/storage/connect/mycat.cc b/storage/connect/mycat.cc
index 6d3e9a346c5..411e96e3dc8 100644
--- a/storage/connect/mycat.cc
+++ b/storage/connect/mycat.cc
@@ -16,9 +16,9 @@
/*************** Mycat CC Program Source Code File (.CC) ***************/
/* PROGRAM NAME: MYCAT */
/* ------------- */
-/* Version 1.6 */
+/* Version 1.7 */
/* */
-/* Author: Olivier Bertrand 2012 - 2018 */
+/* Author: Olivier Bertrand 2012 - 2019 */
/* */
/* WHAT THIS PROGRAM DOES: */
/* ----------------------- */
@@ -93,6 +93,9 @@
#if defined(ZIP_SUPPORT)
#include "tabzip.h"
#endif // ZIP_SUPPORT
+#if defined(REST_SUPPORT)
+#include "tabrest.h"
+#endif // Rest_SUPPORT
#include "mycat.h"
/***********************************************************************/
@@ -117,11 +120,11 @@ char *GetPluginDir(void)
/***********************************************************************/
TABTYPE GetTypeID(const char *type)
{
- return (!type) ? TAB_UNDEF
+ return (!type) ? TAB_UNDEF
: (!stricmp(type, "DOS")) ? TAB_DOS
: (!stricmp(type, "FIX")) ? TAB_FIX
: (!stricmp(type, "BIN")) ? TAB_BIN
- : (!stricmp(type, "CSV")) ? TAB_CSV
+ : (!stricmp(type, "CSV")) ? TAB_CSV
: (!stricmp(type, "FMT")) ? TAB_FMT
: (!stricmp(type, "DBF")) ? TAB_DBF
#if defined(XML_SUPPORT)
@@ -133,30 +136,30 @@ TABTYPE GetTypeID(const char *type)
: (!stricmp(type, "ODBC")) ? TAB_ODBC
#endif
#if defined(JAVA_SUPPORT)
- : (!stricmp(type, "JDBC")) ? TAB_JDBC
+ : (!stricmp(type, "JDBC")) ? TAB_JDBC
#endif
#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
- : (!stricmp(type, "MONGO") && MongoEnabled()) ? TAB_MONGO
+ : (!stricmp(type, "MONGO") && MongoEnabled()) ? TAB_MONGO
#endif
- : (!stricmp(type, "MYSQL")) ? TAB_MYSQL
+ : (!stricmp(type, "MYSQL")) ? TAB_MYSQL
: (!stricmp(type, "MYPRX")) ? TAB_MYSQL
: (!stricmp(type, "DIR")) ? TAB_DIR
#if defined(__WIN__)
- : (!stricmp(type, "MAC")) ? TAB_MAC
- : (!stricmp(type, "WMI")) ? TAB_WMI
+ : (!stricmp(type, "MAC")) ? TAB_MAC
+ : (!stricmp(type, "WMI")) ? TAB_WMI
#endif
- : (!stricmp(type, "TBL")) ? TAB_TBL
- : (!stricmp(type, "XCOL")) ? TAB_XCL
- : (!stricmp(type, "OCCUR")) ? TAB_OCCUR
+ : (!stricmp(type, "TBL")) ? TAB_TBL
+ : (!stricmp(type, "XCOL")) ? TAB_XCL
+ : (!stricmp(type, "OCCUR")) ? TAB_OCCUR
: (!stricmp(type, "CATLG")) ? TAB_PRX // Legacy
: (!stricmp(type, "PROXY")) ? TAB_PRX
: (!stricmp(type, "PIVOT")) ? TAB_PIVOT
: (!stricmp(type, "VIR")) ? TAB_VIR
: (!stricmp(type, "JSON")) ? TAB_JSON
#if defined(ZIP_SUPPORT)
- : (!stricmp(type, "ZIP")) ? TAB_ZIP
+ : (!stricmp(type, "ZIP")) ? TAB_ZIP
#endif
- : (!stricmp(type, "OEM")) ? TAB_OEM : TAB_NIY;
+ : (!stricmp(type, "OEM")) ? TAB_OEM : TAB_NIY;
} // end of GetTypeID
/***********************************************************************/
@@ -166,18 +169,19 @@ bool IsFileType(TABTYPE type)
{
bool isfile;
- switch (type) {
+ switch (type) {
case TAB_DOS:
case TAB_FIX:
case TAB_BIN:
- case TAB_CSV:
+ case TAB_CSV:
case TAB_FMT:
case TAB_DBF:
case TAB_XML:
case TAB_INI:
case TAB_VEC:
case TAB_JSON:
-// case TAB_ZIP:
+ case TAB_REST:
+ // case TAB_ZIP:
isfile= true;
break;
default:
@@ -195,7 +199,7 @@ bool IsExactType(TABTYPE type)
{
bool exact;
- switch (type) {
+ switch (type) {
case TAB_FIX:
case TAB_BIN:
case TAB_DBF:
@@ -220,7 +224,7 @@ bool IsTypeNullable(TABTYPE type)
{
bool nullable;
- switch (type) {
+ switch (type) {
case TAB_MAC:
case TAB_DIR:
nullable= false;
@@ -240,7 +244,7 @@ bool IsTypeFixed(TABTYPE type)
{
bool fix;
- switch (type) {
+ switch (type) {
case TAB_FIX:
case TAB_BIN:
case TAB_VEC:
@@ -262,7 +266,7 @@ bool IsTypeIndexable(TABTYPE type)
{
bool idx;
- switch (type) {
+ switch (type) {
case TAB_DOS:
case TAB_CSV:
case TAB_FMT:
@@ -288,7 +292,7 @@ int GetIndexType(TABTYPE type)
{
int xtyp;
- switch (type) {
+ switch (type) {
case TAB_DOS:
case TAB_CSV:
case TAB_FMT:
@@ -301,9 +305,9 @@ int GetIndexType(TABTYPE type)
break;
case TAB_MYSQL:
case TAB_ODBC:
- case TAB_JDBC:
- case TAB_MONGO:
- xtyp= 2;
+ case TAB_JDBC:
+ case TAB_MONGO:
+ xtyp= 2;
break;
case TAB_VIR:
xtyp= 3;
@@ -375,7 +379,7 @@ PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info)
return NULL;
} else
PlugSetPath(soname, module, GetPluginDir());
-
+
// The exported name is always in uppercase
for (int i = 0; ; i++) {
c = subtype[i];
@@ -452,7 +456,7 @@ CATALOG::CATALOG(void)
memset(&Ctb, 0, sizeof(CURTAB));
Cbuf= NULL;
Cblen= 0;
- DefHuge= false;
+ DefHuge= false;
} // end of CATALOG constructor
/* -------------------------- Class MYCAT ---------------------------- */
@@ -462,7 +466,7 @@ CATALOG::CATALOG(void)
/***********************************************************************/
MYCAT::MYCAT(PHC hc) : CATALOG()
{
- Hc= hc;
+ Hc= hc;
DefHuge= false;
} // end of MYCAT constructor
@@ -479,16 +483,23 @@ void MYCAT::Reset(void)
/***********************************************************************/
PRELDEF MYCAT::GetTableDesc(PGLOBAL g, PTABLE tablep,
LPCSTR type, PRELDEF *)
- {
- if (trace(1))
- printf("GetTableDesc: name=%s am=%s\n", tablep->GetName(), SVP(type));
+{
+ PRELDEF tdp= NULL;
+
+ if (trace(1))
+ htrc("GetTableDesc: name=%s am=%s\n", tablep->GetName(), SVP(type));
+
+ // If not specified get the type of this table
+ //if (!type)
+ // type= Hc->GetStringOption("Type","*");
- // If not specified get the type of this table
- if (!type)
- type= Hc->GetStringOption("Type","*");
+ tdp= MakeTableDesc(g, tablep, type);
- return MakeTableDesc(g, tablep, type);
- } // end of GetTableDesc
+ if (trace(1))
+ htrc("GetTableDesc: tdp=%p\n", tdp);
+
+ return tdp;
+} // end of GetTableDesc
/***********************************************************************/
/* MakeTableDesc: make a table/view description. */
@@ -497,18 +508,22 @@ PRELDEF MYCAT::GetTableDesc(PGLOBAL g, PTABLE tablep,
PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am)
{
TABTYPE tc;
- LPCSTR name = (PSZ)PlugDup(g, tablep->GetName());
- LPCSTR schema = (PSZ)PlugDup(g, tablep->GetSchema());
+ LPCSTR name= (PSZ)PlugDup(g, tablep->GetName());
+ LPCSTR schema= (PSZ)PlugDup(g, tablep->GetSchema());
PRELDEF tdp= NULL;
- if (trace(1))
- printf("MakeTableDesc: name=%s schema=%s am=%s\n",
- name, SVP(schema), SVP(am));
+ if (trace(1))
+ htrc("MakeTableDesc: name=%s schema=%s am=%s\n",
+ name, SVP(schema), SVP(am));
/*********************************************************************/
/* Get a unique enum identifier for types. */
/*********************************************************************/
- tc= GetTypeID(am);
+ if (!am) {
+ tc= Hc->GetRealType();
+ am= Hc->GetStringOption("Type","*");
+ } else
+ tc= GetTypeID(am);
switch (tc) {
case TAB_FIX:
@@ -523,46 +538,52 @@ PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am)
case TAB_XML: tdp= new(g) XMLDEF; break;
#endif // XML_SUPPORT
#if defined(VCT_SUPPORT)
- case TAB_VEC: tdp = new(g) VCTDEF; break;
+ case TAB_VEC: tdp = new(g) VCTDEF; break;
#endif // VCT_SUPPORT
#if defined(ODBC_SUPPORT)
case TAB_ODBC: tdp= new(g) ODBCDEF; break;
#endif // ODBC_SUPPORT
#if defined(JAVA_SUPPORT)
- case TAB_JDBC: tdp= new(g) JDBCDEF; break;
+ case TAB_JDBC: tdp= new(g) JDBCDEF; break;
#endif // JAVA_SUPPORT
#if defined(__WIN__)
case TAB_MAC: tdp= new(g) MACDEF; break;
case TAB_WMI: tdp= new(g) WMIDEF; break;
#endif // __WIN__
case TAB_OEM: tdp= new(g) OEMDEF; break;
- case TAB_TBL: tdp= new(g) TBLDEF; break;
- case TAB_XCL: tdp= new(g) XCLDEF; break;
- case TAB_PRX: tdp= new(g) PRXDEF; break;
- case TAB_OCCUR: tdp= new(g) OCCURDEF; break;
- case TAB_MYSQL: tdp= new(g) MYSQLDEF; break;
+ case TAB_TBL: tdp= new(g) TBLDEF; break;
+ case TAB_XCL: tdp= new(g) XCLDEF; break;
+ case TAB_PRX: tdp= new(g) PRXDEF; break;
+ case TAB_OCCUR: tdp= new(g) OCCURDEF; break;
+ case TAB_MYSQL: tdp= new(g) MYSQLDEF; break;
case TAB_PIVOT: tdp= new(g) PIVOTDEF; break;
case TAB_VIR: tdp= new(g) VIRDEF; break;
case TAB_JSON: tdp= new(g) JSONDEF; break;
#if defined(ZIP_SUPPORT)
- case TAB_ZIP: tdp = new(g) ZIPDEF; break;
+ case TAB_ZIP: tdp = new(g) ZIPDEF; break;
#endif // ZIP_SUPPORT
+#if defined(REST_SUPPORT)
+ case TAB_REST: tdp= new (g) RESTDEF; break;
+#endif // REST_SUPPORT
#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
- case TAB_MONGO:
- if (MongoEnabled()) {
- tdp = new(g) MGODEF;
- break;
- } // endif enabled
- // fall through
+ case TAB_MONGO:
+ if (MongoEnabled()) {
+ tdp = new(g) MGODEF;
+ break;
+ } // endif enabled
+ // fall through
#endif // JAVA_SUPPORT || CMGO_SUPPORT
- default:
- sprintf(g->Message, MSG(BAD_TABLE_TYPE), am, name);
+ default:
+ sprintf(g->Message, MSG(BAD_TABLE_TYPE), am, name);
} // endswitch
// Do make the table/view definition
if (tdp && tdp->Define(g, this, name, schema, am))
tdp= NULL;
+ if (trace(1))
+ htrc("Table %s made\n", am);
+
return tdp;
} // end of MakeTableDesc
@@ -575,26 +596,29 @@ PTDB MYCAT::GetTable(PGLOBAL g, PTABLE tablep, MODE mode, LPCSTR type)
PTDB tdbp= NULL;
// LPCSTR name= tablep->GetName();
- if (trace(1))
- printf("GetTableDB: name=%s\n", tablep->GetName());
+ if (trace(1))
+ htrc("GetTableDB: name=%s\n", tablep->GetName());
// Look for the description of the requested table
tdp= GetTableDesc(g, tablep, type);
if (tdp) {
- if (trace(1))
- printf("tdb=%p type=%s\n", tdp, tdp->GetType());
+ if (trace(1))
+ htrc("tdb=%p type=%s\n", tdp, tdp->GetType());
+
+ if (tablep->GetSchema())
+ tdp->Database = SetPath(g, tablep->GetSchema());
+
+ if (trace(2))
+ htrc("Going to get table...\n");
- if (tablep->GetSchema())
- tdp->Database = SetPath(g, tablep->GetSchema());
-
tdbp= tdp->GetTable(g, mode);
- } // endif tdp
+ } // endif tdp
if (tdbp) {
- if (trace(1))
- printf("tdbp=%p name=%s amtype=%d\n", tdbp, tdbp->GetName(),
- tdbp->GetAmType());
+ if (trace(1))
+ htrc("tdbp=%p name=%s amtype=%d\n", tdbp, tdbp->GetName(),
+ tdbp->GetAmType());
tablep->SetTo_Tdb(tdbp);
tdbp->SetTable(tablep);
tdbp->SetMode(mode);
diff --git a/storage/connect/mycat.h b/storage/connect/mycat.h
index e5a0b783b82..818e535b32d 100644
--- a/storage/connect/mycat.h
+++ b/storage/connect/mycat.h
@@ -14,7 +14,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
/**************** MYCAT H Declares Source Code File (.H) ***************/
-/* Name: MYCAT.H Version 2.3 */
+/* Name: MYCAT.H Version 2.4 */
/* Author: Olivier Bertrand */
/* This file contains the CONNECT plugin MYCAT class definitions. */
/***********************************************************************/
@@ -50,6 +50,8 @@ struct ha_table_option_struct {
const char *filter;
const char *oplist;
const char *data_charset;
+ const char *http;
+ const char *uri;
ulonglong lrecl;
ulonglong elements;
//ulonglong estimate;
diff --git a/storage/connect/mysql-test/connect/r/jdbc_postgresql.result b/storage/connect/mysql-test/connect/r/jdbc_postgresql.result
index bec1dc8725b..07cc3c465ea 100644
--- a/storage/connect/mysql-test/connect/r/jdbc_postgresql.result
+++ b/storage/connect/mysql-test/connect/r/jdbc_postgresql.result
@@ -1,4 +1,4 @@
-SET GLOBAL connect_class_path='C:/MariaDB-10.0/MariaDB/storage/connect/mysql-test/connect/std_data/JavaWrappers.jar;C:/Jconnectors/postgresql-42.2.1.jar';
+SET GLOBAL connect_class_path='C:/MariaDB-10.2/MariaDB/storage/connect/mysql-test/connect/std_data/JavaWrappers.jar;C:/Jconnectors/postgresql-42.2.1.jar';
CREATE TABLE t2 (
command varchar(128) not null,
number int(5) not null flag=1,
diff --git a/storage/connect/osutil.h b/storage/connect/osutil.h
index 7e6b8823b9b..380e7bebb22 100644
--- a/storage/connect/osutil.h
+++ b/storage/connect/osutil.h
@@ -3,7 +3,11 @@
#define __OSUTIL_H__
#if defined(UNIX) || defined(UNIV_LINUX)
+#if defined(MARIADB)
#include "my_global.h"
+#else
+#include "mini-global.h"
+#endif
#include <errno.h>
#include <stddef.h>
#include "os.h"
diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h
index 5446e0d2a07..f10ae209e9d 100644
--- a/storage/connect/plgdbsem.h
+++ b/storage/connect/plgdbsem.h
@@ -1,7 +1,7 @@
/************** PlgDBSem H Declares Source Code File (.H) **************/
-/* Name: PLGDBSEM.H Version 3.7 */
+/* Name: PLGDBSEM.H Version 3.8 */
/* */
-/* (C) Copyright to the author Olivier BERTRAND 1998-2017 */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2019 */
/* */
/* This file contains the CONNECT storage engine definitions. */
/***********************************************************************/
@@ -82,6 +82,7 @@ enum TABTYPE {TAB_UNDEF = 0, /* Table of undefined type */
TAB_JDBC = 26, /* Table accessed via JDBC */
TAB_ZIP = 27, /* ZIP file info table */
TAB_MONGO = 28, /* Table retrieved from MongoDB */
+ TAB_REST = 29, /* Table retrieved from Rest */
TAB_NIY = 30}; /* Table not implemented yet */
enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */
@@ -400,6 +401,7 @@ typedef class VCTDEF *PVCTDEF;
typedef class PIVOTDEF *PPIVOTDEF;
typedef class DOMDEF *PDOMDEF;
typedef class DIRDEF *PDIRDEF;
+typedef class RESTDEF *PRESTDEF;
typedef class OEMDEF *POEMDEF;
typedef class COLCRT *PCOLCRT;
typedef class COLDEF *PCOLDEF;
diff --git a/storage/connect/plugutil.cpp b/storage/connect/plugutil.cpp
index 6790e7eb45c..e74937b942a 100644
--- a/storage/connect/plugutil.cpp
+++ b/storage/connect/plugutil.cpp
@@ -2,11 +2,11 @@
/* */
/* PROGRAM NAME: PLUGUTIL */
/* ------------- */
-/* Version 3.0 */
+/* Version 3.1 */
/* */
/* COPYRIGHT: */
/* ---------- */
-/* (C) Copyright to the author Olivier BERTRAND 1993-2017 */
+/* (C) Copyright to the author Olivier BERTRAND 1993-2019 */
/* */
/* WHAT THIS PROGRAM DOES: */
/* ----------------------- */
@@ -111,21 +111,31 @@ ACTIVITY defActivity = { /* Describes activity and language */
#endif // UNIX
/**************************************************************************/
-/* Tracing output function. */
+/* Conditional tracing output function. */
/**************************************************************************/
-void htrc(char const *fmt, ...)
- {
- va_list ap;
- va_start (ap, fmt);
+void xtrc(uint x, char const *fmt, ...)
+{
+ if (GetTraceValue() & x) {
+ va_list ap;
+ va_start(ap, fmt);
+
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ } // endif x
+} // end of xtrc
-//if (trace == 1)
-// vfprintf(debug, fmt, ap);
-//else
- vfprintf(stderr, fmt, ap);
+/**************************************************************************/
+/* Tracing output function. */
+/**************************************************************************/
+void htrc(char const* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
- va_end (ap);
- } // end of htrc
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+} // end of htrc
/***********************************************************************/
/* Plug initialization routine. */
diff --git a/storage/connect/reldef.cpp b/storage/connect/reldef.cpp
index 30d8063d1a6..8ba8aac3621 100644
--- a/storage/connect/reldef.cpp
+++ b/storage/connect/reldef.cpp
@@ -81,51 +81,51 @@ RELDEF::RELDEF(void)
/* This function return a pointer to the Table Option Struct. */
/***********************************************************************/
PTOS RELDEF::GetTopt(void)
- {
- return Hc->GetTableOptionStruct();
- } // end of GetTopt
+ {
+ return Hc->GetTableOptionStruct();
+ } // end of GetTopt
/***********************************************************************/
/* This function sets an integer table information. */
/***********************************************************************/
bool RELDEF::SetIntCatInfo(PCSZ what, int n)
- {
- return Hc->SetIntegerOption(what, n);
- } // end of SetIntCatInfo
+ {
+ return Hc->SetIntegerOption(what, n);
+ } // end of SetIntCatInfo
/***********************************************************************/
/* This function returns integer table information. */
/***********************************************************************/
int RELDEF::GetIntCatInfo(PCSZ what, int idef)
- {
- int n= Hc->GetIntegerOption(what);
+ {
+ int n= Hc->GetIntegerOption(what);
- return (n == NO_IVAL) ? idef : n;
- } // end of GetIntCatInfo
+ return (n == NO_IVAL) ? idef : n;
+ } // end of GetIntCatInfo
/***********************************************************************/
/* This function returns Boolean table information. */
/***********************************************************************/
bool RELDEF::GetBoolCatInfo(PCSZ what, bool bdef)
- {
- bool b= Hc->GetBooleanOption(what, bdef);
+ {
+ bool b= Hc->GetBooleanOption(what, bdef);
- return b;
- } // end of GetBoolCatInfo
+ return b;
+ } // end of GetBoolCatInfo
/***********************************************************************/
/* This function returns size catalog information. */
/***********************************************************************/
int RELDEF::GetSizeCatInfo(PCSZ what, PCSZ sdef)
- {
- char c;
- PCSZ s;
+ {
+ char c;
+ PCSZ s;
int i, n= 0;
- if (!(s= Hc->GetStringOption(what)))
- s= sdef;
+ if (!(s= Hc->GetStringOption(what)))
+ s= sdef;
- if ((i= sscanf(s, " %d %c ", &n, &c)) == 2)
+ if ((i= sscanf(s, " %d %c ", &n, &c)) == 2)
switch (toupper(c)) {
case 'M':
n *= 1024;
@@ -141,41 +141,41 @@ int RELDEF::GetSizeCatInfo(PCSZ what, PCSZ sdef)
/* This function sets char table information in buf. */
/***********************************************************************/
int RELDEF::GetCharCatInfo(PCSZ what, PCSZ sdef, char *buf, int size)
- {
- PCSZ s= Hc->GetStringOption(what);
+ {
+ PCSZ s= Hc->GetStringOption(what);
- strncpy(buf, ((s) ? s : sdef), size);
- return size;
- } // end of GetCharCatInfo
+ strncpy(buf, ((s) ? s : sdef), size);
+ return size;
+ } // end of GetCharCatInfo
/***********************************************************************/
/* To be used by any TDB's. */
/***********************************************************************/
bool RELDEF::Partitioned(void)
- {
- return Hc->IsPartitioned();
- } // end of Partitioned
+ {
+ return Hc->IsPartitioned();
+ } // end of Partitioned
/***********************************************************************/
/* This function returns string table information. */
/* Default parameter is "*" to get the handler default. */
/***********************************************************************/
char *RELDEF::GetStringCatInfo(PGLOBAL g, PCSZ what, PCSZ sdef)
- {
- char *sval = NULL;
- PCSZ name, s= Hc->GetStringOption(what, sdef);
-
- if (s) {
+ {
+ char *sval = NULL;
+ PCSZ name, s= Hc->GetStringOption(what, sdef);
+
+ if (s) {
if (!Hc->IsPartitioned() ||
(stricmp(what, "filename") && stricmp(what, "tabname")
&& stricmp(what, "connect")))
- sval= PlugDup(g, s);
+ sval= PlugDup(g, s);
else
sval= (char*)s;
} else if (!stricmp(what, "filename")) {
// Return default file name
- PCSZ ftype= Hc->GetStringOption("Type", "*");
+ PCSZ ftype= Hc->GetStringOption("Type", "*");
int i, n;
if (IsFileType(GetTypeID(ftype))) {
@@ -183,7 +183,7 @@ char *RELDEF::GetStringCatInfo(PGLOBAL g, PCSZ what, PCSZ sdef)
sval= (char*)PlugSubAlloc(g, NULL, strlen(name) + 12);
strcat(strcpy(sval, name), ".");
n= strlen(sval);
-
+
// Fold ftype to lower case
for (i= 0; i < 12; i++)
if (!ftype[i]) {
@@ -196,8 +196,8 @@ char *RELDEF::GetStringCatInfo(PGLOBAL g, PCSZ what, PCSZ sdef)
} // endif s
- return sval;
- } // end of GetStringCatInfo
+ return sval;
+ } // end of GetStringCatInfo
/* --------------------------- Class TABDEF -------------------------- */
@@ -223,14 +223,14 @@ TABDEF::TABDEF(void)
/***********************************************************************/
/* Define: initialize the table definition block from XDB file. */
/***********************************************************************/
-bool TABDEF::Define(PGLOBAL g, PCATLG cat,
- LPCSTR name, LPCSTR schema, LPCSTR am)
+bool TABDEF::Define(PGLOBAL g, PCATLG cat,
+ LPCSTR name, LPCSTR schema, LPCSTR am)
{
int poff = 0;
- Hc = ((MYCAT*)cat)->GetHandler();
- Name = (PSZ)name;
- Schema = (PSZ)Hc->GetDBName(schema);
+ Hc = ((MYCAT*)cat)->GetHandler();
+ Name = (PSZ)name;
+ Schema = (PSZ)Hc->GetDBName(schema);
Cat = cat;
Catfunc = GetFuncID(GetStringCatInfo(g, "Catfunc", NULL));
Elemt = GetIntCatInfo("Elements", 0);
@@ -263,14 +263,14 @@ PCSZ TABDEF::GetPath(void)
/* This function returns column table information. */
/***********************************************************************/
int TABDEF::GetColCatInfo(PGLOBAL g)
- {
- char *type= GetStringCatInfo(g, "Type", "*");
+ {
+ char *type= GetStringCatInfo(g, "Type", "*");
char c, fty, eds;
- int i, n, loff, poff, nof, nlg;
- void *field= NULL;
+ int i, n, loff, poff, nof, nlg;
+ void *field= NULL;
TABTYPE tc;
PCOLDEF cdp, lcdp= NULL, tocols= NULL;
- PCOLINFO pcf= (PCOLINFO)PlugSubAlloc(g, NULL, sizeof(COLINFO));
+ PCOLINFO pcf= (PCOLINFO)PlugSubAlloc(g, NULL, sizeof(COLINFO));
memset(pcf, 0, sizeof(COLINFO));
@@ -278,33 +278,33 @@ int TABDEF::GetColCatInfo(PGLOBAL g)
tc= (Catfunc == FNC_NO) ? GetTypeID(type) : TAB_PRX;
// Take care of the column definitions
- i= poff= nof= nlg= 0;
+ i= poff= nof= nlg= 0;
#if defined(__WIN__)
- // Offsets of HTML and DIR tables start from 0, DBF at 1
- loff= (tc == TAB_DBF) ? 1 : (tc == TAB_XML || tc == TAB_DIR) ? -1 : 0;
+ // Offsets of HTML and DIR tables start from 0, DBF at 1
+ loff= (tc == TAB_DBF) ? 1 : (tc == TAB_XML || tc == TAB_DIR) ? -1 : 0;
#else // !__WIN__
- // Offsets of HTML tables start from 0, DIR and DBF at 1
- loff = (tc == TAB_DBF || tc == TAB_DIR) ? 1 : (tc == TAB_XML) ? -1 : 0;
+ // Offsets of HTML tables start from 0, DIR and DBF at 1
+ loff = (tc == TAB_DBF || tc == TAB_DIR) ? 1 : (tc == TAB_XML) ? -1 : 0;
#endif // !__WIN__
while (true) {
- // Default Offset depends on table type
- switch (tc) {
+ // Default Offset depends on table type
+ switch (tc) {
case TAB_DOS:
case TAB_FIX:
case TAB_BIN:
case TAB_VEC:
case TAB_DBF:
- poff= loff + nof; // Default next offset
- nlg= MY_MAX(nlg, poff); // Default lrecl
+ poff= loff + nof; // Default next offset
+ nlg= MY_MAX(nlg, poff); // Default lrecl
break;
case TAB_CSV:
case TAB_FMT:
- nlg+= nof;
+ nlg+= nof;
case TAB_DIR:
case TAB_XML:
- poff= loff + (pcf->Flags & U_VIRTUAL ? 0 : 1);
+ poff= loff + (pcf->Flags & U_VIRTUAL ? 0 : 1);
break;
case TAB_INI:
case TAB_MAC:
@@ -316,39 +316,39 @@ int TABDEF::GetColCatInfo(PGLOBAL g)
poff = 0; // Offset represents an independant flag
break;
default: // VCT PLG ODBC JDBC MYSQL WMI...
- poff = 0; // NA
+ poff = 0; // NA
break;
- } // endswitch tc
+ } // endswitch tc
-// do {
- field= Hc->GetColumnOption(g, field, pcf);
+// do {
+ field= Hc->GetColumnOption(g, field, pcf);
// } while (field && (*pcf->Name =='*' /*|| pcf->Flags & U_VIRTUAL*/));
- if (tc == TAB_DBF && pcf->Type == TYPE_DATE && !pcf->Datefmt) {
- // DBF date format defaults to 'YYYMMDD'
- pcf->Datefmt= "YYYYMMDD";
- pcf->Length= 8;
- } // endif tc
+ if (tc == TAB_DBF && pcf->Type == TYPE_DATE && !pcf->Datefmt) {
+ // DBF date format defaults to 'YYYMMDD'
+ pcf->Datefmt= "YYYYMMDD";
+ pcf->Length= 8;
+ } // endif tc
- if (!field)
- break;
+ if (!field)
+ break;
// Allocate the column description block
cdp= new(g) COLDEF;
if ((nof= cdp->Define(g, NULL, pcf, poff)) < 0)
- return -1; // Error, probably unhandled type
- else
- loff= cdp->GetOffset();
-
- switch (tc) {
- case TAB_VEC:
- cdp->SetOffset(0); // Not to have shift
- case TAB_BIN:
- // BIN/VEC are packed by default
+ return -1; // Error, probably unhandled type
+ else
+ loff= cdp->GetOffset();
+
+ switch (tc) {
+ case TAB_VEC:
+ cdp->SetOffset(0); // Not to have shift
+ case TAB_BIN:
+ // BIN/VEC are packed by default
if (nof) {
- // Field width is the internal representation width
- // that can also depend on the column format
+ // Field width is the internal representation width
+ // that can also depend on the column format
fty = cdp->Decode ? 'C' : 'X';
eds = 0;
n = 0;
@@ -371,38 +371,38 @@ int TABDEF::GetColCatInfo(PGLOBAL g)
if (n)
nof = n;
else switch (fty) {
- case 'X':
+ case 'X':
if (eds && IsTypeChar(cdp->Buf_Type))
nof = sizeof(longlong);
else
nof= cdp->Clen;
break;
- case 'C': break;
- case 'R':
- case 'F': nof = sizeof(float); break;
- case 'I': nof = sizeof(int); break;
- case 'D': nof = sizeof(double); break;
- case 'S': nof = sizeof(short); break;
- case 'T': nof = sizeof(char); break;
- case 'G': nof = sizeof(longlong); break;
- default: /* Wrong format */
+ case 'C': break;
+ case 'R':
+ case 'F': nof = sizeof(float); break;
+ case 'I': nof = sizeof(int); break;
+ case 'D': nof = sizeof(double); break;
+ case 'S': nof = sizeof(short); break;
+ case 'T': nof = sizeof(char); break;
+ case 'G': nof = sizeof(longlong); break;
+ default: /* Wrong format */
sprintf(g->Message, "Invalid format %c", fty);
return -1;
- } // endswitch fty
+ } // endswitch fty
} // endif nof
default:
- break;
- } // endswitch tc
+ break;
+ } // endswitch tc
- if (lcdp)
- lcdp->SetNext(cdp);
- else
- tocols= cdp;
+ if (lcdp)
+ lcdp->SetNext(cdp);
+ else
+ tocols= cdp;
- lcdp= cdp;
+ lcdp= cdp;
i++;
} // endwhile
@@ -410,31 +410,31 @@ int TABDEF::GetColCatInfo(PGLOBAL g)
if (i != GetDegree())
SetDegree(i);
- if (GetDefType() == TYPE_AM_DOS) {
- int ending, recln= 0;
+ if (GetDefType() == TYPE_AM_DOS) {
+ int ending, recln= 0;
- // Was commented because sometimes ending is 0 even when
- // not specified (for instance if quoted is specified)
-// if ((ending= Hc->GetIntegerOption("Ending")) < 0) {
- if ((ending= Hc->GetIntegerOption("Ending")) <= 0) {
+ // Was commented because sometimes ending is 0 even when
+ // not specified (for instance if quoted is specified)
+// if ((ending= Hc->GetIntegerOption("Ending")) < 0) {
+ if ((ending= Hc->GetIntegerOption("Ending")) <= 0) {
ending= (tc == TAB_BIN || tc == TAB_VEC) ? 0 : CRLF;
- Hc->SetIntegerOption("Ending", ending);
- } // endif ending
+ Hc->SetIntegerOption("Ending", ending);
+ } // endif ending
- // Calculate the default record size
- switch (tc) {
+ // Calculate the default record size
+ switch (tc) {
case TAB_FIX:
case TAB_BIN:
recln= nlg + ending; // + length of line ending
break;
case TAB_VEC:
recln= nlg;
-
+
// if ((k= (pak < 0) ? 8 : pak) > 1)
// See above for detailed comment
// Round up lrecl to multiple of 8 or pak
// recln= ((recln + k - 1) / k) * k;
-
+
break;
case TAB_DOS:
case TAB_DBF:
@@ -443,26 +443,30 @@ int TABDEF::GetColCatInfo(PGLOBAL g)
case TAB_CSV:
case TAB_FMT:
// The number of separators (assuming an extra one can exist)
-// recln= poff * ((qotd) ? 3 : 1); to be investigated
- recln= nlg + poff * 3; // To be safe
+// recln= poff * ((qotd) ? 3 : 1); to be investigated
+ recln= nlg + poff * 3; // To be safe
default:
break;
} // endswitch tc
- // lrecl must be at least recln to avoid buffer overflow
- if (trace(1))
- htrc("Lrecl: Calculated=%d defined=%d\n",
- recln, Hc->GetIntegerOption("Lrecl"));
+ // lrecl must be at least recln to avoid buffer overflow
+ if (trace(1))
+ htrc("Lrecl: Calculated=%d defined=%d\n",
+ recln, Hc->GetIntegerOption("Lrecl"));
- recln = MY_MAX(recln, Hc->GetIntegerOption("Lrecl"));
- Hc->SetIntegerOption("Lrecl", recln);
- ((PDOSDEF)this)->SetLrecl(recln);
- } // endif Lrecl
+ recln = MY_MAX(recln, Hc->GetIntegerOption("Lrecl"));
+ Hc->SetIntegerOption("Lrecl", recln);
+ ((PDOSDEF)this)->SetLrecl(recln);
- // Attach the column definition to the tabdef
- SetCols(tocols);
- return poff;
- } // end of GetColCatInfo
+ if (trace(1))
+ htrc("Lrecl set to %d\n", recln);
+
+ } // endif Lrecl
+
+ // Attach the column definition to the tabdef
+ SetCols(tocols);
+ return poff;
+ } // end of GetColCatInfo
/***********************************************************************/
/* SetIndexInfo: retrieve index description from the table structure. */
@@ -487,16 +491,17 @@ PTABDEF OEMDEF::GetXdef(PGLOBAL g)
PCATLG cat = Cat;
/*********************************************************************/
- /* Ensure that the .dll doesn't have a path. */
- /* This is done to ensure that only approved dll from the system */
+ /* Ensure that the module name doesn't have a path. */
+ /* This is done to ensure that only approved libs from the system */
/* directories are used (to make this even remotely secure). */
/*********************************************************************/
if (check_valid_path(Module, strlen(Module))) {
strcpy(g->Message, "Module cannot contain a path");
return NULL;
} else
- PlugSetPath(soname, Module, GetPluginDir());
-
+// PlugSetPath(soname, Module, GetPluginDir()); // Crashes on Fedora
+ strncat(strcpy(soname, GetPluginDir()), Module, _MAX_PATH);
+
#if defined(__WIN__)
// Is the DLL already loaded?
if (!Hdll && !(Hdll = GetModuleHandle(soname)))
@@ -522,31 +527,31 @@ PTABDEF OEMDEF::GetXdef(PGLOBAL g)
// Get the function returning an instance of the external DEF class
if (!(getdef = (XGETDEF)GetProcAddress((HINSTANCE)Hdll, getname))) {
- char buf[256];
- DWORD rc = GetLastError();
-
- sprintf(g->Message, MSG(PROCADD_ERROR), rc, getname);
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
- (LPTSTR)buf, sizeof(buf), NULL);
- strcat(strcat(g->Message, ": "), buf);
- FreeLibrary((HMODULE)Hdll);
+ char buf[256];
+ DWORD rc = GetLastError();
+
+ sprintf(g->Message, MSG(PROCADD_ERROR), rc, getname);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ strcat(strcat(g->Message, ": "), buf);
+ FreeLibrary((HMODULE)Hdll);
return NULL;
} // endif getdef
#else // !__WIN__
const char *error = NULL;
-
+
#if 0 // Don't know what all this stuff does
- Dl_info dl_info;
+ Dl_info dl_info;
- // The OEM lib must retrieve exported CONNECT variables
+ // The OEM lib must retrieve exported CONNECT variables
if (dladdr(&connect_hton, &dl_info)) {
if (dlopen(dl_info.dli_fname, RTLD_NOLOAD | RTLD_NOW | RTLD_GLOBAL) == 0) {
error = dlerror();
sprintf(g->Message, "dlopen failed: %s, OEM not supported", SVP(error));
return NULL;
} // endif dlopen
-
+
} else {
error = dlerror();
sprintf(g->Message, "dladdr failed: %s, OEM not supported", SVP(error));
@@ -626,7 +631,7 @@ bool OEMDEF::DefineAM(PGLOBAL g, LPCSTR, int)
char *desc = (char*)PlugSubAlloc(g, NULL, strlen(Module)
+ strlen(Subtype) + 3);
sprintf(desc, "%s(%s)", Module, Subtype);
- Desc = desc;
+ Desc = desc;
return false;
} // end of DefineAM
@@ -701,17 +706,17 @@ PTDB OEMDEF::GetTable(PGLOBAL g, MODE mode)
txfp = new(g) FIXFAM(defp);
} else if (rfm == RECFM_VCT) {
#if defined(VCT_SUPPORT)
- assert(Pxdef->GetDefType() == TYPE_AM_VCT);
+ assert(Pxdef->GetDefType() == TYPE_AM_VCT);
if (map)
txfp = new(g) VCMFAM((PVCTDEF)defp);
else
txfp = new(g) VCTFAM((PVCTDEF)defp);
#else // !VCT_SUPPORT
- strcpy(g->Message, "VCT no more supported");
- return NULL;
+ strcpy(g->Message, "VCT no more supported");
+ return NULL;
#endif // !VCT_SUPPORT
- } // endif's
+ } // endif's
((PTDBDOS)tdbp)->SetTxfp(txfp);
} // endif Txfp
diff --git a/storage/connect/rest.def b/storage/connect/rest.def
new file mode 100644
index 00000000000..71c76740af9
--- /dev/null
+++ b/storage/connect/rest.def
@@ -0,0 +1,4 @@
+LIBRARY REST2
+EXPORTS
+ GetREST @1
+ ColREST @2
diff --git a/storage/connect/rest.h b/storage/connect/rest.h
new file mode 100644
index 00000000000..f1d77e0a279
--- /dev/null
+++ b/storage/connect/rest.h
@@ -0,0 +1,33 @@
+/***********************************************************************/
+/* Definitions needed by the included files. */
+/***********************************************************************/
+#if !defined(MY_GLOBAL_H)
+#define MY_GLOBAL_H
+typedef unsigned int uint;
+typedef unsigned int uint32;
+typedef unsigned short ushort;
+typedef unsigned long ulong;
+typedef unsigned long DWORD;
+typedef char *LPSTR;
+typedef const char *LPCSTR;
+typedef int BOOL;
+#if defined(_WINDOWS)
+typedef void *HANDLE;
+#else
+typedef int HANDLE;
+#endif
+typedef char *PSZ;
+typedef const char *PCSZ;
+typedef unsigned char BYTE;
+typedef unsigned char uchar;
+typedef long long longlong;
+typedef unsigned long long ulonglong;
+typedef char my_bool;
+struct charset_info_st {};
+typedef const charset_info_st CHARSET_INFO;
+#define FALSE 0
+#define TRUE 1
+#define Item char
+#define MY_MAX(a,b) ((a>b)?(a):(b))
+#define MY_MIN(a,b) ((a<b)?(a):(b))
+#endif // MY_GLOBAL_H \ No newline at end of file
diff --git a/storage/connect/restget.cpp b/storage/connect/restget.cpp
new file mode 100644
index 00000000000..6b184ae6926
--- /dev/null
+++ b/storage/connect/restget.cpp
@@ -0,0 +1,94 @@
+/************* Restget C++ Program Source Code File (.CPP) *************/
+/* Adapted from the sample program of the Casablanca tutorial. */
+/* Copyright Olivier Bertrand 2019. */
+/***********************************************************************/
+#include <cpprest/filestream.h>
+#include <cpprest/http_client.h>
+#if defined(MARIADB)
+#include <my_global.h>
+#else
+#include "mini-global.h"
+#define _OS_H_INCLUDED // Prevent os.h to be called
+#endif
+
+using namespace utility::conversions; // String conversions utilities
+using namespace web; // Common features like URIs.
+using namespace web::http; // Common HTTP functionality
+using namespace web::http::client; // HTTP client features
+using namespace concurrency::streams; // Asynchronous streams
+
+#include "global.h"
+
+/***********************************************************************/
+/* Make a local copy of the requested file. */
+/***********************************************************************/
+int restGetFile(PGLOBAL g, PCSZ http, PCSZ uri, PCSZ fn)
+{
+ int rc = 0;
+ bool xt = trace(515);
+ auto fileStream = std::make_shared<ostream>();
+
+ if (!http || !fn) {
+ strcpy(g->Message, "Missing http or filename");
+ return 2;
+ } // endif
+
+ if (xt)
+ htrc("restGetFile: fn=%s\n", fn);
+
+ // Open stream to output file.
+ pplx::task<void> requestTask = fstream::open_ostream(to_string_t(fn))
+ .then([=](ostream outFile) {
+ *fileStream= outFile;
+
+ if (xt)
+ htrc("Outfile isopen=%d\n", outFile.is_open());
+
+ // Create http_client to send the request.
+ http_client client(to_string_t(http));
+
+ if (uri) {
+ // Build request URI and start the request.
+ uri_builder builder(to_string_t(uri));
+ return client.request(methods::GET, builder.to_string());
+ } else
+ return client.request(methods::GET);
+ })
+
+ // Handle response headers arriving.
+ .then([=](http_response response) {
+ if (xt)
+ htrc("Received response status code:%u\n",
+ response.status_code());
+
+ // Write response body into the file.
+ return response.body().read_to_end(fileStream->streambuf());
+ })
+
+ // Close the file stream.
+ .then([=](size_t n) {
+ if (xt)
+ htrc("Return size=%u\n", n);
+
+ return fileStream->close();
+ });
+
+ // Wait for all the outstanding I/O to complete and handle any exceptions
+ try {
+ requestTask.wait();
+
+ if (xt)
+ htrc("In Wait\n");
+
+ } catch (const std::exception &e) {
+ if (xt)
+ htrc("Error exception: %s\n", e.what());
+ sprintf(g->Message, "Error exception: %s", e.what());
+ rc= 1;
+ } // end try/catch
+
+ if (xt)
+ htrc("restget done: rc=%d\n", rc);
+
+ return rc;
+} // end of restGetFile
diff --git a/storage/connect/tabfmt.cpp b/storage/connect/tabfmt.cpp
index 4d9a46b6af5..847fd515860 100644
--- a/storage/connect/tabfmt.cpp
+++ b/storage/connect/tabfmt.cpp
@@ -193,7 +193,7 @@ PQRYRES CSVColumns(PGLOBAL g, PCSZ dp, PTOS topt, bool info)
if (tdp->Zipped)
tcvp = new(g)TDBCSV(tdp, new(g)UNZFAM(tdp));
else
-#endif
+#endif // ZIP_SUPPORT
tcvp = new(g) TDBCSV(tdp, new(g) DOSFAM(tdp));
tcvp->SetMode(MODE_READ);
diff --git a/storage/connect/tabjdbc.cpp b/storage/connect/tabjdbc.cpp
index 3576f7ef0d5..4d834bcf9e0 100644
--- a/storage/connect/tabjdbc.cpp
+++ b/storage/connect/tabjdbc.cpp
@@ -643,7 +643,9 @@ bool TDBJDBC::OpenDB(PGLOBAL g)
Cnp->InitValue(g);
if ((n = Jcp->GetResultSize(Query->GetStr(), Cnp)) < 0) {
- sprintf(g->Message, "Cannot get result size rc=%d", n);
+ char* msg = PlugDup(g, g->Message);
+
+ sprintf(g->Message, "Get result size: %s (rc=%d)", msg, n);
return true;
} else if (n) {
Jcp->m_Rows = n;
diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp
index 1a7dbd485c6..a96b7fe46d5 100644
--- a/storage/connect/tabjson.cpp
+++ b/storage/connect/tabjson.cpp
@@ -71,15 +71,15 @@ char *GetJsonNull(void);
/***********************************************************************/
PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info)
{
- static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT,
+ static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT,
TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
- static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC,
+ static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC,
FLD_LENGTH, FLD_SCALE, FLD_NULL, FLD_FORMAT};
static unsigned int length[] = {0, 6, 8, 10, 10, 6, 6, 0};
- int i, n = 0;
+ int i, n = 0;
int ncol = sizeof(buftyp) / sizeof(int);
- PJCL jcp;
- JSONDISC *pjdc = NULL;
+ PJCL jcp;
+ JSONDISC *pjdc = NULL;
PQRYRES qrp;
PCOLRES crp;
@@ -89,15 +89,15 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info)
goto skipit;
} // endif info
- if (GetIntegerTableOption(g, topt, "Multiple", 0)) {
- strcpy(g->Message, "Cannot find column definition for multiple table");
- return NULL;
- } // endif Multiple
+ if (GetIntegerTableOption(g, topt, "Multiple", 0)) {
+ strcpy(g->Message, "Cannot find column definition for multiple table");
+ return NULL;
+ } // endif Multiple
- pjdc = new(g) JSONDISC(g, length);
+ pjdc = new(g) JSONDISC(g, length);
- if (!(n = pjdc->GetColumns(g, db, dsn, topt)))
- return NULL;
+ if (!(n = pjdc->GetColumns(g, db, dsn, topt)))
+ return NULL;
skipit:
if (trace(1))
@@ -110,8 +110,8 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info)
buftyp, fldtyp, length, false, false);
crp = qrp->Colresp->Next->Next->Next->Next->Next->Next;
- crp->Name = PlugDup(g, "Nullable");
- crp->Next->Name = PlugDup(g, "Jpath");
+ crp->Name = PlugDup(g, "Nullable");
+ crp->Next->Name = PlugDup(g, "Jpath");
if (info || !qrp)
return qrp;
@@ -122,8 +122,8 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info)
/* Now get the results into blocks. */
/*********************************************************************/
for (i = 0, jcp = pjdc->fjcp; jcp; i++, jcp = jcp->Next) {
- if (jcp->Type == TYPE_UNKNOWN)
- jcp->Type = TYPE_STRING; // Void column
+ if (jcp->Type == TYPE_UNKNOWN)
+ jcp->Type = TYPE_STRING; // Void column
crp = qrp->Colresp; // Column Name
crp->Kdata->SetValue(jcp->Name, i);
@@ -159,382 +159,382 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info)
/***********************************************************************/
JSONDISC::JSONDISC(PGLOBAL g, uint *lg)
{
- length = lg;
- jcp = fjcp = pjcp = NULL;
- tjnp = NULL;
- jpp = NULL;
- tjsp = NULL;
- jsp = NULL;
- row = NULL;
- sep = NULL;
- i = n = bf = ncol = lvl = 0;
- all = false;
-} // end of JSONDISC constructor
+ length = lg;
+ jcp = fjcp = pjcp = NULL;
+ tjnp = NULL;
+ jpp = NULL;
+ tjsp = NULL;
+ jsp = NULL;
+ row = NULL;
+ sep = NULL;
+ i = n = bf = ncol = lvl = 0;
+ all = false;
+} // end of JSONDISC constructor
int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
{
- char filename[_MAX_PATH];
- bool mgo = (GetTypeID(topt->type) == TAB_MONGO);
- PCSZ level = GetStringTableOption(g, topt, "Level", NULL);
-
- if (level) {
- lvl = atoi(level);
- lvl = (lvl > 16) ? 16 : lvl;
- } else
- lvl = 0;
-
- sep = GetStringTableOption(g, topt, "Separator", ".");
-
- /*********************************************************************/
- /* Open the input file. */
- /*********************************************************************/
- tdp = new(g) JSONDEF;
+ char filename[_MAX_PATH];
+ bool mgo = (GetTypeID(topt->type) == TAB_MONGO);
+ PCSZ level = GetStringTableOption(g, topt, "Level", NULL);
+
+ if (level) {
+ lvl = atoi(level);
+ lvl = (lvl > 16) ? 16 : lvl;
+ } else
+ lvl = 0;
+
+ sep = GetStringTableOption(g, topt, "Separator", ".");
+
+ /*********************************************************************/
+ /* Open the input file. */
+ /*********************************************************************/
+ tdp = new(g) JSONDEF;
#if defined(ZIP_SUPPORT)
- tdp->Entry = GetStringTableOption(g, topt, "Entry", NULL);
- tdp->Zipped = GetBooleanTableOption(g, topt, "Zipped", false);
+ tdp->Entry = GetStringTableOption(g, topt, "Entry", NULL);
+ tdp->Zipped = GetBooleanTableOption(g, topt, "Zipped", false);
#endif // ZIP_SUPPORT
- tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL);
-
- if (!(tdp->Database = SetPath(g, db)))
- return 0;
-
- tdp->Objname = GetStringTableOption(g, topt, "Object", NULL);
- tdp->Base = GetIntegerTableOption(g, topt, "Base", 0) ? 1 : 0;
- tdp->Pretty = GetIntegerTableOption(g, topt, "Pretty", 2);
- tdp->Xcol = GetStringTableOption(g, topt, "Expand", NULL);
- tdp->Accept = GetBooleanTableOption(g, topt, "Accept", false);
- tdp->Uri = (dsn && *dsn ? dsn : NULL);
-
- if (!tdp->Fn && !tdp->Uri) {
- strcpy(g->Message, MSG(MISSING_FNAME));
- return 0;
- } // endif Fn
-
- if (tdp->Fn) {
- // We used the file name relative to recorded datapath
- PlugSetPath(filename, tdp->Fn, tdp->GetPath());
- tdp->Fn = PlugDup(g, filename);
- } // endif Fn
-
- if (trace(1))
- htrc("File %s objname=%s pretty=%d lvl=%d\n",
- tdp->Fn, tdp->Objname, tdp->Pretty, lvl);
-
- if (tdp->Uri) {
+ tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL);
+
+ if (!(tdp->Database = SetPath(g, db)))
+ return 0;
+
+ tdp->Objname = GetStringTableOption(g, topt, "Object", NULL);
+ tdp->Base = GetIntegerTableOption(g, topt, "Base", 0) ? 1 : 0;
+ tdp->Pretty = GetIntegerTableOption(g, topt, "Pretty", 2);
+ tdp->Xcol = GetStringTableOption(g, topt, "Expand", NULL);
+ tdp->Accept = GetBooleanTableOption(g, topt, "Accept", false);
+ tdp->Uri = (dsn && *dsn ? dsn : NULL);
+
+ if (!tdp->Fn && !tdp->Uri) {
+ strcpy(g->Message, MSG(MISSING_FNAME));
+ return 0;
+ } // endif Fn
+
+ if (tdp->Fn) {
+ // We used the file name relative to recorded datapath
+ PlugSetPath(filename, tdp->Fn, tdp->GetPath());
+ tdp->Fn = PlugDup(g, filename);
+ } // endif Fn
+
+ if (trace(1))
+ htrc("File %s objname=%s pretty=%d lvl=%d\n",
+ tdp->Fn, tdp->Objname, tdp->Pretty, lvl);
+
+ if (tdp->Uri) {
#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
- tdp->Collname = GetStringTableOption(g, topt, "Name", NULL);
- tdp->Collname = GetStringTableOption(g, topt, "Tabname", tdp->Collname);
- tdp->Schema = GetStringTableOption(g, topt, "Dbname", "test");
- tdp->Options = (PSZ)GetStringTableOption(g, topt, "Colist", "all");
- tdp->Pipe = GetBooleanTableOption(g, topt, "Pipeline", false);
- tdp->Driver = (PSZ)GetStringTableOption(g, topt, "Driver", NULL);
- tdp->Version = GetIntegerTableOption(g, topt, "Version", 3);
- tdp->Wrapname = (PSZ)GetStringTableOption(g, topt, "Wrapper",
- (tdp->Version == 2) ? "Mongo2Interface" : "Mongo3Interface");
- tdp->Pretty = 0;
+ tdp->Collname = GetStringTableOption(g, topt, "Name", NULL);
+ tdp->Collname = GetStringTableOption(g, topt, "Tabname", tdp->Collname);
+ tdp->Schema = GetStringTableOption(g, topt, "Dbname", "test");
+ tdp->Options = (PSZ)GetStringTableOption(g, topt, "Colist", "all");
+ tdp->Pipe = GetBooleanTableOption(g, topt, "Pipeline", false);
+ tdp->Driver = (PSZ)GetStringTableOption(g, topt, "Driver", NULL);
+ tdp->Version = GetIntegerTableOption(g, topt, "Version", 3);
+ tdp->Wrapname = (PSZ)GetStringTableOption(g, topt, "Wrapper",
+ (tdp->Version == 2) ? "Mongo2Interface" : "Mongo3Interface");
+ tdp->Pretty = 0;
#else // !MONGO_SUPPORT
- sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
- return 0;
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
+ return 0;
#endif // !MONGO_SUPPORT
- } // endif Uri
+ } // endif Uri
- if (tdp->Pretty == 2) {
- if (tdp->Zipped) {
+ if (tdp->Pretty == 2) {
+ if (tdp->Zipped) {
#if defined(ZIP_SUPPORT)
- tjsp = new(g) TDBJSON(tdp, new(g) UNZFAM(tdp));
+ tjsp = new(g) TDBJSON(tdp, new(g) UNZFAM(tdp));
#else // !ZIP_SUPPORT
- sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
- return 0;
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
+ return 0;
#endif // !ZIP_SUPPORT
- } else
- tjsp = new(g) TDBJSON(tdp, new(g) MAPFAM(tdp));
-
- if (tjsp->MakeDocument(g))
- return 0;
-
- jsp = (tjsp->GetDoc()) ? tjsp->GetDoc()->GetValue(0) : NULL;
- } else {
- if (!(tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0)))
- {
- if (!mgo) {
- sprintf(g->Message, "LRECL must be specified for pretty=%d", tdp->Pretty);
- return 0;
- } else
- tdp->Lrecl = 8192; // Should be enough
- }
-
- tdp->Ending = GetIntegerTableOption(g, topt, "Ending", CRLF);
-
- if (tdp->Zipped) {
+ } else
+ tjsp = new(g) TDBJSON(tdp, new(g) MAPFAM(tdp));
+
+ if (tjsp->MakeDocument(g))
+ return 0;
+
+ jsp = (tjsp->GetDoc()) ? tjsp->GetDoc()->GetValue(0) : NULL;
+ } else {
+ if (!(tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0)))
+ {
+ if (!mgo) {
+ sprintf(g->Message, "LRECL must be specified for pretty=%d", tdp->Pretty);
+ return 0;
+ } else
+ tdp->Lrecl = 8192; // Should be enough
+ }
+
+ tdp->Ending = GetIntegerTableOption(g, topt, "Ending", CRLF);
+
+ if (tdp->Zipped) {
#if defined(ZIP_SUPPORT)
- tjnp = new(g)TDBJSN(tdp, new(g) UNZFAM(tdp));
+ tjnp = new(g)TDBJSN(tdp, new(g) UNZFAM(tdp));
#else // !ZIP_SUPPORT
- sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
- return NULL;
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
+ return NULL;
#endif // !ZIP_SUPPORT
- } else if (tdp->Uri) {
- if (tdp->Driver && toupper(*tdp->Driver) == 'C') {
+ } else if (tdp->Uri) {
+ if (tdp->Driver && toupper(*tdp->Driver) == 'C') {
#if defined(CMGO_SUPPORT)
- tjnp = new(g) TDBJSN(tdp, new(g) CMGFAM(tdp));
+ tjnp = new(g) TDBJSN(tdp, new(g) CMGFAM(tdp));
#else
- sprintf(g->Message, "Mongo %s Driver not available", "C");
- return 0;
+ sprintf(g->Message, "Mongo %s Driver not available", "C");
+ return 0;
#endif
- } else if (tdp->Driver && toupper(*tdp->Driver) == 'J') {
+ } else if (tdp->Driver && toupper(*tdp->Driver) == 'J') {
#if defined(JAVA_SUPPORT)
- tjnp = new(g) TDBJSN(tdp, new(g) JMGFAM(tdp));
+ tjnp = new(g) TDBJSN(tdp, new(g) JMGFAM(tdp));
#else
- sprintf(g->Message, "Mongo %s Driver not available", "Java");
- return 0;
+ sprintf(g->Message, "Mongo %s Driver not available", "Java");
+ return 0;
#endif
- } else { // Driver not specified
+ } else { // Driver not specified
#if defined(CMGO_SUPPORT)
- tjnp = new(g) TDBJSN(tdp, new(g) CMGFAM(tdp));
+ tjnp = new(g) TDBJSN(tdp, new(g) CMGFAM(tdp));
#elif defined(JAVA_SUPPORT)
- tjnp = new(g) TDBJSN(tdp, new(g) JMGFAM(tdp));
+ tjnp = new(g) TDBJSN(tdp, new(g) JMGFAM(tdp));
#else
- sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
- return 0;
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
+ return 0;
#endif
- } // endif Driver
-
- } else
- tjnp = new(g) TDBJSN(tdp, new(g) DOSFAM(tdp));
-
- tjnp->SetMode(MODE_READ);
-
- // Allocate the parse work memory
- PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL));
- memset(G, 0, sizeof(GLOBAL));
- G->Sarea_Size = tdp->Lrecl * 10;
- G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size);
- PlugSubSet(G->Sarea, G->Sarea_Size);
- G->jump_level = 0;
- tjnp->SetG(G);
-
- if (tjnp->OpenDB(g))
- return 0;
-
- switch (tjnp->ReadDB(g)) {
- case RC_EF:
- strcpy(g->Message, "Void json table");
- case RC_FX:
- goto err;
- default:
- jsp = tjnp->GetRow();
- } // endswitch ReadDB
-
- } // endif pretty
-
- if (!(row = (jsp) ? jsp->GetObject() : NULL)) {
- strcpy(g->Message, "Can only retrieve columns from object rows");
- goto err;
- } // endif row
-
- all = GetBooleanTableOption(g, topt, "Fullarray", false);
- jcol.Name = jcol.Fmt = NULL;
- jcol.Next = NULL;
- jcol.Found = true;
- colname[0] = 0;
-
- if (!tdp->Uri) {
- fmt[0] = '$';
- fmt[1] = '.';
- bf = 2;
- } // endif Uri
-
- /*********************************************************************/
- /* Analyse the JSON tree and define columns. */
- /*********************************************************************/
- for (i = 1; ; i++) {
- for (jpp = row->GetFirst(); jpp; jpp = jpp->GetNext()) {
- strncpy(colname, jpp->GetKey(), 64);
- fmt[bf] = 0;
-
- if (Find(g, jpp->GetVal(), colname, MY_MIN(lvl, 0)))
- goto err;
-
- } // endfor jpp
-
- // Missing column can be null
- for (jcp = fjcp; jcp; jcp = jcp->Next) {
- jcp->Cbn |= !jcp->Found;
- jcp->Found = false;
- } // endfor jcp
-
- if (tdp->Pretty != 2) {
- // Read next record
- switch (tjnp->ReadDB(g)) {
- case RC_EF:
- jsp = NULL;
- break;
- case RC_FX:
- goto err;
- default:
- jsp = tjnp->GetRow();
- } // endswitch ReadDB
-
- } else
- jsp = tjsp->GetDoc()->GetValue(i);
-
- if (!(row = (jsp) ? jsp->GetObject() : NULL))
- break;
-
- } // endfor i
-
- if (tdp->Pretty != 2)
- tjnp->CloseDB(g);
-
- return n;
+ } // endif Driver
+
+ } else
+ tjnp = new(g) TDBJSN(tdp, new(g) DOSFAM(tdp));
+
+ tjnp->SetMode(MODE_READ);
+
+ // Allocate the parse work memory
+ PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL));
+ memset(G, 0, sizeof(GLOBAL));
+ G->Sarea_Size = tdp->Lrecl * 10;
+ G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size);
+ PlugSubSet(G->Sarea, G->Sarea_Size);
+ G->jump_level = 0;
+ tjnp->SetG(G);
+
+ if (tjnp->OpenDB(g))
+ return 0;
+
+ switch (tjnp->ReadDB(g)) {
+ case RC_EF:
+ strcpy(g->Message, "Void json table");
+ case RC_FX:
+ goto err;
+ default:
+ jsp = tjnp->GetRow();
+ } // endswitch ReadDB
+
+ } // endif pretty
+
+ if (!(row = (jsp) ? jsp->GetObject() : NULL)) {
+ strcpy(g->Message, "Can only retrieve columns from object rows");
+ goto err;
+ } // endif row
+
+ all = GetBooleanTableOption(g, topt, "Fullarray", false);
+ jcol.Name = jcol.Fmt = NULL;
+ jcol.Next = NULL;
+ jcol.Found = true;
+ colname[0] = 0;
+
+ if (!tdp->Uri) {
+ fmt[0] = '$';
+ fmt[1] = '.';
+ bf = 2;
+ } // endif Uri
+
+ /*********************************************************************/
+ /* Analyse the JSON tree and define columns. */
+ /*********************************************************************/
+ for (i = 1; ; i++) {
+ for (jpp = row->GetFirst(); jpp; jpp = jpp->GetNext()) {
+ strncpy(colname, jpp->GetKey(), 64);
+ fmt[bf] = 0;
+
+ if (Find(g, jpp->GetVal(), colname, MY_MIN(lvl, 0)))
+ goto err;
+
+ } // endfor jpp
+
+ // Missing column can be null
+ for (jcp = fjcp; jcp; jcp = jcp->Next) {
+ jcp->Cbn |= !jcp->Found;
+ jcp->Found = false;
+ } // endfor jcp
+
+ if (tdp->Pretty != 2) {
+ // Read next record
+ switch (tjnp->ReadDB(g)) {
+ case RC_EF:
+ jsp = NULL;
+ break;
+ case RC_FX:
+ goto err;
+ default:
+ jsp = tjnp->GetRow();
+ } // endswitch ReadDB
+
+ } else
+ jsp = tjsp->GetDoc()->GetValue(i);
+
+ if (!(row = (jsp) ? jsp->GetObject() : NULL))
+ break;
+
+ } // endfor i
+
+ if (tdp->Pretty != 2)
+ tjnp->CloseDB(g);
+
+ return n;
err:
- if (tdp->Pretty != 2)
- tjnp->CloseDB(g);
+ if (tdp->Pretty != 2)
+ tjnp->CloseDB(g);
- return 0;
-} // end of GetColumns
+ return 0;
+} // end of GetColumns
bool JSONDISC::Find(PGLOBAL g, PJVAL jvp, PCSZ key, int j)
{
- char *p, *pc = colname + strlen(colname);
- int ars;
- PJOB job;
- PJAR jar;
-
- if ((valp = jvp ? jvp->GetValue() : NULL)) {
- jcol.Type = valp->GetType();
- jcol.Len = valp->GetValLen();
- jcol.Scale = valp->GetValPrec();
- jcol.Cbn = valp->IsNull();
- } else if (!jvp || jvp->IsNull()) {
- jcol.Type = TYPE_UNKNOWN;
- jcol.Len = jcol.Scale = 0;
- jcol.Cbn = true;
- } else if (j < lvl) {
- if (!fmt[bf])
- strcat(fmt, colname);
-
- p = fmt + strlen(fmt);
- jsp = jvp->GetJson();
-
- switch (jsp->GetType()) {
- case TYPE_JOB:
- job = (PJOB)jsp;
-
- for (PJPR jrp = job->GetFirst(); jrp; jrp = jrp->GetNext()) {
- PCSZ k = jrp->GetKey();
-
- if (*k != '$') {
- strncat(strncat(fmt, sep, 128), k, 128);
- strncat(strncat(colname, "_", 64), k, 64);
- } // endif Key
-
- if (Find(g, jrp->GetVal(), k, j + 1))
- return true;
-
- *p = *pc = 0;
- } // endfor jrp
-
- return false;
- case TYPE_JAR:
- jar = (PJAR)jsp;
-
- if (all || (tdp->Xcol && !stricmp(tdp->Xcol, key)))
- ars = jar->GetSize(false);
- else
- ars = MY_MIN(jar->GetSize(false), 1);
-
- for (int k = 0; k < ars; k++) {
- if (!tdp->Xcol || stricmp(tdp->Xcol, key)) {
- sprintf(buf, "%d", k);
-
- if (tdp->Uri)
- strncat(strncat(fmt, sep, 128), buf, 128);
- else
- strncat(strncat(strncat(fmt, "[", 128), buf, 128), "]", 128);
-
- if (all)
- strncat(strncat(colname, "_", 64), buf, 64);
-
- } else
- strncat(fmt, (tdp->Uri ? sep : "[*]"), 128);
-
- if (Find(g, jar->GetValue(k), "", j))
- return true;
-
- *p = *pc = 0;
- } // endfor k
-
- return false;
- default:
- sprintf(g->Message, "Logical error after %s", fmt);
- return true;
- } // endswitch Type
-
- } else if (lvl >= 0) {
- jcol.Type = TYPE_STRING;
- jcol.Len = 256;
- jcol.Scale = 0;
- jcol.Cbn = true;
- } else
- return false;
-
- AddColumn(g);
- return false;
-} // end of Find
+ char *p, *pc = colname + strlen(colname);
+ int ars;
+ PJOB job;
+ PJAR jar;
+
+ if ((valp = jvp ? jvp->GetValue() : NULL)) {
+ jcol.Type = valp->GetType();
+ jcol.Len = valp->GetValLen();
+ jcol.Scale = valp->GetValPrec();
+ jcol.Cbn = valp->IsNull();
+ } else if (!jvp || jvp->IsNull()) {
+ jcol.Type = TYPE_UNKNOWN;
+ jcol.Len = jcol.Scale = 0;
+ jcol.Cbn = true;
+ } else if (j < lvl) {
+ if (!fmt[bf])
+ strcat(fmt, colname);
+
+ p = fmt + strlen(fmt);
+ jsp = jvp->GetJson();
+
+ switch (jsp->GetType()) {
+ case TYPE_JOB:
+ job = (PJOB)jsp;
+
+ for (PJPR jrp = job->GetFirst(); jrp; jrp = jrp->GetNext()) {
+ PCSZ k = jrp->GetKey();
+
+ if (*k != '$') {
+ strncat(strncat(fmt, sep, 128), k, 128);
+ strncat(strncat(colname, "_", 64), k, 64);
+ } // endif Key
+
+ if (Find(g, jrp->GetVal(), k, j + 1))
+ return true;
+
+ *p = *pc = 0;
+ } // endfor jrp
+
+ return false;
+ case TYPE_JAR:
+ jar = (PJAR)jsp;
+
+ if (all || (tdp->Xcol && !stricmp(tdp->Xcol, key)))
+ ars = jar->GetSize(false);
+ else
+ ars = MY_MIN(jar->GetSize(false), 1);
+
+ for (int k = 0; k < ars; k++) {
+ if (!tdp->Xcol || stricmp(tdp->Xcol, key)) {
+ sprintf(buf, "%d", k);
+
+ if (tdp->Uri)
+ strncat(strncat(fmt, sep, 128), buf, 128);
+ else
+ strncat(strncat(strncat(fmt, "[", 128), buf, 128), "]", 128);
+
+ if (all)
+ strncat(strncat(colname, "_", 64), buf, 64);
+
+ } else
+ strncat(fmt, (tdp->Uri ? sep : "[*]"), 128);
+
+ if (Find(g, jar->GetValue(k), "", j))
+ return true;
+
+ *p = *pc = 0;
+ } // endfor k
+
+ return false;
+ default:
+ sprintf(g->Message, "Logical error after %s", fmt);
+ return true;
+ } // endswitch Type
+
+ } else if (lvl >= 0) {
+ jcol.Type = TYPE_STRING;
+ jcol.Len = 256;
+ jcol.Scale = 0;
+ jcol.Cbn = true;
+ } else
+ return false;
+
+ AddColumn(g);
+ return false;
+} // end of Find
void JSONDISC::AddColumn(PGLOBAL g)
{
- bool b = fmt[bf] != 0; // True if formatted
-
- // Check whether this column was already found
- for (jcp = fjcp; jcp; jcp = jcp->Next)
- if (!strcmp(colname, jcp->Name))
- break;
-
- if (jcp) {
- if (jcp->Type != jcol.Type) {
- if (jcp->Type == TYPE_UNKNOWN)
- jcp->Type = jcol.Type;
- else if (jcol.Type != TYPE_UNKNOWN)
- jcp->Type = TYPE_STRING;
-
- } // endif Type
-
- if (b && (!jcp->Fmt || strlen(jcp->Fmt) < strlen(fmt))) {
- jcp->Fmt = PlugDup(g, fmt);
- length[7] = MY_MAX(length[7], strlen(fmt));
- } // endif fmt
-
- jcp->Len = MY_MAX(jcp->Len, jcol.Len);
- jcp->Scale = MY_MAX(jcp->Scale, jcol.Scale);
- jcp->Cbn |= jcol.Cbn;
- jcp->Found = true;
- } else if (jcol.Type != TYPE_UNKNOWN || tdp->Accept) {
- // New column
- jcp = (PJCL)PlugSubAlloc(g, NULL, sizeof(JCOL));
- *jcp = jcol;
- jcp->Cbn |= (i > 1);
- jcp->Name = PlugDup(g, colname);
- length[0] = MY_MAX(length[0], strlen(colname));
-
- if (b) {
- jcp->Fmt = PlugDup(g, fmt);
- length[7] = MY_MAX(length[7], strlen(fmt));
- } else
- jcp->Fmt = NULL;
-
- if (pjcp) {
- jcp->Next = pjcp->Next;
- pjcp->Next = jcp;
- } else
- fjcp = jcp;
-
- n++;
- } // endif jcp
-
- if (jcp)
- pjcp = jcp;
+ bool b = fmt[bf] != 0; // True if formatted
+
+ // Check whether this column was already found
+ for (jcp = fjcp; jcp; jcp = jcp->Next)
+ if (!strcmp(colname, jcp->Name))
+ break;
+
+ if (jcp) {
+ if (jcp->Type != jcol.Type) {
+ if (jcp->Type == TYPE_UNKNOWN)
+ jcp->Type = jcol.Type;
+ else if (jcol.Type != TYPE_UNKNOWN)
+ jcp->Type = TYPE_STRING;
+
+ } // endif Type
+
+ if (b && (!jcp->Fmt || strlen(jcp->Fmt) < strlen(fmt))) {
+ jcp->Fmt = PlugDup(g, fmt);
+ length[7] = MY_MAX(length[7], strlen(fmt));
+ } // endif fmt
+
+ jcp->Len = MY_MAX(jcp->Len, jcol.Len);
+ jcp->Scale = MY_MAX(jcp->Scale, jcol.Scale);
+ jcp->Cbn |= jcol.Cbn;
+ jcp->Found = true;
+ } else if (jcol.Type != TYPE_UNKNOWN || tdp->Accept) {
+ // New column
+ jcp = (PJCL)PlugSubAlloc(g, NULL, sizeof(JCOL));
+ *jcp = jcol;
+ jcp->Cbn |= (i > 1);
+ jcp->Name = PlugDup(g, colname);
+ length[0] = MY_MAX(length[0], strlen(colname));
+
+ if (b) {
+ jcp->Fmt = PlugDup(g, fmt);
+ length[7] = MY_MAX(length[7], strlen(fmt));
+ } else
+ jcp->Fmt = NULL;
+
+ if (pjcp) {
+ jcp->Next = pjcp->Next;
+ pjcp->Next = jcp;
+ } else
+ fjcp = jcp;
+
+ n++;
+ } // endif jcp
+
+ if (jcp)
+ pjcp = jcp;
} // end of AddColumn
@@ -550,13 +550,13 @@ JSONDEF::JSONDEF(void)
Limit = 1;
Base = 0;
Strict = false;
- Sep = '.';
- Uri = NULL;
- Collname = Options = Filter = NULL;
- Pipe = false;
- Driver = NULL;
- Version = 0;
- Wrapname = NULL;
+ Sep = '.';
+ Uri = NULL;
+ Collname = Options = Filter = NULL;
+ Pipe = false;
+ Driver = NULL;
+ Version = 0;
+ Wrapname = NULL;
} // end of JSONDEF constructor
/***********************************************************************/
@@ -564,41 +564,41 @@ JSONDEF::JSONDEF(void)
/***********************************************************************/
bool JSONDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
{
- Schema = GetStringCatInfo(g, "DBname", Schema);
- Jmode = (JMODE)GetIntCatInfo("Jmode", MODE_OBJECT);
+ Schema = GetStringCatInfo(g, "DBname", Schema);
+ Jmode = (JMODE)GetIntCatInfo("Jmode", MODE_OBJECT);
Objname = GetStringCatInfo(g, "Object", NULL);
Xcol = GetStringCatInfo(g, "Expand", NULL);
Pretty = GetIntCatInfo("Pretty", 2);
Limit = GetIntCatInfo("Limit", 10);
Base = GetIntCatInfo("Base", 0) ? 1 : 0;
- Sep = *GetStringCatInfo(g, "Separator", ".");
- Accept = GetBoolCatInfo("Accept", false);
+ Sep = *GetStringCatInfo(g, "Separator", ".");
+ Accept = GetBoolCatInfo("Accept", false);
- // Don't use url as uri when called from REST OEM module
- if (stricmp(am, "REST") && (Uri = GetStringCatInfo(g, "Connect", NULL))) {
+ // Don't use url as MONGO uri when called from REST
+ if (stricmp(am, "REST") && (Uri = GetStringCatInfo(g, "Connect", NULL))) {
#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
- Collname = GetStringCatInfo(g, "Name",
- (Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name);
- Collname = GetStringCatInfo(g, "Tabname", Collname);
- Options = GetStringCatInfo(g, "Colist", NULL);
- Filter = GetStringCatInfo(g, "Filter", NULL);
- Pipe = GetBoolCatInfo("Pipeline", false);
- Driver = GetStringCatInfo(g, "Driver", NULL);
- Version = GetIntCatInfo("Version", 3);
- Pretty = 0;
+ Collname = GetStringCatInfo(g, "Name",
+ (Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name);
+ Collname = GetStringCatInfo(g, "Tabname", Collname);
+ Options = GetStringCatInfo(g, "Colist", NULL);
+ Filter = GetStringCatInfo(g, "Filter", NULL);
+ Pipe = GetBoolCatInfo("Pipeline", false);
+ Driver = GetStringCatInfo(g, "Driver", NULL);
+ Version = GetIntCatInfo("Version", 3);
+ Pretty = 0;
#if defined(JAVA_SUPPORT)
- if (Version == 2)
- Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo2Interface");
- else
- Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo3Interface");
+ if (Version == 2)
+ Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo2Interface");
+ else
+ Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo3Interface");
#endif // JAVA_SUPPORT
#else // !MONGO_SUPPORT
- sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
- return true;
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
+ return true;
#endif // !MONGO_SUPPORT
- } // endif Uri
+ } // endif Uri
- return DOSDEF::DefineAM(g, (Uri ? "XMGO" : "DOS"), poff);
+ return DOSDEF::DefineAM(g, (Uri ? "XMGO" : "DOS"), poff);
} // end of DefineAM
/***********************************************************************/
@@ -606,6 +606,9 @@ bool JSONDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
/***********************************************************************/
PTDB JSONDEF::GetTable(PGLOBAL g, MODE m)
{
+ if (trace(1))
+ htrc("JSON GetTable Pretty=%d Uri=%s\n", Pretty, SVP(Uri));
+
if (Catfunc == FNC_COL)
return new(g)TDBJCL(this);
@@ -620,47 +623,47 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m)
!(tmp == TMP_FORCE &&
(m == MODE_UPDATE || m == MODE_DELETE));
- if (Uri) {
- if (Driver && toupper(*Driver) == 'C') {
+ if (Uri) {
+ if (Driver && toupper(*Driver) == 'C') {
#if defined(CMGO_SUPPORT)
- txfp = new(g) CMGFAM(this);
+ txfp = new(g) CMGFAM(this);
#else
- sprintf(g->Message, "Mongo %s Driver not available", "C");
- return NULL;
+ sprintf(g->Message, "Mongo %s Driver not available", "C");
+ return NULL;
#endif
- } else if (Driver && toupper(*Driver) == 'J') {
+ } else if (Driver && toupper(*Driver) == 'J') {
#if defined(JAVA_SUPPORT)
- txfp = new(g) JMGFAM(this);
+ txfp = new(g) JMGFAM(this);
#else
- sprintf(g->Message, "Mongo %s Driver not available", "Java");
- return NULL;
+ sprintf(g->Message, "Mongo %s Driver not available", "Java");
+ return NULL;
#endif
- } else { // Driver not specified
+ } else { // Driver not specified
#if defined(CMGO_SUPPORT)
- txfp = new(g) CMGFAM(this);
+ txfp = new(g) CMGFAM(this);
#elif defined(JAVA_SUPPORT)
- txfp = new(g) JMGFAM(this);
-#else // !MONGO_SUPPORT
- sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
- return NULL;
+ txfp = new(g) JMGFAM(this);
+#else // !MONGO_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
+ return NULL;
#endif // !MONGO_SUPPORT
- } // endif Driver
+ } // endif Driver
- } else if (Zipped) {
+ } else if (Zipped) {
#if defined(ZIP_SUPPORT)
- if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) {
- txfp = new(g) UNZFAM(this);
- } else if (m == MODE_INSERT) {
- txfp = new(g) ZIPFAM(this);
- } else {
- strcpy(g->Message, "UPDATE/DELETE not supported for ZIP");
- return NULL;
- } // endif's m
+ if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) {
+ txfp = new(g) UNZFAM(this);
+ } else if (m == MODE_INSERT) {
+ txfp = new(g) ZIPFAM(this);
+ } else {
+ strcpy(g->Message, "UPDATE/DELETE not supported for ZIP");
+ return NULL;
+ } // endif's m
#else // !ZIP_SUPPORT
- sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
- return NULL;
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
+ return NULL;
#endif // !ZIP_SUPPORT
- } else if (Compressed) {
+ } else if (Compressed) {
#if defined(GZ_SUPPORT)
if (Compressed == 1)
txfp = new(g) GZFAM(this);
@@ -670,7 +673,7 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m)
sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "GZ");
return NULL;
#endif // !GZ_SUPPORT
- } else if (map)
+ } else if (map)
txfp = new(g) MAPFAM(this);
else
txfp = new(g) DOSFAM(this);
@@ -678,41 +681,41 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m)
// Txfp must be set for TDBDOS
tdbp = new(g) TDBJSN(this, txfp);
- if (Lrecl) {
- // Allocate the parse work memory
- PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL));
- memset(G, 0, sizeof(GLOBAL));
- G->Sarea_Size = Lrecl * 10;
- G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size);
- PlugSubSet(G->Sarea, G->Sarea_Size);
- G->jump_level = 0;
- ((TDBJSN*)tdbp)->G = G;
- } else {
- strcpy(g->Message, "LRECL is not defined");
- return NULL;
- } // endif Lrecl
-
- } else {
- if (Zipped) {
+ if (Lrecl) {
+ // Allocate the parse work memory
+ PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL));
+ memset(G, 0, sizeof(GLOBAL));
+ G->Sarea_Size = Lrecl * 10;
+ G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size);
+ PlugSubSet(G->Sarea, G->Sarea_Size);
+ G->jump_level = 0;
+ ((TDBJSN*)tdbp)->G = G;
+ } else {
+ strcpy(g->Message, "LRECL is not defined");
+ return NULL;
+ } // endif Lrecl
+
+ } else {
+ if (Zipped) {
#if defined(ZIP_SUPPORT)
- if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) {
- txfp = new(g) UNZFAM(this);
- } else if (m == MODE_INSERT) {
- strcpy(g->Message, "INSERT supported only for zipped JSON when pretty=0");
- return NULL;
- } else {
- strcpy(g->Message, "UPDATE/DELETE not supported for ZIP");
- return NULL;
- } // endif's m
+ if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) {
+ txfp = new(g) UNZFAM(this);
+ } else if (m == MODE_INSERT) {
+ strcpy(g->Message, "INSERT supported only for zipped JSON when pretty=0");
+ return NULL;
+ } else {
+ strcpy(g->Message, "UPDATE/DELETE not supported for ZIP");
+ return NULL;
+ } // endif's m
#else // !ZIP_SUPPORT
- sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
- return NULL;
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
+ return NULL;
#endif // !ZIP_SUPPORT
- } else
- txfp = new(g) MAPFAM(this);
+ } else
+ txfp = new(g) MAPFAM(this);
tdbp = new(g) TDBJSON(this, txfp);
- ((TDBJSON*)tdbp)->G = g;
+ ((TDBJSON*)tdbp)->G = g;
} // endif Pretty
if (Multiple)
@@ -740,16 +743,16 @@ TDBJSN::TDBJSN(PJDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp)
Limit = tdp->Limit;
Pretty = tdp->Pretty;
B = tdp->Base ? 1 : 0;
- Sep = tdp->Sep;
+ Sep = tdp->Sep;
Strict = tdp->Strict;
} else {
Jmode = MODE_OBJECT;
Objname = NULL;
- Xcol = NULL;
+ Xcol = NULL;
Limit = 1;
Pretty = 0;
B = 0;
- Sep = '.';
+ Sep = '.';
Strict = false;
} // endif tdp
@@ -763,7 +766,7 @@ TDBJSN::TDBJSN(PJDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp)
TDBJSN::TDBJSN(TDBJSN *tdbp) : TDBDOS(NULL, tdbp)
{
- G = NULL;
+ G = NULL;
Top = tdbp->Top;
Row = tdbp->Row;
Val = tdbp->Val;
@@ -779,7 +782,7 @@ TDBJSN::TDBJSN(TDBJSN *tdbp) : TDBDOS(NULL, tdbp)
SameRow = tdbp->SameRow;
Xval = tdbp->Xval;
B = tdbp->B;
- Sep = tdbp->Sep;
+ Sep = tdbp->Sep;
Pretty = tdbp->Pretty;
Strict = tdbp->Strict;
Comma = tdbp->Comma;
@@ -788,7 +791,7 @@ TDBJSN::TDBJSN(TDBJSN *tdbp) : TDBDOS(NULL, tdbp)
// Used for update
PTDB TDBJSN::Clone(PTABS t)
{
- G = NULL;
+ G = NULL;
PTDB tp;
PJCOL cp1, cp2;
PGLOBAL g = t->G;
@@ -862,33 +865,33 @@ PJSON TDBJSN::FindRow(PGLOBAL g)
PJSON jsp = Row;
PJVAL val = NULL;
- for (objpath = PlugDup(g, Objname); jsp && objpath; objpath = p) {
- if ((p = strchr(objpath, Sep)))
- *p++ = 0;
+ for (objpath = PlugDup(g, Objname); jsp && objpath; objpath = p) {
+ if ((p = strchr(objpath, Sep)))
+ *p++ = 0;
- if (*objpath != '[' && !IsNum(objpath)) { // objpass is a key
- val = (jsp->GetType() == TYPE_JOB) ?
- jsp->GetObject()->GetValue(objpath) : NULL;
- } else {
- if (*objpath == '[') {
- if (objpath[strlen(objpath) - 1] == ']')
- objpath++;
- else
- return NULL;
- } // endif [
+ if (*objpath != '[' && !IsNum(objpath)) { // objpass is a key
+ val = (jsp->GetType() == TYPE_JOB) ?
+ jsp->GetObject()->GetValue(objpath) : NULL;
+ } else {
+ if (*objpath == '[') {
+ if (objpath[strlen(objpath) - 1] == ']')
+ objpath++;
+ else
+ return NULL;
+ } // endif [
- val = (jsp->GetType() == TYPE_JAR) ?
- jsp->GetArray()->GetValue(atoi(objpath) - B) : NULL;
- } // endif objpath
+ val = (jsp->GetType() == TYPE_JAR) ?
+ jsp->GetArray()->GetValue(atoi(objpath) - B) : NULL;
+ } // endif objpath
- jsp = (val) ? val->GetJson() : NULL;
- } // endfor objpath
+ jsp = (val) ? val->GetJson() : NULL;
+ } // endfor objpath
return jsp;
} // end of FindRow
/***********************************************************************/
-/* OpenDB: Data Base open routine for JSN access method. */
+/* OpenDB: Data Base open routine for JSN access method. */
/***********************************************************************/
bool TDBJSN::OpenDB(PGLOBAL g)
{
@@ -913,15 +916,15 @@ bool TDBJSN::OpenDB(PGLOBAL g)
return true;
} // endswitch Jmode
- } // endif Use
+ } // endif Use
- if (TDBDOS::OpenDB(g))
- return true;
+ if (TDBDOS::OpenDB(g))
+ return true;
- if (Xcol)
- To_Filter = NULL; // Imcompatible
+ if (Xcol)
+ To_Filter = NULL; // Imcompatible
- return false;
+ return false;
} // end of OpenDB
/***********************************************************************/
@@ -971,27 +974,27 @@ int TDBJSN::ReadDB(PGLOBAL g)
NextSame = 0;
M++;
return RC_OK;
- } else if ((rc = TDBDOS::ReadDB(g)) == RC_OK) {
- if (!IsRead() && ((rc = ReadBuffer(g)) != RC_OK))
- // Deferred reading failed
- return rc;
-
- // Recover the memory used for parsing
- PlugSubSet(G->Sarea, G->Sarea_Size);
-
- if ((Row = ParseJson(G, To_Line, strlen(To_Line), &Pretty, &Comma))) {
- Row = FindRow(g);
- SameRow = 0;
- Fpos++;
- M = 1;
- rc = RC_OK;
- } else if (Pretty != 1 || strcmp(To_Line, "]")) {
- strcpy(g->Message, G->Message);
- rc = RC_FX;
- } else
- rc = RC_EF;
-
- } // endif ReadDB
+ } else if ((rc = TDBDOS::ReadDB(g)) == RC_OK) {
+ if (!IsRead() && ((rc = ReadBuffer(g)) != RC_OK))
+ // Deferred reading failed
+ return rc;
+
+ // Recover the memory used for parsing
+ PlugSubSet(G->Sarea, G->Sarea_Size);
+
+ if ((Row = ParseJson(G, To_Line, strlen(To_Line), &Pretty, &Comma))) {
+ Row = FindRow(g);
+ SameRow = 0;
+ Fpos++;
+ M = 1;
+ rc = RC_OK;
+ } else if (Pretty != 1 || strcmp(To_Line, "]")) {
+ strcpy(g->Message, G->Message);
+ rc = RC_FX;
+ } else
+ rc = RC_EF;
+
+ } // endif ReadDB
return rc;
} // end of ReadDB
@@ -1001,68 +1004,68 @@ int TDBJSN::ReadDB(PGLOBAL g)
/***********************************************************************/
int TDBJSN::MakeTopTree(PGLOBAL g, PJSON jsp)
{
- if (Objname) {
- if (!Val) {
- // Parse and allocate Objname item(s)
- char *p;
- char *objpath = PlugDup(g, Objname);
- int i;
- PJOB objp;
- PJAR arp;
- PJVAL val = NULL;
+ if (Objname) {
+ if (!Val) {
+ // Parse and allocate Objname item(s)
+ char *p;
+ char *objpath = PlugDup(g, Objname);
+ int i;
+ PJOB objp;
+ PJAR arp;
+ PJVAL val = NULL;
- Top = NULL;
+ Top = NULL;
- for (; objpath; objpath = p) {
- if ((p = strchr(objpath, Sep)))
- *p++ = 0;
+ for (; objpath; objpath = p) {
+ if ((p = strchr(objpath, Sep)))
+ *p++ = 0;
- if (*objpath != '[' && !IsNum(objpath)) {
- objp = new(g) JOBJECT;
+ if (*objpath != '[' && !IsNum(objpath)) {
+ objp = new(g) JOBJECT;
- if (!Top)
- Top = objp;
+ if (!Top)
+ Top = objp;
- if (val)
- val->SetValue(objp);
+ if (val)
+ val->SetValue(objp);
- val = new(g) JVALUE;
- objp->SetValue(g, val, objpath);
- } else {
- if (*objpath == '[') {
- // Old style
- if (objpath[strlen(objpath) - 1] != ']') {
- sprintf(g->Message, "Invalid Table path %s", Objname);
- return RC_FX;
- } else
- objpath++;
+ val = new(g) JVALUE;
+ objp->SetValue(g, val, objpath);
+ } else {
+ if (*objpath == '[') {
+ // Old style
+ if (objpath[strlen(objpath) - 1] != ']') {
+ sprintf(g->Message, "Invalid Table path %s", Objname);
+ return RC_FX;
+ } else
+ objpath++;
- } // endif objpath
+ } // endif objpath
- arp = new(g) JARRAY;
+ arp = new(g) JARRAY;
- if (!Top)
- Top = arp;
+ if (!Top)
+ Top = arp;
- if (val)
- val->SetValue(arp);
+ if (val)
+ val->SetValue(arp);
- val = new(g) JVALUE;
- i = atoi(objpath) - B;
- arp->SetValue(g, val, i);
- arp->InitArray(g);
- } // endif objpath
+ val = new(g) JVALUE;
+ i = atoi(objpath) - B;
+ arp->SetValue(g, val, i);
+ arp->InitArray(g);
+ } // endif objpath
- } // endfor p
+ } // endfor p
- Val = val;
- } // endif Val
+ Val = val;
+ } // endif Val
- Val->SetValue(jsp);
- } else
- Top = jsp;
+ Val->SetValue(jsp);
+ } else
+ Top = jsp;
- return RC_OK;
+ return RC_OK;
} // end of MakeTopTree
/***********************************************************************/
@@ -1097,11 +1100,11 @@ int TDBJSN::MakeTopTree(PGLOBAL g, PJSON jsp)
/***********************************************************************/
int TDBJSN::WriteDB(PGLOBAL g)
{
- int rc = TDBDOS::WriteDB(g);
+ int rc = TDBDOS::WriteDB(g);
- PlugSubSet(G->Sarea, G->Sarea_Size);
- Row->Clear();
- return rc;
+ PlugSubSet(G->Sarea, G->Sarea_Size);
+ Row->Clear();
+ return rc;
} // end of WriteDB
/* ---------------------------- JSONCOL ------------------------------ */
@@ -1113,12 +1116,12 @@ JSONCOL::JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
: DOSCOL(g, cdp, tdbp, cprec, i, "DOS")
{
Tjp = (TDBJSN *)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp);
- G = Tjp->G;
+ G = Tjp->G;
Jpath = cdp->GetFmt();
MulVal = NULL;
Nodes = NULL;
Nod = 0;
- Sep = Tjp->Sep;
+ Sep = Tjp->Sep;
Xnod = -1;
Xpd = false;
Parsed = false;
@@ -1130,14 +1133,14 @@ JSONCOL::JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
/***********************************************************************/
JSONCOL::JSONCOL(JSONCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp)
{
- G = col1->G;
+ G = col1->G;
Tjp = col1->Tjp;
Jpath = col1->Jpath;
MulVal = col1->MulVal;
Nodes = col1->Nodes;
Nod = col1->Nod;
- Sep = col1->Sep;
- Xnod = col1->Xnod;
+ Sep = col1->Sep;
+ Xnod = col1->Xnod;
Xpd = col1->Xpd;
Parsed = col1->Parsed;
} // end of JSONCOL copy constructor
@@ -1155,7 +1158,7 @@ bool JSONCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
return true;
Tjp = (TDBJSN*)To_Tdb;
- G = Tjp->G;
+ G = Tjp->G;
return false;
} // end of SetBuffer
@@ -1181,130 +1184,130 @@ bool JSONCOL::CheckExpand(PGLOBAL g, int i, PSZ nm, bool b)
/***********************************************************************/
bool JSONCOL::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
{
- int n;
- bool dg = true, b = false;
- PJNODE jnp = &Nodes[i];
-
- //if (*p == '[') p++; // Old syntax .[ or :[
- n = (int)strlen(p);
-
- if (*p) {
- if (p[n - 1] == ']') {
- p[--n] = 0;
- } else if (!IsNum(p)) {
- // Wrong array specification
- sprintf(g->Message, "Invalid array specification %s for %s", p, Name);
- return true;
- } // endif p
-
- } else
- b = true;
-
- // To check whether a numeric Rank was specified
- dg = IsNum(p);
-
- if (!n) {
- // Default specifications
- if (CheckExpand(g, i, nm, false))
- return true;
- else if (jnp->Op != OP_EXP) {
- if (b) {
- // Return 1st value (B is the index base)
- jnp->Rank = Tjp->B;
- jnp->Op = OP_EQ;
- } else if (!Value->IsTypeNum()) {
- jnp->CncVal = AllocateValue(g, (void*)", ", TYPE_STRING);
- jnp->Op = OP_CNC;
- } else
- jnp->Op = OP_ADD;
-
- } // endif OP
-
- } else if (dg) {
- // Return nth value
- jnp->Rank = atoi(p) - Tjp->B;
- jnp->Op = OP_EQ;
- } else if (n == 1) {
- // Set the Op value;
- if (Sep == ':')
- switch (*p) {
- case '*': *p = 'x'; break;
- case 'x':
- case 'X': *p = '*'; break; // Expand this array
- default: break;
- } // endswitch p
-
- switch (*p) {
- case '+': jnp->Op = OP_ADD; break;
- case 'x': jnp->Op = OP_MULT; break;
- case '>': jnp->Op = OP_MAX; break;
- case '<': jnp->Op = OP_MIN; break;
- case '!': jnp->Op = OP_SEP; break; // Average
- case '#': jnp->Op = OP_NUM; break;
- case '*': // Expand this array
- if (!Tjp->Xcol && nm) {
- Xpd = true;
- jnp->Op = OP_EXP;
- Tjp->Xval = i;
- Tjp->Xcol = nm;
- } else if (CheckExpand(g, i, nm, true))
- return true;
-
- break;
- default:
- sprintf(g->Message,
- "Invalid function specification %c for %s", *p, Name);
- return true;
- } // endswitch *p
-
- } else if (*p == '"' && p[n - 1] == '"') {
- // This is a concat specification
- jnp->Op = OP_CNC;
-
- if (n > 2) {
- // Set concat intermediate string
- p[n - 1] = 0;
- jnp->CncVal = AllocateValue(g, p + 1, TYPE_STRING);
- } // endif n
-
- } else {
- sprintf(g->Message, "Wrong array specification for %s", Name);
- return true;
- } // endif's
-
- // For calculated arrays, a local Value must be used
- switch (jnp->Op) {
- case OP_NUM:
- jnp->Valp = AllocateValue(g, TYPE_INT);
- break;
- case OP_ADD:
- case OP_MULT:
- case OP_SEP:
- if (!IsTypeChar(Buf_Type))
- jnp->Valp = AllocateValue(g, Buf_Type, 0, GetPrecision());
- else
- jnp->Valp = AllocateValue(g, TYPE_DOUBLE, 0, 2);
-
- break;
- case OP_MIN:
- case OP_MAX:
- jnp->Valp = AllocateValue(g, Buf_Type, Long, GetPrecision());
- break;
- case OP_CNC:
- if (IsTypeChar(Buf_Type))
- jnp->Valp = AllocateValue(g, TYPE_STRING, Long, GetPrecision());
- else
- jnp->Valp = AllocateValue(g, TYPE_STRING, 512);
-
- break;
- default:
- break;
- } // endswitch Op
-
- if (jnp->Valp)
- MulVal = AllocateValue(g, jnp->Valp);
-
- return false;
+ int n;
+ bool dg = true, b = false;
+ PJNODE jnp = &Nodes[i];
+
+ //if (*p == '[') p++; // Old syntax .[ or :[
+ n = (int)strlen(p);
+
+ if (*p) {
+ if (p[n - 1] == ']') {
+ p[--n] = 0;
+ } else if (!IsNum(p)) {
+ // Wrong array specification
+ sprintf(g->Message, "Invalid array specification %s for %s", p, Name);
+ return true;
+ } // endif p
+
+ } else
+ b = true;
+
+ // To check whether a numeric Rank was specified
+ dg = IsNum(p);
+
+ if (!n) {
+ // Default specifications
+ if (CheckExpand(g, i, nm, false))
+ return true;
+ else if (jnp->Op != OP_EXP) {
+ if (b) {
+ // Return 1st value (B is the index base)
+ jnp->Rank = Tjp->B;
+ jnp->Op = OP_EQ;
+ } else if (!Value->IsTypeNum()) {
+ jnp->CncVal = AllocateValue(g, (void*)", ", TYPE_STRING);
+ jnp->Op = OP_CNC;
+ } else
+ jnp->Op = OP_ADD;
+
+ } // endif OP
+
+ } else if (dg) {
+ // Return nth value
+ jnp->Rank = atoi(p) - Tjp->B;
+ jnp->Op = OP_EQ;
+ } else if (n == 1) {
+ // Set the Op value;
+ if (Sep == ':')
+ switch (*p) {
+ case '*': *p = 'x'; break;
+ case 'x':
+ case 'X': *p = '*'; break; // Expand this array
+ default: break;
+ } // endswitch p
+
+ switch (*p) {
+ case '+': jnp->Op = OP_ADD; break;
+ case 'x': jnp->Op = OP_MULT; break;
+ case '>': jnp->Op = OP_MAX; break;
+ case '<': jnp->Op = OP_MIN; break;
+ case '!': jnp->Op = OP_SEP; break; // Average
+ case '#': jnp->Op = OP_NUM; break;
+ case '*': // Expand this array
+ if (!Tjp->Xcol && nm) {
+ Xpd = true;
+ jnp->Op = OP_EXP;
+ Tjp->Xval = i;
+ Tjp->Xcol = nm;
+ } else if (CheckExpand(g, i, nm, true))
+ return true;
+
+ break;
+ default:
+ sprintf(g->Message,
+ "Invalid function specification %c for %s", *p, Name);
+ return true;
+ } // endswitch *p
+
+ } else if (*p == '"' && p[n - 1] == '"') {
+ // This is a concat specification
+ jnp->Op = OP_CNC;
+
+ if (n > 2) {
+ // Set concat intermediate string
+ p[n - 1] = 0;
+ jnp->CncVal = AllocateValue(g, p + 1, TYPE_STRING);
+ } // endif n
+
+ } else {
+ sprintf(g->Message, "Wrong array specification for %s", Name);
+ return true;
+ } // endif's
+
+ // For calculated arrays, a local Value must be used
+ switch (jnp->Op) {
+ case OP_NUM:
+ jnp->Valp = AllocateValue(g, TYPE_INT);
+ break;
+ case OP_ADD:
+ case OP_MULT:
+ case OP_SEP:
+ if (!IsTypeChar(Buf_Type))
+ jnp->Valp = AllocateValue(g, Buf_Type, 0, GetPrecision());
+ else
+ jnp->Valp = AllocateValue(g, TYPE_DOUBLE, 0, 2);
+
+ break;
+ case OP_MIN:
+ case OP_MAX:
+ jnp->Valp = AllocateValue(g, Buf_Type, Long, GetPrecision());
+ break;
+ case OP_CNC:
+ if (IsTypeChar(Buf_Type))
+ jnp->Valp = AllocateValue(g, TYPE_STRING, Long, GetPrecision());
+ else
+ jnp->Valp = AllocateValue(g, TYPE_STRING, 512);
+
+ break;
+ default:
+ break;
+ } // endswitch Op
+
+ if (jnp->Valp)
+ MulVal = AllocateValue(g, jnp->Valp);
+
+ return false;
} // end of SetArrayOptions
/***********************************************************************/
@@ -1315,87 +1318,87 @@ bool JSONCOL::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
/***********************************************************************/
bool JSONCOL::ParseJpath(PGLOBAL g)
{
- char *p, *p1 = NULL, *p2 = NULL, *pbuf = NULL;
- int i;
- bool a;
-
- if (Parsed)
- return false; // Already done
- else if (InitValue(g))
- return true;
- else if (!Jpath)
- Jpath = Name;
-
- if (To_Tdb->GetOrig()) {
- // This is an updated column, get nodes from origin
- for (PJCOL colp = (PJCOL)Tjp->GetColumns(); colp;
- colp = (PJCOL)colp->GetNext())
- if (!stricmp(Name, colp->GetName())) {
- Nod = colp->Nod;
- Nodes = colp->Nodes;
- Xpd = colp->Xpd;
- goto fin;
- } // endif Name
-
- sprintf(g->Message, "Cannot parse updated column %s", Name);
- return true;
- } // endif To_Orig
-
- pbuf = PlugDup(g, Jpath);
- if (*pbuf == '$') pbuf++;
- if (*pbuf == Sep) pbuf++;
- if (*pbuf == '[') p1 = pbuf++;
-
- // Estimate the required number of nodes
- for (i = 0, p = pbuf; (p = NextChr(p, Sep)); i++, p++)
- Nod++; // One path node found
-
- Nodes = (PJNODE)PlugSubAlloc(g, NULL, (++Nod) * sizeof(JNODE));
- memset(Nodes, 0, (Nod) * sizeof(JNODE));
-
- // Analyze the Jpath for this column
- for (i = 0, p = pbuf; p && i < Nod; i++, p = (p2 ? p2 : NULL)) {
- a = (p1 != NULL);
- p1 = strchr(p, '[');
- p2 = strchr(p, Sep);
-
- if (!p2)
- p2 = p1;
- else if (p1) {
- if (p1 < p2)
- p2 = p1;
- else if (p1 == p2 + 1)
- *p2++ = 0; // Old syntax .[ or :[
- else
- p1 = NULL;
-
- } // endif p1
-
- if (p2)
- *p2++ = 0;
-
- // Jpath must be explicit
- if (a || *p == 0 || *p == '[' || IsNum(p)) {
- // Analyse intermediate array processing
- if (SetArrayOptions(g, p, i, Nodes[i - 1].Key))
- return true;
-
- } else if (*p == '*') {
- // Return JSON
- Nodes[i].Op = OP_XX;
- } else {
- Nodes[i].Key = p;
- Nodes[i].Op = OP_EXIST;
- } // endif's
-
- } // endfor i, p
-
- Nod = i;
+ char *p, *p1 = NULL, *p2 = NULL, *pbuf = NULL;
+ int i;
+ bool a;
+
+ if (Parsed)
+ return false; // Already done
+ else if (InitValue(g))
+ return true;
+ else if (!Jpath)
+ Jpath = Name;
+
+ if (To_Tdb->GetOrig()) {
+ // This is an updated column, get nodes from origin
+ for (PJCOL colp = (PJCOL)Tjp->GetColumns(); colp;
+ colp = (PJCOL)colp->GetNext())
+ if (!stricmp(Name, colp->GetName())) {
+ Nod = colp->Nod;
+ Nodes = colp->Nodes;
+ Xpd = colp->Xpd;
+ goto fin;
+ } // endif Name
+
+ sprintf(g->Message, "Cannot parse updated column %s", Name);
+ return true;
+ } // endif To_Orig
+
+ pbuf = PlugDup(g, Jpath);
+ if (*pbuf == '$') pbuf++;
+ if (*pbuf == Sep) pbuf++;
+ if (*pbuf == '[') p1 = pbuf++;
+
+ // Estimate the required number of nodes
+ for (i = 0, p = pbuf; (p = NextChr(p, Sep)); i++, p++)
+ Nod++; // One path node found
+
+ Nodes = (PJNODE)PlugSubAlloc(g, NULL, (++Nod) * sizeof(JNODE));
+ memset(Nodes, 0, (Nod) * sizeof(JNODE));
+
+ // Analyze the Jpath for this column
+ for (i = 0, p = pbuf; p && i < Nod; i++, p = (p2 ? p2 : NULL)) {
+ a = (p1 != NULL);
+ p1 = strchr(p, '[');
+ p2 = strchr(p, Sep);
+
+ if (!p2)
+ p2 = p1;
+ else if (p1) {
+ if (p1 < p2)
+ p2 = p1;
+ else if (p1 == p2 + 1)
+ *p2++ = 0; // Old syntax .[ or :[
+ else
+ p1 = NULL;
+
+ } // endif p1
+
+ if (p2)
+ *p2++ = 0;
+
+ // Jpath must be explicit
+ if (a || *p == 0 || *p == '[' || IsNum(p)) {
+ // Analyse intermediate array processing
+ if (SetArrayOptions(g, p, i, Nodes[i - 1].Key))
+ return true;
+
+ } else if (*p == '*') {
+ // Return JSON
+ Nodes[i].Op = OP_XX;
+ } else {
+ Nodes[i].Key = p;
+ Nodes[i].Op = OP_EXIST;
+ } // endif's
+
+ } // endfor i, p
+
+ Nod = i;
fin:
- MulVal = AllocateValue(g, Value);
- Parsed = true;
- return false;
+ MulVal = AllocateValue(g, Value);
+ Parsed = true;
+ return false;
} // end of ParseJpath
/***********************************************************************/
@@ -1403,66 +1406,66 @@ fin:
/***********************************************************************/
PSZ JSONCOL::GetJpath(PGLOBAL g, bool proj)
{
- if (Jpath) {
- char *p1, *p2, *mgopath;
- int i = 0;
-
- if (strcmp(Jpath, "*")) {
- p1 = Jpath;
- if (*p1 == '$') p1++;
- if (*p1 == '.') p1++;
- mgopath = PlugDup(g, p1);
- } else
- return NULL;
-
- for (p1 = p2 = mgopath; *p1; p1++)
- if (i) { // Inside []
- if (isdigit(*p1)) {
- if (!proj)
- *p2++ = *p1;
-
- } else if (*p1 == ']' && i == 1) {
- if (proj && p1[1] == '.')
- p1++;
-
- i = 0;
- } else if (*p1 == '.' && i == 2) {
- if (!proj)
- *p2++ = '.';
-
- i = 0;
- } else if (!proj)
- return NULL;
-
- } else switch (*p1) {
- case ':':
- case '.':
- if (isdigit(p1[1]))
- i = 2;
-
- *p2++ = '.';
- break;
- case '[':
- if (*(p2 - 1) != '.')
- *p2++ = '.';
-
- i = 1;
- break;
- case '*':
- if (*(p2 - 1) == '.' && !*(p1 + 1)) {
- p2--; // Suppress last :*
- break;
- } // endif p2
-
- default:
- *p2++ = *p1;
- break;
- } // endswitch p1;
-
- *p2 = 0;
- return mgopath;
- } else
- return NULL;
+ if (Jpath) {
+ char *p1, *p2, *mgopath;
+ int i = 0;
+
+ if (strcmp(Jpath, "*")) {
+ p1 = Jpath;
+ if (*p1 == '$') p1++;
+ if (*p1 == '.') p1++;
+ mgopath = PlugDup(g, p1);
+ } else
+ return NULL;
+
+ for (p1 = p2 = mgopath; *p1; p1++)
+ if (i) { // Inside []
+ if (isdigit(*p1)) {
+ if (!proj)
+ *p2++ = *p1;
+
+ } else if (*p1 == ']' && i == 1) {
+ if (proj && p1[1] == '.')
+ p1++;
+
+ i = 0;
+ } else if (*p1 == '.' && i == 2) {
+ if (!proj)
+ *p2++ = '.';
+
+ i = 0;
+ } else if (!proj)
+ return NULL;
+
+ } else switch (*p1) {
+ case ':':
+ case '.':
+ if (isdigit(p1[1]))
+ i = 2;
+
+ *p2++ = '.';
+ break;
+ case '[':
+ if (*(p2 - 1) != '.')
+ *p2++ = '.';
+
+ i = 1;
+ break;
+ case '*':
+ if (*(p2 - 1) == '.' && !*(p1 + 1)) {
+ p2--; // Suppress last :*
+ break;
+ } // endif p2
+
+ default:
+ *p2++ = *p1;
+ break;
+ } // endswitch p1;
+
+ *p2 = 0;
+ return mgopath;
+ } else
+ return NULL;
} // end of GetJpath
@@ -1471,7 +1474,7 @@ PSZ JSONCOL::GetJpath(PGLOBAL g, bool proj)
/***********************************************************************/
PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp)
{
- if (Value->IsTypeNum()) {
+ if (Value->IsTypeNum()) {
strcpy(g->Message, "Cannot make Json for a numeric column");
Value->Reset();
} else
@@ -1486,22 +1489,22 @@ PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp)
void JSONCOL::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val, int n)
{
if (val) {
- vp->SetNull(false);
+ vp->SetNull(false);
switch (val->GetValType()) {
case TYPE_STRG:
case TYPE_INTG:
- case TYPE_BINT:
- case TYPE_DBL:
- case TYPE_DTM:
- vp->SetValue_pval(val->GetValue());
+ case TYPE_BINT:
+ case TYPE_DBL:
+ case TYPE_DTM:
+ vp->SetValue_pval(val->GetValue());
break;
case TYPE_BOOL:
if (vp->IsTypeNum())
vp->SetValue(val->GetInteger() ? 1 : 0);
else
vp->SetValue_psz((PSZ)(val->GetInteger() ? "true" : "false"));
-
+
break;
case TYPE_JAR:
SetJsonValue(g, vp, val->GetArray()->GetValue(0), n);
@@ -1511,16 +1514,16 @@ void JSONCOL::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val, int n)
vp->SetValue_psz(val->GetObject()->GetText(g, NULL));
break;
// } // endif Type
-
+
default:
- vp->Reset();
- vp->SetNull(true);
- } // endswitch Type
+ vp->Reset();
+ vp->SetNull(true);
+ } // endswitch Type
- } else {
- vp->Reset();
- vp->SetNull(true);
- } // endif val
+ } else {
+ vp->Reset();
+ vp->SetNull(true);
+ } // endif val
} // end of SetJsonValue
@@ -1532,8 +1535,8 @@ void JSONCOL::ReadColumn(PGLOBAL g)
if (!Tjp->SameRow || Xnod >= Tjp->SameRow)
Value->SetValue_pval(GetColumnValue(g, Tjp->Row, 0));
- if (Xpd && Value->IsNull() && !((PJDEF)Tjp->To_Def)->Accept)
- throw("Null expandable JSON value");
+ if (Xpd && Value->IsNull() && !((PJDEF)Tjp->To_Def)->Accept)
+ throw("Null expandable JSON value");
// Set null when applicable
if (!Nullable)
@@ -1580,11 +1583,11 @@ PVAL JSONCOL::GetColumnValue(PGLOBAL g, PJSON row, int i)
else
return CalculateArray(g, arp, i);
- } else {
- // Unexpected array, unwrap it as [0]
- val = arp->GetValue(0);
- i--;
- } // endif's
+ } else {
+ // Unexpected array, unwrap it as [0]
+ val = arp->GetValue(0);
+ i--;
+ } // endif's
break;
case TYPE_JVAL:
@@ -1613,17 +1616,17 @@ PVAL JSONCOL::ExpandArray(PGLOBAL g, PJAR arp, int n)
PJVAL jvp;
JVALUE jval;
- if (!ars) {
- Value->Reset();
- Value->SetNull(true);
- Tjp->NextSame = 0;
- return Value;
- } // endif ars
+ if (!ars) {
+ Value->Reset();
+ Value->SetNull(true);
+ Tjp->NextSame = 0;
+ return Value;
+ } // endif ars
if (!(jvp = arp->GetValue((Nodes[n].Rx = Nodes[n].Nx)))) {
strcpy(g->Message, "Logical error expanding array");
- throw 666;
- } // endif jvp
+ throw 666;
+ } // endif jvp
if (n < Nod - 1 && jvp->GetJson()) {
jval.SetValue(GetColumnValue(g, jvp->GetJson(), n + 1));
@@ -1638,7 +1641,7 @@ PVAL JSONCOL::ExpandArray(PGLOBAL g, PJAR arp, int n)
Xnod = n;
Tjp->NextSame = Xnod;
- } // endif NextSame
+ } // endif NextSame
SetJsonValue(g, Value, jvp, n);
return Value;
@@ -1649,58 +1652,58 @@ PVAL JSONCOL::ExpandArray(PGLOBAL g, PJAR arp, int n)
/***********************************************************************/
PVAL JSONCOL::CalculateArray(PGLOBAL g, PJAR arp, int n)
{
- int i, ars, nv = 0, nextsame = Tjp->NextSame;
- bool err;
+ int i, ars, nv = 0, nextsame = Tjp->NextSame;
+ bool err;
OPVAL op = Nodes[n].Op;
PVAL val[2], vp = Nodes[n].Valp;
PJVAL jvrp, jvp;
JVALUE jval;
vp->Reset();
- ars = MY_MIN(Tjp->Limit, arp->size());
+ ars = MY_MIN(Tjp->Limit, arp->size());
- if (trace(1))
- htrc("CalculateArray: size=%d op=%d nextsame=%d\n",
- ars, op, nextsame);
+ if (trace(1))
+ htrc("CalculateArray: size=%d op=%d nextsame=%d\n",
+ ars, op, nextsame);
- for (i = 0; i < ars; i++) {
- jvrp = arp->GetValue(i);
+ for (i = 0; i < ars; i++) {
+ jvrp = arp->GetValue(i);
- if (trace(1))
- htrc("i=%d nv=%d\n", i, nv);
+ if (trace(1))
+ htrc("i=%d nv=%d\n", i, nv);
- if (!jvrp->IsNull() || (op == OP_CNC && GetJsonNull())) do {
- if (jvrp->IsNull()) {
- jvrp->Value = AllocateValue(g, GetJsonNull(), TYPE_STRING);
- jvp = jvrp;
- } else if (n < Nod - 1 && jvrp->GetJson()) {
+ if (!jvrp->IsNull() || (op == OP_CNC && GetJsonNull())) do {
+ if (jvrp->IsNull()) {
+ jvrp->Value = AllocateValue(g, GetJsonNull(), TYPE_STRING);
+ jvp = jvrp;
+ } else if (n < Nod - 1 && jvrp->GetJson()) {
Tjp->NextSame = nextsame;
jval.SetValue(GetColumnValue(g, jvrp->GetJson(), n + 1));
jvp = &jval;
} else
jvp = jvrp;
-
- if (trace(1))
- htrc("jvp=%s null=%d\n",
- jvp->GetString(g), jvp->IsNull() ? 1 : 0);
- if (!nv++) {
+ if (trace(1))
+ htrc("jvp=%s null=%d\n",
+ jvp->GetString(g), jvp->IsNull() ? 1 : 0);
+
+ if (!nv++) {
SetJsonValue(g, vp, jvp, n);
continue;
} else
SetJsonValue(g, MulVal, jvp, n);
- if (!MulVal->IsNull()) {
- switch (op) {
+ if (!MulVal->IsNull()) {
+ switch (op) {
case OP_CNC:
if (Nodes[n].CncVal) {
val[0] = Nodes[n].CncVal;
err = vp->Compute(g, val, 1, op);
} // endif CncVal
-
+
val[0] = MulVal;
err = vp->Compute(g, val, 1, op);
- break;
+ break;
// case OP_NUM:
case OP_SEP:
val[0] = Nodes[n].Valp;
@@ -1715,16 +1718,16 @@ PVAL JSONCOL::CalculateArray(PGLOBAL g, PJAR arp, int n)
if (err)
vp->Reset();
-
- if (trace(1)) {
- char buf(32);
- htrc("vp='%s' err=%d\n",
- vp->GetCharString(&buf), err ? 1 : 0);
+ if (trace(1)) {
+ char buf(32);
- } // endif trace
+ htrc("vp='%s' err=%d\n",
+ vp->GetCharString(&buf), err ? 1 : 0);
- } // endif Null
+ } // endif trace
+
+ } // endif Null
} while (Tjp->NextSame > nextsame);
@@ -1754,8 +1757,8 @@ PJSON JSONCOL::GetRow(PGLOBAL g)
PJAR arp;
PJSON nwr, row = Tjp->Row;
- for (int i = 0; i < Nod && row; i++) {
- if (Nodes[i+1].Op == OP_XX)
+ for (int i = 0; i < Nod && row; i++) {
+ if (Nodes[i+1].Op == OP_XX)
break;
else switch (row->GetType()) {
case TYPE_JOB:
@@ -1766,19 +1769,19 @@ PJSON JSONCOL::GetRow(PGLOBAL g)
val = ((PJOB)row)->GetValue(Nodes[i].Key);
break;
case TYPE_JAR:
- arp = (PJAR)row;
+ arp = (PJAR)row;
- if (!Nodes[i].Key) {
+ if (!Nodes[i].Key) {
if (Nodes[i].Op == OP_EQ)
val = arp->GetValue(Nodes[i].Rank);
else
val = arp->GetValue(Nodes[i].Rx);
} else {
- // Unexpected array, unwrap it as [0]
- val = arp->GetValue(0);
- i--;
- } // endif Nodes
+ // Unexpected array, unwrap it as [0]
+ val = arp->GetValue(0);
+ i--;
+ } // endif Nodes
break;
case TYPE_JVAL:
@@ -1828,10 +1831,10 @@ PJSON JSONCOL::GetRow(PGLOBAL g)
/***********************************************************************/
void JSONCOL::WriteColumn(PGLOBAL g)
{
- if (Xpd && Tjp->Pretty < 2) {
- strcpy(g->Message, "Cannot write expanded column when Pretty is not 2");
- throw 666;
- } // endif Xpd
+ if (Xpd && Tjp->Pretty < 2) {
+ strcpy(g->Message, "Cannot write expanded column when Pretty is not 2");
+ throw 666;
+ } // endif Xpd
/*********************************************************************/
/* Check whether this node must be written. */
@@ -1865,8 +1868,8 @@ void JSONCOL::WriteColumn(PGLOBAL g)
if (!(jsp = ParseJson(G, s, (int)strlen(s)))) {
strcpy(g->Message, s);
- throw 666;
- } // endif jsp
+ throw 666;
+ } // endif jsp
if (arp) {
if (Nod > 1 && Nodes[Nod-2].Op == OP_EQ)
@@ -1888,10 +1891,10 @@ void JSONCOL::WriteColumn(PGLOBAL g)
// fall through
case TYPE_DATE:
case TYPE_INT:
- case TYPE_TINY:
- case TYPE_SHORT:
- case TYPE_BIGINT:
- case TYPE_DOUBLE:
+ case TYPE_TINY:
+ case TYPE_SHORT:
+ case TYPE_BIGINT:
+ case TYPE_DOUBLE:
if (arp) {
if (Nodes[Nod-1].Op == OP_EQ)
arp->SetValue(G, new(G) JVALUE(G, Value), Nodes[Nod-1].Rank);
@@ -1982,7 +1985,7 @@ int TDBJSON::MakeDocument(PGLOBAL g)
return RC_OK;
/*********************************************************************/
- /* Create the mapping file object in mode read. */
+ /* Create the mapping file object in mode read. */
/*********************************************************************/
Mode = MODE_READ;
@@ -2011,70 +2014,70 @@ int TDBJSON::MakeDocument(PGLOBAL g)
if (!jsp && g->Message[0])
return RC_FX;
- if ((objpath = PlugDup(g, Objname))) {
- if (*objpath == '$') objpath++;
- if (*objpath == '.') objpath++;
-
- /*********************************************************************/
- /* Find the table in the tree structure. */
- /*********************************************************************/
- for (; jsp && objpath; objpath = p) {
- if ((p = strchr(objpath, Sep)))
- *p++ = 0;
-
- if (*objpath != '[' && !IsNum(objpath)) {
- // objpass is a key
- if (jsp->GetType() != TYPE_JOB) {
- strcpy(g->Message, "Table path does not match the json file");
- return RC_FX;
- } // endif Type
-
- key = objpath;
- objp = jsp->GetObject();
- arp = NULL;
- val = objp->GetValue(key);
-
- if (!val || !(jsp = val->GetJson())) {
- sprintf(g->Message, "Cannot find object key %s", key);
- return RC_FX;
- } // endif val
-
- } else {
- if (*objpath == '[') {
- // Old style
- if (objpath[strlen(objpath) - 1] != ']') {
- sprintf(g->Message, "Invalid Table path %s", Objname);
- return RC_FX;
- } else
- objpath++;
-
- } // endif objpath
-
- if (jsp->GetType() != TYPE_JAR) {
- strcpy(g->Message, "Table path does not match the json file");
- return RC_FX;
- } // endif Type
-
- arp = jsp->GetArray();
- objp = NULL;
- i = atoi(objpath) - B;
- val = arp->GetValue(i);
-
- if (!val) {
- sprintf(g->Message, "Cannot find array value %d", i);
- return RC_FX;
- } // endif val
-
- } // endif
-
- jsp = val->GetJson();
- } // endfor objpath
-
- } // endif objpath
+ if ((objpath = PlugDup(g, Objname))) {
+ if (*objpath == '$') objpath++;
+ if (*objpath == '.') objpath++;
+
+ /*********************************************************************/
+ /* Find the table in the tree structure. */
+ /*********************************************************************/
+ for (; jsp && objpath; objpath = p) {
+ if ((p = strchr(objpath, Sep)))
+ *p++ = 0;
+
+ if (*objpath != '[' && !IsNum(objpath)) {
+ // objpass is a key
+ if (jsp->GetType() != TYPE_JOB) {
+ strcpy(g->Message, "Table path does not match the json file");
+ return RC_FX;
+ } // endif Type
+
+ key = objpath;
+ objp = jsp->GetObject();
+ arp = NULL;
+ val = objp->GetValue(key);
+
+ if (!val || !(jsp = val->GetJson())) {
+ sprintf(g->Message, "Cannot find object key %s", key);
+ return RC_FX;
+ } // endif val
+
+ } else {
+ if (*objpath == '[') {
+ // Old style
+ if (objpath[strlen(objpath) - 1] != ']') {
+ sprintf(g->Message, "Invalid Table path %s", Objname);
+ return RC_FX;
+ } else
+ objpath++;
+
+ } // endif objpath
+
+ if (jsp->GetType() != TYPE_JAR) {
+ strcpy(g->Message, "Table path does not match the json file");
+ return RC_FX;
+ } // endif Type
+
+ arp = jsp->GetArray();
+ objp = NULL;
+ i = atoi(objpath) - B;
+ val = arp->GetValue(i);
+
+ if (!val) {
+ sprintf(g->Message, "Cannot find array value %d", i);
+ return RC_FX;
+ } // endif val
+
+ } // endif
+
+ jsp = val->GetJson();
+ } // endfor objpath
+
+ } // endif objpath
if (jsp && jsp->GetType() == TYPE_JAR)
Doc = jsp->GetArray();
- else {
+ else {
// The table is void or is just one object or one value
Doc = new(g) JARRAY;
@@ -2152,7 +2155,7 @@ int TDBJSON::MakeIndex(PGLOBAL g, PIXDEF pxdf, bool)
} else
return RC_OK;
- } // end of MakeIndex
+ } // end of MakeIndex
/***********************************************************************/
/* Return the position in the table. */
@@ -2230,11 +2233,11 @@ bool TDBJSON::OpenDB(PGLOBAL g)
return true;
} // endswitch Jmode
- if (Xcol)
- To_Filter = NULL; // Imcompatible
+ if (Xcol)
+ To_Filter = NULL; // Imcompatible
- Use = USE_OPEN;
- return false;
+ Use = USE_OPEN;
+ return false;
} // end of OpenDB
/***********************************************************************/
@@ -2244,7 +2247,7 @@ int TDBJSON::ReadDB(PGLOBAL)
{
int rc;
- N++;
+ N++;
if (NextSame) {
SameRow = NextSame;
@@ -2355,8 +2358,8 @@ void TDBJSON::CloseDB(PGLOBAL g)
TDBJCL::TDBJCL(PJDEF tdp) : TDBCAT(tdp)
{
Topt = tdp->GetTopt();
- Db = tdp->Schema;
- Dsn = tdp->Uri;
+ Db = tdp->Schema;
+ Dsn = tdp->Uri;
} // end of TDBJCL constructor
/***********************************************************************/
diff --git a/storage/connect/tabrest.cpp b/storage/connect/tabrest.cpp
new file mode 100644
index 00000000000..9e1a643c89f
--- /dev/null
+++ b/storage/connect/tabrest.cpp
@@ -0,0 +1,201 @@
+/*************** Rest C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: Rest Version 1.5 */
+/* (C) Copyright to the author Olivier BERTRAND 2018 - 2019 */
+/* This program is the REST Web API support for MariaDB. */
+/* When compiled without MARIADB defined, it is the EOM module code. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Definitions needed by the included files. */
+/***********************************************************************/
+#if defined(MARIADB)
+#include <my_global.h> // All MariaDB stuff
+#else // !MARIADB OEM module
+#include "mini-global.h"
+#define _MAX_PATH 260
+#if !defined(__WIN__)
+#define __stdcall
+#endif // !__WIN__
+#define _OS_H_INCLUDED // Prevent os.h to be called
+#endif // !MARIADB
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* (x)table.h is header containing the TDBASE declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "filamtxt.h"
+#include "tabdos.h"
+#include "plgxml.h"
+#include "tabxml.h"
+#include "tabjson.h"
+#include "tabfmt.h"
+#include "tabrest.h"
+
+/***********************************************************************/
+/* Get the file from the Web. */
+/***********************************************************************/
+int restGetFile(PGLOBAL g, PCSZ http, PCSZ uri, PCSZ fn);
+
+#if defined(__WIN__)
+static PCSZ slash = "\\";
+#else // !__WIN__
+static PCSZ slash = "/";
+#define stricmp strcasecmp
+#endif // !__WIN__
+
+#if !defined(MARIADB)
+/***********************************************************************/
+/* DB static variables. */
+/***********************************************************************/
+int TDB::Tnum;
+int DTVAL::Shift;
+int CSORT::Limit = 0;
+double CSORT::Lg2 = log(2.0);
+size_t CSORT::Cpn[1000] = { 0 };
+
+/***********************************************************************/
+/* These functions are exported from the REST library. */
+/***********************************************************************/
+extern "C" {
+ PTABDEF __stdcall GetREST(PGLOBAL, void*);
+ PQRYRES __stdcall ColREST(PGLOBAL, PTOS, char*, char*, bool);
+} // extern "C"
+
+/***********************************************************************/
+/* This function returns a table definition class. */
+/***********************************************************************/
+PTABDEF __stdcall GetREST(PGLOBAL g, void *memp)
+{
+ return new(g, memp) RESTDEF;
+} // end of GetREST
+#endif // !MARIADB
+
+/***********************************************************************/
+/* Return the columns definition to MariaDB. */
+/***********************************************************************/
+#if defined(MARIADB)
+PQRYRES RESTColumns(PGLOBAL g, PTOS tp, char *tab, char *db, bool info)
+#else // !MARIADB
+PQRYRES __stdcall ColREST(PGLOBAL g, PTOS tp, char *tab, char *db, bool info)
+#endif // !MARIADB
+{
+ PQRYRES qrp= NULL;
+ char filename[_MAX_PATH + 1]; // MAX PATH ???
+ PCSZ http, uri, fn, ftype;
+
+ http = GetStringTableOption(g, tp, "Http", NULL);
+ uri = GetStringTableOption(g, tp, "Uri", NULL);
+ fn = GetStringTableOption(g, tp, "Filename", "rest.json");
+#if defined(MARIADB)
+ ftype = GetStringTableOption(g, tp, "Type", "JSON");
+#else // !MARIADB
+ // OEM tables must specify the file type
+ ftype = GetStringTableOption(g, tp, "Ftype", "JSON");
+#endif // !MARIADB
+
+ // We used the file name relative to recorded datapath
+ strcat(strcat(strcat(strcpy(filename, "."), slash), db), slash);
+ strncat(filename, fn, _MAX_PATH);
+
+ // Retrieve the file from the web and copy it locally
+ if (http && restGetFile(g, http, uri, filename)) {
+ // sprintf(g->Message, "Failed to get file at %s", http);
+ } else if (!stricmp(ftype, "XML"))
+ qrp = XMLColumns(g, db, tab, tp, info);
+ else if (!stricmp(ftype, "JSON"))
+ qrp = JSONColumns(g, db, NULL, tp, info);
+ else if (!stricmp(ftype, "CSV"))
+ qrp = CSVColumns(g, NULL, tp, info);
+ else
+ sprintf(g->Message, "Usupported file type %s", ftype);
+
+ return qrp;
+} // end of RESTColumns
+
+/* -------------------------- Class RESTDEF -------------------------- */
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values. */
+/***********************************************************************/
+bool RESTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+{
+ char filename[_MAX_PATH + 1];
+ int rc = 0, n;
+ LPCSTR ftype;
+
+#if defined(MARIADB)
+ ftype = GetStringCatInfo(g, "Type", "JSON");
+#else // !MARIADB
+ // OEM tables must specify the file type
+ ftype = GetStringCatInfo(g, "Ftype", "JSON");
+#endif // !MARIADB
+
+ if (trace(515))
+ htrc("ftype = %s am = %s\n", ftype, SVP(am));
+
+ n = (!stricmp(ftype, "JSON")) ? 1
+ : (!stricmp(ftype, "XML")) ? 2
+ : (!stricmp(ftype, "CSV")) ? 3 : 0;
+
+ if (n == 0) {
+ htrc("DefineAM: Unsupported REST table type %s", am);
+ sprintf(g->Message, "Unsupported REST table type %s", am);
+ return true;
+ } // endif n
+
+ Http = GetStringCatInfo(g, "Http", NULL);
+ Uri = GetStringCatInfo(g, "Uri", NULL);
+ Fn = GetStringCatInfo(g, "Filename", "rest.json");
+
+ // We used the file name relative to recorded datapath
+ //PlugSetPath(filename, Fn, GetPath());
+ strncat(strcpy(filename, GetPath()), Fn, _MAX_PATH);
+
+ // Retrieve the file from the web and copy it locally
+ rc = restGetFile(g, Http, Uri, filename);
+
+ if (trace(515))
+ htrc("Return from restGetFile: rc=%d\n", rc);
+
+ if (rc)
+ return true;
+ else switch (n) {
+ case 1: Tdp = new (g) JSONDEF; break;
+ case 2: Tdp = new (g) XMLDEF; break;
+ case 3: Tdp = new (g) CSVDEF; break;
+ default: Tdp = NULL;
+ } // endswitch n
+
+ // Do make the table/view definition
+ if (Tdp && Tdp->Define(g, Cat, Name, Schema, "REST"))
+ Tdp = NULL; // Error occured
+
+ if (trace(515))
+ htrc("Tdp defined\n", rc);
+
+ // Return true in case of error
+ return (Tdp == NULL);
+} // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB RESTDEF::GetTable(PGLOBAL g, MODE m)
+{
+ if (trace(515))
+ htrc("REST GetTable mode=%d\n", m);
+
+ if (m != MODE_READ && m != MODE_READX) {
+ strcpy(g->Message, "REST tables are currently read only");
+ return NULL;
+ } // endif m
+
+ return Tdp->GetTable(g, m); // Leave file type do the job
+} // end of GetTable
+
+/* ---------------------- End of Class RESTDEF ----------------------- */
diff --git a/storage/connect/tabrest.h b/storage/connect/tabrest.h
new file mode 100644
index 00000000000..1725f256079
--- /dev/null
+++ b/storage/connect/tabrest.h
@@ -0,0 +1,29 @@
+/*************** TabRest H Declares Source Code File (.H) **************/
+/* Name: tabrest.h Version 1.0 */
+/* (C) Copyright to the author Olivier BERTRAND 2019 */
+/* This file contains the common tabrest classes declares. */
+/***********************************************************************/
+#pragma once
+
+/***********************************************************************/
+/* Restest table. */
+/***********************************************************************/
+class RESTDEF : public TABDEF { /* Table description */
+public:
+ // Constructor
+ RESTDEF(void) { Tdp = NULL; Http = Uri = Fn = NULL; }
+
+ // Implementation
+ virtual const char *GetType(void) { return "REST"; }
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+
+protected:
+ // Members
+ PRELDEF Tdp;
+ PCSZ Http; /* Web connection HTTP */
+ PCSZ Uri; /* Web connection URI */
+ PCSZ Fn; /* The intermediate file name */
+}; // end of class RESTDEF
diff --git a/storage/connect/tabtbl.cpp b/storage/connect/tabtbl.cpp
index b2dbdd70e06..1150824464f 100644
--- a/storage/connect/tabtbl.cpp
+++ b/storage/connect/tabtbl.cpp
@@ -281,7 +281,7 @@ bool TDBTBL::InitTableList(PGLOBAL g)
} // endfor tp
- hc->get_table()->s->connect_string.str = scs;
+ hc->get_table()->s->connect_string.str = (char*)scs;
hc->get_table()->s->connect_string.length = sln;
//NumTables = n;
diff --git a/storage/connect/user_connect.cc b/storage/connect/user_connect.cc
index dec50aa8e6c..8abd33079d6 100644
--- a/storage/connect/user_connect.cc
+++ b/storage/connect/user_connect.cc
@@ -11,7 +11,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
/**
@file user_connect.cc
diff --git a/storage/connect/user_connect.h b/storage/connect/user_connect.h
index af40a88cea0..53064e620f2 100644
--- a/storage/connect/user_connect.h
+++ b/storage/connect/user_connect.h
@@ -11,7 +11,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
/** @file user_connect.h
diff --git a/storage/heap/hp_scan.c b/storage/heap/hp_scan.c
index 3315cb05b3f..f07efe6cf67 100644
--- a/storage/heap/hp_scan.c
+++ b/storage/heap/hp_scan.c
@@ -50,7 +50,9 @@ int heap_scan(register HP_INFO *info, uchar *record)
}
else
{
- info->next_block+=share->block.records_in_block;
+ /* increase next_block to the next records_in_block boundary */
+ ulong rem= info->next_block % share->block.records_in_block;
+ info->next_block+=share->block.records_in_block - rem;
if (info->next_block >= share->records+share->deleted)
{
info->next_block= share->records+share->deleted;
diff --git a/storage/innobase/btr/btr0scrub.cc b/storage/innobase/btr/btr0scrub.cc
index 67c06016c72..3c367fb2784 100644
--- a/storage/innobase/btr/btr0scrub.cc
+++ b/storage/innobase/btr/btr0scrub.cc
@@ -626,13 +626,8 @@ btr_scrub_get_table_and_index(
scrub_data->current_table = NULL;
}
- /* argument to dict_table_open_on_index_id */
- bool dict_locked = true;
-
/* open table based on index_id */
- dict_table_t* table = dict_table_open_on_index_id(
- index_id,
- dict_locked);
+ dict_table_t* table = dict_table_open_on_index_id(index_id);
if (table != NULL) {
/* mark table as being scrubbed */
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index c655d7a1587..ae13e5790d5 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -1068,14 +1068,8 @@ buf_page_is_corrupted(
size_t checksum_field2 = 0;
uint32_t crc32 = 0;
bool crc32_inited = false;
- ulint zip_size = 0;
bool crc32_chksum = false;
-
- zip_size = FSP_FLAGS_GET_ZIP_SSIZE(fsp_flags);
- if (zip_size) {
- zip_size = (UNIV_ZIP_SIZE_MIN >> 1) << zip_size;
- }
-
+ const ulint zip_size = fil_space_t::zip_size(fsp_flags);
ulint page_type = mach_read_from_2(read_buf + FIL_PAGE_TYPE);
/* We can trust page type if page compression is set on tablespace
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index b5bd73ed5ec..fea537166f9 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -266,7 +266,7 @@ dict_table_try_drop_aborted(
if (table == NULL) {
table = dict_table_open_on_id_low(
- table_id, DICT_ERR_IGNORE_NONE, FALSE);
+ table_id, DICT_ERR_IGNORE_FK_NOKEY, FALSE);
} else {
ut_ad(table->id == table_id);
}
@@ -750,7 +750,7 @@ dict_table_open_on_id(
table_id,
table_op == DICT_TABLE_OP_LOAD_TABLESPACE
? DICT_ERR_IGNORE_RECOVER_LOCK
- : DICT_ERR_IGNORE_NONE,
+ : DICT_ERR_IGNORE_FK_NOKEY,
table_op == DICT_TABLE_OP_OPEN_ONLY_IF_CACHED);
if (table != NULL) {
@@ -896,7 +896,7 @@ dict_table_open_on_name(
if (table != NULL) {
/* If table is encrypted or corrupted */
- if (ignore_err == DICT_ERR_IGNORE_NONE
+ if (!(ignore_err & ~DICT_ERR_IGNORE_FK_NOKEY)
&& !table->is_readable()) {
/* Make life easy for drop table. */
dict_sys.prevent_eviction(table);
@@ -2764,11 +2764,6 @@ dict_index_build_internal_fts(
}
/*====================== FOREIGN KEY PROCESSING ========================*/
-#define DB_FOREIGN_KEY_IS_PREFIX_INDEX 200
-#define DB_FOREIGN_KEY_COL_NOT_NULL 201
-#define DB_FOREIGN_KEY_COLS_NOT_EQUAL 202
-#define DB_FOREIGN_KEY_INDEX_NOT_FOUND 203
-
/** Check whether the dict_table_t is a partition.
A partitioned table on the SQL level is composed of InnoDB tables,
where each InnoDB table is a [sub]partition including its secondary indexes
@@ -2875,7 +2870,7 @@ dict_foreign_find_index(
/*!< in: nonzero if none of
the columns must be declared
NOT NULL */
- ulint* error, /*!< out: error code */
+ fkerr_t* error, /*!< out: error code */
ulint* err_col_no,
/*!< out: column number where
error happened */
@@ -2883,17 +2878,15 @@ dict_foreign_find_index(
/*!< out: index where error
happened */
{
- dict_index_t* index;
-
ut_ad(mutex_own(&dict_sys.mutex));
if (error) {
- *error = DB_FOREIGN_KEY_INDEX_NOT_FOUND;
+ *error = FK_INDEX_NOT_FOUND;
}
- index = dict_table_get_first_index(table);
-
- while (index != NULL) {
+ for (dict_index_t* index = dict_table_get_first_index(table);
+ index;
+ index = dict_table_get_next_index(index)) {
if (types_idx != index
&& !index->to_be_dropped
&& !dict_index_is_online_ddl(index)
@@ -2901,42 +2894,17 @@ dict_foreign_find_index(
table, col_names, columns, n_cols,
index, types_idx,
check_charsets, check_null,
- error, err_col_no,err_index)) {
+ error, err_col_no, err_index)) {
if (error) {
- *error = DB_SUCCESS;
+ *error = FK_SUCCESS;
}
return(index);
}
-
- index = dict_table_get_next_index(index);
}
return(NULL);
}
-#ifdef WITH_WSREP
-dict_index_t*
-wsrep_dict_foreign_find_index(
-/*====================*/
- dict_table_t* table, /*!< in: table */
- const char** col_names, /*!< in: column names, or NULL
- to use table->col_names */
- const char** columns,/*!< in: array of column names */
- ulint n_cols, /*!< in: number of columns */
- dict_index_t* types_idx, /*!< in: NULL or an index to whose types the
- column types must match */
- ibool check_charsets,
- /*!< in: whether to check charsets.
- only has an effect if types_idx != NULL */
- ulint check_null)
- /*!< in: nonzero if none of the columns must
- be declared NOT NULL */
-{
- return dict_foreign_find_index(
- table, col_names, columns, n_cols, types_idx, check_charsets,
- check_null, NULL, NULL, NULL);
-}
-#endif /* WITH_WSREP */
/**********************************************************************//**
Report an error in a foreign key definition. */
static
@@ -3033,15 +3001,11 @@ dict_foreign_add_to_cache(
}
if (ref_table && !for_in_cache->referenced_table) {
- ulint index_error;
- ulint err_col;
- dict_index_t *err_index=NULL;
-
index = dict_foreign_find_index(
ref_table, NULL,
for_in_cache->referenced_col_names,
for_in_cache->n_fields, for_in_cache->foreign_index,
- check_charsets, false, &index_error, &err_col, &err_index);
+ check_charsets, false);
if (index == NULL
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
@@ -3073,10 +3037,6 @@ dict_foreign_add_to_cache(
}
if (for_table && !for_in_cache->foreign_table) {
- ulint index_error;
- ulint err_col;
- dict_index_t *err_index=NULL;
-
index = dict_foreign_find_index(
for_table, col_names,
for_in_cache->foreign_col_names,
@@ -3084,8 +3044,7 @@ dict_foreign_add_to_cache(
for_in_cache->referenced_index, check_charsets,
for_in_cache->type
& (DICT_FOREIGN_ON_DELETE_SET_NULL
- | DICT_FOREIGN_ON_UPDATE_SET_NULL),
- &index_error, &err_col, &err_index);
+ | DICT_FOREIGN_ON_UPDATE_SET_NULL));
if (index == NULL
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
@@ -3797,7 +3756,7 @@ dict_foreign_push_index_error(
const char* latest_foreign, /*!< in: start of latest foreign key
constraint name */
const char** columns, /*!< in: foreign key columns */
- ulint index_error, /*!< in: error code */
+ fkerr_t index_error, /*!< in: error code */
ulint err_col, /*!< in: column where error happened
*/
dict_index_t* err_index, /*!< in: index where error happened
@@ -3806,37 +3765,37 @@ dict_foreign_push_index_error(
FILE* ef) /*!< in: output stream */
{
switch (index_error) {
- case DB_FOREIGN_KEY_INDEX_NOT_FOUND: {
+ case FK_SUCCESS:
+ break;
+ case FK_INDEX_NOT_FOUND:
fprintf(ef,
- "%s table '%s' with foreign key constraint"
+ "%s table %s with foreign key constraint"
" failed. There is no index in the referenced"
" table where the referenced columns appear"
" as the first columns near '%s'.\n",
operation, create_name, latest_foreign);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
- "%s table '%s' with foreign key constraint"
+ "%s table %s with foreign key constraint"
" failed. There is no index in the referenced"
" table where the referenced columns appear"
" as the first columns near '%s'.",
operation, create_name, latest_foreign);
- break;
- }
- case DB_FOREIGN_KEY_IS_PREFIX_INDEX: {
+ return;
+ case FK_IS_PREFIX_INDEX:
fprintf(ef,
- "%s table '%s' with foreign key constraint"
+ "%s table %s with foreign key constraint"
" failed. There is only prefix index in the referenced"
" table where the referenced columns appear"
" as the first columns near '%s'.\n",
operation, create_name, latest_foreign);
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
- "%s table '%s' with foreign key constraint"
+ "%s table %s with foreign key constraint"
" failed. There is only prefix index in the referenced"
" table where the referenced columns appear"
" as the first columns near '%s'.",
operation, create_name, latest_foreign);
- break;
- }
- case DB_FOREIGN_KEY_COL_NOT_NULL: {
+ return;
+ case FK_COL_NOT_NULL:
fprintf(ef,
"%s table %s with foreign key constraint"
" failed. You have defined a SET NULL condition but "
@@ -3847,9 +3806,8 @@ dict_foreign_push_index_error(
" failed. You have defined a SET NULL condition but "
"column '%s' on index is defined as NOT NULL near '%s'.",
operation, create_name, columns[err_col], latest_foreign);
- break;
- }
- case DB_FOREIGN_KEY_COLS_NOT_EQUAL: {
+ return;
+ case FK_COLS_NOT_EQUAL:
dict_field_t* field;
const char* col_name;
field = dict_index_get_nth_field(err_index, err_col);
@@ -3868,11 +3826,9 @@ dict_foreign_push_index_error(
" failed. Field type or character set for column '%s' "
"does not mach referenced column '%s' near '%s'.",
operation, create_name, columns[err_col], col_name, latest_foreign);
- break;
- }
- default:
- ut_error;
+ return;
}
+ DBUG_ASSERT(!"unknown error");
}
/*********************************************************************//**
@@ -3904,7 +3860,7 @@ dict_create_foreign_constraints_low(
const char* start_of_latest_foreign = sql_string;
const char* start_of_latest_set = NULL;
FILE* ef = dict_foreign_err_file;
- ulint index_error = DB_SUCCESS;
+ fkerr_t index_error = FK_SUCCESS;
dict_index_t* err_index = NULL;
ulint err_col;
const char* constraint_name;
@@ -6247,7 +6203,7 @@ dict_foreign_qualify_index(
/*!< in: nonzero if none of
the columns must be declared
NOT NULL */
- ulint* error, /*!< out: error code */
+ fkerr_t* error, /*!< out: error code */
ulint* err_col_no,
/*!< out: column number where
error happened */
@@ -6275,7 +6231,7 @@ dict_foreign_qualify_index(
/* We do not accept column prefix
indexes here */
if (error && err_col_no && err_index) {
- *error = DB_FOREIGN_KEY_IS_PREFIX_INDEX;
+ *error = FK_IS_PREFIX_INDEX;
*err_col_no = i;
*err_index = (dict_index_t*)index;
}
@@ -6285,7 +6241,7 @@ dict_foreign_qualify_index(
if (check_null
&& (field->col->prtype & DATA_NOT_NULL)) {
if (error && err_col_no && err_index) {
- *error = DB_FOREIGN_KEY_COL_NOT_NULL;
+ *error = FK_COL_NOT_NULL;
*err_col_no = i;
*err_index = (dict_index_t*)index;
}
@@ -6315,7 +6271,7 @@ dict_foreign_qualify_index(
dict_index_get_nth_col(types_idx, i),
check_charsets)) {
if (error && err_col_no && err_index) {
- *error = DB_FOREIGN_KEY_COLS_NOT_EQUAL;
+ *error = FK_COLS_NOT_EQUAL;
*err_col_no = i;
*err_index = (dict_index_t*)index;
}
diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc
index 173e8121ee1..4adf886118b 100644
--- a/storage/innobase/dict/dict0load.cc
+++ b/storage/innobase/dict/dict0load.cc
@@ -3077,7 +3077,7 @@ func_exit:
mem_heap_free(heap);
ut_ad(!table
- || ignore_err != DICT_ERR_IGNORE_NONE
+ || (ignore_err & ~DICT_ERR_IGNORE_FK_NOKEY)
|| !table->is_readable()
|| !table->corrupted);
@@ -3766,29 +3766,14 @@ dict_load_table_id_on_index_id(
return(found);
}
-UNIV_INTERN
-dict_table_t*
-dict_table_open_on_index_id(
-/*========================*/
- index_id_t index_id, /*!< in: index id */
- bool dict_locked) /*!< in: dict locked */
+dict_table_t* dict_table_open_on_index_id(index_id_t index_id)
{
- if (!dict_locked) {
- mutex_enter(&dict_sys.mutex);
- }
-
- ut_ad(mutex_own(&dict_sys.mutex));
table_id_t table_id;
dict_table_t * table = NULL;
if (dict_load_table_id_on_index_id(index_id, &table_id)) {
- bool local_dict_locked = true;
- table = dict_table_open_on_id(table_id,
- local_dict_locked,
+ table = dict_table_open_on_id(table_id, true,
DICT_TABLE_OP_LOAD_TABLESPACE);
}
- if (!dict_locked) {
- mutex_exit(&dict_sys.mutex);
- }
return table;
}
diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc
index 50b73222607..ad74525be15 100644
--- a/storage/innobase/fil/fil0crypt.cc
+++ b/storage/innobase/fil/fil0crypt.cc
@@ -354,6 +354,34 @@ fil_space_destroy_crypt_data(
}
}
+/** Fill crypt data information to the give page.
+It should be called during ibd file creation.
+@param[in] flags tablespace flags
+@param[in,out] page first page of the tablespace */
+void
+fil_space_crypt_t::fill_page0(
+ ulint flags,
+ byte* page)
+{
+ const uint len = sizeof(iv);
+ const ulint offset = FSP_HEADER_OFFSET
+ + fsp_header_get_encryption_offset(
+ fil_space_t::zip_size(flags));
+ page0_offset = offset;
+
+ memcpy(page + offset, CRYPT_MAGIC, MAGIC_SZ);
+ mach_write_to_1(page + offset + MAGIC_SZ, type);
+ mach_write_to_1(page + offset + MAGIC_SZ + 1, len);
+ memcpy(page + offset + MAGIC_SZ + 2, &iv, len);
+
+ mach_write_to_4(page + offset + MAGIC_SZ + 2 + len,
+ min_key_version);
+ mach_write_to_4(page + offset + MAGIC_SZ + 2 + len + 4,
+ key_id);
+ mach_write_to_1(page + offset + MAGIC_SZ + 2 + len + 8,
+ encryption);
+}
+
/******************************************************************
Write crypt data to a page (0)
@param[in] space tablespace
@@ -2488,9 +2516,11 @@ static void fil_crypt_rotation_list_fill()
/* Protect the tablespace while we may
release fil_system.mutex. */
space->n_pending_ops++;
+#ifndef DBUG_OFF
fil_space_t* s= fil_system.read_page0(
space->id);
ut_ad(!s || s == space);
+#endif
space->n_pending_ops--;
if (!space->size) {
/* Page 0 was not loaded.
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index 0c00671214b..b46a5d33843 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -725,6 +725,7 @@ static void fil_flush_low(fil_space_t* space, bool metadata = false)
switch (space->purpose) {
case FIL_TYPE_TEMPORARY:
ut_ad(0); // we already checked for this
+ /* fall through */
case FIL_TYPE_TABLESPACE:
case FIL_TYPE_IMPORT:
fil_n_pending_tablespace_flushes++;
@@ -2927,8 +2928,6 @@ fil_ibd_create(
byte* page;
bool success;
bool has_data_dir = FSP_FLAGS_HAS_DATA_DIR(flags) != 0;
- fil_space_t* space = NULL;
- fil_space_crypt_t *crypt_data = NULL;
ut_ad(!is_system_tablespace(space_id));
ut_ad(!srv_read_only_mode);
@@ -3019,6 +3018,19 @@ err_exit:
fsp_header_init_fields(page, space_id, flags);
mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space_id);
+ /* Create crypt data if the tablespace is either encrypted or user has
+ requested it to remain unencrypted. */
+ fil_space_crypt_t *crypt_data = (mode != FIL_ENCRYPTION_DEFAULT
+ || srv_encrypt_tables)
+ ? fil_space_create_crypt_data(mode, key_id)
+ : NULL;
+
+ if (crypt_data) {
+ /* Write crypt data information in page0 while creating
+ ibd file. */
+ crypt_data->fill_page0(flags, page);
+ }
+
if (ulint zip_size = fil_space_t::zip_size(flags)) {
page_zip_des_t page_zip;
page_zip_set_size(&page_zip, zip_size);
@@ -3066,15 +3078,9 @@ err_exit:
}
}
- /* Create crypt data if the tablespace is either encrypted or user has
- requested it to remain unencrypted. */
- if (mode == FIL_ENCRYPTION_ON || mode == FIL_ENCRYPTION_OFF ||
- srv_encrypt_tables) {
- crypt_data = fil_space_create_crypt_data(mode, key_id);
- }
-
- space = fil_space_create(name, space_id, flags, FIL_TYPE_TABLESPACE,
- crypt_data, mode);
+ fil_space_t* space = fil_space_create(name, space_id, flags,
+ FIL_TYPE_TABLESPACE,
+ crypt_data, mode);
if (!space) {
free(crypt_data);
*err = DB_ERROR;
diff --git a/storage/innobase/fsp/fsp0file.cc b/storage/innobase/fsp/fsp0file.cc
index 4143e246f99..4869160b883 100644
--- a/storage/innobase/fsp/fsp0file.cc
+++ b/storage/innobase/fsp/fsp0file.cc
@@ -699,7 +699,8 @@ Datafile::find_space_id()
/* For noncompressed pages, the page size must be
equal to srv_page_size. */
- if (page_size == srv_page_size) {
+ if (page_size == srv_page_size
+ && !fil_space_t::zip_size(fsp_flags)) {
noncompressed_ok = !buf_page_is_corrupted(
false, page, fsp_flags);
}
@@ -707,7 +708,7 @@ Datafile::find_space_id()
bool compressed_ok = false;
if (srv_page_size <= UNIV_PAGE_SIZE_DEF
- && page_size <= srv_page_size) {
+ && page_size == fil_space_t::zip_size(fsp_flags)) {
compressed_ok = !buf_page_is_corrupted(
false, page, fsp_flags);
}
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 116625bbe11..9f4c04741b6 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -218,6 +218,7 @@ extern my_bool srv_background_scrub_data_compressed;
extern uint srv_background_scrub_data_interval;
extern uint srv_background_scrub_data_check_interval;
#ifdef UNIV_DEBUG
+my_bool innodb_evict_tables_on_commit_debug;
extern my_bool srv_scrub_force_testing;
#endif
@@ -2988,7 +2989,7 @@ static bool innobase_query_caching_table_check(
const char* norm_name)
{
dict_table_t* table = dict_table_open_on_name(
- norm_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
+ norm_name, FALSE, FALSE, DICT_ERR_IGNORE_FK_NOKEY);
if (table == NULL) {
return false;
@@ -5938,9 +5939,7 @@ ha_innobase::open(const char* name, int, uint)
the rollback invoking dict_index_t::clear_instant_alter() while
open table handles exist in client connections. */
- dict_table_t* ib_table;
char norm_name[FN_REFLEN];
- dict_err_ignore_t ignore_err = DICT_ERR_IGNORE_NONE;
DBUG_ENTER("ha_innobase::open");
@@ -5954,15 +5953,8 @@ ha_innobase::open(const char* name, int, uint)
char* is_part = is_partition(norm_name);
THD* thd = ha_thd();
-
- /* Check whether FOREIGN_KEY_CHECKS is set to 0. If so, the table
- can be opened even if some FK indexes are missing. If not, the table
- can't be opened in the same situation */
- if (thd_test_options(thd, OPTION_NO_FOREIGN_KEY_CHECKS)) {
- ignore_err = DICT_ERR_IGNORE_FK_NOKEY;
- }
-
- ib_table = open_dict_table(name, norm_name, is_part, ignore_err);
+ dict_table_t* ib_table = open_dict_table(name, norm_name, is_part,
+ DICT_ERR_IGNORE_FK_NOKEY);
DEBUG_SYNC(thd, "ib_open_after_dict_open");
@@ -10001,17 +9993,6 @@ next_record:
}
#ifdef WITH_WSREP
-extern dict_index_t*
-wsrep_dict_foreign_find_index(
-/*==========================*/
- dict_table_t* table,
- const char** col_names,
- const char** columns,
- ulint n_cols,
- dict_index_t* types_idx,
- ibool check_charsets,
- ulint check_null);
-
inline
const char*
wsrep_key_type_to_str(Wsrep_service_key_type type)
@@ -10075,7 +10056,7 @@ wsrep_append_foreign_key(
foreign->referenced_table_name_lookup);
if (foreign->referenced_table) {
foreign->referenced_index =
- wsrep_dict_foreign_find_index(
+ dict_foreign_find_index(
foreign->referenced_table, NULL,
foreign->referenced_col_names,
foreign->n_fields,
@@ -10089,7 +10070,7 @@ wsrep_append_foreign_key(
if (foreign->foreign_table) {
foreign->foreign_index =
- wsrep_dict_foreign_find_index(
+ dict_foreign_find_index(
foreign->foreign_table, NULL,
foreign->foreign_col_names,
foreign->n_fields,
@@ -13028,8 +13009,8 @@ innobase_rename_table(
row_mysql_lock_data_dictionary(trx);
}
- dict_table_t* table = dict_table_open_on_name(norm_from, TRUE, FALSE,
- DICT_ERR_IGNORE_NONE);
+ dict_table_t* table = dict_table_open_on_name(
+ norm_from, TRUE, FALSE, DICT_ERR_IGNORE_FK_NOKEY);
/* Since DICT_BG_YIELD has sleep for 250 milliseconds,
Convert lock_wait_timeout unit from second to 250 milliseconds */
@@ -14149,7 +14130,7 @@ ha_innobase::defragment_table(
normalize_table_name(norm_name, name);
table = dict_table_open_on_name(norm_name, FALSE,
- FALSE, DICT_ERR_IGNORE_NONE);
+ FALSE, DICT_ERR_IGNORE_FK_NOKEY);
for (index = dict_table_get_first_index(table); index;
index = dict_table_get_next_index(index)) {
@@ -19394,6 +19375,11 @@ static MYSQL_SYSVAR_BOOL(trx_purge_view_update_only_debug,
" but the each purges were not done yet.",
NULL, NULL, FALSE);
+static MYSQL_SYSVAR_BOOL(evict_tables_on_commit_debug,
+ innodb_evict_tables_on_commit_debug, PLUGIN_VAR_OPCMDARG,
+ "On transaction commit, try to evict tables from the data dictionary cache.",
+ NULL, NULL, FALSE);
+
static MYSQL_SYSVAR_UINT(data_file_size_debug,
srv_sys_space_size_debug,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
@@ -19755,6 +19741,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(trx_rseg_n_slots_debug),
MYSQL_SYSVAR(limit_optimistic_insert_debug),
MYSQL_SYSVAR(trx_purge_view_update_only_debug),
+ MYSQL_SYSVAR(evict_tables_on_commit_debug),
MYSQL_SYSVAR(data_file_size_debug),
MYSQL_SYSVAR(fil_make_page_dirty_debug),
MYSQL_SYSVAR(saved_page_number_debug),
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 3d8f068b188..f280c735e05 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -3181,7 +3181,7 @@ innobase_col_to_mysql(
case DATA_SYS:
/* These column types should never be shipped to MySQL. */
ut_ad(0);
-
+ /* fall through */
case DATA_FLOAT:
case DATA_DOUBLE:
case DATA_DECIMAL:
@@ -9935,8 +9935,7 @@ commit_cache_rebuild(
/** Set of column numbers */
typedef std::set<ulint, std::less<ulint>, ut_allocator<ulint> > col_set;
-/** Store the column number of the columns in a list belonging
-to indexes which are not being dropped.
+/** Collect (not instantly dropped) columns from dropped indexes
@param[in] ctx In-place ALTER TABLE context
@param[in, out] drop_col_list list which will be set, containing columns
which is part of index being dropped
@@ -9945,7 +9944,7 @@ to indexes which are not being dropped.
being dropped */
static
void
-get_col_list_to_be_dropped(
+collect_columns_from_dropped_indexes(
const ha_innobase_inplace_ctx* ctx,
col_set& drop_col_list,
col_set& drop_v_col_list)
@@ -9966,6 +9965,12 @@ get_col_list_to_be_dropped(
} else {
ulint col_no = dict_col_get_no(idx_col);
+ if (ctx->col_map
+ && ctx->col_map[col_no]
+ == ULINT_UNDEFINED) {
+ // this column was instantly dropped
+ continue;
+ }
drop_col_list.insert(col_no);
}
}
@@ -10282,25 +10287,21 @@ commit_cache_norebuild(
col_set drop_list;
col_set v_drop_list;
- col_set::const_iterator col_it;
/* Check if the column, part of an index to be dropped is part of any
other index which is not being dropped. If it so, then set the ord_part
of the column to 0. */
- get_col_list_to_be_dropped(ctx, drop_list, v_drop_list);
+ collect_columns_from_dropped_indexes(ctx, drop_list, v_drop_list);
- for (col_it = drop_list.begin(); col_it != drop_list.end(); ++col_it) {
- if (!check_col_exists_in_indexes(ctx->new_table,
- *col_it, false)) {
- ctx->new_table->cols[*col_it].ord_part = 0;
+ for (ulint col : drop_list) {
+ if (!check_col_exists_in_indexes(ctx->new_table, col, false)) {
+ ctx->new_table->cols[col].ord_part = 0;
}
}
- for (col_it = v_drop_list.begin();
- col_it != v_drop_list.end(); ++col_it) {
- if (!check_col_exists_in_indexes(ctx->new_table,
- *col_it, true)) {
- ctx->new_table->v_cols[*col_it].m_col.ord_part = 0;
+ for (ulint col : v_drop_list) {
+ if (!check_col_exists_in_indexes(ctx->new_table, col, true)) {
+ ctx->new_table->v_cols[col].m_col.ord_part = 0;
}
}
diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
index 99b6971f603..32782c27b55 100644
--- a/storage/innobase/include/dict0dict.h
+++ b/storage/innobase/include/dict0dict.h
@@ -116,12 +116,7 @@ dict_table_open_on_id(
/**********************************************************************//**
Returns a table object based on table id.
@return table, NULL if does not exist */
-UNIV_INTERN
-dict_table_t*
-dict_table_open_on_index_id(
-/*==================*/
- table_id_t table_id, /*!< in: table id */
- bool dict_locked) /*!< in: TRUE=data dictionary locked */
+dict_table_t* dict_table_open_on_index_id(index_id_t index_id)
__attribute__((warn_unused_result));
/********************************************************************//**
Decrements the count of open handles to a table. */
@@ -489,6 +484,21 @@ dict_table_open_on_name(
dict_err_ignore_t ignore_err)
MY_ATTRIBUTE((warn_unused_result));
+/** Outcome of dict_foreign_find_index() or dict_foreign_qualify_index() */
+enum fkerr_t
+{
+ /** A backing index was found for a FOREIGN KEY constraint */
+ FK_SUCCESS = 0,
+ /** There is no index that covers the columns in the constraint. */
+ FK_INDEX_NOT_FOUND,
+ /** The index is for a prefix index, not a full column. */
+ FK_IS_PREFIX_INDEX,
+ /** A condition of SET NULL conflicts with a NOT NULL column. */
+ FK_COL_NOT_NULL,
+ /** The column types do not match */
+ FK_COLS_NOT_EQUAL
+};
+
/*********************************************************************//**
Tries to find an index whose first fields are the columns in the array,
in the same order and is not marked for deletion and is not the same
@@ -515,11 +525,11 @@ dict_foreign_find_index(
/*!< in: nonzero if none of
the columns must be declared
NOT NULL */
- ulint* error, /*!< out: error code */
- ulint* err_col_no,
+ fkerr_t* error = NULL, /*!< out: error code */
+ ulint* err_col_no = NULL,
/*!< out: column number where
error happened */
- dict_index_t** err_index)
+ dict_index_t** err_index = NULL)
/*!< out: index where error
happened */
@@ -595,7 +605,7 @@ dict_foreign_qualify_index(
/*!< in: nonzero if none of
the columns must be declared
NOT NULL */
- ulint* error, /*!< out: error code */
+ fkerr_t* error, /*!< out: error code */
ulint* err_col_no,
/*!< out: column number where
error happened */
diff --git a/storage/innobase/include/dict0types.h b/storage/innobase/include/dict0types.h
index 9f6edb0351f..d0e1ddaa664 100644
--- a/storage/innobase/include/dict0types.h
+++ b/storage/innobase/include/dict0types.h
@@ -66,11 +66,11 @@ Note: please define the IGNORE_ERR_* as bits, so their value can
be or-ed together */
enum dict_err_ignore_t {
DICT_ERR_IGNORE_NONE = 0, /*!< no error to ignore */
- DICT_ERR_IGNORE_INDEX_ROOT = 1, /*!< ignore error if index root
- page is FIL_NULL or incorrect value */
- DICT_ERR_IGNORE_CORRUPT = 2, /*!< skip corrupted indexes */
- DICT_ERR_IGNORE_FK_NOKEY = 4, /*!< ignore error if any foreign
+ DICT_ERR_IGNORE_FK_NOKEY = 1, /*!< ignore error if any foreign
key is missing */
+ DICT_ERR_IGNORE_INDEX_ROOT = 2, /*!< ignore error if index root
+ page is FIL_NULL or incorrect value */
+ DICT_ERR_IGNORE_CORRUPT = 4, /*!< skip corrupted indexes */
DICT_ERR_IGNORE_RECOVER_LOCK = 8,
/*!< Used when recovering table locks
for resurrected transactions.
diff --git a/storage/innobase/include/fil0crypt.h b/storage/innobase/include/fil0crypt.h
index 7a54cb4d53f..79924edceb4 100644
--- a/storage/innobase/include/fil0crypt.h
+++ b/storage/innobase/include/fil0crypt.h
@@ -178,6 +178,12 @@ struct fil_space_crypt_t : st_encryption_scheme
return (encryption == FIL_ENCRYPTION_OFF);
}
+ /** Fill crypt data information to the give page.
+ It should be called during ibd file creation.
+ @param[in] flags tablespace flags
+ @param[in,out] page first page of the tablespace */
+ void fill_page0(ulint flags, byte* page);
+
/** Write crypt data to a page (0)
@param[in] space tablespace
@param[in,out] page0 first page of the tablespace
diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
index d6188362e9a..e972fffa5bf 100644
--- a/storage/innobase/include/srv0srv.h
+++ b/storage/innobase/include/srv0srv.h
@@ -539,6 +539,7 @@ extern my_bool srv_ibuf_disable_background_merge;
#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
#ifdef UNIV_DEBUG
+extern my_bool innodb_evict_tables_on_commit_debug;
extern my_bool srv_sync_debug;
extern my_bool srv_purge_view_update_only_debug;
diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h
index 4175128217b..437459865fe 100644
--- a/storage/innobase/include/trx0sys.h
+++ b/storage/innobase/include/trx0sys.h
@@ -644,11 +644,8 @@ public:
{
mutex_enter(&element->mutex);
lf_hash_search_unpin(pins);
- trx= element->trx;
- if (!trx);
- else if (UNIV_UNLIKELY(trx_id != trx->id))
- trx= NULL;
- else {
+ if ((trx= element->trx)) {
+ DBUG_ASSERT(trx_id == trx->id);
if (do_ref_count)
trx->reference();
ut_d(validate_element(trx));
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index 7e7558aff32..dc7a66ea317 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -1217,9 +1217,7 @@ lock_sec_rec_some_has_impl(
/* Some transaction may have an implicit x-lock on the record only
if the max trx id for the page >= min trx id for the trx list, or
- database recovery is running. We do not write the changes of a page
- max trx id to the log, and therefore during recovery, this value
- for a page may be incorrect. */
+ database recovery is running. */
if (max_trx_id < trx_sys.get_min_trx_id()) {
@@ -6192,9 +6190,6 @@ lock_trx_release_locks(
/*--------------------------------------*/
trx_mutex_enter(trx);
trx->state = TRX_STATE_COMMITTED_IN_MEMORY;
- /* Ensure that rw_trx_hash_t::find() will no longer find
- this transaction. */
- trx->id = 0;
trx_mutex_exit(trx);
/*--------------------------------------*/
diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc
index 75e6b500c07..2c255478969 100644
--- a/storage/innobase/mtr/mtr0mtr.cc
+++ b/storage/innobase/mtr/mtr0mtr.cc
@@ -753,7 +753,7 @@ mtr_t::Command::prepare_write()
switch (m_impl->m_log_mode) {
case MTR_LOG_SHORT_INSERTS:
ut_ad(0);
- /* fall through (write no redo log) */
+ /* fall through */
case MTR_LOG_NO_REDO:
case MTR_LOG_NONE:
ut_ad(m_impl->m_log.size() == 0);
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
index a036821cab1..64e38f7ff2f 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -871,8 +871,12 @@ row_ins_foreign_report_add_err(
fk_str = dict_print_info_on_foreign_key_in_create_format(trx, foreign,
TRUE);
fputs(fk_str.c_str(), ef);
- fprintf(ef, " in parent table, in index %s",
- foreign->foreign_index->name());
+ if (foreign->foreign_index) {
+ fprintf(ef, " in parent table, in index %s",
+ foreign->foreign_index->name());
+ } else {
+ fputs(" in parent table", ef);
+ }
if (entry) {
fputs(" tuple:\n", ef);
/* TODO: DB_TRX_ID and DB_ROLL_PTR may be uninitialized.
@@ -1656,34 +1660,51 @@ row_ins_check_foreign_constraint(
|| !check_table->is_readable()
|| check_index == NULL) {
- if (!srv_read_only_mode && check_ref) {
- FILE* ef = dict_foreign_err_file;
- std::string fk_str;
-
- row_ins_set_detailed(trx, foreign);
-
- row_ins_foreign_trx_print(trx);
-
- fputs("Foreign key constraint fails for table ", ef);
- ut_print_name(ef, trx,
- foreign->foreign_table_name);
- fputs(":\n", ef);
- fk_str = dict_print_info_on_foreign_key_in_create_format(
- trx, foreign, TRUE);
- fputs(fk_str.c_str(), ef);
- fprintf(ef, "\nTrying to add to index %s tuple:\n",
- foreign->foreign_index->name());
+ FILE* ef = dict_foreign_err_file;
+ std::string fk_str;
+
+ row_ins_set_detailed(trx, foreign);
+ row_ins_foreign_trx_print(trx);
+
+ fputs("Foreign key constraint fails for table ", ef);
+ ut_print_name(ef, trx, check_ref
+ ? foreign->foreign_table_name
+ : foreign->referenced_table_name);
+ fputs(":\n", ef);
+ fk_str = dict_print_info_on_foreign_key_in_create_format(
+ trx, foreign, TRUE);
+ fputs(fk_str.c_str(), ef);
+ if (check_ref) {
+ if (foreign->foreign_index) {
+ fprintf(ef, "\nTrying to add to index %s"
+ " tuple:\n",
+ foreign->foreign_index->name());
+ } else {
+ fputs("\nTrying to add tuple:\n", ef);
+ }
dtuple_print(ef, entry);
fputs("\nBut the parent table ", ef);
- ut_print_name(ef, trx,
- foreign->referenced_table_name);
- fputs("\nor its .ibd file does"
+ ut_print_name(ef, trx, foreign->referenced_table_name);
+ fputs("\nor its .ibd file or the required index does"
" not currently exist!\n", ef);
- mutex_exit(&dict_foreign_err_mutex);
-
err = DB_NO_REFERENCED_ROW;
+ } else {
+ if (foreign->referenced_index) {
+ fprintf(ef, "\nTrying to modify index %s"
+ " tuple:\n",
+ foreign->referenced_index->name());
+ } else {
+ fputs("\nTrying to modify tuple:\n", ef);
+ }
+ dtuple_print(ef, entry);
+ fputs("\nBut the referencing table ", ef);
+ ut_print_name(ef, trx, foreign->foreign_table_name);
+ fputs("\nor its .ibd file or the required index does"
+ " not currently exist!\n", ef);
+ err = DB_ROW_IS_REFERENCED;
}
+ mutex_exit(&dict_foreign_err_mutex);
goto exit_func;
}
@@ -1949,6 +1970,7 @@ row_ins_check_foreign_constraints(
/*==============================*/
dict_table_t* table, /*!< in: table */
dict_index_t* index, /*!< in: index */
+ bool pk, /*!< in: index->is_primary() */
dtuple_t* entry, /*!< in: index entry for index */
que_thr_t* thr) /*!< in: query thread */
{
@@ -1957,6 +1979,8 @@ row_ins_check_foreign_constraints(
trx_t* trx;
ibool got_s_lock = FALSE;
+ DBUG_ASSERT(index->is_primary() == pk);
+
trx = thr_get_trx(thr);
DEBUG_SYNC_C_IF_THD(thr_get_trx(thr)->mysql_thd,
@@ -1968,7 +1992,8 @@ row_ins_check_foreign_constraints(
foreign = *it;
- if (foreign->foreign_index == index) {
+ if (foreign->foreign_index == index
+ || (pk && !foreign->foreign_index)) {
dict_table_t* ref_table = NULL;
dict_table_t* referenced_table
= foreign->referenced_table;
@@ -3177,7 +3202,7 @@ row_ins_clust_index_entry(
if (!index->table->foreign_set.empty()) {
err = row_ins_check_foreign_constraints(
- index->table, index, entry, thr);
+ index->table, index, true, entry, thr);
if (err != DB_SUCCESS) {
DBUG_RETURN(err);
@@ -3276,7 +3301,7 @@ row_ins_sec_index_entry(
if (!index->table->foreign_set.empty()) {
err = row_ins_check_foreign_constraints(index->table, index,
- entry, thr);
+ false, entry, thr);
if (err != DB_SUCCESS) {
return(err);
diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc
index 1a10657cf99..fb0a376dd34 100644
--- a/storage/innobase/row/row0log.cc
+++ b/storage/innobase/row/row0log.cc
@@ -1795,6 +1795,7 @@ row_log_table_apply_insert(
break;
default:
ut_ad(0);
+ /* fall through */
case DB_INVALID_NULL:
ut_ad(row == NULL);
return(error);
@@ -2082,6 +2083,7 @@ row_log_table_apply_update(
break;
default:
ut_ad(0);
+ /* fall through */
case DB_INVALID_NULL:
ut_ad(row == NULL);
return(error);
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index f3f6cf9ed77..7e593d1ebec 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -1419,11 +1419,13 @@ row_insert_for_mysql(
&blob_heap);
if (ins_mode != ROW_INS_NORMAL) {
+#ifndef DBUG_OFF
ut_ad(table->vers_start != table->vers_end);
const mysql_row_templ_t* t
= prebuilt->get_template_by_col(table->vers_end);
ut_ad(t);
ut_ad(t->mysql_col_len == 8);
+#endif
if (ins_mode == ROW_INS_HISTORICAL) {
set_tuple_col_8(node->row, table->vers_end, trx->id,
@@ -1431,9 +1433,11 @@ row_insert_for_mysql(
} else /* ROW_INS_VERSIONED */ {
set_tuple_col_8(node->row, table->vers_end, TRX_ID_MAX,
node->vers_end_buf);
+#ifndef DBUG_OFF
t = prebuilt->get_template_by_col(table->vers_start);
ut_ad(t);
ut_ad(t->mysql_col_len == 8);
+#endif
set_tuple_col_8(node->row, table->vers_start, trx->id,
node->vers_start_buf);
}
@@ -2878,7 +2882,7 @@ row_discard_tablespace_begin(
dict_table_t* table;
table = dict_table_open_on_name(
- name, TRUE, FALSE, DICT_ERR_IGNORE_NONE);
+ name, TRUE, FALSE, DICT_ERR_IGNORE_FK_NOKEY);
if (table) {
dict_stats_wait_bg_to_stop_using_table(table, trx);
@@ -3262,7 +3266,7 @@ row_drop_table_from_cache(
dict_sys.remove(table);
- if (dict_load_table(tablename, true, DICT_ERR_IGNORE_NONE)) {
+ if (dict_load_table(tablename, true, DICT_ERR_IGNORE_FK_NOKEY)) {
ib::error() << "Not able to remove table "
<< ut_get_name(trx, tablename)
<< " from the dictionary cache!";
@@ -4174,7 +4178,7 @@ row_rename_table_for_mysql(
dict_locked = trx->dict_operation_lock_mode == RW_X_LATCH;
table = dict_table_open_on_name(old_name, dict_locked, FALSE,
- DICT_ERR_IGNORE_NONE);
+ DICT_ERR_IGNORE_FK_NOKEY);
/* We look for pattern #P# to see if the table is partitioned
MySQL table. */
@@ -4222,7 +4226,7 @@ row_rename_table_for_mysql(
par_case_name, old_name, FALSE);
#endif
table = dict_table_open_on_name(par_case_name, dict_locked, FALSE,
- DICT_ERR_IGNORE_NONE);
+ DICT_ERR_IGNORE_FK_NOKEY);
}
if (!table) {
diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc
index cfed0804373..88dea6c7995 100644
--- a/storage/innobase/row/row0uins.cc
+++ b/storage/innobase/row/row0uins.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2018, MariaDB Corporation.
+Copyright (c) 2017, 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
@@ -566,6 +566,7 @@ row_undo_ins(
switch (node->rec_type) {
default:
ut_ad(!"wrong undo record type");
+ /* fall through */
case TRX_UNDO_INSERT_REC:
/* Skip the clustered index (the first index) */
node->index = dict_table_get_next_index(node->index);
diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
index 5266b467091..8b1ddfc36a6 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -987,21 +987,20 @@ row_upd_build_difference_binary(
TABLE* mysql_table,
dberr_t* error)
{
- upd_field_t* upd_field;
ulint len;
upd_t* update;
ulint n_diff;
- ulint i;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint n_fld = dtuple_get_n_fields(entry);
- ulint n_v_fld = dtuple_get_n_v_fields(entry);
+ const ulint n_v_fld = dtuple_get_n_v_fields(entry);
rec_offs_init(offsets_);
/* This function is used only for a clustered index */
ut_a(dict_index_is_clust(index));
ut_ad(!index->table->skip_alter_undo);
+ ut_ad(entry->n_fields <= index->n_fields);
+ ut_ad(entry->n_fields >= index->n_core_fields);
- update = upd_create(n_fld + n_v_fld, heap);
+ update = upd_create(index->n_fields + n_v_fld, heap);
n_diff = 0;
@@ -1012,7 +1011,7 @@ row_upd_build_difference_binary(
ut_ad(rec_offs_validate(rec, index, offsets));
}
- for (i = 0; i < n_fld; i++) {
+ for (ulint i = 0; i < entry->n_fields; i++) {
const byte* data = rec_get_nth_cfield(rec, index, offsets, i,
&len);
const dfield_t* dfield = dtuple_get_nth_field(entry, i);
@@ -1027,17 +1026,22 @@ row_upd_build_difference_binary(
if (!dfield_is_ext(dfield)
!= !rec_offs_nth_extern(offsets, i)
|| !dfield_data_is_binary_equal(dfield, len, data)) {
-
- upd_field = upd_get_nth_field(update, n_diff);
-
- dfield_copy(&(upd_field->new_val), dfield);
-
- upd_field_set_field_no(upd_field, i, index);
-
- n_diff++;
+ upd_field_t* uf = upd_get_nth_field(update, n_diff++);
+ dfield_copy(&uf->new_val, dfield);
+ upd_field_set_field_no(uf, i, index);
}
}
+ for (ulint i = entry->n_fields; i < index->n_fields; i++) {
+ upd_field_t* uf = upd_get_nth_field(update, n_diff++);
+ const dict_col_t* col = dict_index_get_nth_col(index, i);
+ /* upd_create() zero-initialized uf */
+ uf->new_val.data = const_cast<byte*>(col->instant_value(&len));
+ uf->new_val.len = static_cast<unsigned>(len);
+ dict_col_copy_type(col, &uf->new_val.type);
+ upd_field_set_field_no(uf, i, index);
+ }
+
/* Check the virtual columns updates. Even if there is no non-virtual
column (base columns) change, we will still need to build the
indexed virtual column value so that undo log would log them (
@@ -1062,7 +1066,7 @@ row_upd_build_difference_binary(
&mysql_table,
&record, &vcol_storage);
- for (i = 0; i < n_v_fld; i++) {
+ for (ulint i = 0; i < n_v_fld; i++) {
const dict_v_col_t* col
= dict_table_get_nth_v_col(index->table, i);
@@ -1090,24 +1094,16 @@ row_upd_build_difference_binary(
entry, i);
if (!dfield_data_is_binary_equal(
- dfield, vfield->len,
- static_cast<byte*>(vfield->data))) {
- upd_field = upd_get_nth_field(update, n_diff);
-
- upd_field->old_v_val = static_cast<dfield_t*>(
- mem_heap_alloc(
- heap,
- sizeof *upd_field->old_v_val));
-
- dfield_copy(upd_field->old_v_val, vfield);
-
- dfield_copy(&(upd_field->new_val), dfield);
-
- upd_field_set_v_field_no(
- upd_field, i, index);
-
- n_diff++;
-
+ dfield, vfield->len,
+ static_cast<byte*>(vfield->data))) {
+ upd_field_t* uf = upd_get_nth_field(update,
+ n_diff++);
+ uf->old_v_val = static_cast<dfield_t*>(
+ mem_heap_alloc(heap,
+ sizeof *uf->old_v_val));
+ dfield_copy(uf->old_v_val, vfield);
+ dfield_copy(&uf->new_val, dfield);
+ upd_field_set_v_field_no(uf, i, index);
}
}
diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc
index 00fbac10c82..58172bccc84 100644
--- a/storage/innobase/srv/srv0start.cc
+++ b/storage/innobase/srv/srv0start.cc
@@ -2171,6 +2171,19 @@ files_checked:
is at most one data dictionary transaction
active at a time. */
if (srv_force_recovery < SRV_FORCE_NO_TRX_UNDO) {
+ /* If the following call is ever
+ removed, the first-time
+ ha_innobase::open() must hold (or
+ acquire and release) a table lock that
+ conflicts with
+ trx_resurrect_table_locks(), to ensure
+ that any recovered incomplete ALTER
+ TABLE will have been rolled
+ back. Otherwise, dict_table_t::instant
+ could be cleared by rollback invoking
+ dict_index_t::clear_instant_alter()
+ while open table handles exist in
+ client connections. */
trx_rollback_recovered(false);
}
}
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index 1ed5a8dff47..46a0581025e 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -497,6 +497,7 @@ trx_free_at_shutdown(trx_t *trx)
transaction was never committed and therefore lock_trx_release()
was not called. */
trx->lock.table_locks.clear();
+ trx->id = 0;
trx_free(trx);
}
@@ -1239,6 +1240,22 @@ trx_update_mod_tables_timestamp(
const time_t now = time(NULL);
trx_mod_tables_t::const_iterator end = trx->mod_tables.end();
+#ifdef UNIV_DEBUG
+# if MYSQL_VERSION_ID >= 100405
+# define dict_sys_mutex dict_sys.mutex
+# else
+# define dict_sys_mutex dict_sys->mutex
+# endif
+
+ const bool preserve_tables = !innodb_evict_tables_on_commit_debug
+ || trx->is_recovered /* avoid trouble with XA recovery */
+# if 1 /* if dict_stats_exec_sql() were not playing dirty tricks */
+ || mutex_own(&dict_sys_mutex)
+# else /* this would be more proper way to do it */
+ || trx->dict_operation_lock_mode || trx->dict_operation
+# endif
+ ;
+#endif
for (trx_mod_tables_t::const_iterator it = trx->mod_tables.begin();
it != end;
@@ -1252,7 +1269,27 @@ trx_update_mod_tables_timestamp(
"garbage" in table->update_time is justified because
protecting it with a latch here would be too performance
intrusive. */
- it->first->update_time = now;
+ dict_table_t* table = it->first;
+ table->update_time = now;
+#ifdef UNIV_DEBUG
+ if (preserve_tables || table->get_ref_count()) {
+ /* do not evict when committing DDL operations
+ or if some other transaction is holding the
+ table handle */
+ continue;
+ }
+ /* recheck while holding the mutex that blocks
+ table->acquire() */
+ mutex_enter(&dict_sys_mutex);
+ if (!table->get_ref_count()) {
+# if MYSQL_VERSION_ID >= 100405
+ dict_sys.remove(table, true);
+# else
+ dict_table_remove_from_cache_low(table, true);
+# endif
+ }
+ mutex_exit(&dict_sys_mutex);
+#endif
}
trx->mod_tables.clear();
@@ -1337,10 +1374,8 @@ trx_commit_in_memory(
trx_sys.deregister_rw(trx);
}
- /* trx->id will be cleared in lock_trx_release_locks(trx). */
- ut_ad(trx->read_only || !trx->rsegs.m_redo.rseg || trx->id);
lock_trx_release_locks(trx);
- ut_ad(trx->id == 0);
+ ut_ad(trx->read_only || !trx->rsegs.m_redo.rseg || trx->id);
/* Remove the transaction from the list of active
transactions now that it no longer holds any user locks. */
@@ -1360,6 +1395,8 @@ trx_commit_in_memory(
UT_LIST_REMOVE(trx->lock.evicted_tables, table);
dict_mem_table_free(table);
}
+
+ trx->id = 0;
}
ut_ad(!trx->rsegs.m_redo.undo);
diff --git a/storage/maria/ma_ft_nlq_search.c b/storage/maria/ma_ft_nlq_search.c
index 7becf1d7136..f7aa3afec9a 100644
--- a/storage/maria/ma_ft_nlq_search.c
+++ b/storage/maria/ma_ft_nlq_search.c
@@ -79,13 +79,13 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
MARIA_KEY key;
float tmp_weight;
DBUG_ENTER("walk_and_match");
- LINT_INIT_STRUCT(subkeys);
word->weight=LWS_FOR_QUERY;
_ma_ft_make_key(info, &key, aio->keynr, keybuff, word, 0);
key.data_length-= HA_FT_WLEN;
doc_cnt=0;
+ subkeys.i= 0;
if (share->lock_key_trees)
mysql_rwlock_rdlock(&share->keyinfo[aio->keynr].root_lock);
diff --git a/storage/myisam/ft_nlq_search.c b/storage/myisam/ft_nlq_search.c
index 6c36c327d81..3e433b71761 100644
--- a/storage/myisam/ft_nlq_search.c
+++ b/storage/myisam/ft_nlq_search.c
@@ -77,13 +77,13 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
uint extra= HA_FT_WLEN + info->s->rec_reflength;
float tmp_weight;
DBUG_ENTER("walk_and_match");
- LINT_INIT_STRUCT(subkeys);
word->weight=LWS_FOR_QUERY;
keylen=_ft_make_key(info,aio->keynr,keybuff,word,0);
keylen-=HA_FT_WLEN;
doc_cnt=0;
+ subkeys.i= 0;
if (share->concurrent_insert)
mysql_rwlock_rdlock(&share->key_root_lock[aio->keynr]);
diff --git a/storage/perfschema/pfs_instr.cc b/storage/perfschema/pfs_instr.cc
index b6736cf3102..f90c6475f22 100644
--- a/storage/perfschema/pfs_instr.cc
+++ b/storage/perfschema/pfs_instr.cc
@@ -1265,7 +1265,6 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass,
char dirbuffer[FN_REFLEN];
size_t dirlen;
const char *normalized_filename;
- int normalized_length;
dirlen= dirname_length(safe_filename);
if (dirlen == 0)
@@ -1296,7 +1295,7 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass,
*buf_end= '\0';
normalized_filename= buffer;
- normalized_length= (int)strlen(normalized_filename);
+ uint normalized_length= static_cast<uint>(strlen(normalized_filename));
PFS_file **entry;
uint retry_count= 0;
@@ -1345,7 +1344,7 @@ search:
pfs->m_class= klass;
pfs->m_enabled= klass->m_enabled && flag_global_instrumentation;
pfs->m_timed= klass->m_timed;
- strncpy(pfs->m_filename, normalized_filename, normalized_length);
+ strncpy(pfs->m_filename, normalized_filename, normalized_length + 1);
pfs->m_filename[normalized_length]= '\0';
pfs->m_filename_length= normalized_length;
pfs->m_file_stat.m_open_count= 1;
diff --git a/storage/rocksdb/mysql-test/rocksdb/include/index_merge1.inc b/storage/rocksdb/mysql-test/rocksdb/include/index_merge1.inc
index 91bcc68adb4..b5cf7bff763 100644
--- a/storage/rocksdb/mysql-test/rocksdb/include/index_merge1.inc
+++ b/storage/rocksdb/mysql-test/rocksdb/include/index_merge1.inc
@@ -58,6 +58,10 @@ while ($1)
eval set @d=@d*2;
dec $1;
}
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
--enable_query_log
analyze table t0;
@@ -329,6 +333,10 @@ alter table t2 add index i321(key3, key2, key1);
-- disable_query_log
-- disable_result_log
analyze table t2;
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
-- enable_result_log
-- enable_query_log
@@ -371,6 +379,10 @@ insert into t4 select key1,key1,key1 div 10, key1 % 10, key1 % 10, key1 from t0;
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t4;
-- enable_result_log
-- enable_query_log
@@ -397,6 +409,10 @@ insert into t1 select * from t0;
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
-- enable_result_log
-- enable_query_log
@@ -463,6 +479,10 @@ update t3 set key9=key1,keyA=key1,keyB=key1,keyC=key1;
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t3;
-- enable_result_log
-- enable_query_log
@@ -486,6 +506,10 @@ update t0 set key8=123 where key1 < 3 or key2 < 4;
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t0;
-- enable_result_log
-- enable_query_log
@@ -496,6 +520,10 @@ select * from t0 where key1 < 3 or key2 < 4;
delete from t0 where key1 < 3 or key2 < 4;
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t0;
-- enable_result_log
-- enable_query_log
@@ -509,6 +537,10 @@ create table t4 (a int);
insert into t4 values (1),(4),(3);
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t4;
-- enable_result_log
-- enable_query_log
@@ -533,6 +565,10 @@ select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4
update t0 set key1=1;
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t0;
-- enable_result_log
-- enable_query_log
@@ -556,6 +592,10 @@ update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500;
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t0;
-- enable_result_log
-- enable_query_log
@@ -612,6 +652,10 @@ select count(*) from t1;
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
-- enable_result_log
-- enable_query_log
@@ -652,6 +696,10 @@ create table t3 (
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t0;
analyze table t1;
analyze table t2;
@@ -733,6 +781,10 @@ insert into t2 select * from t1;
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
analyze table t2;
-- enable_result_log
@@ -787,6 +839,10 @@ insert into t3 values (1,1,'data');
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t0;
analyze table t1;
analyze table t2;
@@ -822,6 +878,10 @@ INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
-- enable_result_log
-- enable_query_log
diff --git a/storage/rocksdb/mysql-test/rocksdb/include/index_merge2.inc b/storage/rocksdb/mysql-test/rocksdb/include/index_merge2.inc
index 9fd2390c401..7e5cec40a80 100644
--- a/storage/rocksdb/mysql-test/rocksdb/include/index_merge2.inc
+++ b/storage/rocksdb/mysql-test/rocksdb/include/index_merge2.inc
@@ -43,6 +43,10 @@ while ($1)
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
-- enable_result_log
-- enable_query_log
@@ -68,6 +72,10 @@ alter table t1 add primary key (str1, zeroval, str2, str3);
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
-- enable_result_log
-- enable_query_log
@@ -101,6 +109,10 @@ while ($1)
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
-- enable_result_log
-- enable_query_log
@@ -143,6 +155,10 @@ select count(*) from t1;
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t2;
-- enable_result_log
-- enable_query_log
@@ -379,6 +395,10 @@ update t1 set key2=key1,key3=key1;
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
-- enable_result_log
-- enable_query_log
@@ -417,6 +437,10 @@ INSERT INTO t1 VALUES
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
-- enable_result_log
-- enable_query_log
@@ -472,6 +496,10 @@ INSERT INTO t1 VALUES (1,1,'a'), (2,2,'b');
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
-- enable_result_log
-- enable_query_log
diff --git a/storage/rocksdb/mysql-test/rocksdb/include/index_merge_ror.inc b/storage/rocksdb/mysql-test/rocksdb/include/index_merge_ror.inc
index ed270802db1..21219d1aa95 100644
--- a/storage/rocksdb/mysql-test/rocksdb/include/index_merge_ror.inc
+++ b/storage/rocksdb/mysql-test/rocksdb/include/index_merge_ror.inc
@@ -119,6 +119,10 @@ select count(*) from t1;
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t0;
analyze table t1;
-- enable_result_log
@@ -141,6 +145,10 @@ insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 100, 100, 'key4
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
-- enable_result_log
-- enable_query_log
@@ -193,6 +201,10 @@ update t1 set key1=200,key2=200 where key1=100 and key2=100;
delete from t1 where key1=200 and key2=200;
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
-- enable_result_log
-- enable_query_log
@@ -210,6 +222,10 @@ delete from t1 where key3=100 and key4=100;
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
-- enable_result_log
-- enable_query_log
@@ -236,6 +252,10 @@ insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
-- enable_result_log
-- enable_query_log
@@ -250,6 +270,10 @@ insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, -1, 200,'key4')
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
-- enable_result_log
-- enable_query_log
@@ -264,6 +288,10 @@ insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 200, -1,'key3')
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
-- enable_result_log
-- enable_query_log
@@ -392,6 +420,10 @@ select count(a) from t2 where b='BBBBBBBB';
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t2;
-- enable_result_log
-- enable_query_log
@@ -405,6 +437,10 @@ select count(a) from t2 ignore index(a,b) where a='AAAAAAAA' and b='AAAAAAAA';
insert into t2 values ('ab', 'ab', 'uh', 'oh');
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t2;
-- enable_result_log
-- enable_query_log
diff --git a/storage/rocksdb/mysql-test/rocksdb/include/index_merge_ror_cpk.inc b/storage/rocksdb/mysql-test/rocksdb/include/index_merge_ror_cpk.inc
index 9f1e2d77621..f0d18a50bff 100644
--- a/storage/rocksdb/mysql-test/rocksdb/include/index_merge_ror_cpk.inc
+++ b/storage/rocksdb/mysql-test/rocksdb/include/index_merge_ror_cpk.inc
@@ -68,6 +68,10 @@ set autocommit=1;
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
-- enable_result_log
-- enable_query_log
@@ -159,6 +163,10 @@ WHERE (SELECT COUNT(*) FROM t2 WHERE t2.f3 = 'h' AND t2.f2 = t1.f1) = 0 AND t1.f
-- disable_query_log
-- disable_result_log
+if ($engine_type == RocksDB)
+{
+ set global rocksdb_force_flush_memtable_now=1;
+}
analyze table t1;
analyze table t2;
-- enable_result_log
diff --git a/storage/rocksdb/mysql-test/rocksdb/r/index_merge_rocksdb2.result b/storage/rocksdb/mysql-test/rocksdb/r/index_merge_rocksdb2.result
index e0248737381..b34ec78cd03 100644
--- a/storage/rocksdb/mysql-test/rocksdb/r/index_merge_rocksdb2.result
+++ b/storage/rocksdb/mysql-test/rocksdb/r/index_merge_rocksdb2.result
@@ -23,10 +23,11 @@ INDEX i8(key8)
);
analyze table t0;
Table Op Msg_type Msg_text
+test.t0 analyze status Engine-independent statistics collected
test.t0 analyze status OK
explain select * from t0 where key1 < 3 or key1 > 1020;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t0 range i1 i1 4 NULL 2 Using index condition; Using where
+1 SIMPLE t0 range i1 i1 4 NULL 4 Using index condition
explain
select * from t0 where key1 < 3 or key2 > 1020;
id select_type table type possible_keys key key_len ref rows Extra
@@ -267,12 +268,12 @@ select * from t0,t1 where (t0.key1=t1.key1) and
(t0.key1=3 or t0.key2<4) and t1.key1=2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ref i1,i2 i1 4 const 2 Using where
-1 SIMPLE t1 ref i1 i1 4 const 1
+1 SIMPLE t1 ref i1 i1 4 const 2
explain select * from t0,t1 where t0.key1 = 5 and
(t1.key1 = t0.key1 or t1.key8 = t0.key1);
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t0 ref i1 i1 4 const 1
-1 SIMPLE t1 index_merge i1,i8 i1,i8 4,4 NULL 2 Using union(i1,i8); Using where; Using join buffer (flat, BNL join)
+1 SIMPLE t0 ref i1 i1 4 const 2
+1 SIMPLE t1 index_merge i1,i8 i1,i8 4,4 NULL 4 Using union(i1,i8); Using where; Using join buffer (flat, BNL join)
explain select * from t0,t1 where t0.key1 < 3 and
(t1.key1 = t0.key1 or t1.key8 = t0.key1);
id select_type table type possible_keys key key_len ref rows Extra
@@ -286,7 +287,7 @@ id select_type table type possible_keys key key_len ref rows Extra
NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL
explain select * from (select * from t1 where key1 = 3 or key2 =3) as Z where key8 >5;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index_merge i1,i2,i8 i1,i2 4,4 NULL 2 Using union(i1,i2); Using where
+1 SIMPLE t1 index_merge i1,i2,i8 i1,i2 4,4 NULL 4 Using union(i1,i2); Using where
create table t3 like t0;
insert into t3 select * from t0;
alter table t3 add key9 int not null, add index i9(key9);
@@ -392,10 +393,10 @@ count(*)
8704
explain select * from t1 WHERE cola = 'foo' AND colb = 'bar';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL # Using intersect(cola,colb); Using where
+1 SIMPLE t1 ref cola,colb cola 3 const # Using index condition; Using where
explain select * from t1 force index(cola,colb) WHERE cola = 'foo' AND colb = 'bar';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL # Using intersect(cola,colb); Using where
+1 SIMPLE t1 ref cola,colb cola 3 const # Using index condition; Using where
drop table t1;
CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES(1);
@@ -478,7 +479,7 @@ a filler b
must use union, not sort-union:
explain select * from t2 where a=4 or b=4;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t2 index_merge a,b a,b 5,5 NULL # Using union(a,b); Using where
+1 SIMPLE t2 ALL a,b NULL NULL NULL # Using where
select * from t2 where a=4 or b=4;
a filler b
4 4 0
@@ -603,7 +604,7 @@ count(*)
64801
explain select key1,key2 from t1 where key1=100 and key2=100;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index_merge key1,key2 key2,key1 5,5 NULL # Using intersect(key2,key1); Using where; Using index
+1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL # Using intersect(key1,key2); Using where; Using index
select key1,key2 from t1 where key1=100 and key2=100;
key1 key2
100 100
@@ -789,7 +790,7 @@ show warnings;
Level Code Message
explain select pk from t1 where key1 = 1 and key2 = 1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref key1,key2 key1 5 const 2 Using where
+1 SIMPLE t1 index_merge key1,key2 key2,key1 4,5 NULL 1 Using intersect(key2,key1); Using where; Using index
select pk from t1 where key2 = 1 and key1 = 1;
pk
26
@@ -826,6 +827,7 @@ insert into t1 (key1a, key1b, key2a, key2b, key3a, key3b)
select key1a, key1b, key2a, key2b, key3a, key3b from t1;
analyze table t1;
Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
select count(*) from t1;
count(*)
@@ -1057,7 +1059,7 @@ SELECT a
FROM t1
WHERE c = 1 AND b = 1 AND d = 1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref c,bd c 5 const 2 Using where
+1 SIMPLE t1 index_merge c,bd c,bd 5,10 NULL 1 Using intersect(c,bd); Using where; Using index
CREATE TABLE t2 ( a INT )
SELECT a
FROM t1
@@ -1288,7 +1290,7 @@ primary key (pk1, pk2)
);
explain select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range PRIMARY,key1 key1 12 NULL ROWS Using index condition
+1 SIMPLE t1 range PRIMARY,key1 PRIMARY 8 NULL ROWS Using where
select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
pk1 pk2 key1 key2 pktail1ok pktail2ok pktail3bad pktail4bad pktail5bad pk2copy badkey filler1 filler2
1 10 0 0 0 0 0 0 0 10 0 filler-data-10 filler2
@@ -1321,16 +1323,16 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref key1 key1 4 const ROWS Using where
explain select * from t1 where pk1 < 7500 and key1 = 10;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range PRIMARY,key1 key1 8 NULL ROWS Using index condition
+1 SIMPLE t1 range PRIMARY,key1 PRIMARY 4 NULL ROWS Using where
explain select * from t1 where pktail1ok=1 and key1=10;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index_merge key1,pktail1ok key1,pktail1ok 4,4 NULL 1 Using intersect(key1,pktail1ok); Using where
+1 SIMPLE t1 ref key1,pktail1ok key1 4 const 2 Using where
explain select * from t1 where pktail2ok=1 and key1=10;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index_merge key1,pktail2ok key1,pktail2ok 4,4 NULL 1 Using intersect(key1,pktail2ok); Using where
+1 SIMPLE t1 ref key1,pktail2ok key1 4 const 2 Using where
explain select * from t1 where (pktail2ok=1 and pk1< 50000) or key1=10;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index_merge PRIMARY,key1,pktail2ok PRIMARY,key1 4,4 NULL ROWS Using union(PRIMARY,key1); Using where
+1 SIMPLE t1 index_merge PRIMARY,key1,pktail2ok pktail2ok,key1 8,4 NULL ROWS Using sort_union(pktail2ok,key1); Using where
explain select * from t1 where pktail3bad=1 and key1=10;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref key1,pktail3bad EITHER_KEY 4 const ROWS Using where
@@ -1393,7 +1395,7 @@ EXPLAIN SELECT t1.f1 FROM t1
WHERE (SELECT COUNT(*) FROM t2 WHERE t2.f3 = 'h' AND t2.f2 = t1.f1) = 0 AND t1.f1 = 2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 const PRIMARY PRIMARY 4 const 1 Using index
-2 SUBQUERY t2 ref f2,f3 f2 5 const 1 Using where
+2 SUBQUERY t2 index_merge f2,f3 f3,f2 2,5 NULL 1 Using intersect(f3,f2); Using where; Using index
DROP TABLE t1,t2;
set global rocksdb_force_flush_memtable_now=1;
#
@@ -1412,5 +1414,5 @@ INSERT INTO t1 SELECT id + 8, id2 + 8, id3 +8 FROM t1;
INSERT INTO t1 SELECT id + 16, 7, 0 FROM t1;
EXPLAIN SELECT SQL_NO_CACHE count(*) FROM t1 WHERE id2=7 AND id3=0;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref id2,id3,covering_index covering_index 8 const,const 1 Using index
+1 SIMPLE t1 ref id2,id3,covering_index covering_index 8 const,const 2 Using index
DROP TABLE t1;
diff --git a/storage/rocksdb/mysql-test/rocksdb/t/allow_to_start_after_corruption.test b/storage/rocksdb/mysql-test/rocksdb/t/allow_to_start_after_corruption.test
index 67b2d5f96d7..e084b57fbda 100644
--- a/storage/rocksdb/mysql-test/rocksdb/t/allow_to_start_after_corruption.test
+++ b/storage/rocksdb/mysql-test/rocksdb/t/allow_to_start_after_corruption.test
@@ -1,6 +1,8 @@
--source include/have_rocksdb.inc
--source include/not_valgrind.inc
+--let $restart_noprint=2
+
--echo #
--echo # Test how MyRocks behaves when RocksDB reports corrupted data.
--echo #
diff --git a/storage/rocksdb/mysql-test/rocksdb/t/autoinc_debug.test b/storage/rocksdb/mysql-test/rocksdb/t/autoinc_debug.test
index b17548063d9..99e28f3b55e 100644
--- a/storage/rocksdb/mysql-test/rocksdb/t/autoinc_debug.test
+++ b/storage/rocksdb/mysql-test/rocksdb/t/autoinc_debug.test
@@ -3,6 +3,8 @@
--source include/have_log_bin.inc
--source include/not_valgrind.inc
+--let $restart_noprint=2
+
--echo #
--echo # Testing upgrading from server without merges for auto_increment
--echo # to new server with such support.
diff --git a/storage/rocksdb/mysql-test/rocksdb/t/disabled.def b/storage/rocksdb/mysql-test/rocksdb/t/disabled.def
index 5115056acdd..e2c7f143250 100644
--- a/storage/rocksdb/mysql-test/rocksdb/t/disabled.def
+++ b/storage/rocksdb/mysql-test/rocksdb/t/disabled.def
@@ -85,8 +85,6 @@ rpl_row_triggers : Requires read-free slave.
compact_deletes: MDEV-12663 : rocksdb.compact_deletes times out and causes other tests to fail
blind_delete_without_tx_api: MDEV-12286: rocksdb.blind_delete_without_tx_api test fails
-unique_check: wrong error number
-autoinc_vars_thread: debug sync point wait timed out
information_schema: MDEV-14372: unstable testcase
##
@@ -94,9 +92,6 @@ information_schema: MDEV-14372: unstable testcase
##
mysqlbinlog_gtid_skip_empty_trans_rocksdb : MariaRocks: requires GTIDs
-autoinc_debug: Fails with wrong results
drop_table: Hangs on shutdown
-allow_to_start_after_corruption : result difference and assertion failure
-index_merge_rocksdb2 : result difference
rocksdb_range2 : result difference, update after MDEV-16746 is fixed
add_index_inplace: FORCE INDEX gives wrong count
diff --git a/storage/sphinx/ha_sphinx.cc b/storage/sphinx/ha_sphinx.cc
index 337a1dc22a1..9cf10df4189 100644
--- a/storage/sphinx/ha_sphinx.cc
+++ b/storage/sphinx/ha_sphinx.cc
@@ -2285,7 +2285,8 @@ int ha_sphinx::HandleMysqlError ( MYSQL * pConn, int iErrCode )
CSphSEThreadTable * pTable = GetTls ();
if ( pTable )
{
- strncpy ( pTable->m_tStats.m_sLastMessage, mysql_error ( pConn ), sizeof ( pTable->m_tStats.m_sLastMessage ) );
+ strncpy ( pTable->m_tStats.m_sLastMessage, mysql_error ( pConn ), sizeof pTable->m_tStats.m_sLastMessage - 1 );
+ pTable->m_tStats.m_sLastMessage[sizeof pTable->m_tStats.m_sLastMessage - 1] = '\0';
pTable->m_tStats.m_bLastError = true;
}
@@ -2552,7 +2553,8 @@ bool ha_sphinx::UnpackSchema ()
CSphSEThreadTable * pTable = GetTls ();
if ( pTable )
{
- strncpy ( pTable->m_tStats.m_sLastMessage, sMessage, sizeof(pTable->m_tStats.m_sLastMessage) );
+ strncpy ( pTable->m_tStats.m_sLastMessage, sMessage, sizeof pTable->m_tStats.m_sLastMessage - 1 );
+ pTable->m_tStats.m_sLastMessage[sizeof pTable->m_tStats.m_sLastMessage - 1] = '\0';
pTable->m_tStats.m_bLastError = ( uStatus==SEARCHD_ERROR );
}
@@ -2973,7 +2975,8 @@ int ha_sphinx::index_read ( byte * buf, const byte * key, uint key_len, enum ha_
SPH_RET ( HA_ERR_END_OF_FILE );
}
- strncpy ( pTable->m_tStats.m_sLastMessage, sMessage, sizeof(pTable->m_tStats.m_sLastMessage) );
+ strncpy ( pTable->m_tStats.m_sLastMessage, sMessage, sizeof pTable->m_tStats.m_sLastMessage - 1 );
+ pTable->m_tStats.m_sLastMessage[sizeof pTable->m_tStats.m_sLastMessage - 1] = '\0';
SafeDeleteArray ( sMessage );
if ( uRespStatus!=SEARCHD_WARNING )
diff --git a/storage/tokudb/mysql-test/rpl/r/rpl_extra_col_master_tokudb.result b/storage/tokudb/mysql-test/rpl/r/rpl_extra_col_master_tokudb.result
index 83578f20404..6982078d2b8 100644
--- a/storage/tokudb/mysql-test/rpl/r/rpl_extra_col_master_tokudb.result
+++ b/storage/tokudb/mysql-test/rpl/r/rpl_extra_col_master_tokudb.result
@@ -468,7 +468,7 @@ INSERT INTO t10 () VALUES(1,@b1,DEFAULT,'Kyle',DEFAULT),
connection slave;
include/wait_for_slave_sql_error_and_skip.inc [errno=1677]
-Last_SQL_Error = 'Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5)''
+Last_SQL_Error = 'Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5 octets) character set latin1''
*** Drop t10 ***
connection master;
@@ -510,7 +510,7 @@ INSERT INTO t11 () VALUES(1,@b1,'Testing is fun','Kyle',DEFAULT),
connection slave;
include/wait_for_slave_sql_error_and_skip.inc [errno=1677]
-Last_SQL_Error = 'Column 2 of table 'test.t11' cannot be converted from type 'blob' to type 'varchar(254)''
+Last_SQL_Error = 'Column 2 of table 'test.t11' cannot be converted from type 'blob' to type 'varchar(254 octets) character set latin1''
*** Drop t11 ***
connection master;
diff --git a/storage/tokudb/mysql-test/rpl/r/rpl_extra_col_slave_tokudb.result b/storage/tokudb/mysql-test/rpl/r/rpl_extra_col_slave_tokudb.result
index 3f29138b946..318d5496255 100644
--- a/storage/tokudb/mysql-test/rpl/r/rpl_extra_col_slave_tokudb.result
+++ b/storage/tokudb/mysql-test/rpl/r/rpl_extra_col_slave_tokudb.result
@@ -64,7 +64,7 @@ a b c
connection slave;
START SLAVE;
include/wait_for_slave_sql_error.inc [errno=1677]
-Last_SQL_Error = 'Column 2 of table 'test.t2' cannot be converted from type 'char(10)' to type 'char(5)''
+Last_SQL_Error = 'Column 2 of table 'test.t2' cannot be converted from type 'char(10 octets)' to type 'char(5 octets) character set latin1''
STOP SLAVE;
RESET SLAVE;
SELECT * FROM t2 ORDER BY a;
@@ -160,7 +160,7 @@ INSERT INTO t5 () VALUES(1,'Kyle',200.23,1,'b1b1',23.00098),
********************************************
connection slave;
include/wait_for_slave_sql_error_and_skip.inc [errno=1677]
-Last_SQL_Error = 'Column 1 of table 'test.t5' cannot be converted from type 'varchar(6)' to type 'char(5)''
+Last_SQL_Error = 'Column 1 of table 'test.t5' cannot be converted from type 'varchar(6 octets)' to type 'char(5 octets) character set latin1''
*** Drop t5 ***
connection master;
DROP TABLE t5;
@@ -188,7 +188,7 @@ INSERT INTO t6 () VALUES(1,'Kyle',200.23,1),
********************************************
connection slave;
include/wait_for_slave_sql_error.inc [errno=1677]
-Last_SQL_Error = 'Column 1 of table 'test.t6' cannot be converted from type 'varchar(6)' to type 'char(5)''
+Last_SQL_Error = 'Column 1 of table 'test.t6' cannot be converted from type 'varchar(6 octets)' to type 'char(5 octets) character set latin1''
*** Drop t6 ***
include/rpl_reset.inc
connection master;
@@ -310,7 +310,7 @@ INSERT INTO t10 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
********************************************
connection slave;
include/wait_for_slave_sql_error_and_skip.inc [errno=1677]
-Last_SQL_Error = 'Column 2 of table 'test.t10' cannot be converted from type 'char(5)' to type 'double''
+Last_SQL_Error = 'Column 2 of table 'test.t10' cannot be converted from type 'char(5 octets)' to type 'double''
*** Drop t10 ***
connection master;
DROP TABLE t10;
@@ -338,7 +338,7 @@ INSERT INTO t11 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
********************************************
connection slave;
include/wait_for_slave_sql_error_and_skip.inc [errno=1677]
-Last_SQL_Error = 'Column 2 of table 'test.t11' cannot be converted from type 'varchar(254)' to type 'int(11)''
+Last_SQL_Error = 'Column 2 of table 'test.t11' cannot be converted from type 'varchar(254 octets)' to type 'int(11)''
*** Drop t11 ***
connection master;
DROP TABLE t11;
diff --git a/storage/tokudb/mysql-test/rpl/r/rpl_row_basic_3tokudb.result b/storage/tokudb/mysql-test/rpl/r/rpl_row_basic_3tokudb.result
index 32a42143180..e638a1aab12 100644
--- a/storage/tokudb/mysql-test/rpl/r/rpl_row_basic_3tokudb.result
+++ b/storage/tokudb/mysql-test/rpl/r/rpl_row_basic_3tokudb.result
@@ -565,7 +565,7 @@ INSERT INTO t5 VALUES (1, "", 1);
INSERT INTO t5 VALUES (2, repeat(_utf8'a', 255), 2);
connection slave;
include/wait_for_slave_sql_error.inc [errno=1677]
-Last_SQL_Error = 'Column 1 of table 'test.t5' cannot be converted from type 'char(255)' to type 'char(16)''
+Last_SQL_Error = 'Column 1 of table 'test.t5' cannot be converted from type 'char(765 octets)' to type 'char(48 octets) character set utf8''
include/rpl_reset.inc
[expecting slave to stop]
connection master;
@@ -573,7 +573,7 @@ INSERT INTO t6 VALUES (1, "", 1);
INSERT INTO t6 VALUES (2, repeat(_utf8'a', 255), 2);
connection slave;
include/wait_for_slave_sql_error.inc [errno=1677]
-Last_SQL_Error = 'Column 1 of table 'test.t6' cannot be converted from type 'char(255)' to type 'char(128)''
+Last_SQL_Error = 'Column 1 of table 'test.t6' cannot be converted from type 'char(765 octets)' to type 'char(384 octets) character set utf8''
include/rpl_reset.inc
[expecting slave to replicate correctly]
connection master;
diff --git a/wsrep-lib b/wsrep-lib
-Subproject 0f676bd89378c7c823cff7ae7cdaef3cafcca23
+Subproject 58aa3e821f575532870c5f76f6f1cf833458eed
diff --git a/zlib/CMakeLists.txt b/zlib/CMakeLists.txt
index f654f98bfc4..810ec8ae0cb 100644
--- a/zlib/CMakeLists.txt
+++ b/zlib/CMakeLists.txt
@@ -1,4 +1,3 @@
-
# Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
@@ -145,3 +144,6 @@ elseif(UNIX)
# On unix-like platforms the library is almost always called libz
set_target_properties(zlib PROPERTIES OUTPUT_NAME z)
endif()
+
+
+RESTRICT_SYMBOL_EXPORTS(zlib)