diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2021-10-13 12:03:32 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2021-10-13 12:03:32 +0300 |
commit | a736a3174a4e7c0d92a38901ae61f563d4afede7 (patch) | |
tree | 348d15f7c9cc883e86d852fbddc780f506669ee4 | |
parent | b44e12fef176bfc0884fb2c5f4ba7f42bf054f44 (diff) | |
parent | 4a7dfda373ff9e28e4f4f35bad76cbfc20934a9a (diff) | |
download | mariadb-git-a736a3174a4e7c0d92a38901ae61f563d4afede7.tar.gz |
Merge 10.3 into 10.4
54 files changed, 754 insertions, 121 deletions
diff --git a/.gitignore b/.gitignore index b3cbd1d430d..99c47b46966 100644 --- a/.gitignore +++ b/.gitignore @@ -373,6 +373,7 @@ x86/ build/ bld/ [Bb]in/ +/cmake-build-debug/ [Oo]bj/ # Roslyn cache directories @@ -555,7 +556,7 @@ compile_commands.json .vscode/ # Clion && other JetBrains ides -.idea +/.idea/ .cache/clangd diff --git a/client/mysql.cc b/client/mysql.cc index 7b3f34b755f..5db52a3ef36 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1672,11 +1672,14 @@ static struct my_option my_long_options[] = &opt_default_auth, &opt_default_auth, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"binary-mode", 0, - "By default, ASCII '\\0' is disallowed and '\\r\\n' is translated to '\\n'. " - "This switch turns off both features, and also turns off parsing of all client" - "commands except \\C and DELIMITER, in non-interactive mode (for input " - "piped to mysql or loaded using the 'source' command). This is necessary " - "when processing output from mysqlbinlog that may contain blobs.", + "Binary mode allows certain character sequences to be processed as data " + "that would otherwise be treated with a special meaning by the parser. " + "Specifically, this switch turns off parsing of all client commands except " + "\\C and DELIMITER in non-interactive mode (i.e., when binary mode is " + "combined with either 1) piped input, 2) the --batch mysql option, or 3) " + "the 'source' command). Also, in binary mode, occurrences of '\\r\\n' and " + "ASCII '\\0' are preserved within strings, whereas by default, '\\r\\n' is " + "translated to '\\n' and '\\0' is disallowed in user input.", &opt_binary_mode, &opt_binary_mode, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"connect-expired-password", 0, "Notify the server that this client is prepared to handle expired " @@ -2316,8 +2319,15 @@ static bool add_line(String &buffer, char *line, size_t line_length, { // Found possbile one character command like \c - if (!(inchar = (uchar) *++pos)) - break; // readline adds one '\' + /* + The null-terminating character (ASCII '\0') marks the end of user + input. Then, by default, upon encountering a '\0' while parsing, it + should stop. However, some data naturally contains binary zeros + (e.g., zipped files). Real_binary_mode signals the parser to expect + '\0' within the data and not to end parsing if found. + */ + if (!(inchar = (uchar) *++pos) && (!real_binary_mode || !*in_string)) + break; // readline adds one '\' if (*in_string || inchar == 'N') // \N is short for NULL { // Don't allow commands in string *out++='\\'; diff --git a/include/ft_global.h b/include/ft_global.h index 725363c3aa8..9f2d52610ba 100644 --- a/include/ft_global.h +++ b/include/ft_global.h @@ -90,7 +90,8 @@ void ft_free_stopwords(void); FT_INFO *ft_init_search(uint,void *, uint, uchar *, size_t, CHARSET_INFO *, uchar *); -my_bool ft_boolean_check_syntax_string(const uchar *); +my_bool ft_boolean_check_syntax_string(const uchar *, size_t length, + CHARSET_INFO *cs); /* Internal symbols for fulltext between maria and MyISAM */ diff --git a/include/my_context.h b/include/my_context.h index ea0e3496887..45d2a7d7ffa 100644 --- a/include/my_context.h +++ b/include/my_context.h @@ -52,6 +52,9 @@ struct my_context { #ifdef MY_CONTEXT_USE_UCONTEXT +#if defined(__APPLE__) && !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE +#endif #include <ucontext.h> struct my_context { diff --git a/include/my_global.h b/include/my_global.h index ae8835a2a50..a4c694fd196 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -159,7 +159,7 @@ # if defined(__i386__) || defined(__ppc__) # define SIZEOF_CHARP 4 # define SIZEOF_LONG 4 -# elif defined(__x86_64__) || defined(__ppc64__) +# elif defined(__x86_64__) || defined(__ppc64__) || defined(__aarch64__) # define SIZEOF_CHARP 8 # define SIZEOF_LONG 8 # else diff --git a/include/mysql_com.h b/include/mysql_com.h index 65f686f3063..f63cf0ac5c2 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -193,13 +193,13 @@ enum enum_indicator_type #define FIELD_FLAGS_COLUMN_FORMAT_MASK (3U << FIELD_FLAGS_COLUMN_FORMAT) #define FIELD_IS_DROPPED (1U << 26) /* Intern: Field is being dropped */ -#define VERS_SYS_START_FLAG (1 << 27) /* autogenerated column declared with +#define VERS_ROW_START (1 << 27) /* autogenerated column declared with `generated always as row start` (see II.a SQL Standard) */ -#define VERS_SYS_END_FLAG (1 << 28) /* autogenerated column declared with +#define VERS_ROW_END (1 << 28) /* autogenerated column declared with `generated always as row end` (see II.a SQL Standard).*/ -#define VERS_SYSTEM_FIELD (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG) +#define VERS_SYSTEM_FIELD (VERS_ROW_START | VERS_ROW_END) #define VERS_UPDATE_UNVERSIONED_FLAG (1 << 29) /* column that doesn't support system versioning when table itself supports it*/ diff --git a/man/mysql.1 b/man/mysql.1 index c2eda6d7e72..2acb71656a0 100644 --- a/man/mysql.1 +++ b/man/mysql.1 @@ -206,7 +206,14 @@ option\&. .\" binary-mode option: mysql \fB\-\-binary\-mode\fR .sp -By default, ASCII '\e0' is disallowed and '\er\en' is translated to '\en'\&. This switch turns off both features, and also turns off parsing of all client commands except \eC and DELIMITER, in non-interactive mode (for input piped to mysql or loaded using the 'source' command)\&. This is necessary when processing output from mysqlbinlog that may contain blobs\&. +Binary mode allows certain character sequences to be processed as data that +would otherwise be treated with a special meaning by the parser\&. +Specifically, this switch turns off parsing of all client commands except \eC +and DELIMITER in non-interactive mode (i\&.e\&., when binary mode is combined +with either 1) piped input, 2) the --batch mysql option, or 3) the 'source' +command)\&. Also, in binary mode, occurrences of '\er\en' and ASCII '\e0' are +preserved within strings, whereas by default, '\er\en' is translated to '\en' +and '\e0' is disallowed in user input\&. .RE .sp .RS 4 diff --git a/mysql-test/main/ctype_utf16_def.result b/mysql-test/main/ctype_utf16_def.result index 98b6f7d913d..b5827d45619 100644 --- a/mysql-test/main/ctype_utf16_def.result +++ b/mysql-test/main/ctype_utf16_def.result @@ -8,3 +8,8 @@ character_set_server utf16 SHOW VARIABLES LIKE 'ft_stopword_file'; Variable_name Value ft_stopword_file (built-in) +# +# MDEV-23269 SIGSEGV in ft_boolean_check_syntax_string on setting ft_boolean_syntax +# +SET GLOBAL ft_boolean_syntax='+ -><()~*:""&|'; +SET GLOBAL ft_boolean_syntax=DEFAULT; diff --git a/mysql-test/main/ctype_utf16_def.test b/mysql-test/main/ctype_utf16_def.test index 0829cd53285..c6de842f618 100644 --- a/mysql-test/main/ctype_utf16_def.test +++ b/mysql-test/main/ctype_utf16_def.test @@ -7,3 +7,10 @@ call mtr.add_suppression("'utf16' can not be used as client character set"); SHOW VARIABLES LIKE 'collation_server'; SHOW VARIABLES LIKE 'character_set_server'; SHOW VARIABLES LIKE 'ft_stopword_file'; + +--echo # +--echo # MDEV-23269 SIGSEGV in ft_boolean_check_syntax_string on setting ft_boolean_syntax +--echo # + +SET GLOBAL ft_boolean_syntax='+ -><()~*:""&|'; +SET GLOBAL ft_boolean_syntax=DEFAULT; diff --git a/mysql-test/main/ctype_utf32_def.opt b/mysql-test/main/ctype_utf32_def.opt new file mode 100644 index 00000000000..3b0880cbff3 --- /dev/null +++ b/mysql-test/main/ctype_utf32_def.opt @@ -0,0 +1 @@ +--character-set-server=utf32,latin1 --collation-server=utf32_general_ci diff --git a/mysql-test/main/ctype_utf32_def.result b/mysql-test/main/ctype_utf32_def.result new file mode 100644 index 00000000000..611072eb75b --- /dev/null +++ b/mysql-test/main/ctype_utf32_def.result @@ -0,0 +1,6 @@ +call mtr.add_suppression("'utf32' can not be used as client character set"); +# +# MDEV-23269 SIGSEGV in ft_boolean_check_syntax_string on setting ft_boolean_syntax +# +SET GLOBAL ft_boolean_syntax='+ -><()~*:""&|'; +SET GLOBAL ft_boolean_syntax=DEFAULT; diff --git a/mysql-test/main/ctype_utf32_def.test b/mysql-test/main/ctype_utf32_def.test new file mode 100644 index 00000000000..e23f96052d3 --- /dev/null +++ b/mysql-test/main/ctype_utf32_def.test @@ -0,0 +1,9 @@ +--source include/have_utf32.inc +call mtr.add_suppression("'utf32' can not be used as client character set"); + +--echo # +--echo # MDEV-23269 SIGSEGV in ft_boolean_check_syntax_string on setting ft_boolean_syntax +--echo # + +SET GLOBAL ft_boolean_syntax='+ -><()~*:""&|'; +SET GLOBAL ft_boolean_syntax=DEFAULT; diff --git a/mysql-test/main/default.result b/mysql-test/main/default.result index 0d2c2e6acbc..e8f5bd8e48a 100644 --- a/mysql-test/main/default.result +++ b/mysql-test/main/default.result @@ -3387,6 +3387,14 @@ CREATE OR REPLACE TABLE t1(i int); ALTER TABLE t1 ADD b CHAR(255) DEFAULT `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`; ERROR 42S22: Unknown column 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' in 'DEFAULT' DROP TABLE t1; +# +# MDEV-18278 Misleading error message in error log upon failed table creation +# +create table t1 (a int as (a)); +ERROR 01000: Expression for field `a` is referring to uninitialized field `a` +show warnings; +Level Code Message +Error 4029 Expression for field `a` is referring to uninitialized field `a` # end of 10.2 test # # MDEV-22703 DEFAULT() on a BLOB column can overwrite the default @@ -3403,3 +3411,4 @@ length(DEFAULT(h)) 25 INSERT INTO t1 () VALUES (); drop table t1; +# end of 10.3 test diff --git a/mysql-test/main/default.test b/mysql-test/main/default.test index c0561deac67..bcd6ef7a9fb 100644 --- a/mysql-test/main/default.test +++ b/mysql-test/main/default.test @@ -2109,6 +2109,13 @@ CREATE OR REPLACE TABLE t1(i int); ALTER TABLE t1 ADD b CHAR(255) DEFAULT `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`; DROP TABLE t1; +--echo # +--echo # MDEV-18278 Misleading error message in error log upon failed table creation +--echo # +--error ER_EXPRESSION_REFERS_TO_UNINIT_FIELD +create table t1 (a int as (a)); +show warnings; + --echo # end of 10.2 test --echo # @@ -2126,3 +2133,5 @@ SELECT DEFAULT(h) FROM t1; SELECT length(DEFAULT(h)) FROM t1; INSERT INTO t1 () VALUES (); drop table t1; + +--echo # end of 10.3 test diff --git a/mysql-test/main/delayed_blob.opt b/mysql-test/main/delayed_blob.opt new file mode 100644 index 00000000000..e442a822046 --- /dev/null +++ b/mysql-test/main/delayed_blob.opt @@ -0,0 +1 @@ +--init_connect="set @a='something unique to have MTR start a dedicated mariadbd for this test and shutdown it after the test'" diff --git a/mysql-test/main/delayed_blob.result b/mysql-test/main/delayed_blob.result new file mode 100644 index 00000000000..caa2e3ae5fe --- /dev/null +++ b/mysql-test/main/delayed_blob.result @@ -0,0 +1,17 @@ +# +# MDEV-25925 Warning: Memory not freed: 32 on INSERT DELAYED +# +SET sql_mode='TRADITIONAL'; +CREATE TABLE t1 (c BLOB) ENGINE=MyISAM; +INSERT DELAYED INTO t1 VALUES (''||''); +ERROR 22007: Truncated incorrect DOUBLE value: '' +DROP TABLE t1; +SET sql_mode=DEFAULT; +# +# MDEV-24467 Memory not freed after failed INSERT DELAYED +# +CREATE TABLE t1 (a VARCHAR(1)) ENGINE=MyISAM; +ALTER TABLE t1 ADD b BLOB DEFAULT 'x'; +INSERT DELAYED INTO t1 (a) VALUES ('foo'); +ERROR 22001: Data too long for column 'a' at row 1 +DROP TABLE t1; diff --git a/mysql-test/main/delayed_blob.test b/mysql-test/main/delayed_blob.test new file mode 100644 index 00000000000..bf3e01a8825 --- /dev/null +++ b/mysql-test/main/delayed_blob.test @@ -0,0 +1,21 @@ +--echo # +--echo # MDEV-25925 Warning: Memory not freed: 32 on INSERT DELAYED +--echo # + +SET sql_mode='TRADITIONAL'; +CREATE TABLE t1 (c BLOB) ENGINE=MyISAM; +--error ER_TRUNCATED_WRONG_VALUE +INSERT DELAYED INTO t1 VALUES (''||''); +DROP TABLE t1; +SET sql_mode=DEFAULT; + + +--echo # +--echo # MDEV-24467 Memory not freed after failed INSERT DELAYED +--echo # + +CREATE TABLE t1 (a VARCHAR(1)) ENGINE=MyISAM; +ALTER TABLE t1 ADD b BLOB DEFAULT 'x'; +--error ER_DATA_TOO_LONG +INSERT DELAYED INTO t1 (a) VALUES ('foo'); +DROP TABLE t1; diff --git a/mysql-test/main/func_str.result b/mysql-test/main/func_str.result index a1522c473d3..d50a77544f3 100644 --- a/mysql-test/main/func_str.result +++ b/mysql-test/main/func_str.result @@ -5014,6 +5014,18 @@ DROP TABLE t1; # End of 10.1 tests # # +# Start of 10.2 tests +# +# +# MDEV-24742 Server crashes in Charset::numchars / String::numchars +# +SELECT NULL IN (RIGHT(AES_ENCRYPT('foo','bar'), LAST_INSERT_ID()), 'qux'); +NULL IN (RIGHT(AES_ENCRYPT('foo','bar'), LAST_INSERT_ID()), 'qux') +NULL +# +# End of 10.2 tests +# +# # Start of 10.3 tests # # diff --git a/mysql-test/main/func_str.test b/mysql-test/main/func_str.test index efde77f21eb..6a9fbc71371 100644 --- a/mysql-test/main/func_str.test +++ b/mysql-test/main/func_str.test @@ -1988,6 +1988,22 @@ DROP TABLE t1; --echo # +--echo # Start of 10.2 tests +--echo # + +--echo # +--echo # MDEV-24742 Server crashes in Charset::numchars / String::numchars +--echo # + +SELECT NULL IN (RIGHT(AES_ENCRYPT('foo','bar'), LAST_INSERT_ID()), 'qux'); + + +--echo # +--echo # End of 10.2 tests +--echo # + + +--echo # --echo # Start of 10.3 tests --echo # diff --git a/mysql-test/main/invisible_field.result b/mysql-test/main/invisible_field.result index 9b42b043ec6..081c1ada1ee 100644 --- a/mysql-test/main/invisible_field.result +++ b/mysql-test/main/invisible_field.result @@ -538,7 +538,7 @@ a b insert into t2 values(1); select a,b from t2; a b -NULL 1 +12 1 drop table t1,t2; create table t1 (a int invisible, b int, c int); create table t2 (a int, b int, d int); @@ -627,3 +627,18 @@ drop table t1; create table t1 (a int, b int invisible); insert delayed into t1 values (1); drop table t1; +# +# MDEV-25891 Computed default for INVISIBLE column is ignored in INSERT +# +create table t1( +a int, +x int default (a), +y int default (a) invisible, +z int default (33) invisible); +insert into t1 values (1, default); +insert into t1 (a) values (2); +select a, x, y, z from t1; +a x y z +1 1 1 33 +2 2 2 33 +drop table t1; diff --git a/mysql-test/main/invisible_field.test b/mysql-test/main/invisible_field.test index 7a48347ec29..558ca7aa3a2 100644 --- a/mysql-test/main/invisible_field.test +++ b/mysql-test/main/invisible_field.test @@ -279,3 +279,16 @@ create table t1 (a int, b int invisible); insert delayed into t1 values (1); # cleanup drop table t1; + +--echo # +--echo # MDEV-25891 Computed default for INVISIBLE column is ignored in INSERT +--echo # +create table t1( + a int, + x int default (a), + y int default (a) invisible, + z int default (33) invisible); +insert into t1 values (1, default); +insert into t1 (a) values (2); +select a, x, y, z from t1; +drop table t1; diff --git a/mysql-test/main/multi_update.result b/mysql-test/main/multi_update.result index 4001a47ecd4..3ec9ea0caa5 100644 --- a/mysql-test/main/multi_update.result +++ b/mysql-test/main/multi_update.result @@ -1151,3 +1151,13 @@ b 1 3 drop tables t1, t2; +# +# MDEV-22464 Server crash on UPDATE with nested subquery +# +create table t1 (a int) ; +insert into t1 (a) values (1),(2),(3) ; +select a from t1 where a= (select 2 from t1 having (a = 3)); +ERROR 21000: Subquery returns more than 1 row +update t1 set a= (select 2 from t1 having (a = 3)); +ERROR 21000: Subquery returns more than 1 row +drop tables t1; diff --git a/mysql-test/main/multi_update.test b/mysql-test/main/multi_update.test index 84f06a7c165..3ee36f97fc5 100644 --- a/mysql-test/main/multi_update.test +++ b/mysql-test/main/multi_update.test @@ -1087,3 +1087,14 @@ update t1 left join t2 on a = b set b= 3 order by b; select * from t2; drop tables t1, t2; + +--echo # +--echo # MDEV-22464 Server crash on UPDATE with nested subquery +--echo # +create table t1 (a int) ; +insert into t1 (a) values (1),(2),(3) ; +--error ER_SUBQUERY_NO_1_ROW +select a from t1 where a= (select 2 from t1 having (a = 3)); +--error ER_SUBQUERY_NO_1_ROW +update t1 set a= (select 2 from t1 having (a = 3)); +drop tables t1; diff --git a/mysql-test/main/mysql_binary_zero_insert.result b/mysql-test/main/mysql_binary_zero_insert.result new file mode 100644 index 00000000000..0bed7487b3e --- /dev/null +++ b/mysql-test/main/mysql_binary_zero_insert.result @@ -0,0 +1,54 @@ +# Note: This test assumes NO_BACKSLASH_ESCAPES is not set in SQL_MODE. +############################## +# Setup +############################## +# +# Saving old state +# +set @old_sql_mode= @@global.SQL_MODE; +set @@global.SQL_MODE= ""; +# +# Create table for data entry +# +CREATE TABLE tb (`id` int(11) NOT NULL AUTO_INCREMENT,`cb` longblob DEFAULT NULL, PRIMARY KEY (`id`)) AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; +RESET MASTER; +############################## +# Test Case +############################## +# +# \0 (0x5c00 in binary) should be allowed in data strings if +# --binary-mode is enabled. +# +FOUND 10 /\x5c\x00/ in binary_zero_inserts.sql +# MYSQL --binary-mode test < MYSQL_TMP_DIR/binary_zero_inserts.sql +# +# Ensure a row exists from each insert statement with a \0 +# +SELECT COUNT(*)=8 from tb; +COUNT(*)=8 +1 +# +# Ensure that the binary zero was parsed and exists in the row data +# Note: We only look for 00 because the 5c only served as an escape +# in parsing. +# +# MYSQL_DUMP test tb --hex-blob | grep INSERT > MYSQL_TMP_DIR/dump.sql +FOUND 10 /00/ in dump.sql +# +# Ensure data consistency on mysqlbinlog replay +# +FLUSH LOGS; +# MYSQL_BINLOG MYSQLD_DATADIR/binlog_file > MYSQL_TMP_DIR/binlog_zeros.sql +FOUND 10 /\x5c\x00/ in binlog_zeros.sql +# MYSQL --binary-mode test < MYSQL_TMP_DIR/binlog_zeros.sql +# Table checksum is equivalent before and after binlog replay +# +# A \0 should still be treated as end-of-query in binary mode. +# +# MYSQL --binary-mode -B test < MYSQL_TMP_DIR/binary_zero_eoq.sql +############################## +# Cleanup +############################## +SET @@global.sql_mode= @old_sql_mode; +drop table tb; +RESET MASTER; diff --git a/mysql-test/main/mysql_binary_zero_insert.test b/mysql-test/main/mysql_binary_zero_insert.test new file mode 100644 index 00000000000..b327c8a4d1e --- /dev/null +++ b/mysql-test/main/mysql_binary_zero_insert.test @@ -0,0 +1,170 @@ +# +# Purpose: +# This test ensures that the mysql client is able to properly handle the +# binary data sequence 0x5c00, i.e. the null-terminating character \0, in a +# string when --binary-mode is enabled. Specifically, this sequence is valid to +# appear anywhere within a binary data string, and it should not end the string +# or SQL command. Additionally, \0 outside of a string should still end the +# query. +# +# Methodology: +# This test initially inserts data with binary strings containing \0. To +# ensure the mysql client is able to process this data correctly, perl is used +# to create a SQL file that contains \0 in strings, and this file is used as +# input into the client. The row data is then validated by searching for binary +# zeros in mysqldump output. +# +# +# References: +# MDEV-25444: mysql --binary-mode is not able to replay some mysqlbinlog +# outputs + +--echo # Note: This test assumes NO_BACKSLASH_ESCAPES is not set in SQL_MODE. + +--source include/have_log_bin.inc + +--echo ############################## +--echo # Setup +--echo ############################## + +--echo # +--echo # Saving old state +--echo # +set @old_sql_mode= @@global.SQL_MODE; +set @@global.SQL_MODE= ""; + +--echo # +--echo # Create table for data entry +--echo # +CREATE TABLE tb (`id` int(11) NOT NULL AUTO_INCREMENT,`cb` longblob DEFAULT NULL, PRIMARY KEY (`id`)) AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; + +# Will replay binlog later and we don't want to recreate the table +RESET MASTER; + + +--echo ############################## +--echo # Test Case +--echo ############################## + +--echo # +--echo # \0 (0x5c00 in binary) should be allowed in data strings if +--echo # --binary-mode is enabled. +--echo # +--perl + my $dir= $ENV{'MYSQL_TMP_DIR'}; + open (my $FILE, '>', "$dir/binary_zero_inserts.sql") or die "open(): $!"; + + print $FILE "TRUNCATE TABLE tb;\n"; + + # INSERT INTO tb(cb) VALUES(_binary '\0'); + print $FILE "INSERT INTO tb(cb) VALUES (_binary '"; + print $FILE pack "H*","5c00"; + print $FILE "');\n"; + + # INSERT INTO tb(cb) VALUES(_binary '\0A'); + print $FILE "INSERT INTO tb(cb) VALUES (_binary '"; + print $FILE pack "H*","5c0041"; + print $FILE "');\n"; + + # INSERT INTO tb(cb) VALUES(_binary 'A\0'); + print $FILE "INSERT INTO tb(cb) VALUES (_binary '"; + print $FILE pack "H*","415c00"; + print $FILE "');\n"; + + # INSERT INTO tb(cb) VALUES(_binary 'A\0B'); + print $FILE "INSERT INTO tb(cb) VALUES (_binary '"; + print $FILE pack "H*","415c0042"; + print $FILE "');\n"; + + # INSERT INTO tb(cb) VALUES(_binary '\0A\0'); + print $FILE "INSERT INTO tb(cb) VALUES (_binary '"; + print $FILE pack "H*","5c00415c00"; + print $FILE "');\n"; + + # INSERT INTO tb(cb) VALUES(_binary '\\\0'); + print $FILE "INSERT INTO tb(cb) VALUES (_binary '"; + print $FILE pack "H*","5c5c5c00"; + print $FILE "');\n"; + + # INSERT INTO tb(cb) VALUES(_binary '\0\0'); + print $FILE "INSERT INTO tb(cb) VALUES (_binary '"; + print $FILE pack "H*","5c005c00"; + print $FILE "');\n"; + + # INSERT INTO tb(cb) VALUES(_binary '\\0'); + print $FILE "INSERT INTO tb(cb) VALUES (_binary '"; + print $FILE pack "H*","5c5c00"; + print $FILE "');\n"; + + close ($FILE); +EOF +--let SEARCH_PATTERN= \x5c\x00 +--let SEARCH_FILE= $MYSQL_TMP_DIR/binary_zero_inserts.sql +--source include/search_pattern_in_file.inc +--echo # MYSQL --binary-mode test < MYSQL_TMP_DIR/binary_zero_inserts.sql +--exec $MYSQL --binary-mode test < $MYSQL_TMP_DIR/binary_zero_inserts.sql + +--echo # +--echo # Ensure a row exists from each insert statement with a \0 +--echo # +SELECT COUNT(*)=8 from tb; + +--echo # +--echo # Ensure that the binary zero was parsed and exists in the row data +--echo # Note: We only look for 00 because the 5c only served as an escape +--echo # in parsing. +--echo # +--echo # MYSQL_DUMP test tb --hex-blob | grep INSERT > MYSQL_TMP_DIR/dump.sql +--exec $MYSQL_DUMP test tb --hex-blob | grep INSERT > $MYSQL_TMP_DIR/dump.sql +--let SEARCH_PATTERN= 00 +--let SEARCH_FILE= $MYSQL_TMP_DIR/dump.sql +--source include/search_pattern_in_file.inc + +--echo # +--echo # Ensure data consistency on mysqlbinlog replay +--echo # +--let $good_checksum= `CHECKSUM TABLE tb` +let $MYSQLD_DATADIR= `SELECT @@datadir`; +let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); +FLUSH LOGS; +--echo # MYSQL_BINLOG MYSQLD_DATADIR/binlog_file > MYSQL_TMP_DIR/binlog_zeros.sql +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/$binlog_file > $MYSQL_TMP_DIR/binlog_zeros.sql +--let SEARCH_PATTERN= \x5c\x00 +--let SEARCH_FILE= $MYSQL_TMP_DIR/binlog_zeros.sql +--source include/search_pattern_in_file.inc +--echo # MYSQL --binary-mode test < MYSQL_TMP_DIR/binlog_zeros.sql +--exec $MYSQL --binary-mode test < $MYSQL_TMP_DIR/binlog_zeros.sql +if ($good_checksum != `CHECKSUM TABLE tb`) +{ + die "Blob with binary zero data changed after binary log replay"; +} +--echo # Table checksum is equivalent before and after binlog replay + +--echo # +--echo # A \0 should still be treated as end-of-query in binary mode. +--echo # +--perl + my $dir= $ENV{'MYSQL_TMP_DIR'}; + open (my $FILE, '>', "$dir/binary_zero_eoq.sql") or die "open(): $!"; + + # INSERT INTO tb(cb) VALUES(_binary 'text')\0 + print $FILE "INSERT INTO tb(cb) VALUES (_binary 'text')"; + print $FILE pack "H*","5c00"; + + close ($FILE); +EOF +--echo # MYSQL --binary-mode -B test < MYSQL_TMP_DIR/binary_zero_eoq.sql +--exec $MYSQL --binary-mode -B test < $MYSQL_TMP_DIR/binary_zero_eoq.sql + + +--echo ############################## +--echo # Cleanup +--echo ############################## + +--remove_file $MYSQL_TMP_DIR/binary_zero_inserts.sql +--remove_file $MYSQL_TMP_DIR/binary_zero_eoq.sql +--remove_file $MYSQL_TMP_DIR/binlog_zeros.sql +--remove_file $MYSQL_TMP_DIR/dump.sql +SET @@global.sql_mode= @old_sql_mode; +drop table tb; +RESET MASTER; diff --git a/mysql-test/suite/innodb/r/mdev-14846.result b/mysql-test/suite/innodb/r/mdev-14846.result new file mode 100644 index 00000000000..219bd718feb --- /dev/null +++ b/mysql-test/suite/innodb/r/mdev-14846.result @@ -0,0 +1,52 @@ +CREATE TABLE t1 ( +pk INT, +f1 VARCHAR(10) NOT NULL, +f2 VARCHAR(10) NULL, +f3 INT UNSIGNED NULL, +KEY (f1), +PRIMARY KEY (pk) +) ENGINE=InnoDB; +CREATE OR REPLACE ALGORITHM=MERGE VIEW v4 AS SELECT * FROM t1; +INSERT INTO t1 VALUES (1,'k','g',6),(2,'y','r',0),(3,'t','q',1),(4,'a','r',NULL),(5,'z','t',NULL); +CREATE TABLE t2 (f VARCHAR(10) NULL) ENGINE=InnoDB; +INSERT INTO t2 VALUES (NULL),('g'),('e'),('g'); +CREATE TABLE t3 ( +f1 VARCHAR(10) NOT NULL, +f2 VARCHAR(10) NULL, +f3 INT UNSIGNED NULL +) ENGINE=InnoDB; +INSERT INTO t3 VALUES ('k','n',9),('y','b',8),('m','w',6); +CREATE TABLE t4 (f INT NULL) ENGINE=InnoDB; +INSERT INTO t4 VALUES (8),(9); +UPDATE t1 SET t1.pk = -109 WHERE t1.f1 IN ( SELECT 'a' FROM t4 WHERE f >= 1 ); +SET DEBUG_SYNC='now SIGNAL con1_dml'; +connect con1,localhost,root,,test; +SET DEBUG_SYNC='now WAIT_FOR con1_dml'; +begin; +SELECT * FROM t1 for update; +pk f1 f2 f3 +-109 a r NULL +1 k g 6 +2 y r 0 +3 t q 1 +5 z t NULL +SET DEBUG_SYNC='now SIGNAL default_dml'; +connection default; +SET DEBUG_SYNC='now WAIT_FOR default_dml'; +UPDATE t3 AS alias1 LEFT JOIN t3 AS alias2 ON ( alias1.f1 <> alias1.f2 ) SET alias1.f3 = 59 WHERE ( EXISTS ( SELECT t1.f3 FROM t1 WHERE t1.f1 = alias1.f1 ) ) OR alias2.f1 = 'h'; +connect con2,localhost,root,,test; +set debug_sync='now WAIT_FOR default_dml'; +SET DEBUG_SYNC='now SIGNAL con1_dml2'; +disconnect con2; +connection con1; +SET DEBUG_SYNC='now WAIT_FOR con1_dml2'; +UPDATE v4, t1 SET t1.pk = 76 WHERE t1.f2 IN ( SELECT t2.f FROM t2 INNER JOIN t3 ); +connection default; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +connection con1; +COMMIT; +disconnect con1; +connection default; +DROP VIEW v4; +DROP TABLE t1, t2, t3, t4; +set debug_sync= reset; diff --git a/mysql-test/suite/innodb/t/mdev-14846.opt b/mysql-test/suite/innodb/t/mdev-14846.opt new file mode 100644 index 00000000000..c8fe0561390 --- /dev/null +++ b/mysql-test/suite/innodb/t/mdev-14846.opt @@ -0,0 +1 @@ +--loose-innodb_lock_waits diff --git a/mysql-test/suite/innodb/t/mdev-14846.test b/mysql-test/suite/innodb/t/mdev-14846.test new file mode 100644 index 00000000000..adcefecd52f --- /dev/null +++ b/mysql-test/suite/innodb/t/mdev-14846.test @@ -0,0 +1,70 @@ +--source include/have_innodb.inc +--source include/count_sessions.inc +--source include/have_debug_sync.inc + +CREATE TABLE t1 ( + pk INT, + f1 VARCHAR(10) NOT NULL, + f2 VARCHAR(10) NULL, + f3 INT UNSIGNED NULL, + KEY (f1), + PRIMARY KEY (pk) +) ENGINE=InnoDB; + +CREATE OR REPLACE ALGORITHM=MERGE VIEW v4 AS SELECT * FROM t1; +INSERT INTO t1 VALUES (1,'k','g',6),(2,'y','r',0),(3,'t','q',1),(4,'a','r',NULL),(5,'z','t',NULL); + +CREATE TABLE t2 (f VARCHAR(10) NULL) ENGINE=InnoDB; +INSERT INTO t2 VALUES (NULL),('g'),('e'),('g'); + +CREATE TABLE t3 ( + f1 VARCHAR(10) NOT NULL, + f2 VARCHAR(10) NULL, + f3 INT UNSIGNED NULL +) ENGINE=InnoDB; + +INSERT INTO t3 VALUES ('k','n',9),('y','b',8),('m','w',6); + +CREATE TABLE t4 (f INT NULL) ENGINE=InnoDB; +INSERT INTO t4 VALUES (8),(9); +UPDATE t1 SET t1.pk = -109 WHERE t1.f1 IN ( SELECT 'a' FROM t4 WHERE f >= 1 ); +SET DEBUG_SYNC='now SIGNAL con1_dml'; + +--connect (con1,localhost,root,,test) +SET DEBUG_SYNC='now WAIT_FOR con1_dml'; +begin; +SELECT * FROM t1 for update; # Holds x lock of all records in the table t1 +SET DEBUG_SYNC='now SIGNAL default_dml'; + +--connection default +SET DEBUG_SYNC='now WAIT_FOR default_dml'; +--send UPDATE t3 AS alias1 LEFT JOIN t3 AS alias2 ON ( alias1.f1 <> alias1.f2 ) SET alias1.f3 = 59 WHERE ( EXISTS ( SELECT t1.f3 FROM t1 WHERE t1.f1 = alias1.f1 ) ) OR alias2.f1 = 'h' +# It holds the lock of all record in t3 and tries to acquire record lock for the table t1. + +--connect (con2,localhost,root,,test) +set debug_sync='now WAIT_FOR default_dml'; +let $wait_condition= +select count(*) > 0 from information_schema.innodb_lock_waits; +--source include/wait_condition.inc +SET DEBUG_SYNC='now SIGNAL con1_dml2'; +disconnect con2; + +# Cleanup +--connection con1 +SET DEBUG_SYNC='now WAIT_FOR con1_dml2'; +UPDATE v4, t1 SET t1.pk = 76 WHERE t1.f2 IN ( SELECT t2.f FROM t2 INNER JOIN t3 ); +# It holds the record lock on table t1 and tries to acquire record lock on t3. +# leads to deadlock (con1 trx is waiting for default trx and vice versa) + +--connection default +--error ER_LOCK_DEADLOCK +--reap + +connection con1; +COMMIT; +disconnect con1; + +--connection default +DROP VIEW v4; +DROP TABLE t1, t2, t3, t4; +set debug_sync= reset; diff --git a/mysql-test/suite/plugins/r/feedback_plugin_send.result b/mysql-test/suite/plugins/r/feedback_plugin_send.result index 5a48c703ec4..69046e16dd9 100644 --- a/mysql-test/suite/plugins/r/feedback_plugin_send.result +++ b/mysql-test/suite/plugins/r/feedback_plugin_send.result @@ -24,7 +24,23 @@ VARIABLE_VALUE>0 VARIABLE_NAME 1 Collation used utf8mb4_bin 1 Collation used utf8_bin 1 Collation used utf8_general_ci +prepare stmt from "SELECT VARIABLE_VALUE>0, VARIABLE_NAME FROM INFORMATION_SCHEMA.FEEDBACK WHERE VARIABLE_NAME LIKE 'Collation used %' ORDER BY VARIABLE_NAME"; +execute stmt; +VARIABLE_VALUE>0 VARIABLE_NAME +1 Collation used binary +1 Collation used latin1_swedish_ci +1 Collation used utf8mb4_bin +1 Collation used utf8_bin +1 Collation used utf8_general_ci +execute stmt; +VARIABLE_VALUE>0 VARIABLE_NAME +1 Collation used binary +1 Collation used latin1_swedish_ci +1 Collation used utf8mb4_bin +1 Collation used utf8_bin +1 Collation used utf8_general_ci +deallocate prepare stmt; set global sql_mode=ONLY_FULL_GROUP_BY; # restart -6: feedback plugin: report to 'http://mariadb.org/feedback_plugin/post' was sent -6: feedback plugin: server replied 'ok' +feedback plugin: report to 'http://mariadb.org/feedback_plugin/post' was sent +feedback plugin: server replied 'ok' diff --git a/mysql-test/suite/plugins/t/feedback_plugin_send.test b/mysql-test/suite/plugins/t/feedback_plugin_send.test index b28f9d4cb38..0ea1814ec29 100644 --- a/mysql-test/suite/plugins/t/feedback_plugin_send.test +++ b/mysql-test/suite/plugins/t/feedback_plugin_send.test @@ -38,6 +38,6 @@ perl; while ($_=<LOG>) { $logg{$&}++ if /feedback plugin:.*/; } - print "$logg{$_}: $_\n" for sort keys %logg; + print "$_\n" for sort keys %logg; close LOG; EOF diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index b2dbbba7027..c3feab166c9 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -762,3 +762,22 @@ delete from t1; set system_versioning_alter_history= keep; alter ignore table t1 drop pk; drop table t1; +# +# MDEV-22660 SIGSEGV on adding system versioning and modifying system column +# +create or replace table t1 (a int); +alter table t1 +add row_start timestamp(6) as row start, +add row_end timestamp(6) as row end, +add period for system_time(row_start, row_end), +with system versioning, +modify row_end varchar(8); +ERROR HY000: PERIOD FOR SYSTEM_TIME must use columns `row_start` and `row_end` +alter table t1 +add row_start timestamp(6) as row start, +add row_end timestamp(6) as row end, +add period for system_time(row_start, row_end), +with system versioning, +modify row_start varchar(8); +ERROR HY000: PERIOD FOR SYSTEM_TIME must use columns `row_start` and `row_end` +drop table t1; diff --git a/mysql-test/suite/versioning/t/alter.test b/mysql-test/suite/versioning/t/alter.test index 16f391b1454..f826ba470f1 100644 --- a/mysql-test/suite/versioning/t/alter.test +++ b/mysql-test/suite/versioning/t/alter.test @@ -653,3 +653,25 @@ set system_versioning_alter_history= keep; alter ignore table t1 drop pk; # cleanup drop table t1; + + +--echo # +--echo # MDEV-22660 SIGSEGV on adding system versioning and modifying system column +--echo # +create or replace table t1 (a int); +--error ER_VERS_PERIOD_COLUMNS +alter table t1 + add row_start timestamp(6) as row start, + add row_end timestamp(6) as row end, + add period for system_time(row_start, row_end), + with system versioning, + modify row_end varchar(8); +--error ER_VERS_PERIOD_COLUMNS +alter table t1 + add row_start timestamp(6) as row start, + add row_end timestamp(6) as row end, + add period for system_time(row_start, row_end), + with system versioning, + modify row_start varchar(8); +# cleanup +drop table t1; diff --git a/mysys/my_context.c b/mysys/my_context.c index 5423f59d19b..4153927d335 100644 --- a/mysys/my_context.c +++ b/mysys/my_context.c @@ -29,6 +29,10 @@ #endif #ifdef MY_CONTEXT_USE_UCONTEXT +#ifdef __APPLE__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif /* The makecontext() only allows to pass integers into the created context :-( We want to pass pointers, so we do it this kinda hackish way. @@ -154,6 +158,9 @@ my_context_destroy(struct my_context *c) DBUG_FREE_CODE_STATE(&c->dbug_state); } +#ifdef __APPLE__ +#pragma GCC diagnostic pop +#endif #endif /* MY_CONTEXT_USE_UCONTEXT */ diff --git a/sql/field.cc b/sql/field.cc index 8b82077f452..2226137b043 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2394,7 +2394,7 @@ Field *Field::make_new_field(MEM_ROOT *root, TABLE *new_table, tmp->unireg_check= Field::NONE; tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG | ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG | - VERS_SYS_START_FLAG | VERS_SYS_END_FLAG | + VERS_ROW_START | VERS_ROW_END | VERS_UPDATE_UNVERSIONED_FLAG); tmp->reset_fields(); tmp->invisible= VISIBLE; diff --git a/sql/field.h b/sql/field.h index 5c2ba4c5c84..a51f279e59b 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1600,7 +1600,7 @@ public: bool vers_sys_field() const { - return flags & (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG); + return flags & (VERS_ROW_START | VERS_ROW_END); } bool vers_update_unversioned() const @@ -4805,7 +4805,7 @@ public: } bool vers_sys_field() const { - return flags & (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG); + return flags & (VERS_ROW_START | VERS_ROW_END); } void create_length_to_internal_length_bit(); void create_length_to_internal_length_newdecimal(); @@ -5175,6 +5175,15 @@ public: } /* Used to make a clone of this object for ALTER/CREATE TABLE */ Create_field *clone(MEM_ROOT *mem_root) const; + + bool is_some_bigint() const + { + return type_handler() == &type_handler_longlong || + type_handler() == &type_handler_vers_trx_id; + } + + bool vers_check_timestamp(const Lex_table_name &table_name) const; + bool vers_check_bigint(const Lex_table_name &table_name) const; }; diff --git a/sql/handler.cc b/sql/handler.cc index 757fa95a9a3..4e891f5d640 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -7438,11 +7438,11 @@ bool Vers_parse_info::is_end(const char *name) const } bool Vers_parse_info::is_start(const Create_field &f) const { - return f.flags & VERS_SYS_START_FLAG; + return f.flags & VERS_ROW_START; } bool Vers_parse_info::is_end(const Create_field &f) const { - return f.flags & VERS_SYS_END_FLAG; + return f.flags & VERS_ROW_END; } static Create_field *vers_init_sys_field(THD *thd, const char *field_name, int flags, bool integer) @@ -7502,8 +7502,8 @@ bool Vers_parse_info::fix_implicit(THD *thd, Alter_info *alter_info) period= start_end_t(default_start, default_end); as_row= period; - if (vers_create_sys_field(thd, default_start, alter_info, VERS_SYS_START_FLAG) || - vers_create_sys_field(thd, default_end, alter_info, VERS_SYS_END_FLAG)) + if (vers_create_sys_field(thd, default_start, alter_info, VERS_ROW_START) || + vers_create_sys_field(thd, default_end, alter_info, VERS_ROW_END)) { return true; } @@ -7662,7 +7662,7 @@ bool Vers_parse_info::fix_alter_info(THD *thd, Alter_info *alter_info, return true; } my_error(ER_VERS_DUPLICATE_ROW_START_END, MYF(0), - f->flags & VERS_SYS_START_FLAG ? "START" : "END", f->field_name.str); + f->flags & VERS_ROW_START ? "START" : "END", f->field_name.str); return true; } } @@ -7767,13 +7767,13 @@ Vers_parse_info::fix_create_like(Alter_info &alter_info, HA_CREATE_INFO &create_ while ((f= it++)) { - if (f->flags & VERS_SYS_START_FLAG) + if (f->flags & VERS_ROW_START) { f_start= f; if (f_end) break; } - else if (f->flags & VERS_SYS_END_FLAG) + else if (f->flags & VERS_ROW_END) { f_end= f; if (f_start) @@ -7835,37 +7835,31 @@ bool Vers_parse_info::check_conditions(const Lex_table_name &table_name, return false; } -static bool is_versioning_timestamp(const Create_field *f) -{ - return f->type_handler() == &type_handler_timestamp2 && - f->length == MAX_DATETIME_FULL_WIDTH; -} -static bool is_some_bigint(const Create_field *f) +bool Create_field::vers_check_timestamp(const Lex_table_name &table_name) const { - return f->type_handler() == &type_handler_longlong || - f->type_handler() == &type_handler_vers_trx_id; -} - -static bool is_versioning_bigint(const Create_field *f) -{ - return is_some_bigint(f) && f->flags & UNSIGNED_FLAG && - f->length == MY_INT64_NUM_DECIMAL_DIGITS - 1; -} + if (type_handler() == &type_handler_timestamp2 && + length == MAX_DATETIME_FULL_WIDTH) + return false; -static bool require_timestamp(const Create_field *f, Lex_table_name table_name) -{ - my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), f->field_name.str, "TIMESTAMP(6)", + my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), field_name.str, "TIMESTAMP(6)", table_name.str); return true; } -static bool require_bigint(const Create_field *f, Lex_table_name table_name) + + +bool Create_field::vers_check_bigint(const Lex_table_name &table_name) const { - my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), f->field_name.str, + if (is_some_bigint() && flags & UNSIGNED_FLAG && + length == MY_INT64_NUM_DECIMAL_DIGITS - 1) + return false; + + my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), field_name.str, "BIGINT(20) UNSIGNED", table_name.str); return true; } + bool Vers_parse_info::check_sys_fields(const Lex_table_name &table_name, const Lex_table_name &db, Alter_info *alter_info, @@ -7880,37 +7874,37 @@ bool Vers_parse_info::check_sys_fields(const Lex_table_name &table_name, List_iterator<Create_field> it(alter_info->create_list); while (Create_field *f= it++) { - if (!row_start && f->flags & VERS_SYS_START_FLAG) + if (!row_start && f->flags & VERS_ROW_START) row_start= f; - else if (!row_end && f->flags & VERS_SYS_END_FLAG) + else if (!row_end && f->flags & VERS_ROW_END) row_end= f; } - const bool expect_timestamp= - !can_native || !is_some_bigint(row_start) || !is_some_bigint(row_end); - - if (expect_timestamp) + if (!row_start || !row_end) { - if (!is_versioning_timestamp(row_start)) - return require_timestamp(row_start, table_name); + my_error(ER_VERS_PERIOD_COLUMNS, MYF(0), as_row.start.str, as_row.end.str); + return true; + } - if (!is_versioning_timestamp(row_end)) - return require_timestamp(row_end, table_name); + if (!can_native || + !row_start->is_some_bigint() || + !row_end->is_some_bigint()) + { + if (row_start->vers_check_timestamp(table_name) || + row_end->vers_check_timestamp(table_name)) + return true; } else { - if (!is_versioning_bigint(row_start)) - return require_bigint(row_start, table_name); - - if (!is_versioning_bigint(row_end)) - return require_bigint(row_end, table_name); - } + if (row_start->vers_check_bigint(table_name) || + row_end->vers_check_bigint(table_name)) + return true; - if (is_versioning_bigint(row_start) && is_versioning_bigint(row_end) && - !TR_table::use_transaction_registry) - { - my_error(ER_VERS_TRT_IS_DISABLED, MYF(0)); - return true; + if (!TR_table::use_transaction_registry) + { + my_error(ER_VERS_TRT_IS_DISABLED, MYF(0)); + return true; + } } return false; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 4f62452aa5a..4e9d9df0990 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -359,6 +359,8 @@ String *Item_aes_crypt::val_str(String *str2) rkey, AES_KEY_LENGTH / 8, 0, 0)) { str2->length((uint) aes_length); + DBUG_ASSERT(collation.collation == &my_charset_bin); + str2->set_charset(&my_charset_bin); return str2; } } diff --git a/sql/item_vers.cc b/sql/item_vers.cc index 792c434b8c3..9a594533628 100644 --- a/sql/item_vers.cc +++ b/sql/item_vers.cc @@ -30,7 +30,7 @@ bool Item_func_history::val_bool() { Item_field *f= static_cast<Item_field *>(args[0]); DBUG_ASSERT(f->fixed); - DBUG_ASSERT(f->field->flags & VERS_SYS_END_FLAG); + DBUG_ASSERT(f->field->flags & VERS_ROW_END); return !f->field->is_max(); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index ba1d477882f..ec77366129a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -8832,7 +8832,9 @@ static int get_options(int *argc_ptr, char ***argv_ptr) if (global_system_variables.low_priority_updates) thr_upgraded_concurrent_insert_lock= TL_WRITE_LOW_PRIORITY; - if (ft_boolean_check_syntax_string((uchar*) ft_boolean_syntax)) + if (ft_boolean_check_syntax_string((uchar*) ft_boolean_syntax, + strlen(ft_boolean_syntax), + system_charset_info)) { sql_print_error("Invalid ft-boolean-syntax string: %s", ft_boolean_syntax); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 88cb16e3e7d..5132b0e2e85 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8869,6 +8869,8 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values, if (!thd->is_error()) { thd->abort_on_warning= FALSE; + if (table->default_field && table->update_default_fields(ignore_errors)) + goto err; if (table->versioned()) table->vers_update_fields(); if (table->vfield && diff --git a/sql/sql_explain.h b/sql/sql_explain.h index ce3f3ef06e1..6575511bd52 100644 --- a/sql/sql_explain.h +++ b/sql/sql_explain.h @@ -121,11 +121,13 @@ public: */ enum explain_connection_type connection_type; +protected: /* A node may have children nodes. When a node's explain structure is created, children nodes may not yet have QPFs. This is why we store ids. */ Dynamic_array<int> children; +public: void add_child(int select_no) { children.append(select_no); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f34632b3df8..4bf15bfbb9b 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1288,7 +1288,18 @@ values_loop_end: abort: #ifndef EMBEDDED_LIBRARY if (lock_type == TL_WRITE_DELAYED) + { end_delayed_insert(thd); + /* + In case of an error (e.g. data truncation), the data type specific data + in fields (e.g. Field_blob::value) was not taken over + by the delayed writer thread. All fields in table_list->table + will be freed by free_root() soon. We need to free the specific + data before free_root() to avoid a memory leak. + */ + for (Field **ptr= table_list->table->field ; *ptr ; ptr++) + (*ptr)->free(); + } #endif if (table != NULL) table->file->ha_release_auto_increment(); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index c6db441220e..93002677fbd 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -8924,7 +8924,7 @@ bool LEX::last_field_generated_always_as_row_start() Vers_parse_info &info= vers_get_info(); Lex_ident *p= &info.as_row.start; return last_field_generated_always_as_row_start_or_end(p, "START", - VERS_SYS_START_FLAG); + VERS_ROW_START); } @@ -8933,7 +8933,7 @@ bool LEX::last_field_generated_always_as_row_end() Vers_parse_info &info= vers_get_info(); Lex_ident *p= &info.as_row.end; return last_field_generated_always_as_row_start_or_end(p, "END", - VERS_SYS_END_FLAG); + VERS_ROW_END); } void st_select_lex_unit::reset_distinct() diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1eb0a492ecd..2010260eaf6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4663,7 +4663,8 @@ mysql_select(THD *thd, bool free_join= 1; DBUG_ENTER("mysql_select"); - select_lex->context.resolve_in_select_list= TRUE; + if (!fields.is_empty()) + select_lex->context.resolve_in_select_list= true; JOIN *join; if (select_lex->join != 0) { @@ -20737,26 +20738,33 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, will be re-evaluated again. It could be fixed, but, probably, it's not worth doing now. */ - if (tab->select_cond && !tab->select_cond->val_int()) + if (tab->select_cond) { - /* The condition attached to table tab is false */ - if (tab == join_tab) - { - found= 0; - if (not_exists_opt_is_applicable) - DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS); - } - else + const longlong res= tab->select_cond->val_int(); + if (join->thd->is_error()) + DBUG_RETURN(NESTED_LOOP_ERROR); + + if (!res) { - /* - Set a return point if rejected predicate is attached - not to the last table of the current nest level. - */ - join->return_tab= tab; - if (not_exists_opt_is_applicable) - DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS); + /* The condition attached to table tab is false */ + if (tab == join_tab) + { + found= 0; + if (not_exists_opt_is_applicable) + DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS); + } else - DBUG_RETURN(NESTED_LOOP_OK); + { + /* + Set a return point if rejected predicate is attached + not to the last table of the current nest level. + */ + join->return_tab= tab; + if (not_exists_opt_is_applicable) + DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS); + else + DBUG_RETURN(NESTED_LOOP_OK); + } } } } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 31fb2f6a654..40efe1ec550 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2302,11 +2302,11 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, } else { - if (field->flags & VERS_SYS_START_FLAG) + if (field->flags & VERS_ROW_START) { packet->append(STRING_WITH_LEN(" GENERATED ALWAYS AS ROW START")); } - else if (field->flags & VERS_SYS_END_FLAG) + else if (field->flags & VERS_ROW_END) { packet->append(STRING_WITH_LEN(" GENERATED ALWAYS AS ROW END")); } @@ -6119,7 +6119,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, } else if (field->flags & VERS_SYSTEM_FIELD) { - if (field->flags & VERS_SYS_START_FLAG) + if (field->flags & VERS_ROW_START) { table->field[21]->store(STRING_WITH_LEN("ROW START"), cs); buf.set(STRING_WITH_LEN("STORED GENERATED"), cs); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index dbe5ac15172..12e09e7bcb2 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -8280,7 +8280,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, def= new (thd->mem_root) Create_field(thd, field, field); def->invisible= INVISIBLE_SYSTEM; alter_info->flags|= ALTER_CHANGE_COLUMN; - if (field->flags & VERS_SYS_START_FLAG) + if (field->flags & VERS_ROW_START) create_info->vers_info.as_row.start= def->field_name= Vers_parse_info::default_start; else create_info->vers_info.as_row.end= def->field_name= Vers_parse_info::default_end; @@ -8321,9 +8321,9 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, !vers_system_invisible) { StringBuffer<NAME_LEN*3> tmp; - if (!(dropped_sys_vers_fields & VERS_SYS_START_FLAG)) + if (!(dropped_sys_vers_fields & VERS_ROW_START)) append_drop_column(thd, &tmp, table->vers_start_field()); - if (!(dropped_sys_vers_fields & VERS_SYS_END_FLAG)) + if (!(dropped_sys_vers_fields & VERS_ROW_END)) append_drop_column(thd, &tmp, table->vers_end_field()); my_error(ER_MISSING, MYF(0), table->s->table_name.str, tmp.c_ptr()); goto err; diff --git a/sql/sql_type.cc b/sql/sql_type.cc index c349a433075..e0a6169df3d 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -7776,7 +7776,7 @@ Field *Type_handler_longlong:: const Column_definition_attributes *attr, uint32 flags) const { - if (flags & (VERS_SYS_START_FLAG|VERS_SYS_END_FLAG)) + if (flags & (VERS_ROW_START|VERS_ROW_END)) return new (mem_root) Field_vers_trx_id(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(), diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 14d45d951eb..53a978794f2 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1105,7 +1105,9 @@ static Sys_var_ulong Sys_flush_time( static bool check_ftb_syntax(sys_var *self, THD *thd, set_var *var) { return ft_boolean_check_syntax_string((uchar*) - (var->save_result.string_value.str)); + (var->save_result.string_value.str), + var->save_result.string_value.length, + self->charset(thd)); } static bool query_cache_flush(sys_var *self, THD *thd, enum_var_type type) { diff --git a/sql/table.cc b/sql/table.cc index 421a728c648..e24309fdd70 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1299,7 +1299,10 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table, if (check_vcol_forward_refs(field, field->vcol_info, 0) || check_vcol_forward_refs(field, field->check_constraint, 1) || check_vcol_forward_refs(field, field->default_value, 0)) + { + *error_reported= true; goto end; + } } table->find_constraint_correlated_indexes(); @@ -2359,9 +2362,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (versioned) { if (i == vers.start_fieldno) - flags|= VERS_SYS_START_FLAG; + flags|= VERS_ROW_START; else if (i == vers.end_fieldno) - flags|= VERS_SYS_END_FLAG; + flags|= VERS_ROW_END; if (flags & VERS_SYSTEM_FIELD) { diff --git a/storage/connect/bsonudf.cpp b/storage/connect/bsonudf.cpp index 0c7112ee15f..771e72b8dbd 100644 --- a/storage/connect/bsonudf.cpp +++ b/storage/connect/bsonudf.cpp @@ -12,6 +12,7 @@ #include <mysql.h> #include <sql_error.h> #include <stdio.h> +#include <cassert> #include "bsonudf.h" @@ -621,7 +622,7 @@ PVAL BJNX::GetCalcValue(PGLOBAL g, PBVAL bap, int n) { // For calculated arrays, a local Value must be used int lng = 0; - short type, prec = 0; + short type = 0, prec = 0; bool b = n < Nod - 1; PVAL valp; PBVAL vlp, vp; @@ -690,7 +691,7 @@ PVAL BJNX::GetCalcValue(PGLOBAL g, PBVAL bap, int n) break; default: - break; + DBUG_ASSERT(!"Implement new op type support."); } // endswitch Op return valp = AllocateValue(g, type, lng, prec); @@ -4978,7 +4979,7 @@ char *bbin_array_add(UDF_INIT *initid, UDF_ARGS *args, char *result, uint n = 2; int* x = GetIntArgPtr(g, args, n); BJNX bnx(g, NULL, TYPE_STRING); - PBVAL jarp, top, jvp = NULL; + PBVAL jarp = NULL, top = NULL, jvp = NULL; PBVAL jsp = bnx.MakeValue(args, 0, true, &top); if (bnx.CheckPath(g, args, jsp, jvp, 2)) @@ -5611,7 +5612,7 @@ char *bbin_object_values(UDF_INIT *initid, UDF_ARGS *args, char *result, if (!bsp) { if (!CheckMemory(g, initid, args, 1, true, true)) { BJNX bnx(g); - PBVAL top, jarp; + PBVAL top, jarp = NULL; PBVAL jvp = bnx.MakeValue(args, 0, true, &top); if (jvp->Type == TYPE_JOB) { diff --git a/storage/connect/inihandl.cpp b/storage/connect/inihandl.cpp index 9270e18721c..de04fa91883 100644 --- a/storage/connect/inihandl.cpp +++ b/storage/connect/inihandl.cpp @@ -193,7 +193,7 @@ static void PROFILE_Save( FILE *file, PROFILESECTION *section ) secno++; } - for (key = section->key; key; key = key->next) + for (key = section->key; key; key = key->next) { if (key->name[0]) { fprintf(file, "%s", SVP(key->name)); @@ -201,9 +201,9 @@ static void PROFILE_Save( FILE *file, PROFILESECTION *section ) fprintf(file, "=%s", SVP(key->value)); fprintf(file, "\n"); - } // endif key->name - - } // endfor section + } // endif key->name + } + } // endfor section } // end of PROFILE_Save diff --git a/storage/connect/tabbson.cpp b/storage/connect/tabbson.cpp index 3b1f1c84d1a..a7c561318c7 100644 --- a/storage/connect/tabbson.cpp +++ b/storage/connect/tabbson.cpp @@ -871,7 +871,7 @@ PBVAL BCUTIL::MakeBson(PGLOBAL g, PBVAL jsp, int n) /***********************************************************************/ PBVAL BCUTIL::GetRowValue(PGLOBAL g, PBVAL row, int i) { - int nod = Cp->Nod, n = nod - 1; + int nod = Cp->Nod; JNODE *nodes = Cp->Nodes; PBVAL arp; PBVAL bvp = NULL; diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index b2e8a15fbd3..d354fd93209 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -795,13 +795,9 @@ loop: /** Flush the recently written changes to the log file. and invoke log_mutex_enter(). */ -static -void -log_write_flush_to_disk_low() +static void log_write_flush_to_disk_low() { - /* FIXME: This is not holding log_sys.mutex while - calling os_event_set()! */ - ut_a(log_sys.n_pending_flushes == 1); /* No other threads here */ + ut_a(log_sys.n_pending_flushes); bool do_flush = srv_file_flush_method != SRV_O_DSYNC; @@ -809,7 +805,6 @@ log_write_flush_to_disk_low() fil_flush(SRV_LOG_SPACE_FIRST_ID); } - log_mutex_enter(); if (do_flush) { log_sys.flushed_to_disk_lsn = log_sys.current_flush_lsn; @@ -1123,7 +1118,7 @@ ATTRIBUTE_COLD void log_write_and_flush() /* Code adapted from log_write_flush_to_disk_low() */ - ut_a(log_sys.n_pending_flushes == 1); /* No other threads here */ + ut_a(log_sys.n_pending_flushes); if (srv_file_flush_method != SRV_O_DSYNC) fil_flush(SRV_LOG_SPACE_FIRST_ID); diff --git a/storage/myisam/ft_parser.c b/storage/myisam/ft_parser.c index b400990d934..bc50301fab2 100644 --- a/storage/myisam/ft_parser.c +++ b/storage/myisam/ft_parser.c @@ -78,18 +78,25 @@ FT_WORD * ft_linearize(TREE *wtree, MEM_ROOT *mem_root) DBUG_RETURN(wlist); } -my_bool ft_boolean_check_syntax_string(const uchar *str) +my_bool ft_boolean_check_syntax_string(const uchar *str, size_t length, + CHARSET_INFO *cs) { uint i, j; + if (cs->mbminlen != 1) + { + DBUG_ASSERT(0); + return 1; + } + if (!str || - (strlen((char*) str)+1 != sizeof(DEFAULT_FTB_SYNTAX)) || + (length + 1 != sizeof(DEFAULT_FTB_SYNTAX)) || (str[0] != ' ' && str[1] != ' ')) return 1; for (i=0; i<sizeof(DEFAULT_FTB_SYNTAX); i++) { /* limiting to 7-bit ascii only */ - if ((unsigned char)(str[i]) > 127 || my_isalnum(default_charset_info, str[i])) + if ((unsigned char)(str[i]) > 127 || my_isalnum(cs, str[i])) return 1; for (j=0; j<i; j++) if (str[i] == str[j] && (i != 11 || j != 10)) |