diff options
65 files changed, 1540 insertions, 340 deletions
diff --git a/BUILD/FINISH.sh b/BUILD/FINISH.sh index fd51f2f5dfe..015f973d8a8 100644 --- a/BUILD/FINISH.sh +++ b/BUILD/FINISH.sh @@ -44,7 +44,13 @@ cd ../storage/rocksdb/rocksdb git submodule update cd ../../maria/libmarias3 git submodule update -cd ../../.." +cd ../../.. +cd storage/columnstore/columnstore +git submodule update +cd ../../.. +cd wsrep-lib +git submodule update +cd .." fi commands="$commands path=`dirname $0` diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index bc4c65d5f6b..9cd022f8ad8 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -32,6 +32,7 @@ Usage: $0 [-h|-n] [configure-options] -n, --just-print Don't actually run any commands; just print them. -c, --just-configure Stop after running configure. Combined with --just-print shows configure options. + --just-clean Clean up compilation files and update sub modules --extra-configs=xxx Add this to configure options --extra-flags=xxx Add this C and CXX flags --extra-cflags=xxx Add this to C flags @@ -71,6 +72,8 @@ parse_options() just_configure=1;; -n | --just-print | --print) just_print=1;; + --just-clean) + just_clean=1;; --verbose) verbose_make=1;; -h | --help) @@ -94,6 +97,7 @@ fi prefix="/usr/local/mysql" just_print= +just_clean= just_configure= warning_mode= maintainer_mode= diff --git a/CMakeLists.txt b/CMakeLists.txt index 7072214ba23..d6cf989711d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,11 +123,13 @@ FOREACH(_base ENDIF() ENDFOREACH() +IF(NOT RPM AND NOT DEB) FOREACH(tool gtar tar) STRING(TOUPPER ${tool} TOOL) FIND_PROGRAM(${TOOL}_EXECUTABLE ${tool} DOC "path to the executable") MARK_AS_ADVANCED(${TOOL}_EXECUTABLE) ENDFOREACH() +ENDIF() FIND_PACKAGE(Git) diff --git a/cmake/FindGit.cmake b/cmake/FindGit.cmake new file mode 100644 index 00000000000..8178b614a3e --- /dev/null +++ b/cmake/FindGit.cmake @@ -0,0 +1,13 @@ +if(GIT_EXECUTABLE) + set(GIT_FOUND TRUE) + return() +endif() +if(DEFINED GIT_EXECUTABLE) + set(GIT_FOUND FALSE) + return() +endif() + +set(orig_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) +unset(CMAKE_MODULE_PATH) +include(FindGit) +set(CMAKE_MODULE_PATH ${orig_CMAKE_MODULE_PATH}) diff --git a/cmake/FindJNI.cmake b/cmake/FindJNI.cmake index fb2f4801a70..12305d7c86d 100644 --- a/cmake/FindJNI.cmake +++ b/cmake/FindJNI.cmake @@ -1,4 +1,9 @@ +if(JAVA_AWT_LIBRARY) + set(JNI_FOUND TRUE) + return() +endif() if(DEFINED JAVA_AWT_LIBRARY) + set(JNI_FOUND FALSE) return() endif() diff --git a/cmake/FindJava.cmake b/cmake/FindJava.cmake index 95bbf8682cd..714f56b1f72 100644 --- a/cmake/FindJava.cmake +++ b/cmake/FindJava.cmake @@ -1,4 +1,9 @@ +if(Java_JAVA_EXECUTABLE) + set(JAVA_FOUND TRUE) + return() +endif() if(DEFINED Java_JAVA_EXECUTABLE) + set(JAVA_FOUND FALSE) return() endif() diff --git a/cmake/build_configurations/mysql_release.cmake b/cmake/build_configurations/mysql_release.cmake index 520665a2947..82db50ffe7d 100644 --- a/cmake/build_configurations/mysql_release.cmake +++ b/cmake/build_configurations/mysql_release.cmake @@ -84,6 +84,12 @@ ENDIF() SET(WITH_INNODB_SNAPPY OFF CACHE STRING "") SET(WITH_NUMA 0 CACHE BOOL "") +SET(CPU_LEVEL1_DCACHE_LINESIZE 0) + +IF(NOT EXISTS ${CMAKE_SOURCE_DIR}/.git) + SET(GIT_EXECUTABLE GIT_EXECUTABLE-NOTFOUND CACHE FILEPATH "") +ENDIF() + IF(WIN32) SET(INSTALL_MYSQLTESTDIR "" CACHE STRING "") SET(INSTALL_SQLBENCHDIR "" CACHE STRING "") @@ -97,7 +103,6 @@ ELSEIF(RPM) SET(WITH_ZLIB system CACHE STRING "") SET(CHECKMODULE /usr/bin/checkmodule CACHE FILEPATH "") SET(SEMODULE_PACKAGE /usr/bin/semodule_package CACHE FILEPATH "") - SET(WITH_JEMALLOC "yes" CACHE STRING "") SET(PLUGIN_AUTH_SOCKET YES CACHE STRING "") SET(WITH_EMBEDDED_SERVER ON CACHE BOOL "") # not yet, SLES 12.3 doesn't provide pcre2 @@ -107,7 +112,6 @@ ELSEIF(DEB) SET(WITH_ZLIB system CACHE STRING "") SET(WITH_LIBWRAP ON) SET(HAVE_EMBEDDED_PRIVILEGE_CONTROL ON) - SET(WITH_JEMALLOC "yes" CACHE STRING "") SET(PLUGIN_AUTH_SOCKET YES CACHE STRING "") SET(WITH_EMBEDDED_SERVER ON CACHE BOOL "") SET(WITH_PCRE system CACHE STRING "") diff --git a/cmake/cpack_rpm.cmake b/cmake/cpack_rpm.cmake index 69688833c41..412e5cbf4ef 100644 --- a/cmake/cpack_rpm.cmake +++ b/cmake/cpack_rpm.cmake @@ -125,8 +125,6 @@ SET(ignored "%ignore ${CMAKE_INSTALL_PREFIX}/share/man" "%ignore ${CMAKE_INSTALL_PREFIX}/share/man/man1" "%ignore ${CMAKE_INSTALL_PREFIX}/share/man/man8" - "%ignore ${CMAKE_INSTALL_PREFIX}/share/man/man1*" - "%ignore ${CMAKE_INSTALL_PREFIX}/share/man/man8*" "%ignore ${CMAKE_INSTALL_PREFIX}/share/pkgconfig" ) diff --git a/cmake/cpu_info.cmake b/cmake/cpu_info.cmake index 1acfad5897f..2abeb5e12c1 100644 --- a/cmake/cpu_info.cmake +++ b/cmake/cpu_info.cmake @@ -15,6 +15,8 @@ # Symbols with information about the CPU. +IF(NOT DEFINED CPU_LEVEL1_DCACHE_LINESIZE) + IF(CMAKE_SYSTEM_NAME MATCHES "Darwin") FIND_PROGRAM(SYSCTL sysctl) MARK_AS_ADVANCED(SYSCTL) @@ -37,3 +39,5 @@ ELSE() ) ENDIF() ENDIF() + +ENDIF() diff --git a/dbug/CMakeLists.txt b/dbug/CMakeLists.txt index d45401be290..d938788aded 100644 --- a/dbug/CMakeLists.txt +++ b/dbug/CMakeLists.txt @@ -30,7 +30,7 @@ IF(NOT CMAKE_CROSSCOMPILING OR DEFINED CMAKE_CROSSCOMPILING_EMULATOR) TARGET_LINK_LIBRARIES(factorial dbug) ENDIF() -IF(NOT WIN32 AND NOT CMAKE_GENERATOR MATCHES Xcode) +IF(NOT WIN32 AND NOT CMAKE_GENERATOR MATCHES Xcode AND NOT RPM AND NOT DEB) FIND_PROGRAM(GROFF groff) FIND_PROGRAM(NROFF nroff) MARK_AS_ADVANCED(GROFF) diff --git a/debian/mariadb-plugin-connect.install b/debian/mariadb-plugin-connect.install index e2500269438..6cf529163cd 100644 --- a/debian/mariadb-plugin-connect.install +++ b/debian/mariadb-plugin-connect.install @@ -1,2 +1,6 @@ etc/mysql/mariadb.conf.d/connect.cnf usr/lib/mysql/plugin/ha_connect.so +usr/share/mysql/Mongo2.jar +usr/share/mysql/Mongo3.jar +usr/share/mysql/JavaWrappers.jar +usr/share/mysql/JdbcInterface.jar diff --git a/mysql-test/main/cte_nonrecursive.result b/mysql-test/main/cte_nonrecursive.result index 54283f1ccf1..763e51f61cb 100644 --- a/mysql-test/main/cte_nonrecursive.result +++ b/mysql-test/main/cte_nonrecursive.result @@ -1763,6 +1763,207 @@ a c 2 1 7 3 drop table t1; +# +# MDEV-23886: Stored Function returning the result of a query +# that uses CTE over a table twice +# +create table t1 (c1 int); +insert into t1 values (1),(2),(6); +create function f1() returns int return +( with cte1 as (select c1 from t1) +select sum(c1) from +(select * from cte1 union all select * from cte1) dt +); +select f1(); +f1() +18 +create function f2() returns int return +( with cte1 as (select c1 from t1) +select sum(s.c1) from cte1 as s, cte1 as t where s.c1=t.c1 +); +select f2(); +f2() +9 +create function f3() returns int return +( with cte1 as (select c1 from t1) +select +case +when exists(select 1 from cte1 where c1 between 1 and 2) then 1 +when exists(select 1 from cte1 where c1 between 5 and 6) then 2 +else 0 +end +); +select f3(); +f3() +1 +create view v1 as (select c1 from t1); +create function f4() returns int return +( select sum(c1) from +(select * from v1 union all select * from v1) dt +); +select f4(); +f4() +18 +create function f5() returns int return +( select sum(s.c1) from v1 as s, v1 as t where s.c1=t.c1 +); +select f5(); +f5() +9 +create view v2(s) as +with cte1 as (select c1 from t1) +select sum(c1) from (select * from cte1 union all select * from cte1) dt; +create function f6() returns int return +(select s from v2); +select f6(); +f6() +18 +create function f7() returns int return +( select r.s from v2 as r, v2 as t where r.s=t.s +); +select f7(); +f7() +18 +select f5() + f6(); +f5() + f6() +27 +prepare stmt from "select f5() + f6();"; +execute stmt; +f5() + f6() +27 +execute stmt; +f5() + f6() +27 +deallocate prepare stmt; +drop function f1; +drop function f2; +drop function f3; +drop function f4; +drop function f5; +drop function f6; +drop function f7; +drop view v1; +drop view v2; +create table t2 (a int, b int); +insert into t2 +with cte1 as (select c1 from t1) +select * from cte1 as s, cte1 as t where s.c1=t.c1 and s.c1 > 5; +select * from t2; +a b +6 6 +create procedure p1() +begin +insert into t2 +with cte1 as (select c1 from t1) +select * from cte1 as s, cte1 as t where s.c1=t.c1 and s.c1 <= 2 and t.c1 >= 2; +end | +call p1(); +select * from t2; +a b +6 6 +2 2 +drop procedure p1; +# checking CTE resolution for queries with hanging CTEs +with +cte1(a) as (select * from t1 where c1 <= 2), +cte2(b) as (select * from cte1 where a >= 2), +cte3 as (select * from cte1,cte2 where cte1.a < cte2.b) +select * from cte3; +a b +1 2 +select * from t2; +a b +6 6 +2 2 +with +cte1(a) as (select * from t1 where c1 <= 2), +cte2(b) as (select * from cte1 where a >= 2), +cte3 as (select * from cte1,cte2 where cte1.a < cte2.b) +select * from t2; +a b +6 6 +2 2 +with +cte1(a) as (select * from t1 where c1 <= 2), +cte2(b) as (select * from cte1 where c1 >= 2), +cte3 as (select * from cte1,cte2 where cte1.a < cte2.b) +select * from t2; +ERROR 42S22: Unknown column 'c1' in 'where clause' +with +cte1(a) as (select * from t1 where c1 <= 2), +cte2(b) as (select * from cte1 where a >= 2), +cte3 as (select * from cte1,cte2 where cte1.a < cte2.c1) +select * from t2; +ERROR 42S22: Unknown column 'cte2.c1' in 'where clause' +with +cte1 as (select * from t1 where c1 <= 2), +cte2(a,b) as (select * from cte1 as s1, cte1 as s2 where s1.c1=s2.c1) +select * from cte2; +a b +1 1 +2 2 +with +cte1 as (select * from t1 where c1 <= 2), +cte2(a,b) as (select * from cte1 as s1, cte1 as s2 where s1.c1=s2.c1) +select * from t2; +a b +6 6 +2 2 +with +cte1 as (select * from t1 where c1 <= 2), +cte2(a,b) as (select * from cte1 as s1, cte1 as s2 where s1.c1=c1) +select * from t2; +ERROR 23000: Column 'c1' in where clause is ambiguous +with cte3 as +( with cte2(a,b) as +( with cte1 as (select * from t1 where c1 <= 2) +select * from cte1 as s1, cte1 as s2 where s1.c1=s2.c1) +select r1.a,r2.b from cte2 as r1, cte2 as r2) +select * from cte3; +a b +1 1 +2 1 +1 2 +2 2 +with cte3 as +( with cte2(a,b) as +( with cte1 as (select * from t1 where c1 <= 2) +select * from cte1 as s1, cte1 as s2 where s1.c1=s2.c1) +select r1.a,r2.b from cte2 as r1, cte2 as r2) +select * from t2; +a b +6 6 +2 2 +with cte3 as +( with cte2(a,b) as +( with cte1 as (select * from t1 where c1 <= 2) +select * from cte1 as s1, cte1 as s2 where s1.c1=s2.c1) +select r1.c1,r2.c1 from cte2 as r1, cte2 as r2) +select * from t2; +ERROR 42S22: Unknown column 'r1.c1' in 'field list' +create procedure p1() +begin +insert into t2 +with cte1 as (select c1 from t1) +select * from t1 as s, t1 as t where s.c1=t.c1 and s.c1 <= 2 and t.c1 >= 2; +end | +call p1(); +select * from t2; +a b +6 6 +2 2 +2 2 +drop procedure p1; +create procedure p1() +begin +insert into t2 +with cte1 as (select a from t1) +select * from t1 as s, t1 as t where s.c1=t.c1 and s.c1 <= 2 and t.c1 >= 2; +end | +call p1(); +ERROR 42S22: Unknown column 'a' in 'field list' +drop procedure p1; +drop table t1,t2; # End of 10.2 tests # # MDEV-21673: several references to CTE that uses diff --git a/mysql-test/main/cte_nonrecursive.test b/mysql-test/main/cte_nonrecursive.test index a4a1a1784cd..59dae44cb66 100644 --- a/mysql-test/main/cte_nonrecursive.test +++ b/mysql-test/main/cte_nonrecursive.test @@ -1273,6 +1273,208 @@ select a, c from cte as r2 where a > 4; drop table t1; +--echo # +--echo # MDEV-23886: Stored Function returning the result of a query +--echo # that uses CTE over a table twice +--echo # + +create table t1 (c1 int); +insert into t1 values (1),(2),(6); + +create function f1() returns int return +( with cte1 as (select c1 from t1) + select sum(c1) from + (select * from cte1 union all select * from cte1) dt +); +select f1(); + +create function f2() returns int return +( with cte1 as (select c1 from t1) + select sum(s.c1) from cte1 as s, cte1 as t where s.c1=t.c1 +); +select f2(); + +create function f3() returns int return +( with cte1 as (select c1 from t1) + select + case + when exists(select 1 from cte1 where c1 between 1 and 2) then 1 + when exists(select 1 from cte1 where c1 between 5 and 6) then 2 + else 0 + end +); +select f3(); + +create view v1 as (select c1 from t1); + +create function f4() returns int return +( select sum(c1) from + (select * from v1 union all select * from v1) dt +); +select f4(); + +create function f5() returns int return +( select sum(s.c1) from v1 as s, v1 as t where s.c1=t.c1 +); +select f5(); + +create view v2(s) as +with cte1 as (select c1 from t1) +select sum(c1) from (select * from cte1 union all select * from cte1) dt; + +create function f6() returns int return +(select s from v2); +select f6(); + +create function f7() returns int return +( select r.s from v2 as r, v2 as t where r.s=t.s +); +select f7(); + +select f5() + f6(); + +prepare stmt from "select f5() + f6();"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +drop function f1; +drop function f2; +drop function f3; +drop function f4; +drop function f5; +drop function f6; +drop function f7; + +drop view v1; +drop view v2; + +create table t2 (a int, b int); + +insert into t2 +with cte1 as (select c1 from t1) +select * from cte1 as s, cte1 as t where s.c1=t.c1 and s.c1 > 5; + +select * from t2; + +delimiter |; + +create procedure p1() +begin +insert into t2 +with cte1 as (select c1 from t1) +select * from cte1 as s, cte1 as t where s.c1=t.c1 and s.c1 <= 2 and t.c1 >= 2; +end | + +delimiter ;| + +call p1(); +select * from t2; + +drop procedure p1; + +--echo # checking CTE resolution for queries with hanging CTEs + +with +cte1(a) as (select * from t1 where c1 <= 2), +cte2(b) as (select * from cte1 where a >= 2), +cte3 as (select * from cte1,cte2 where cte1.a < cte2.b) +select * from cte3; + +select * from t2; + +with +cte1(a) as (select * from t1 where c1 <= 2), +cte2(b) as (select * from cte1 where a >= 2), +cte3 as (select * from cte1,cte2 where cte1.a < cte2.b) +select * from t2; + +--error ER_BAD_FIELD_ERROR +with +cte1(a) as (select * from t1 where c1 <= 2), +cte2(b) as (select * from cte1 where c1 >= 2), +cte3 as (select * from cte1,cte2 where cte1.a < cte2.b) +select * from t2; + +--error ER_BAD_FIELD_ERROR +with +cte1(a) as (select * from t1 where c1 <= 2), +cte2(b) as (select * from cte1 where a >= 2), +cte3 as (select * from cte1,cte2 where cte1.a < cte2.c1) +select * from t2; + +with +cte1 as (select * from t1 where c1 <= 2), +cte2(a,b) as (select * from cte1 as s1, cte1 as s2 where s1.c1=s2.c1) +select * from cte2; + +with +cte1 as (select * from t1 where c1 <= 2), +cte2(a,b) as (select * from cte1 as s1, cte1 as s2 where s1.c1=s2.c1) +select * from t2; + +--error ER_NON_UNIQ_ERROR +with +cte1 as (select * from t1 where c1 <= 2), +cte2(a,b) as (select * from cte1 as s1, cte1 as s2 where s1.c1=c1) +select * from t2; + +with cte3 as +( with cte2(a,b) as + ( with cte1 as (select * from t1 where c1 <= 2) + select * from cte1 as s1, cte1 as s2 where s1.c1=s2.c1) + select r1.a,r2.b from cte2 as r1, cte2 as r2) +select * from cte3; + +with cte3 as +( with cte2(a,b) as + ( with cte1 as (select * from t1 where c1 <= 2) + select * from cte1 as s1, cte1 as s2 where s1.c1=s2.c1) + select r1.a,r2.b from cte2 as r1, cte2 as r2) +select * from t2; + +--error ER_BAD_FIELD_ERROR +with cte3 as +( with cte2(a,b) as + ( with cte1 as (select * from t1 where c1 <= 2) + select * from cte1 as s1, cte1 as s2 where s1.c1=s2.c1) + select r1.c1,r2.c1 from cte2 as r1, cte2 as r2) +select * from t2; + +delimiter |; + +create procedure p1() +begin +insert into t2 +with cte1 as (select c1 from t1) +select * from t1 as s, t1 as t where s.c1=t.c1 and s.c1 <= 2 and t.c1 >= 2; +end | + +delimiter ;| + +call p1(); +select * from t2; + +drop procedure p1; + +delimiter |; + +create procedure p1() +begin +insert into t2 +with cte1 as (select a from t1) +select * from t1 as s, t1 as t where s.c1=t.c1 and s.c1 <= 2 and t.c1 >= 2; +end | + +delimiter ;| + +--error ER_BAD_FIELD_ERROR +call p1(); + +drop procedure p1; + +drop table t1,t2; + --echo # End of 10.2 tests --echo # diff --git a/mysql-test/main/ctype_filename.result b/mysql-test/main/ctype_filename.result index 2eee5d2888e..739fa979f28 100644 --- a/mysql-test/main/ctype_filename.result +++ b/mysql-test/main/ctype_filename.result @@ -22,21 +22,50 @@ SELECT @a:=CONVERT('aя' USING filename) AS `@a`, BINARY @a, REVERSE(@a), HEX(@a @a BINARY @a REVERSE(@a) HEX(@a) HEX(REVERSE(@a)) aя a@r1 яa 61407231 40723161 # +# Beginning of 10.2 test. +# +# MDEV-25462: Assertion `m_status == DA_ERROR || m_status == DA_OK || +# m_status == DA_OK_BULK' failed in Diagnostics_area::message from +# get_schema_tables_record +# +SELECT @@character_set_client, @@character_set_connection, @@character_set_results; +@@character_set_client @@character_set_connection @@character_set_results +utf8mb3 utf8mb3 utf8mb3 +SET @old_character_set_client= @@character_set_client; +SET @old_character_set_connection= @@character_set_connection; +SET @old_character_set_results= @@character_set_results; +SET NAMES 'filename'; +ERROR 42000: Variable 'character_set_client' can't be set to the value of 'filename' +SELECT @@character_set_client, @@character_set_connection, @@character_set_results; +@@character_set_client @@character_set_connection @@character_set_results +utf8mb3 utf8mb3 utf8mb3 +CREATE VIEW v2 AS SELECT 1; +SHOW TABLE STATUS; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary +v2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL VIEW NULL NULL +DROP VIEW v2; +SET @@character_set_client= @old_character_set_client; +SET @@character_set_connection= @old_character_set_connection; +SET @@character_set_results= @old_character_set_results; +# +# End of 10.2 test +# +# # MDEV-22022 Various mangled SQL statements will crash 10.3 to 10.5 debug builds # SET CHARACTER_SET_CLIENT=17; +ERROR 42000: Variable 'character_set_client' can't be set to the value of '17' SELECT doc.`Children`.0 FROM t1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?Children??0?FROM?t1' at line 1 +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.0 FROM t1' at line 1 SET NAMES latin1; -# -# Start of 10.5 tests -# +# End of 10.3 tests # # MDEV-22043 Special character leads to assertion in my_wc_to_printable_generic on 10.5.2 (debug) # SET NAMES filename; +ERROR 42000: Variable 'character_set_client' can't be set to the value of 'filename' EXECUTE IMMEDIATE _latin1 0x01; -ERROR 42000: You@0020have@0020an@0020error@0020in@0020your@0020SQL@0020syntax@003b@0020check@0020the@0020manual@0020that@0020corresponds@0020to@0020your@0020MariaDB@0020server@0020version@0020for@0020the@0020right@0020syntax@0020to@0020use@0020near@0020@0027@005c0001@0027@0020at@0020line@00201 +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '\0001' at line 1 SET NAMES utf8; # # MDEV-23435 Functions do not convert numbers to character_set_results @@ -103,6 +132,4 @@ a c @002d1 @002d1 DROP TABLE t1; SET NAMES utf8; -# # End of 10.5 tests -# diff --git a/mysql-test/main/ctype_filename.test b/mysql-test/main/ctype_filename.test index 17ab71e3985..ba42d1a2807 100644 --- a/mysql-test/main/ctype_filename.test +++ b/mysql-test/main/ctype_filename.test @@ -28,25 +28,49 @@ select convert(convert(',' using filename) using binary); SET NAMES utf8; SELECT @a:=CONVERT('aя' USING filename) AS `@a`, BINARY @a, REVERSE(@a), HEX(@a), HEX(REVERSE(@a)); +--echo # +--echo # Beginning of 10.2 test. +--echo # +--echo # MDEV-25462: Assertion `m_status == DA_ERROR || m_status == DA_OK || +--echo # m_status == DA_OK_BULK' failed in Diagnostics_area::message from +--echo # get_schema_tables_record +--echo # + +SELECT @@character_set_client, @@character_set_connection, @@character_set_results; +SET @old_character_set_client= @@character_set_client; +SET @old_character_set_connection= @@character_set_connection; +SET @old_character_set_results= @@character_set_results; +--error ER_WRONG_VALUE_FOR_VAR +SET NAMES 'filename'; +SELECT @@character_set_client, @@character_set_connection, @@character_set_results; +CREATE VIEW v2 AS SELECT 1; +SHOW TABLE STATUS; +DROP VIEW v2; +SET @@character_set_client= @old_character_set_client; +SET @@character_set_connection= @old_character_set_connection; +SET @@character_set_results= @old_character_set_results; + +--echo # +--echo # End of 10.2 test +--echo # --echo # --echo # MDEV-22022 Various mangled SQL statements will crash 10.3 to 10.5 debug builds --echo # +--error ER_WRONG_VALUE_FOR_VAR SET CHARACTER_SET_CLIENT=17; --error ER_PARSE_ERROR SELECT doc.`Children`.0 FROM t1; SET NAMES latin1; - ---echo # ---echo # Start of 10.5 tests ---echo # +--echo # End of 10.3 tests --echo # --echo # MDEV-22043 Special character leads to assertion in my_wc_to_printable_generic on 10.5.2 (debug) --echo # +--error ER_WRONG_VALUE_FOR_VAR SET NAMES filename; --error ER_PARSE_ERROR EXECUTE IMMEDIATE _latin1 0x01; @@ -114,7 +138,4 @@ SET NAMES utf8; --enable_ps_protocol - ---echo # --echo # End of 10.5 tests ---echo # diff --git a/mysql-test/main/mysqld--help.result b/mysql-test/main/mysqld--help.result index 99d84bb3457..5d014240faa 100644 --- a/mysql-test/main/mysqld--help.result +++ b/mysql-test/main/mysqld--help.result @@ -1579,7 +1579,7 @@ lc-messages-dir MYSQL_SHAREDIR/ lc-time-names en_US local-infile TRUE lock-wait-timeout 86400 -log-bin (No default value) +log-bin foo log-bin-compress FALSE log-bin-compress-min-len 256 log-bin-index (No default value) diff --git a/mysql-test/main/mysqld--help.test b/mysql-test/main/mysqld--help.test index 4405b198951..f918670d319 100644 --- a/mysql-test/main/mysqld--help.test +++ b/mysql-test/main/mysqld--help.test @@ -13,7 +13,7 @@ # force symbolic-links=0 (valgrind build has a different default) # -exec $MYSQLD_BOOTSTRAP_CMD --symbolic-links=0 --lower-case-table-names=1 --help --verbose > $MYSQL_TMP_DIR/mysqld--help.txt 2>&1; +exec $MYSQLD_BOOTSTRAP_CMD --symbolic-links=0 --log-bin=foo --lower-case-table-names=1 --help --verbose > $MYSQL_TMP_DIR/mysqld--help.txt 2>&1; # The inline perl code below will copy $MYSQL_TMP_DIR/mysqld--help.txt # to output, but filter away some variable stuff (e.g. paths). diff --git a/mysql-test/main/subselect4.result b/mysql-test/main/subselect4.result index 7daa0e5be87..78df05f4859 100644 --- a/mysql-test/main/subselect4.result +++ b/mysql-test/main/subselect4.result @@ -2721,7 +2721,15 @@ id select_type table type possible_keys key key_len ref rows Extra SELECT a FROM t1 WHERE (a, a) IN (SELECT 1, 2) AND a = (SELECT MIN(b) FROM t2); a DROP TABLE t1,t2; -# End of 10.2 tests +# +# MDEV-22462: Item_in_subselect::create_single_in_to_exists_cond(JOIN *, Item **, Item **): Assertion `false' failed. +# +select 1 from dual where 1 in (select 5 from dual where 1); +1 +create table t1 (a int); +insert into t1 values (1),(2),(3); +update t1 set a = 2 where a in (select a from dual where a = a); +drop table t1; # # MDEV-18335: Assertion `!error || error == 137' failed in subselect_rowid_merge_engine::init # @@ -2848,6 +2856,17 @@ INSERT INTO t2 VALUES (3),(4); SELECT 1 IN (SELECT (SELECT a FROM t1) AS x FROM t2 GROUP BY x); ERROR 21000: Subquery returns more than 1 row drop table t1,t2; +# +# MDEV-25629: Crash in get_sort_by_table() in subquery with order by having outer ref +# +CREATE TABLE t1 (i1 int); +insert into t1 values (1),(2); +SELECT 1 +FROM (t1 JOIN t1 AS ref_t1 ON +(t1.i1 > (SELECT ref_t1.i1 AS c0 FROM t1 b ORDER BY -c0))); +ERROR 21000: Subquery returns more than 1 row +DROP TABLE t1; +# End of 10.2 tests # End of 10.3 tests # # MDEV-19134: EXISTS() slower if ORDER BY is defined diff --git a/mysql-test/main/subselect4.test b/mysql-test/main/subselect4.test index a1a4108de37..2f65db875f8 100644 --- a/mysql-test/main/subselect4.test +++ b/mysql-test/main/subselect4.test @@ -2236,7 +2236,17 @@ SELECT a FROM t1 WHERE (a, a) IN (SELECT 1, 2) AND a = (SELECT MIN(b) FROM t2); DROP TABLE t1,t2; ---echo # End of 10.2 tests +--echo # +--echo # MDEV-22462: Item_in_subselect::create_single_in_to_exists_cond(JOIN *, Item **, Item **): Assertion `false' failed. +--echo # + +select 1 from dual where 1 in (select 5 from dual where 1); + +create table t1 (a int); +insert into t1 values (1),(2),(3); + +update t1 set a = 2 where a in (select a from dual where a = a); +drop table t1; --echo # --echo # MDEV-18335: Assertion `!error || error == 137' failed in subselect_rowid_merge_engine::init @@ -2355,6 +2365,21 @@ INSERT INTO t2 VALUES (3),(4); # Optional, fails either way SELECT 1 IN (SELECT (SELECT a FROM t1) AS x FROM t2 GROUP BY x); drop table t1,t2; +--echo # +--echo # MDEV-25629: Crash in get_sort_by_table() in subquery with order by having outer ref +--echo # +CREATE TABLE t1 (i1 int); +insert into t1 values (1),(2); + +--error ER_SUBQUERY_NO_1_ROW +SELECT 1 +FROM (t1 JOIN t1 AS ref_t1 ON + (t1.i1 > (SELECT ref_t1.i1 AS c0 FROM t1 b ORDER BY -c0))); + +DROP TABLE t1; + +--echo # End of 10.2 tests + --echo # End of 10.3 tests --echo # diff --git a/mysql-test/main/trigger-trans.result b/mysql-test/main/trigger-trans.result index c58c4230a40..24ef9a4291a 100644 --- a/mysql-test/main/trigger-trans.result +++ b/mysql-test/main/trigger-trans.result @@ -229,3 +229,16 @@ INSERT INTO t2 (id) VALUES (1); disconnect con2; connection default; DROP TABLE t3, t2, t1; +# +# MDEV-25738 Assertion `ticket->m_duration == MDL_EXPLICIT' failed in +# void MDL_context::release_lock(MDL_ticket*) +# +CREATE TABLE t1 (id int(11)) ENGINE=InnoDB; +SET max_statement_time= 0.001; +LOCK TABLES t1 WRITE; +CREATE TRIGGER tr16 AFTER UPDATE ON t1 FOR EACH ROW INSERT INTO t1 VALUES (1); +DROP TABLE t1; +SET max_statement_time= default; +# +# End of 10.5 tests +# diff --git a/mysql-test/main/trigger-trans.test b/mysql-test/main/trigger-trans.test index 17656c3516e..378da045e0a 100644 --- a/mysql-test/main/trigger-trans.test +++ b/mysql-test/main/trigger-trans.test @@ -233,3 +233,19 @@ DROP TABLE t3, t2, t1; # Wait till we reached the initial number of concurrent sessions --source include/wait_until_count_sessions.inc + +--echo # +--echo # MDEV-25738 Assertion `ticket->m_duration == MDL_EXPLICIT' failed in +--echo # void MDL_context::release_lock(MDL_ticket*) +--echo # + +CREATE TABLE t1 (id int(11)) ENGINE=InnoDB; +SET max_statement_time= 0.001; +LOCK TABLES t1 WRITE; +CREATE TRIGGER tr16 AFTER UPDATE ON t1 FOR EACH ROW INSERT INTO t1 VALUES (1); +DROP TABLE t1; +SET max_statement_time= default; + +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/mysql-test/suite/binlog/r/binlog_admin_cmd_kill.result b/mysql-test/suite/binlog/r/binlog_admin_cmd_kill.result index a2eb7ee5c0a..d9bfead8dd1 100644 --- a/mysql-test/suite/binlog/r/binlog_admin_cmd_kill.result +++ b/mysql-test/suite/binlog/r/binlog_admin_cmd_kill.result @@ -20,7 +20,7 @@ master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (f INT) ENGINE=INNODB master-bin.000001 # Gtid # # GTID #-#-# master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (f INT) ENGINE=INNODB DROP TABLE t1,t2; -FLUSH LOGS; +RESET MASTER; # # Kill OPTIMIZE command after table modification # diff --git a/mysql-test/suite/binlog/t/binlog_admin_cmd_kill.test b/mysql-test/suite/binlog/t/binlog_admin_cmd_kill.test index 9b248097ae2..e2397f0eab8 100644 --- a/mysql-test/suite/binlog/t/binlog_admin_cmd_kill.test +++ b/mysql-test/suite/binlog/t/binlog_admin_cmd_kill.test @@ -56,7 +56,7 @@ SET debug_sync = 'reset'; --source include/show_binlog_events.inc DROP TABLE t1,t2; -FLUSH LOGS; +RESET MASTER; --echo # --echo # Kill OPTIMIZE command after table modification @@ -81,6 +81,9 @@ eval KILL $thd_id; SET debug_sync = 'reset'; --disconnect con1 +--let $wait_binlog_event= OPTIMIZE +--source include/wait_for_binlog_event.inc + DROP TABLE t1,t2; let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); FLUSH LOGS; diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def index 5bc61bc98a1..740abcc9314 100644 --- a/mysql-test/suite/galera/disabled.def +++ b/mysql-test/suite/galera/disabled.def @@ -43,11 +43,11 @@ galera_var_notify_cmd : MDEV-21905 Galera test galera_var_notify_cmd causes hang galera_var_reject_queries : assertion in inline_mysql_socket_send galera_var_replicate_myisam_on : MDEV-24062 Galera test failure on galera_var_replicate_myisam_on galera_var_retry_autocommit: MDEV-18181 Galera test failure on galera.galera_var_retry_autocommit -#galera_wan : MDEV-17259 Test failure on galera.galera_wan galera_wsrep_provider_unset_set: wsrep_provider is read-only for security reasons mysql-wsrep#198 : MDEV-24446: galera.mysql-wsrep#198 MTR failed: query 'reap' failed: 2000: Unknown MySQL error partition : MDEV-19958 Galera test failure on galera.partition pxc-421: wsrep_provider is read-only for security reasons query_cache: MDEV-15805 Test failure on galera.query_cache -#sql_log_bin : MDEV-21491 galera.sql_log_bin versioning_trx_id: MDEV-18590: galera.versioning_trx_id: Test failure: mysqltest: Result content mismatch + +MDEV-25562: MDEV-25562 FIXME: lock wait timeout exceeded diff --git a/mysql-test/suite/galera/r/MDEV-25562.result b/mysql-test/suite/galera/r/MDEV-25562.result new file mode 100644 index 00000000000..b0d77af374b --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-25562.result @@ -0,0 +1,16 @@ +connection node_2; +connection node_1; +SET SESSION WSREP_ON=0; +FLUSH TABLES WITH READ LOCK AND DISABLE CHECKPOINT; +SET SESSION WSREP_ON=1; +UNLOCK TABLES; +SET GLOBAL wsrep_ignore_apply_errors=1; +CREATE TABLE t1 (a CHAR(1)) engine=innodb; +CREATE TABLE t1 (a CHAR(1)) engine=innodb; +ERROR 42S01: Table 't1' already exists +SHOW PROCEDURE STATUS WHERE db = 'test'; +Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation +SET GLOBAL read_only=1; +SET GLOBAL wsrep_ignore_apply_errors=DEFAULT; +SET GLOBAL read_only=DEFAULT; +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/MDEV-25562.test b/mysql-test/suite/galera/t/MDEV-25562.test new file mode 100644 index 00000000000..01729936b08 --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-25562.test @@ -0,0 +1,23 @@ +# +# MDEV-25562 Assertion `pause_seqno_.is_undefined() == false' failed in void wsrep::server_state::resume() +# + +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SET SESSION WSREP_ON=0; +FLUSH TABLES WITH READ LOCK AND DISABLE CHECKPOINT; +SET SESSION WSREP_ON=1; +UNLOCK TABLES; + +SET GLOBAL wsrep_ignore_apply_errors=1; +CREATE TABLE t1 (a CHAR(1)) engine=innodb; +--error ER_TABLE_EXISTS_ERROR +CREATE TABLE t1 (a CHAR(1)) engine=innodb; +SHOW PROCEDURE STATUS WHERE db = 'test'; +SET GLOBAL read_only=1; + +SET GLOBAL wsrep_ignore_apply_errors=DEFAULT; +SET GLOBAL read_only=DEFAULT; +DROP TABLE t1; + diff --git a/mysql-test/suite/innodb_fts/r/innodb-fts-ddl.result b/mysql-test/suite/innodb_fts/r/innodb-fts-ddl.result index b50bf047265..a64086c9802 100644 --- a/mysql-test/suite/innodb_fts/r/innodb-fts-ddl.result +++ b/mysql-test/suite/innodb_fts/r/innodb-fts-ddl.result @@ -264,6 +264,18 @@ t1 CREATE TABLE `t1` ( `f1` int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 DROP TABLE t1; +# +# MDEV-25271 Double free of table when inplace alter +# FTS add index fails +# +call mtr.add_suppression("InnoDB: Operating system error number .* in a file operation."); +call mtr.add_suppression("InnoDB: Error number .* means"); +call mtr.add_suppression("InnoDB: Cannot create file"); +call mtr.add_suppression("InnoDB: Failed to create"); +CREATE TABLE t1(a TEXT, FTS_DOC_ID BIGINT UNSIGNED NOT NULL UNIQUE) ENGINE=InnoDB; +ALTER TABLE t1 ADD FULLTEXT(a), ALGORITHM=INPLACE; +ERROR HY000: Got error 11 "Resource temporarily unavailable" from storage engine InnoDB +DROP TABLE t1; CREATE TABLE t1 (a VARCHAR(3)) ENGINE=InnoDB; ALTER TABLE t1 ADD FULLTEXT KEY(a), ADD COLUMN b VARCHAR(3), ADD FULLTEXT KEY(b); DROP TABLE t1; diff --git a/mysql-test/suite/innodb_fts/r/misc_debug.result b/mysql-test/suite/innodb_fts/r/misc_debug.result index 10e3cf8874d..41f8d08ea7d 100644 --- a/mysql-test/suite/innodb_fts/r/misc_debug.result +++ b/mysql-test/suite/innodb_fts/r/misc_debug.result @@ -52,3 +52,16 @@ CHECK TABLE t1; Table Op Msg_type Msg_text test.t1 check status OK DROP TABLE t1; +# +# MDEV-25663 Double free of transaction during TRUNCATE +# +call mtr.add_suppression("InnoDB: \\(Too many concurrent transactions\\)"); +SET DEBUG_DBUG='-d,ib_create_table_fail_too_many_trx'; +CREATE TABLE t1 (b CHAR(12), FULLTEXT KEY(b)) engine=InnoDB; +SET @save_dbug= @@debug_dbug; +SET debug_dbug='+d,ib_create_table_fail_too_many_trx'; +TRUNCATE t1; +ERROR HY000: Got error -1 "Internal error < 0 (Not system error)" from storage engine InnoDB +SET debug_dbug=@save_dbug; +DROP TABLE t1; +# End of 10.3 tests diff --git a/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.opt b/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.opt new file mode 100644 index 00000000000..e6ae8d0fe0a --- /dev/null +++ b/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.opt @@ -0,0 +1 @@ +--enable-plugin-innodb-sys-tables diff --git a/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.test b/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.test index 7c56811a2d9..78494910b48 100644 --- a/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.test +++ b/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.test @@ -319,6 +319,25 @@ ALTER TABLE t1 ADD FTS_DOC_ID INT UNSIGNED NOT NULL, ALGORITHM=INPLACE; SHOW CREATE TABLE t1; DROP TABLE t1; +--echo # +--echo # MDEV-25271 Double free of table when inplace alter +--echo # FTS add index fails +--echo # +call mtr.add_suppression("InnoDB: Operating system error number .* in a file operation."); +call mtr.add_suppression("InnoDB: Error number .* means"); +call mtr.add_suppression("InnoDB: Cannot create file"); +call mtr.add_suppression("InnoDB: Failed to create"); + +let MYSQLD_DATADIR=`select @@datadir`; +CREATE TABLE t1(a TEXT, FTS_DOC_ID BIGINT UNSIGNED NOT NULL UNIQUE) ENGINE=InnoDB; +let $fts_aux_file= `select concat('FTS_',right(concat(repeat('0',16), lower(hex(TABLE_ID))),16),'_BEING_DELETED.ibd') FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME='test/t1'`; +write_file $MYSQLD_DATADIR/test/$fts_aux_file; +EOF +--error ER_GET_ERRNO +ALTER TABLE t1 ADD FULLTEXT(a), ALGORITHM=INPLACE; +DROP TABLE t1; +remove_file $MYSQLD_DATADIR/test/$fts_aux_file; + # Add more than one FTS index CREATE TABLE t1 (a VARCHAR(3)) ENGINE=InnoDB; ALTER TABLE t1 ADD FULLTEXT KEY(a), ADD COLUMN b VARCHAR(3), ADD FULLTEXT KEY(b); diff --git a/mysql-test/suite/innodb_fts/t/misc_debug.test b/mysql-test/suite/innodb_fts/t/misc_debug.test index 461e3f1d9d4..90cb84976ce 100644 --- a/mysql-test/suite/innodb_fts/t/misc_debug.test +++ b/mysql-test/suite/innodb_fts/t/misc_debug.test @@ -83,3 +83,18 @@ ALTER TABLE t1 ADD bl INT AS (LENGTH(b)) VIRTUAL; CHECK TABLE t1; DROP TABLE t1; --source include/wait_until_count_sessions.inc + +--echo # +--echo # MDEV-25663 Double free of transaction during TRUNCATE +--echo # +call mtr.add_suppression("InnoDB: \\(Too many concurrent transactions\\)"); +SET DEBUG_DBUG='-d,ib_create_table_fail_too_many_trx'; + +CREATE TABLE t1 (b CHAR(12), FULLTEXT KEY(b)) engine=InnoDB; +SET @save_dbug= @@debug_dbug; +SET debug_dbug='+d,ib_create_table_fail_too_many_trx'; +--error ER_GET_ERRNO +TRUNCATE t1; +SET debug_dbug=@save_dbug; +DROP TABLE t1; +--echo # End of 10.3 tests diff --git a/mysql-test/suite/perfschema/r/hostcache_ipv4_auth_ed25519.result b/mysql-test/suite/perfschema/r/hostcache_ipv4_auth_ed25519.result new file mode 100644 index 00000000000..6e3d928509c --- /dev/null +++ b/mysql-test/suite/perfschema/r/hostcache_ipv4_auth_ed25519.result @@ -0,0 +1,121 @@ +install soname 'auth_ed25519'; +flush status; +flush hosts; +flush user_resources; +flush privileges; +select `User`, `Host` from mysql.`user` where `host` like '%\\%%'; +User Host +select `User`, `Host` from mysql.`user` where `user` like '192.%'; +User Host +select `User`, `Host` from mysql.`user` where `user` like '2001:%'; +User Host +select `User`, `Host` from mysql.`user` where `user` like 'santa.claus.%'; +User Host +create user plug1@'santa.claus.ipv4.example.com' + identified with ed25519; +update mysql.global_priv set priv=json_set(priv, '$.authentication_string', 'foo') where user='plug1'; +flush privileges; +create user plug2@'santa.claus.ipv4.example.com' + identified with ED25519 as 'vubFBzIrapbfHct1/J72dnUryz5VS7lA6XHH8sIx4TI'; +set @saved_dbug = @@global.debug_dbug; +set global debug_dbug= "+d,vio_peer_addr_fake_ipv4,getnameinfo_fake_ipv4,getaddrinfo_fake_good_ipv4"; +connect(127.0.0.1,plug1,foo,test,PORT,SOCKET); +connect con1, 127.0.0.1, plug1,foo,,$MASTER_MYPORT; +ERROR 28000: Access denied for user 'plug1'@'santa.claus.ipv4.example.com' (using password: YES) +# Dumping performance_schema.host_cache +IP 192.0.2.4 +HOST santa.claus.ipv4.example.com +HOST_VALIDATED YES +SUM_CONNECT_ERRORS 1 +COUNT_HOST_BLOCKED_ERRORS 0 +COUNT_NAMEINFO_TRANSIENT_ERRORS 0 +COUNT_NAMEINFO_PERMANENT_ERRORS 0 +COUNT_FORMAT_ERRORS 0 +COUNT_ADDRINFO_TRANSIENT_ERRORS 0 +COUNT_ADDRINFO_PERMANENT_ERRORS 0 +COUNT_FCRDNS_ERRORS 0 +COUNT_HOST_ACL_ERRORS 0 +COUNT_NO_AUTH_PLUGIN_ERRORS 0 +COUNT_AUTH_PLUGIN_ERRORS 0 +COUNT_HANDSHAKE_ERRORS 1 +COUNT_PROXY_USER_ERRORS 0 +COUNT_PROXY_USER_ACL_ERRORS 0 +COUNT_AUTHENTICATION_ERRORS 0 +COUNT_SSL_ERRORS 0 +COUNT_MAX_USER_CONNECTIONS_ERRORS 0 +COUNT_MAX_USER_CONNECTIONS_PER_HOUR_ERRORS 0 +COUNT_DEFAULT_DATABASE_ERRORS 0 +COUNT_INIT_CONNECT_ERRORS 0 +COUNT_LOCAL_ERRORS 0 +COUNT_UNKNOWN_ERRORS 0 +FIRST_ERROR_SEEN set +LAST_ERROR_SEEN set +connect(127.0.0.1,plug2,bar,test,PORT,SOCKET); +connect con1, 127.0.0.1, plug2,bar,,$MASTER_MYPORT; +ERROR 28000: Access denied for user 'plug2'@'santa.claus.ipv4.example.com' (using password: YES) +# Dumping performance_schema.host_cache +IP 192.0.2.4 +HOST santa.claus.ipv4.example.com +HOST_VALIDATED YES +SUM_CONNECT_ERRORS 1 +COUNT_HOST_BLOCKED_ERRORS 0 +COUNT_NAMEINFO_TRANSIENT_ERRORS 0 +COUNT_NAMEINFO_PERMANENT_ERRORS 0 +COUNT_FORMAT_ERRORS 0 +COUNT_ADDRINFO_TRANSIENT_ERRORS 0 +COUNT_ADDRINFO_PERMANENT_ERRORS 0 +COUNT_FCRDNS_ERRORS 0 +COUNT_HOST_ACL_ERRORS 0 +COUNT_NO_AUTH_PLUGIN_ERRORS 0 +COUNT_AUTH_PLUGIN_ERRORS 0 +COUNT_HANDSHAKE_ERRORS 1 +COUNT_PROXY_USER_ERRORS 0 +COUNT_PROXY_USER_ACL_ERRORS 0 +COUNT_AUTHENTICATION_ERRORS 1 +COUNT_SSL_ERRORS 0 +COUNT_MAX_USER_CONNECTIONS_ERRORS 0 +COUNT_MAX_USER_CONNECTIONS_PER_HOUR_ERRORS 0 +COUNT_DEFAULT_DATABASE_ERRORS 0 +COUNT_INIT_CONNECT_ERRORS 0 +COUNT_LOCAL_ERRORS 0 +COUNT_UNKNOWN_ERRORS 0 +FIRST_ERROR_SEEN set +LAST_ERROR_SEEN set +connect con1, 127.0.0.1, plug2,foo,,$MASTER_MYPORT; +select current_user(); +current_user() +plug2@santa.claus.ipv4.example.com +disconnect con1; +connection default; +# Dumping performance_schema.host_cache +IP 192.0.2.4 +HOST santa.claus.ipv4.example.com +HOST_VALIDATED YES +SUM_CONNECT_ERRORS 0 +COUNT_HOST_BLOCKED_ERRORS 0 +COUNT_NAMEINFO_TRANSIENT_ERRORS 0 +COUNT_NAMEINFO_PERMANENT_ERRORS 0 +COUNT_FORMAT_ERRORS 0 +COUNT_ADDRINFO_TRANSIENT_ERRORS 0 +COUNT_ADDRINFO_PERMANENT_ERRORS 0 +COUNT_FCRDNS_ERRORS 0 +COUNT_HOST_ACL_ERRORS 0 +COUNT_NO_AUTH_PLUGIN_ERRORS 0 +COUNT_AUTH_PLUGIN_ERRORS 0 +COUNT_HANDSHAKE_ERRORS 1 +COUNT_PROXY_USER_ERRORS 0 +COUNT_PROXY_USER_ACL_ERRORS 0 +COUNT_AUTHENTICATION_ERRORS 1 +COUNT_SSL_ERRORS 0 +COUNT_MAX_USER_CONNECTIONS_ERRORS 0 +COUNT_MAX_USER_CONNECTIONS_PER_HOUR_ERRORS 0 +COUNT_DEFAULT_DATABASE_ERRORS 0 +COUNT_INIT_CONNECT_ERRORS 0 +COUNT_LOCAL_ERRORS 0 +COUNT_UNKNOWN_ERRORS 0 +FIRST_ERROR_SEEN set +LAST_ERROR_SEEN set +drop user plug1@'santa.claus.ipv4.example.com'; +drop user plug2@'santa.claus.ipv4.example.com'; +set @@global.debug_dbug = @saved_dbug; +uninstall plugin ed25519; diff --git a/mysql-test/suite/perfschema/t/hostcache_ipv4_auth_ed25519.test b/mysql-test/suite/perfschema/t/hostcache_ipv4_auth_ed25519.test new file mode 100644 index 00000000000..4c68d3af51e --- /dev/null +++ b/mysql-test/suite/perfschema/t/hostcache_ipv4_auth_ed25519.test @@ -0,0 +1,56 @@ +# +# Tests for the performance_schema host_cache. +# +# Test authorization with auth plugins. +# error reporting in: +# - column COUNT_AUTH_PLUGIN_ERRORS +# - column COUNT_PROXY_USER_ERRORS +# - column COUNT_PROXY_USER_ACL_ERRORS + +source include/not_embedded.inc; +source include/have_debug.inc; +source include/have_perfschema.inc; +source include/have_plugin_auth.inc; +source include/have_hostname_cache.inc; + +if (!$AUTH_ED25519_SO) { + skip No auth_ed25519 plugin; +} +install soname 'auth_ed25519'; + +# Enforce a clean state +source ../include/wait_for_pfs_thread_count.inc; +source ../include/hostcache_set_state.inc; + +create user plug1@'santa.claus.ipv4.example.com' + identified with ed25519; +update mysql.global_priv set priv=json_set(priv, '$.authentication_string', 'foo') where user='plug1'; +flush privileges; + +create user plug2@'santa.claus.ipv4.example.com' + identified with ED25519 as 'vubFBzIrapbfHct1/J72dnUryz5VS7lA6XHH8sIx4TI'; + +set @saved_dbug = @@global.debug_dbug; +set global debug_dbug= "+d,vio_peer_addr_fake_ipv4,getnameinfo_fake_ipv4,getaddrinfo_fake_good_ipv4"; + +replace_result $MASTER_MYPORT PORT $MASTER_MYSOCK SOCKET; +error ER_ACCESS_DENIED_ERROR; +connect con1, 127.0.0.1, plug1,foo,,$MASTER_MYPORT; +source ../include/hostcache_dump.inc; + +replace_result $MASTER_MYPORT PORT $MASTER_MYSOCK SOCKET; +error ER_ACCESS_DENIED_ERROR; +connect con1, 127.0.0.1, plug2,bar,,$MASTER_MYPORT; +source ../include/hostcache_dump.inc; + +connect con1, 127.0.0.1, plug2,foo,,$MASTER_MYPORT; +select current_user(); +disconnect con1; +connection default; +source ../include/hostcache_dump.inc; + +drop user plug1@'santa.claus.ipv4.example.com'; +drop user plug2@'santa.claus.ipv4.example.com'; + +set @@global.debug_dbug = @saved_dbug; +uninstall plugin ed25519; diff --git a/mysys/crc32/crc32c.cc b/mysys/crc32/crc32c.cc index 082d467e7da..b48e744a663 100644 --- a/mysys/crc32/crc32c.cc +++ b/mysys/crc32/crc32c.cc @@ -517,12 +517,12 @@ static int arch_ppc_probe(void) { return arch_ppc_crc32; } -#elif _AIX +#elif defined(_AIX) || defined(__OpenBSD__) static int arch_ppc_probe(void) { arch_ppc_crc32 = 0; #if defined(__powerpc64__) - // AIX 7.1+ has vector crypto features on all POWER 8+ + // AIX 7.1+/OpenBSD has vector crypto features on all POWER 8+ arch_ppc_crc32 = 1; #endif /* __powerpc64__ */ diff --git a/mysys/my_largepage.c b/mysys/my_largepage.c index c3fc97ffe0a..0fdc4e17a26 100644 --- a/mysys/my_largepage.c +++ b/mysys/my_largepage.c @@ -336,8 +336,10 @@ uchar *my_large_malloc(size_t *size, myf my_flags) # warning "No explicit large page (HUGETLB pages) support in Linux < 3.8" #endif #elif defined(MAP_ALIGNED) - mapflag|= MAP_ALIGNED_SUPER | - MAP_ALIGNED(my_bit_log2_size_t(large_page_size)); + mapflag|= MAP_ALIGNED(my_bit_log2_size_t(large_page_size)); +#if defined(MAP_ALIGNED_SUPER) + mapflag|= MAP_ALIGNED_SUPER; +#endif #endif aligned_size= MY_ALIGN(*size, (size_t) large_page_size); } diff --git a/plugin/auth_ed25519/server_ed25519.c b/plugin/auth_ed25519/server_ed25519.c index 6fec98c56fc..b789bd34ca4 100644 --- a/plugin/auth_ed25519/server_ed25519.c +++ b/plugin/auth_ed25519/server_ed25519.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2017, MariaDB + Copyright (c) 2017, 2021, 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 @@ -42,7 +42,7 @@ static int auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) /* prepare random nonce */ if (my_random_bytes((unsigned char *)nonce, (int)sizeof(nonce))) - return CR_AUTH_USER_CREDENTIALS; + return CR_ERROR; // eh? OpenSSL error /* send it */ if (vio->write_packet(vio, reply + CRYPTO_BYTES, NONCE_BYTES)) @@ -55,7 +55,7 @@ static int auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) if (crypto_sign_open(reply, CRYPTO_BYTES + NONCE_BYTES, (unsigned char*)info->auth_string)) - return CR_ERROR; + return CR_AUTH_USER_CREDENTIALS; // wrong password provided by the user return CR_OK; } diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh index f4ac2e9936d..952a37f75d2 100644 --- a/scripts/wsrep_sst_common.sh +++ b/scripts/wsrep_sst_common.sh @@ -875,7 +875,9 @@ get_openssl() readonly OPENSSL_BINARY } +# # Generate a string equivalent to 16 random bytes +# wsrep_gen_secret() { get_openssl @@ -889,16 +891,36 @@ wsrep_gen_secret() fi } +# +# Checking if the address passed to us is local. +# If the second parameter is nonzero, then this function +# does not check for matches with local domain names: +# is_local_ip() { - [ "$1" = '127.0.0.1' ] && return 0 - [ "$1" = '127.0.0.2' ] && return 0 - [ "$1" = 'localhost' ] && return 0 - [ "$1" = '[::1]' ] && return 0 - [ "$1" = "$(hostname -s)" ] && return 0 - [ "$1" = "$(hostname -f)" ] && return 0 - [ "$1" = "$(hostname -d)" ] && return 0 - + # Rapid recognition of the most common cases: + [ "$1" = '127.0.0.1' -o \ + "$1" = '127.0.0.2' -o \ + "$1" = 'localhost' -o \ + "$1" = '[::1]' ] && return 0 + # If the address starts with "127." this is probably a local + # address, but we need to clarify what follows this prefix: + if [ "${1#127.}" != "$1" ]; then + # All 127.0.0.0/8 addresses are local: + if echo "$1" | grep -q -E '^127\.[0-9]+\.[0-9]+\.[0-9]+$'; then + return 0 + fi + fi + # If the second parameter is nonzero, then we will skip + # the domain name check: + if [ "${2:-0}" -eq 0 ]; then + # We consider all the names of a given host to be local addresses: + [ "$1" = "$(hostname -s)" -o \ + "$1" = "$(hostname -f)" -o \ + "$1" = "$(hostname -d)" ] && return 0 + fi + # Now let's check if the given address is assigned to + # one of the network cards: local ip_util="$(command -v ip)" if [ -n "$ip_util" ]; then # ip address show ouput format is " inet[6] <address>/<mask>": @@ -914,7 +936,6 @@ is_local_ip() | grep -F " $1 " >/dev/null && return 0 fi fi - return 1 } diff --git a/sql/item.cc b/sql/item.cc index b98270022cc..12cbc8f79b6 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5941,6 +5941,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) */ set_max_sum_func_level(thd, select); set_field(new_field); + depended_from= (*((Item_field**)res))->depended_from; return 0; } else diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 0cdd9a5fc5c..a87b4687915 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1870,7 +1870,6 @@ double Item_in_subselect::val_real() As far as Item_in_subselect called only from Item_in_optimizer this method should not be used */ - DBUG_ASSERT(0); DBUG_ASSERT(fixed()); if (forced_const) return value; @@ -2345,11 +2344,12 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join, */ Item *item= (Item*) select_lex->item_list.head(); - if (select_lex->table_list.elements) + if (select_lex->table_list.elements || + !(select_lex->master_unit()->is_unit_op())) { Item *having= item; Item *orig_item= item; - + item= func->create(thd, expr, item); if (!abort_on_null && orig_item->maybe_null()) { @@ -2393,32 +2393,29 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join, } else { - if (select_lex->master_unit()->is_unit_op()) - { - LEX_CSTRING field_name= {STRING_WITH_LEN("<result>") }; - Item *new_having= - func->create(thd, expr, - new (thd->mem_root) Item_ref_null_helper(thd, + DBUG_ASSERT(select_lex->master_unit()->is_unit_op()); + LEX_CSTRING field_name= {STRING_WITH_LEN("<result>") }; + Item *new_having= + func->create(thd, expr, + new (thd->mem_root) Item_ref_null_helper(thd, &select_lex->context, this, &select_lex->ref_pointer_array[0], no_matter_name, field_name)); - if (!abort_on_null && left_expr->maybe_null()) - { - disable_cond_guard_for_const_null_left_expr(0); - if (!(new_having= new (thd->mem_root) Item_func_trig_cond(thd, new_having, - get_cond_guard(0)))) - DBUG_RETURN(true); - } - - new_having->name= in_having_cond; - if (fix_having(new_having, select_lex)) + if (!abort_on_null && left_expr->maybe_null()) + { + disable_cond_guard_for_const_null_left_expr(0); + if (!(new_having= new (thd->mem_root) + Item_func_trig_cond(thd, new_having, get_cond_guard(0)))) DBUG_RETURN(true); - *having_item= new_having; } - else - DBUG_ASSERT(false); + + new_having->name= in_having_cond; + if (fix_having(new_having, select_lex)) + DBUG_RETURN(true); + + *having_item= new_having; } } diff --git a/sql/lock.cc b/sql/lock.cc index d62a8d49979..f6cdd40fa0b 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -1124,21 +1124,22 @@ void Global_read_lock::unlock_global_read_lock(THD *thd) thd->mdl_context.release_lock(m_mdl_global_read_lock); #ifdef WITH_WSREP - if (m_state == GRL_ACQUIRED_AND_BLOCKS_COMMIT) + if (m_state == GRL_ACQUIRED_AND_BLOCKS_COMMIT && + wsrep_locked_seqno != WSREP_SEQNO_UNDEFINED) { Wsrep_server_state& server_state= Wsrep_server_state::instance(); if (server_state.state() == Wsrep_server_state::s_donor || (WSREP_NNULL(thd) && server_state.state() != Wsrep_server_state::s_synced)) { - /* TODO: maybe redundant here?: */ - wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; server_state.resume(); + wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; } else if (WSREP_NNULL(thd) && server_state.state() == Wsrep_server_state::s_synced) { server_state.resume_and_resync(); + wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; } } #endif /* WITH_WSREP */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d32c66891a9..6eba8e11d58 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4977,7 +4977,7 @@ static int init_server_components() } #endif /* WITH_WSREP */ - if (opt_bin_log) + if (!opt_help && opt_bin_log) { if (mysql_bin_log.open_index_file(opt_binlog_index_name, opt_bin_logname, TRUE)) diff --git a/sql/mysqld.h b/sql/mysqld.h index ddfec106b60..768b81d59fc 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -711,7 +711,7 @@ extern struct st_VioSSLFd * ssl_acceptor_fd; */ extern my_bool opt_large_pages; extern uint opt_large_page_size; -extern char lc_messages_dir[FN_REFLEN]; +extern MYSQL_PLUGIN_IMPORT char lc_messages_dir[FN_REFLEN]; extern char *lc_messages_dir_ptr, *log_error_file_ptr; extern MYSQL_PLUGIN_IMPORT char reg_ext[FN_EXTLEN]; extern MYSQL_PLUGIN_IMPORT uint reg_ext_length; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 0812d61ced8..d1cf5c2d9bd 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -3492,8 +3492,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, Json_writer_object trace_command(thd); Json_writer_array trace_command_steps(thd, "steps"); if (open_tables) - res= check_dependencies_in_with_clauses(m_lex->with_clauses_list) || - instr->exec_open_and_lock_tables(thd, m_lex->query_tables); + res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables); if (likely(!res)) { diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 3a4c83e3139..605723a3b96 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -13909,7 +13909,12 @@ static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf) done: if (set_user_salt_if_needed(mpvio->acl_user, mpvio->curr_auth, mpvio->plugin)) + { + ai->thd->clear_error(); // authenticating user should not see these errors + my_error(ER_ACCESS_DENIED_ERROR, MYF(0), ai->thd->security_ctx->user, + ai->thd->security_ctx->host_or_ip, ER_THD(ai->thd, ER_YES)); goto err; + } ai->user_name= ai->thd->security_ctx->user; ai->user_name_length= (uint) strlen(ai->user_name); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 9c07e3de272..5982d8a92e1 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3591,7 +3591,11 @@ open_and_process_table(THD *thd, TABLE_LIST *tables, uint *counter, uint flags, if (tables->derived) { if (!tables->view) + { + if (!tables->is_derived()) + tables->set_derived(); goto end; + } /* We restore view's name and database wiped out by derived tables processing and fall back to standard open process in order to @@ -3601,35 +3605,6 @@ open_and_process_table(THD *thd, TABLE_LIST *tables, uint *counter, uint flags, tables->db= tables->view_db; tables->table_name= tables->view_name; } - else if (tables->select_lex) - { - /* - Check whether 'tables' refers to a table defined in a with clause. - If so set the reference to the definition in tables->with. - */ - if (!tables->with) - tables->with= tables->select_lex->find_table_def_in_with_clauses(tables); - /* - If 'tables' is defined in a with clause set the pointer to the - specification from its definition in tables->derived. - */ - if (tables->with) - { - if (tables->is_recursive_with_table() && - !tables->is_with_table_recursive_reference()) - { - tables->with->rec_outer_references++; - With_element *with_elem= tables->with; - while ((with_elem= with_elem->get_next_mutually_recursive()) != - tables->with) - with_elem->rec_outer_references++; - } - if (tables->set_as_with_table(thd, tables->with)) - DBUG_RETURN(1); - else - goto end; - } - } if (!tables->derived && is_infoschema_db(&tables->db)) { diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 7d4467c78ca..7c2014fe4b0 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2804,6 +2804,62 @@ void THD::close_active_vio() #endif +/* + @brief MySQL parser used for recursive invocations + + @param old_lex The LEX structure in the state when this parser + is called recursively + @param lex The LEX structure used to parse a new SQL fragment + @param str The SQL fragment to parse + @param str_len The length of the SQL fragment to parse + @param stmt_prepare_mode true <=> when parsing a prepare statement + + @details + This function is to be used when parsing of an SQL fragment is + needed within one of the grammar rules. + + @notes + Currently the function is used only when the specification of a CTE + is parsed for the not first and not recursive references of the CTE. + + @retval false On a successful parsing of the fragment + @retval true Otherwise +*/ + +bool THD::sql_parser(LEX *old_lex, LEX *lex, + char *str, uint str_len, bool stmt_prepare_mode) +{ + extern int MYSQLparse(THD * thd); + extern int ORAparse(THD * thd); + + bool parse_status= false; + Parser_state parser_state; + Parser_state *old_parser_state= m_parser_state; + + if (parser_state.init(this, str, str_len)) + return true; + + m_parser_state= &parser_state; + parser_state.m_lip.stmt_prepare_mode= stmt_prepare_mode; + parser_state.m_lip.multi_statements= false; + parser_state.m_lip.m_digest= NULL; + + lex->param_list= old_lex->param_list; + lex->sphead= old_lex->sphead; + lex->spname= old_lex->spname; + lex->spcont= old_lex->spcont; + lex->sp_chistics= old_lex->sp_chistics; + lex->trg_chistics= old_lex->trg_chistics; + + parse_status= (variables.sql_mode & MODE_ORACLE) ? + ORAparse(this) : MYSQLparse(this) != 0; + + m_parser_state= old_parser_state; + + return parse_status; +} + + struct Item_change_record: public ilink { Item **place; diff --git a/sql/sql_class.h b/sql/sql_class.h index 2fa50882ebf..3f748c6a206 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1081,7 +1081,7 @@ mysqld_collation_get_by_name(const char *name, myf utf8_flag, static inline bool is_supported_parser_charset(CHARSET_INFO *cs) { - return MY_TEST(cs->mbminlen == 1); + return MY_TEST(cs->mbminlen == 1 && cs->number != 17 /* filename */); } /** THD registry */ @@ -4637,14 +4637,11 @@ public: to resolve all CTE names as we don't need this message to be thrown for any CTE references. */ - if (!lex->with_clauses_list) + if (!lex->with_cte_resolution) { my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); return TRUE; } - /* This will allow to throw an error later for non-CTE references */ - to->str= NULL; - to->length= 0; return FALSE; } @@ -5398,7 +5395,6 @@ public: THD_TRANS::EXECUTED_TABLE_ADMIN_CMD)); } - uint get_net_wait_timeout() { if (in_active_multi_stmt_transaction()) @@ -5449,7 +5445,10 @@ public: Item *sp_prepare_func_item(Item **it_addr, uint cols= 1); bool sp_eval_expr(Field *result_field, Item **expr_item_ptr); - myf get_utf8_flag() + bool sql_parser(LEX *old_lex, LEX *lex, + char *str, uint str_len, bool stmt_prepare_mode); + + myf get_utf8_flag() const { return (variables.old_behavior & OLD_MODE_UTF8_IS_UTF8MB3 ? MY_UTF8_IS_UTF8MB3 : 0); diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index ad4a37d0fbe..396b3f2c8a9 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -84,7 +84,7 @@ void st_select_lex_unit::set_with_clause(With_clause *with_cl) true on failure */ -bool check_dependencies_in_with_clauses(With_clause *with_clauses_list) +bool LEX::check_dependencies_in_with_clauses() { for (With_clause *with_clause= with_clauses_list; with_clause; @@ -102,6 +102,201 @@ bool check_dependencies_in_with_clauses(With_clause *with_clauses_list) /** @brief + Resolve references to CTE in specification of hanging CTE + + @details + A CTE to which there are no references in the query is called hanging CTE. + Although such CTE is not used for execution its specification must be + subject to context analysis. All errors concerning references to + non-existing tables or fields occurred in the specification must be + reported as well as all other errors caught at the prepare stage. + The specification of a hanging CTE might contain references to other + CTE outside of the specification and within it if the specification + contains a with clause. This function resolves all such references for + all hanging CTEs encountered in the processed query. + + @retval + false on success + true on failure +*/ + +bool +LEX::resolve_references_to_cte_in_hanging_cte() +{ + for (With_clause *with_clause= with_clauses_list; + with_clause; with_clause= with_clause->next_with_clause) + { + for (With_element *with_elem= with_clause->with_list.first; + with_elem; with_elem= with_elem->next) + { + if (!with_elem->is_referenced()) + { + TABLE_LIST *first_tbl= + with_elem->spec->first_select()->table_list.first; + TABLE_LIST **with_elem_end_pos= with_elem->head->tables_pos.end_pos; + if (first_tbl && resolve_references_to_cte(first_tbl, with_elem_end_pos)) + return true; + } + } + } + return false; +} + + +/** + @brief + Resolve table references to CTE from a sub-chain of table references + + @param tables Points to the beginning of the sub-chain + @param tables_last Points to the address with the sub-chain barrier + + @details + The method resolves tables references to CTE from the chain of + table references specified by the parameters 'tables' and 'tables_last'. + It resolves the references against the CTE definition occurred in a query + or the specification of a CTE whose parsing tree is represented by + this LEX structure. The method is always called right after the process + of parsing the query or of the specification of a CTE has been finished, + thus the chain of table references used in the parsed fragment has been + already built. It is assumed that parameters of the method specify a + a sub-chain of this chain. + If a table reference can be potentially a table reference to a CTE and it + has not been resolved yet then the method tries to find the definition + of the CTE against which the reference can be resolved. If it succeeds + it sets the field TABLE_LIST::with to point to the found definition. + It also sets the field TABLE_LIST::derived to point to the specification + of the found CTE and sets TABLE::db.str to empty_c_string. This will + allow to handle this table reference like a reference to a derived handle. + If another table reference has been already resolved against this CTE + and this CTE is not recursive then a clone of the CTE specification is + constructed using the function With_element::clone_parsed_spec() and + TABLE_LIST::derived is set to point to this clone rather than to the + original specification. + If the method does not find a matched CTE definition in the parsed fragment + then in the case when the flag this->only_cte_resolution is set to true + it just moves to the resolution of the next table reference from the + specified sub-chain while in the case when this->only_cte_resolution is set + to false the method additionally sets an mdl request for this table + reference. + + @notes + The flag this->only_cte_resolution is set to true in the cases when + the failure to resolve a table reference as a CTE reference within + the fragment associated with this LEX structure does not imply that + this table reference cannot be resolved as such at all. + + @retval false On success: no errors reported, no memory allocations failed + @retval true Otherwise +*/ + +bool LEX::resolve_references_to_cte(TABLE_LIST *tables, + TABLE_LIST **tables_last) +{ + With_element *with_elem= 0; + + for (TABLE_LIST *tbl= tables; tbl != *tables_last; tbl= tbl->next_global) + { + if (tbl->derived) + continue; + if (!tbl->db.str && !tbl->with) + tbl->with= tbl->select_lex->find_table_def_in_with_clauses(tbl); + if (!tbl->with) // no CTE matches table reference tbl + { + if (only_cte_resolution) + continue; + if (!tbl->db.str) // no database specified in table reference tbl + { + if (!thd->db.str) // no default database is set + { + my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); + return true; + } + if (copy_db_to(&tbl->db)) + return true; + if (!(tbl->table_options & TL_OPTION_ALIAS)) + MDL_REQUEST_INIT(&tbl->mdl_request, MDL_key::TABLE, + tbl->db.str, tbl->table_name.str, + tbl->mdl_type, MDL_TRANSACTION); + tbl->mdl_request.set_type((tbl->lock_type >= TL_WRITE_ALLOW_WRITE) ? + MDL_SHARED_WRITE : MDL_SHARED_READ); + } + continue; + } + with_elem= tbl->with; + if (tbl->is_recursive_with_table() && + !tbl->is_with_table_recursive_reference()) + { + tbl->with->rec_outer_references++; + while ((with_elem= with_elem->get_next_mutually_recursive()) != + tbl->with) + with_elem->rec_outer_references++; + } + if (!with_elem->is_used_in_query || with_elem->is_recursive) + { + tbl->derived= with_elem->spec; + if (tbl->derived != tbl->select_lex->master_unit() && + !with_elem->is_recursive && + !tbl->is_with_table_recursive_reference()) + { + tbl->derived->move_as_slave(tbl->select_lex); + } + with_elem->is_used_in_query= true; + } + else + { + if (!(tbl->derived= tbl->with->clone_parsed_spec(thd->lex, tbl))) + return true; + } + tbl->db.str= empty_c_string; + tbl->db.length= 0; + tbl->schema_table= 0; + if (tbl->derived) + { + tbl->derived->first_select()->set_linkage(DERIVED_TABLE_TYPE); + tbl->select_lex->add_statistics(tbl->derived); + } + if (tbl->with->is_recursive && tbl->is_with_table_recursive_reference()) + continue; + with_elem->inc_references(); + } + return false; +} + + +/** + @brief + Find out dependencies between CTEs, resolve references to them + + @details + The function can be called in two modes. With this->with_cte_resolution + set to false the function only finds out all dependencies between CTEs + used in a query expression with a WITH clause whose parsing has been + just finished. Based on these dependencies recursive CTEs are detected. + If this->with_cte_resolution is set to true the function additionally + resolves all references to CTE occurred in this query expression. + + @retval + true on failure + false on success +*/ + +bool +LEX::check_cte_dependencies_and_resolve_references() +{ + if (check_dependencies_in_with_clauses()) + return true; + if (!with_cte_resolution) + return false; + if (resolve_references_to_cte(query_tables, query_tables_last)) + return true; + if (resolve_references_to_cte_in_hanging_cte()) + return true; + return false; +} + + +/** + @brief Check dependencies between tables defined in this with clause @details @@ -138,10 +333,11 @@ bool With_clause::check_dependencies() elem != with_elem; elem= elem->next) { - if (lex_string_cmp(system_charset_info, with_elem->query_name, - elem->query_name) == 0) + if (lex_string_cmp(system_charset_info, with_elem->get_name(), + elem->get_name()) == 0) { - my_error(ER_DUP_QUERY_NAME, MYF(0), with_elem->query_name->str); + my_error(ER_DUP_QUERY_NAME, MYF(0), + with_elem->get_name_str()); return true; } } @@ -248,13 +444,12 @@ With_element *With_clause::find_table_def(TABLE_LIST *table, with_elem != barrier; with_elem= with_elem->next) { - if (my_strcasecmp(system_charset_info, with_elem->query_name->str, - table->table_name.str) == 0 && + if (my_strcasecmp(system_charset_info, with_elem->get_name_str(), + table->table_name.str) == 0 && !table->is_fqtn) { table->set_derived(); - table->db.str= empty_c_string; - table->db.length= 0; + with_elem->referenced= true; return with_elem; } } @@ -611,7 +806,7 @@ bool With_clause::check_anchors() if (elem == with_elem) { my_error(ER_RECURSIVE_WITHOUT_ANCHORS, MYF(0), - with_elem->query_name->str); + with_elem->get_name_str()); return true; } } @@ -644,7 +839,7 @@ bool With_clause::check_anchors() if (elem->work_dep_map & elem->get_elem_map()) { my_error(ER_UNACCEPTABLE_MUTUAL_RECURSION, MYF(0), - with_elem->query_name->str); + with_elem->get_name_str()); return true; } } @@ -798,7 +993,8 @@ bool With_element::set_unparsed_spec(THD *thd, @brief Create a clone of the specification for the given with table - @param thd The context of the statement containing this with element + @param old_lex The LEX structure created for the query or CTE specification + where this With_element is defined @param with_table The reference to the table defined in this element for which the clone is created. @@ -808,12 +1004,13 @@ bool With_element::set_unparsed_spec(THD *thd, this element. The clone is created when the string with the specification saved in unparsed_spec is fed into the parser as an input string. The parsing - this string a unit object representing the specification is build. + this string a unit object representing the specification is built. A chain of all table references occurred in the specification is also formed. The method includes the new unit and its sub-unit into hierarchy of the units of the main query. I also insert the constructed chain of the table references into the chain of all table references of the main query. + The method resolves all references to CTE in the clone. @note Clones is created only for not first references to tables defined in @@ -829,116 +1026,128 @@ bool With_element::set_unparsed_spec(THD *thd, NULL - otherwise */ -st_select_lex_unit *With_element::clone_parsed_spec(THD *thd, +st_select_lex_unit *With_element::clone_parsed_spec(LEX *old_lex, TABLE_LIST *with_table) { + THD *thd= old_lex->thd; LEX *lex; - st_select_lex_unit *res= NULL; - Query_arena backup; - Query_arena *arena= thd->activate_stmt_arena_if_needed(&backup); - bool has_tmp_tables; + st_select_lex_unit *res= NULL; if (!(lex= (LEX*) new(thd->mem_root) st_lex_local)) - { - if (arena) - thd->restore_active_arena(arena, &backup); return res; - } - LEX *old_lex= thd->lex; thd->lex= lex; bool parse_status= false; - Parser_state parser_state; - TABLE_LIST *spec_tables; - TABLE_LIST *spec_tables_tail; st_select_lex *with_select; char save_end= unparsed_spec.str[unparsed_spec.length]; ((char*) &unparsed_spec.str[unparsed_spec.length])[0]= '\0'; - if (parser_state.init(thd, (char*) unparsed_spec.str, (unsigned int)unparsed_spec.length)) - goto err; - parser_state.m_lip.stmt_prepare_mode= stmt_prepare_mode; - parser_state.m_lip.multi_statements= false; - parser_state.m_lip.m_digest= NULL; lex_start(thd); lex->clone_spec_offset= unparsed_spec_offset; - lex->param_list= old_lex->param_list; - lex->sphead= old_lex->sphead; - lex->spname= old_lex->spname; - lex->spcont= old_lex->spcont; - lex->sp_chistics= old_lex->sp_chistics; - - lex->stmt_lex= old_lex; - parse_status= parse_sql(thd, &parser_state, 0); + lex->with_cte_resolution= true; + + /* + The specification of a CTE is to be parsed as a regular query. + At the very end of the parsing query the function + check_cte_dependencies_and_resolve_references() will be called. + It will check the dependencies between CTEs that are defined + within the query and will resolve CTE references in this query. + If a table reference is not resolved as a CTE reference within + this query it still can be resolved as a reference to a CTE defined + in the same clause as the CTE whose specification is to be parsed + or defined in an embedding CTE definition. + + Example: + with + cte1 as ( ... ), + cte2 as ([WITH ...] select ... from cte1 ...) + select ... from cte2 as r, ..., cte2 as s ... + + Here the specification of cte2 has be cloned for table reference + with alias s1. The specification contains a reference to cte1 + that is defined outside this specification. If the reference to + cte1 cannot be resolved within the specification of cte2 it's + not necessarily has to be a reference to a non-CTE table. That's + why the flag lex->only_cte_resolution has to be set to true + before parsing of the specification of cte2 invoked by this + function starts. Otherwise an mdl_lock would be requested for s + and this would not be correct. + */ + + lex->only_cte_resolution= true; + + lex->stmt_lex= old_lex->stmt_lex ? old_lex->stmt_lex : old_lex; + + parse_status= thd->sql_parser(old_lex, lex, + (char*) unparsed_spec.str, + (unsigned int)unparsed_spec.length, + stmt_prepare_mode); + ((char*) &unparsed_spec.str[unparsed_spec.length])[0]= save_end; - with_select= lex->first_select_lex(); + with_select= lex->unit.first_select(); if (parse_status) goto err; - if (check_dependencies_in_with_clauses(lex->with_clauses_list)) - goto err; - - spec_tables= lex->query_tables; - spec_tables_tail= 0; - has_tmp_tables= thd->has_temporary_tables(); - for (TABLE_LIST *tbl= spec_tables; - tbl; - tbl= tbl->next_global) - { - if (has_tmp_tables && !tbl->derived && !tbl->schema_table && - thd->open_temporary_table(tbl)) - goto err; - spec_tables_tail= tbl; - } - if (spec_tables) + /* + The global chain of TABLE_LIST objects created for the specification that + just has been parsed is added to such chain that contains the reference + to the CTE whose specification is parsed right after the TABLE_LIST object + created for the reference. + */ + if (lex->query_tables) { - if (with_table->next_global) + head->tables_pos.set_start_pos(&with_table->next_global); + head->tables_pos.set_end_pos(lex->query_tables_last); + TABLE_LIST *next_tbl= with_table->next_global; + if (next_tbl) { - spec_tables_tail->next_global= with_table->next_global; - with_table->next_global->prev_global= &spec_tables_tail->next_global; + *(lex->query_tables->prev_global= next_tbl->prev_global)= + lex->query_tables; + *(next_tbl->prev_global= lex->query_tables_last)= next_tbl; } else { - old_lex->query_tables_last= &spec_tables_tail->next_global; + *(lex->query_tables->prev_global= old_lex->query_tables_last)= + lex->query_tables; + old_lex->query_tables_last= lex->query_tables_last; } - spec_tables->prev_global= &with_table->next_global; - with_table->next_global= spec_tables; } res= &lex->unit; res->with_element= this; + /* + The unit of the specification that just has been parsed is included + as a slave of the select that contained in its from list the table + reference for which the unit has been created. + */ lex->unit.include_down(with_table->select_lex); - lex->unit.set_slave(with_select); + lex->unit.set_slave(with_select); + lex->unit.cloned_from= spec; old_lex->all_selects_list= (st_select_lex*) (lex->all_selects_list-> insert_chain_before( (st_select_lex_node **) &(old_lex->all_selects_list), with_select)); - if (check_dependencies_in_with_clauses(lex->with_clauses_list)) - res= NULL; + /* - Resolve references to CTE from the spec_tables list that has not - been resolved yet. + Now all references to the CTE defined outside of the cloned specification + has to be resolved. Additionally if old_lex->only_cte_resolution == false + for the table references that has not been resolved requests for mdl_locks + has to be set. */ - for (TABLE_LIST *tbl= spec_tables; - tbl; - tbl= tbl->next_global) + lex->only_cte_resolution= old_lex->only_cte_resolution; + if (lex->resolve_references_to_cte(lex->query_tables, + lex->query_tables_last)) { - if (!tbl->with) - tbl->with= with_select->find_table_def_in_with_clauses(tbl); - if (tbl == spec_tables_tail) - break; - } - if (check_table_access(thd, SELECT_ACL, spec_tables, FALSE, UINT_MAX, FALSE)) + res= NULL; goto err; + } - lex->sphead= NULL; // in order not to delete lex->sphead + lex->sphead= NULL; // in order not to delete lex->sphead lex_end(lex); err: - if (arena) - thd->restore_active_arena(arena, &backup); thd->lex= old_lex; return res; } @@ -1145,59 +1354,6 @@ With_element *st_select_lex::find_table_def_in_with_clauses(TABLE_LIST *table) } -/** - @brief - Set the specifying unit in this reference to a with table - - @details - The method assumes that the given element with_elem defines the table T - this table reference refers to. - If this is the first reference to T the method just sets its specification - in the field 'derived' as the unit that yields T. Otherwise the method - first creates a clone specification and sets rather this clone in this field. - - @retval - false on success - true on failure -*/ - -bool TABLE_LIST::set_as_with_table(THD *thd, With_element *with_elem) -{ - if (table) - { - /* - This table was prematurely identified as a temporary table. - We correct it here, but it's not a nice solution in the case - when the temporary table with this name is not used anywhere - else in the query. - */ - thd->mark_tmp_table_as_free_for_reuse(table); - table= 0; - } - with= with_elem; - schema_table= NULL; - if (!with_elem->is_referenced() || with_elem->is_recursive) - { - derived= with_elem->spec; - if (derived != select_lex->master_unit() && - !with_elem->is_recursive && - !is_with_table_recursive_reference()) - { - derived->move_as_slave(select_lex); - } - } - else - { - if(!(derived= with_elem->clone_parsed_spec(thd, this))) - return true; - } - derived->first_select()->set_linkage(DERIVED_TABLE_TYPE); - select_lex->add_statistics(derived); - with_elem->inc_references(); - return false; -} - - bool TABLE_LIST::is_recursive_with_table() { return with && with->is_recursive; @@ -1297,7 +1453,7 @@ bool st_select_lex::check_unrestricted_recursive(bool only_standard_compliant) if (only_standard_compliant && with_elem->is_unrestricted()) { my_error(ER_NOT_STANDARD_COMPLIANT_RECURSIVE, - MYF(0), with_elem->query_name->str); + MYF(0), with_elem->get_name_str()); return true; } @@ -1514,7 +1670,7 @@ static void list_strlex_print(THD *thd, String *str, List<Lex_ident_sys> *list) void With_element::print(THD *thd, String *str, enum_query_type query_type) { - str->append(query_name); + str->append(get_name()); if (column_list.elements) { List_iterator_fast<Lex_ident_sys> li(column_list); diff --git a/sql/sql_cte.h b/sql/sql_cte.h index 4c42dd23614..44628df3ff8 100644 --- a/sql/sql_cte.h +++ b/sql/sql_cte.h @@ -25,6 +25,39 @@ struct st_unit_ctxt_elem; /** + @class With_element_head + @brief Head of the definition of a CTE table + + It contains the name of the CTE and it contains the position of the subchain + of table references used in the definition in the global chain of table + references used in the query where this definition is encountered. +*/ + +class With_element_head : public Sql_alloc +{ + /* The name of the defined CTE */ + LEX_CSTRING *query_name; + +public: + /* + The structure describing the subchain of the table references used in + the specification of the defined CTE in the global chain of table + references used in the query. The structure is fully defined only + after the CTE definition has been parsed. + */ + TABLE_CHAIN tables_pos; + + With_element_head(LEX_CSTRING *name) + : query_name(name) + { + tables_pos.set_start_pos(0); + tables_pos.set_end_pos(0); + } + friend class With_element; +}; + + +/** @class With_element @brief Definition of a CTE table @@ -85,9 +118,22 @@ private: subqueries and specifications of other with elements). */ uint references; + + /* + true <=> this With_element is referred in the query in which the + element is defined + */ + bool referenced; + + /* + true <=> this With_element is needed for the execution of the query + in which the element is defined + */ + bool is_used_in_query; + /* Unparsed specification of the query that specifies this element. - It used to build clones of the specification if they are needed. + It's used to build clones of the specification if they are needed. */ LEX_CSTRING unparsed_spec; /* Offset of the specification in the input string */ @@ -101,10 +147,12 @@ private: public: /* - The name of the table introduced by this with elememt. The name - can be used in FROM lists of the queries in the scope of the element. + Contains the name of the defined With element and the position of + the subchain of the tables references used by its definition in the + global chain of TABLE_LIST objects created for the whole query. */ - LEX_CSTRING *query_name; + With_element_head *head; + /* Optional list of column names to name the columns of the table introduced by this with element. It is used in the case when the names are not @@ -163,18 +211,27 @@ public: /* List of derived tables containing recursive references to this CTE */ SQL_I_List<TABLE_LIST> derived_with_rec_ref; - With_element(LEX_CSTRING *name, + With_element(With_element_head *h, List <Lex_ident_sys> list, st_select_lex_unit *unit) : next(NULL), base_dep_map(0), derived_dep_map(0), sq_dep_map(0), work_dep_map(0), mutually_recursive(0), top_level_dep_map(0), sq_rec_ref(NULL), next_mutually_recursive(NULL), references(0), - query_name(name), column_list(list), cycle_list(0), spec(unit), + referenced(false), is_used_in_query(false), + head(h), column_list(list), cycle_list(0), spec(unit), is_recursive(false), rec_outer_references(0), with_anchor(false), level(0), rec_result(NULL) { unit->with_element= this; } + LEX_CSTRING *get_name() { return head->query_name; } + const char *get_name_str() { return get_name()->str; } + + void set_tables_start_pos(TABLE_LIST **pos) + { head->tables_pos.set_start_pos(pos); } + void set_tables_end_pos(TABLE_LIST **pos) + { head->tables_pos.set_end_pos(pos); } + bool check_dependencies_in_spec(); void check_dependencies_in_select(st_select_lex *sl, st_unit_ctxt_elem *ctxt, @@ -201,9 +258,9 @@ public: bool set_unparsed_spec(THD *thd, const char *spec_start, const char *spec_end, my_ptrdiff_t spec_offset); - st_select_lex_unit *clone_parsed_spec(THD *thd, TABLE_LIST *with_table); + st_select_lex_unit *clone_parsed_spec(LEX *old_lex, TABLE_LIST *with_table); - bool is_referenced() { return references != 0; } + bool is_referenced() { return referenced; } void inc_references() { references++; } @@ -263,6 +320,12 @@ public: void set_cycle_list(List<Lex_ident_sys> *cycle_list_arg); friend class With_clause; + + friend + bool LEX::resolve_references_to_cte(TABLE_LIST *tables, + TABLE_LIST **tables_last); + friend + bool LEX::resolve_references_to_cte_in_hanging_cte(); }; const uint max_number_of_elements_in_with_clause= sizeof(table_map)*8; @@ -361,8 +424,10 @@ public: friend class With_element; friend - bool - check_dependencies_in_with_clauses(With_clause *with_clauses_list); + bool LEX::check_dependencies_in_with_clauses(); + + friend + bool LEX::resolve_references_to_cte_in_hanging_cte(); }; inline diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 05574daf42b..4c4c438564d 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2019, Oracle and/or its affiliates. - Copyright (c) 2009, 2020, MariaDB Corporation + Copyright (c) 2009, 2021, 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 @@ -1255,6 +1255,8 @@ void LEX::start(THD *thd_arg) describe= 0; context_analysis_only= 0; derived_tables= 0; + with_cte_resolution= false; + only_cte_resolution= false; parsing_options.reset(); part_info= 0; m_sql_cmd= NULL; @@ -2925,6 +2927,7 @@ void st_select_lex_unit::init_query() with_wrapped_tvc= 0; is_view= 0; describe= 0; + cloned_from= 0; columns_are_renamed= 0; } @@ -9079,6 +9082,8 @@ bool LEX::check_main_unit_semantics() if (unit.set_nest_level(0) || unit.check_parameters(first_select_lex())) return TRUE; + if (check_cte_dependencies_and_resolve_references()) + return TRUE; return FALSE; } @@ -9805,8 +9810,8 @@ bool LEX::main_select_push(bool service) { DBUG_ENTER("LEX::main_select_push"); DBUG_PRINT("info", ("service: %u", service)); - current_select_number= 1; - builtin_select.select_number= 1; + current_select_number= ++thd->lex->stmt_lex->current_select_number; + builtin_select.select_number= current_select_number; builtin_select.is_service_select= service; if (push_select(&builtin_select)) DBUG_RETURN(TRUE); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 27895af80d8..196d0d80b04 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -895,6 +895,8 @@ public: With_clause *with_clause; /* With element where this unit is used as the specification (if any) */ With_element *with_element; + /* The unit used as a CTE specification from which this unit is cloned */ + st_select_lex_unit *cloned_from; /* thread handler */ THD *thd; /* @@ -1563,7 +1565,9 @@ public: } With_element *get_with_element() { - return master_unit()->with_element; + return master_unit()->cloned_from ? + master_unit()->cloned_from->with_element : + master_unit()->with_element; } With_element *find_table_def_in_with_clauses(TABLE_LIST *table); bool check_unrestricted_recursive(bool only_standard_compliant); @@ -3357,6 +3361,20 @@ public: bool parse_vcol_expr:1; bool analyze_stmt:1; /* TRUE<=> this is "ANALYZE $stmt" */ bool explain_json:1; + /* + true <=> The parsed fragment requires resolution of references to CTE + at the end of parsing. This name resolution process involves searching + for possible dependencies between CTE defined in the parsed fragment and + detecting possible recursive references. + The flag is set to true if the fragment contains CTE definitions. + */ + bool with_cte_resolution:1; + /* + true <=> only resolution of references to CTE are required in the parsed + fragment, no checking of dependencies between CTE is required. + This flag is used only when parsing clones of CTE specifications. + */ + bool only_cte_resolution:1; bool local_file:1; bool check_exists:1; bool verbose:1, no_write_to_binlog:1; @@ -4749,6 +4767,12 @@ public: const LEX_CSTRING *constraint_name, Table_ident *ref_table_name, DDL_options ddl_options); + bool check_dependencies_in_with_clauses(); + bool resolve_references_to_cte_in_hanging_cte(); + bool check_cte_dependencies_and_resolve_references(); + bool resolve_references_to_cte(TABLE_LIST *tables, + TABLE_LIST **tables_last); + }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 91b8ec138a0..da72bc8e7de 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3520,9 +3520,6 @@ mysql_execute_command(THD *thd) thd->get_stmt_da()->opt_clear_warning_info(thd->query_id); } - if (check_dependencies_in_with_clauses(thd->lex->with_clauses_list)) - DBUG_RETURN(1); - #ifdef HAVE_REPLICATION if (unlikely(thd->slave_thread)) { @@ -8212,7 +8209,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->is_fqtn= TRUE; ptr->db= table->db; } - else if (lex->copy_db_to(&ptr->db)) + else if (!lex->with_cte_resolution && lex->copy_db_to(&ptr->db)) DBUG_RETURN(0); else ptr->is_fqtn= FALSE; @@ -8227,9 +8224,11 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, if (ptr->db.length && ptr->db.str != any_db.str) ptr->db.length= my_casedn_str(files_charset_info, (char*) ptr->db.str); } - + ptr->table_name= table->table; - ptr->lock_type= lock_type; + ptr->lock_type= lock_type; + ptr->mdl_type= mdl_type; + ptr->table_options= table_options; ptr->updating= MY_TEST(table_options & TL_OPTION_UPDATING); /* TODO: remove TL_OPTION_FORCE_INDEX as it looks like it's not used */ ptr->force_index= MY_TEST(table_options & TL_OPTION_FORCE_INDEX); @@ -8916,8 +8915,10 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type, bool for_update tables->lock_type= lock_type; tables->skip_locked= skip_locked; tables->updating= for_update; - tables->mdl_request.set_type((lock_type >= TL_FIRST_WRITE) ? - MDL_SHARED_WRITE : MDL_SHARED_READ); + + if (tables->db.length) + tables->mdl_request.set_type((lock_type >= TL_FIRST_WRITE) ? + MDL_SHARED_WRITE : MDL_SHARED_READ); } DBUG_VOID_RETURN; } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index fc75eab564f..1db04c4656f 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2325,9 +2325,6 @@ static bool check_prepared_statement(Prepared_statement *stmt) if (tables) thd->get_stmt_da()->opt_clear_warning_info(thd->query_id); - if (check_dependencies_in_with_clauses(thd->lex->with_clauses_list)) - goto error; - if (sql_command_flags[sql_command] & CF_HA_CLOSE) mysql_ha_rm_tables(thd, tables); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 957fe44d621..474dd413f52 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2004, 2012, Oracle and/or its affiliates. - Copyright (c) 2010, 2018, MariaDB + Copyright (c) 2010, 2021, 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 @@ -483,7 +483,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) thd->variables.lock_wait_timeout)) goto end; - if (!create) { bool if_exists= thd->lex->if_exists(); @@ -599,9 +598,8 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) table= tables->table; #ifdef WITH_WSREP - if (WSREP(thd) && - !wsrep_should_replicate_ddl(thd, table->s->db_type())) - goto wsrep_error_label; + if (WSREP(thd) && !wsrep_should_replicate_ddl(thd, table->s->db_type())) + goto end; #endif /* Later on we will need it to downgrade the lock */ @@ -725,9 +723,11 @@ end: thd->mdl_context.release_lock(mdl_request_for_trn.ticket); DBUG_RETURN(result); + #ifdef WITH_WSREP wsrep_error_label: - DBUG_RETURN(true); + DBUG_ASSERT(result == 1); + goto end; #endif drop_orphan_trn: diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 3fc55552f6b..eb5c1bff200 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2004, 2013, Oracle and/or its affiliates. - Copyright (c) 2011, 2016, MariaDB Corporation + Copyright (c) 2011, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -34,7 +34,6 @@ #include "sp_cache.h" #include "datadict.h" // dd_frm_is_view() #include "sql_derived.h" -#include "sql_cte.h" // check_dependencies_in_with_clauses() #include "opt_trace.h" #include "ddl_log.h" #include "debug.h" // debug_crash_here @@ -440,12 +439,6 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, lex->link_first_table_back(view, link_to_local); view->open_type= OT_BASE_ONLY; - if (check_dependencies_in_with_clauses(lex->with_clauses_list)) - { - res= TRUE; - goto err_no_relink; - } - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); /* @@ -944,6 +937,13 @@ static int mysql_register_view(THD *thd, DDL_LOG_STATE *ddl_log_state, LEX *lex= thd->lex; /* + Ensure character set number != 17 (character set = filename) and mbminlen=1 + because these character sets are not parser friendly, which can give weird + sequence in .frm file of view and later give parsing error. + */ + DBUG_ASSERT(thd->charset()->mbminlen == 1 && thd->charset()->number != 17); + + /* View definition query -- a SELECT statement that fully defines view. It is generated from the Item-tree built from the original (specified by the user) query. The idea is that generated query should eliminates all @@ -1485,9 +1485,6 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, TABLE_LIST *tbl; Security_context *security_ctx= 0; - if (check_dependencies_in_with_clauses(thd->lex->with_clauses_list)) - goto err; - /* Check rights to run commands which show underlying tables. In the optimizer trace we would not like to show trace for diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index d1f22006e1d..37cdfc20030 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -294,6 +294,7 @@ void _CONCAT_UNDERSCORED(turn_parser_debug_on,yyparse)() class sp_head *sphead; class sp_name *spname; class sp_variable *spvar; + class With_element_head *with_element_head; class With_clause *with_clause; class Virtual_column_info *virtual_column; @@ -1788,7 +1789,7 @@ End SQL_MODE_ORACLE_SPECIFIC */ %type <with_clause> with_clause -%type <lex_str_ptr> query_name +%type <with_element_head> with_element_head %type <ident_sys_list> comma_separated_ident_list @@ -2981,7 +2982,11 @@ call: if (unlikely(Lex->call_statement_start(thd, $2))) MYSQL_YYABORT; } - opt_sp_cparam_list {} + opt_sp_cparam_list + { + if (Lex->check_cte_dependencies_and_resolve_references()) + MYSQL_YYABORT; + } ; /* CALL parameters */ @@ -3788,6 +3793,8 @@ expr_lex: $$->sp_lex_in_use= true; $$->set_item($2); Lex->pop_select(); //min select + if (Lex->check_cte_dependencies_and_resolve_references()) + MYSQL_YYABORT; if ($$->sphead->restore_lex(thd)) MYSQL_YYABORT; } @@ -12989,6 +12996,8 @@ do: { Lex->insert_list= $3; Lex->pop_select(); //main select + if (Lex->check_cte_dependencies_and_resolve_references()) + MYSQL_YYABORT; } ; @@ -15170,6 +15179,7 @@ with_clause: if (unlikely(with_clause == NULL)) MYSQL_YYABORT; lex->derived_tables|= DERIVED_WITH; + lex->with_cte_resolution= true; lex->curr_with_clause= with_clause; with_clause->add_to_list(Lex->with_clauses_list_last_next); if (lex->current_select && @@ -15197,7 +15207,7 @@ with_list: with_list_element: - query_name + with_element_head opt_with_column_list AS '(' query_expression ')' opt_cycle { @@ -15215,6 +15225,7 @@ with_list_element: { elem->set_cycle_list($7); } + elem->set_tables_end_pos(lex->query_tables_last); } ; @@ -15275,12 +15286,15 @@ comma_separated_ident_list: ; -query_name: +with_element_head: ident { - $$= (LEX_CSTRING *) thd->memdup(&$1, sizeof(LEX_CSTRING)); - if (unlikely($$ == NULL)) + LEX_CSTRING *name= + (LEX_CSTRING *) thd->memdup(&$1, sizeof(LEX_CSTRING)); + $$= new (thd->mem_root) With_element_head(name); + if (unlikely(name == NULL || $$ == NULL)) MYSQL_YYABORT; + $$->tables_pos.set_start_pos(Lex->query_tables_last); } ; diff --git a/sql/table.h b/sql/table.h index 1b8919f4e59..183ade8f1d9 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2116,6 +2116,29 @@ struct vers_select_conds_t struct LEX; class Index_hint; + +/* + @struct TABLE_CHAIN + @brief Subchain of global chain of table references + + The structure contains a pointer to the address of the next_global + pointer to the first TABLE_LIST objectof the subchain and the address + of the next_global pointer to the element right after the last + TABLE_LIST object of the subchain. For an empty subchain both pointers + have the same value. +*/ + +struct TABLE_CHAIN +{ + TABLE_CHAIN() {} + + TABLE_LIST **start_pos; + TABLE_LIST ** end_pos; + + void set_start_pos(TABLE_LIST **pos) { start_pos= pos; } + void set_end_pos(TABLE_LIST **pos) { end_pos= pos; } +}; + struct TABLE_LIST { TABLE_LIST() {} /* Remove gcc warning */ @@ -2451,6 +2474,20 @@ struct TABLE_LIST /* call back function for asking handler about caching in query cache */ qc_engine_callback callback_func; thr_lock_type lock_type; + + /* + Two fields below are set during parsing this table reference in the cases + when the table reference can be potentially a reference to a CTE table. + In this cases the fact that the reference is a reference to a CTE or not + will be ascertained at the very end of parsing of the query when referencies + to CTE are resolved. For references to CTE and to derived tables no mdl + requests are needed while for other table references they are. If a request + is possibly postponed the info that allows to issue this request must be + saved in 'mdl_type' and 'table_options'. + */ + enum_mdl_type mdl_type; + ulong table_options; + uint outer_join; /* Which join type */ uint shared; /* Used in multi-upd */ bool updatable; /* VIEW/TABLE can be updated now */ diff --git a/sql/threadpool_generic.cc b/sql/threadpool_generic.cc index 19193be0354..e83676179b7 100644 --- a/sql/threadpool_generic.cc +++ b/sql/threadpool_generic.cc @@ -234,14 +234,19 @@ static void *native_event_get_userdata(native_event *event) #elif defined(HAVE_KQUEUE) /* - NetBSD is incompatible with other BSDs , last parameter in EV_SET macro - (udata, user data) needs to be intptr_t, whereas it needs to be void* - everywhere else. + NetBSD prior to 9.99.17 is incompatible with other BSDs, last parameter + in EV_SET macro (udata, user data) needs to be intptr_t, whereas it needs + to be void* everywhere else. */ #ifdef __NetBSD__ +#include <sys/param.h> +# if !__NetBSD_Prereq__(9,99,17) #define MY_EV_SET(a, b, c, d, e, f, g) EV_SET(a, b, c, d, e, f, (intptr_t)g) -#else +# endif +#endif + +#ifndef MY_EV_SET #define MY_EV_SET(a, b, c, d, e, f, g) EV_SET(a, b, c, d, e, f, g) #endif diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index 14ab86cf2d8..ebb61bb487b 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -423,11 +423,11 @@ IF(CONNECT_WITH_JDBC AND JAVA_FOUND AND JNI_FOUND) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/mysql-test/connect/std_data/JavaWrappers.jar ${CMAKE_CURRENT_BINARY_DIR}/JdbcInterface.jar - DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) + DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT connect-engine) IF(CONNECT_WITH_MONGO) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/mysql-test/connect/std_data/Mongo2.jar ${CMAKE_CURRENT_SOURCE_DIR}/mysql-test/connect/std_data/Mongo3.jar - DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) + DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT connect-engine) ENDIF() ENDIF() diff --git a/storage/connect/javaconn.cpp b/storage/connect/javaconn.cpp index eda5d31c80b..03c9ecb9221 100644 --- a/storage/connect/javaconn.cpp +++ b/storage/connect/javaconn.cpp @@ -57,8 +57,8 @@ extern "C" HINSTANCE s_hModule; // Saved module handle extern char *JvmPath; // The connect_jvm_path global variable value extern char *ClassPath; // The connect_class_path global variable value -char *GetPluginDir(void); char *GetJavaWrapper(void); // The connect_java_wrapper variable value +extern MYSQL_PLUGIN_IMPORT char lc_messages_dir[FN_REFLEN]; /***********************************************************************/ /* Static JAVAConn objects. */ @@ -401,23 +401,23 @@ bool JAVAConn::Open(PGLOBAL g) } // endif ClassPath #if 0 - // Java source will be compiled as a jar file installed in the plugin dir + // Java source will be compiled as a jar file installed in the mysql share dir jpop->Append(sep); - jpop->Append(GetPluginDir()); + jpop->Append(lc_messages_dir); jpop->Append("JdbcInterface.jar"); #endif // 0 - // All wrappers are pre-compiled in JavaWrappers.jar in the plugin dir + // All wrappers are pre-compiled in JavaWrappers.jar in the mysql share dir jpop->Append(sep); - jpop->Append(GetPluginDir()); + jpop->Append(lc_messages_dir); jpop->Append("JavaWrappers.jar"); #if defined(MONGO_SUPPORT) jpop->Append(sep); - jpop->Append(GetPluginDir()); + jpop->Append(lc_messages_dir); jpop->Append("Mongo3.jar"); jpop->Append(sep); - jpop->Append(GetPluginDir()); + jpop->Append(lc_messages_dir); jpop->Append("Mongo2.jar"); #endif // MONGO_SUPPORT diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index e77f10d3209..6ef39391849 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -1682,7 +1682,6 @@ PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp, int n) /***********************************************************************/ PJVAL JSONCOL::GetRowValue(PGLOBAL g, PJSON row, int i) { - int n = Nod - 1; PJVAL val = NULL; for (; i < Nod && row; i++) { diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index 515abf94060..050c8eb7d23 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -1750,15 +1750,14 @@ fts_create_one_common_table( error = row_create_index_for_mysql(index, trx, NULL, FIL_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY); + if (error == DB_SUCCESS) { + return new_table; + } } - if (error != DB_SUCCESS) { - dict_mem_table_free(new_table); - new_table = NULL; - ib::warn() << "Failed to create FTS common table " - << fts_table_name; - } - return(new_table); + ib::warn() << "Failed to create FTS common table " << fts_table_name; + trx->error_state = error; + return NULL; } /** Creates the common auxiliary tables needed for supporting an FTS index @@ -1813,7 +1812,8 @@ fts_create_common_tables( dict_table_t* common_table = fts_create_one_common_table( trx, table, full_name[i], fts_table.suffix, heap); - if (common_table == NULL) { + if (!common_table) { + trx->error_state = DB_SUCCESS; error = DB_ERROR; goto func_exit; } @@ -1928,16 +1928,15 @@ fts_create_one_index_table( error = row_create_index_for_mysql(index, trx, NULL, FIL_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY); - } - if (error != DB_SUCCESS) { - dict_mem_table_free(new_table); - new_table = NULL; - ib::warn() << "Failed to create FTS index table " - << table_name; + if (error == DB_SUCCESS) { + return new_table; + } } - return(new_table); + ib::warn() << "Failed to create FTS index table " << table_name; + trx->error_state = error; + return NULL; } /** Creates the column specific ancillary tables needed for supporting an diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 2b6089c4814..aea5ac42010 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -5966,7 +5966,9 @@ ha_innobase::open(const char* name, int, uint) /* Index block size in InnoDB: used by MySQL in query optimization */ stats.block_size = static_cast<uint>(srv_page_size); - if (m_prebuilt->table == NULL + const my_bool for_vc_purge = THDVAR(thd, background_thread); + + if (for_vc_purge || !m_prebuilt->table || m_prebuilt->table->is_temporary() || m_prebuilt->table->persistent_autoinc || !m_prebuilt->table->is_readable()) { @@ -5993,7 +5995,7 @@ ha_innobase::open(const char* name, int, uint) ut_ad(!m_prebuilt->table || table->versioned() == m_prebuilt->table->versioned()); - if (!THDVAR(thd, background_thread)) { + if (!for_vc_purge) { info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST | HA_STATUS_OPEN); } @@ -12956,7 +12958,6 @@ create_table_info_t::create_table_update_dict() if (m_flags2 & DICT_TF2_FTS) { if (!innobase_fts_load_stopword(innobase_table, NULL, m_thd)) { dict_table_close(innobase_table, FALSE, FALSE); - m_trx->free(); DBUG_RETURN(-1); } @@ -13076,7 +13077,8 @@ ha_innobase::create( DBUG_ASSERT(trx_state_eq(trx, TRX_STATE_NOT_STARTED)); } - if (int error = info.create_table(own_trx)) { + int error = info.create_table(own_trx); + if (error) { /* Drop the being-created table before rollback, so that rollback can possibly rename back a table that could have been renamed before the failed creation. */ @@ -13088,22 +13090,18 @@ ha_innobase::create( } trx_rollback_for_mysql(trx); row_mysql_unlock_data_dictionary(trx); - if (own_trx) { - trx->free(); - } - DBUG_RETURN(error); + } else { + innobase_commit_low(trx); + row_mysql_unlock_data_dictionary(trx); + ut_ad(!srv_read_only_mode); + error = info.create_table_update_dict(); } - innobase_commit_low(trx); - row_mysql_unlock_data_dictionary(trx); - if (own_trx) { trx->free(); } - ut_ad(!srv_read_only_mode); - - DBUG_RETURN(info.create_table_update_dict()); + DBUG_RETURN(error); } /** Create a new table to an InnoDB database. diff --git a/storage/mroonga/vendor/groonga/CMakeLists.txt b/storage/mroonga/vendor/groonga/CMakeLists.txt index ebb8b6906ec..b6ad3a9e50d 100644 --- a/storage/mroonga/vendor/groonga/CMakeLists.txt +++ b/storage/mroonga/vendor/groonga/CMakeLists.txt @@ -588,14 +588,13 @@ else() set(GRN_WITH_MESSAGE_PACK FALSE) endif() -find_program(RUBY NAMES - "ruby2.3" "ruby23" - "ruby2.2" "ruby22" - "ruby2.1" "ruby21" - "ruby") - option(GRN_WITH_MRUBY "use mruby" OFF) if(GRN_WITH_MRUBY) + find_program(RUBY NAMES + "ruby2.3" "ruby23" + "ruby2.2" "ruby22" + "ruby2.1" "ruby21" + "ruby") set(MRUBY_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/vendor/mruby-source/include") set(MRUBY_LIBS mruby) diff --git a/support-files/rpm/server-posttrans.sh b/support-files/rpm/server-posttrans.sh index 313274c6140..d91ff65e04f 100644 --- a/support-files/rpm/server-posttrans.sh +++ b/support-files/rpm/server-posttrans.sh @@ -3,7 +3,7 @@ if [ -r %{restart_flag} ] ; then # only restart the server if it was already running if [ -x /usr/bin/systemctl ] ; then /usr/bin/systemctl daemon-reload > /dev/null 2>&1 - if [ /usr/bin/systemctl is-active mysql ]; then + if /usr/bin/systemctl is-active mysql; then /usr/bin/systemctl restart mysql > /dev/null 2>&1 else /usr/bin/systemctl try-restart mariadb.service > /dev/null 2>&1 |