diff options
41 files changed, 668 insertions, 399 deletions
diff --git a/client/mysql.cc b/client/mysql.cc index 9ce5faf4d58..0fba75cfa32 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2018, Oracle and/or its affiliates. - Copyright (c) 2009, 2018, MariaDB Corporation + Copyright (c) 2009, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -40,6 +40,7 @@ #include "my_readline.h" #include <signal.h> #include <violite.h> +#include <my_sys.h> #include <source_revision.h> #if defined(USE_LIBEDIT_INTERFACE) && defined(HAVE_LOCALE_H) #include <locale.h> @@ -4697,7 +4698,8 @@ sql_real_connect(char *host,char *database,char *user,char *password, select_limit,max_join_size); mysql_options(&mysql, MYSQL_INIT_COMMAND, init_command); } - + if (!strcmp(default_charset,MYSQL_AUTODETECT_CHARSET_NAME)) + default_charset= (char *)my_default_csname(); mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); if (!do_connect(&mysql, host, user, password, database, diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index ef8cb27e672..a4e06b46d94 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -26,6 +26,7 @@ #include <welcome_copyright_notice.h> #include <my_rnd.h> #include <password.h> +#include <my_sys.h> #define ADMIN_VERSION "9.1" #define MAX_MYSQL_VAR 512 @@ -371,6 +372,8 @@ int main(int argc,char *argv[]) if (shared_memory_base_name) mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); #endif + if (!strcmp(default_charset,MYSQL_AUTODETECT_CHARSET_NAME)) + default_charset= (char *)my_default_csname(); mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); error_flags= (myf)(opt_nobeep ? 0 : ME_BELL); diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 1a10bc55f66..aaf77dbb743 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -440,8 +440,10 @@ static int get_options(int *argc, char ***argv) else default_charset= (char*) MYSQL_AUTODETECT_CHARSET_NAME; } - if (strcmp(default_charset, MYSQL_AUTODETECT_CHARSET_NAME) && - !get_charset_by_csname(default_charset, MY_CS_PRIMARY, MYF(MY_WME))) + if (!strcmp(default_charset, MYSQL_AUTODETECT_CHARSET_NAME)) + default_charset= (char *)my_default_csname(); + + if (!get_charset_by_csname(default_charset, MY_CS_PRIMARY, MYF(MY_WME))) { printf("Unsupported character set: %s\n", default_charset); DBUG_RETURN(1); diff --git a/client/mysqlimport.c b/client/mysqlimport.c index dbb2e8f7dba..32ad74dd5d1 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -30,6 +30,8 @@ #define IMPORT_VERSION "3.7" #include "client_priv.h" +#include <my_sys.h> + #include "mysql_version.h" #include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */ @@ -472,8 +474,9 @@ static MYSQL *db_connect(char *host, char *database, if (opt_default_auth && *opt_default_auth) mysql_options(mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); - - mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset); + if (!strcmp(default_charset,MYSQL_AUTODETECT_CHARSET_NAME)) + default_charset= (char *)my_default_csname(); + mysql_options(mysql, MYSQL_SET_CHARSET_NAME, my_default_csname()); mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0); mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "program_name", "mysqlimport"); diff --git a/client/mysqlshow.c b/client/mysqlshow.c index b56d334915b..dfa1eac3673 100644 --- a/client/mysqlshow.c +++ b/client/mysqlshow.c @@ -135,6 +135,8 @@ int main(int argc, char **argv) if (shared_memory_base_name) mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); #endif + if (!strcmp(default_charset,MYSQL_AUTODETECT_CHARSET_NAME)) + default_charset= (char *)my_default_csname(); mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); if (opt_plugin_dir && *opt_plugin_dir) diff --git a/include/my_sys.h b/include/my_sys.h index 3fc36bdd75b..62c76adedfc 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -1049,6 +1049,7 @@ extern char *get_tty_password(const char *opt_message); /* File system character set */ extern CHARSET_INFO *fs_character_set(void); #endif +extern const char *my_default_csname(void); extern size_t escape_quotes_for_mysql(CHARSET_INFO *charset_info, char *to, size_t to_length, const char *from, size_t length); diff --git a/mysql-test/main/charset_client_win.result b/mysql-test/main/charset_client_win.result new file mode 100644 index 00000000000..08a32b0b80f --- /dev/null +++ b/mysql-test/main/charset_client_win.result @@ -0,0 +1,2 @@ +@@character_set_client +cp1257 diff --git a/mysql-test/main/charset_client_win.test b/mysql-test/main/charset_client_win.test new file mode 100644 index 00000000000..b4a21d4f0a4 --- /dev/null +++ b/mysql-test/main/charset_client_win.test @@ -0,0 +1,2 @@ +--source include/windows.inc +--exec chcp 1257 > NUL && $MYSQL --default-character-set=auto -e "select @@character_set_client" diff --git a/mysql-test/suite/maria/alter.result b/mysql-test/suite/maria/alter.result index c63688dddd6..ea72328a38f 100644 --- a/mysql-test/suite/maria/alter.result +++ b/mysql-test/suite/maria/alter.result @@ -47,3 +47,46 @@ t1 CREATE TABLE `t1` ( ) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1 CREATE TABLE t2 SELECT * FROM t1; DROP TABLE t1, t2; +# +# MDEV-19055 Assertion `(_my_thread_var())->thr_errno != 0' failed in pagecache_read +# +CREATE OR REPLACE TABLE t1 (x INT) ENGINE=Aria; +CREATE TEMPORARY TABLE t2 (a TIME) ENGINE=Aria; +ALTER TABLE t2 ADD b DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP; +ALTER TABLE t2 ADD CHECK (b = 4); +INSERT IGNORE INTO t2 () VALUES (),(),(),(); +ALTER IGNORE TABLE t2 ADD c INT; +SELECT count(a),sum(a) FROM t2; +count(a) sum(a) +0 NULL +DELETE FROM t2 ORDER BY c LIMIT 1; +INSERT IGNORE INTO t2 SELECT * FROM t2; +OPTIMIZE TABLE t2; +Table Op Msg_type Msg_text +test.t2 optimize status OK +SELECT count(a),sum(a) FROM t2; +count(a) sum(a) +0 NULL +INSERT IGNORE INTO t2 SELECT * FROM t2; +SET SQL_MODE= 'STRICT_ALL_TABLES'; +SELECT count(a),sum(a) FROM t2; +count(a) sum(a) +0 NULL +ALTER TABLE t2 CHANGE IF EXISTS d c INT; +ERROR 22007: Incorrect datetime value: '4' +SELECT count(a),sum(a) FROM t2; +count(a) sum(a) +0 NULL +ALTER IGNORE TABLE t2 ADD IF NOT EXISTS e BIT; +ALTER TABLE t1 MODIFY IF EXISTS xx INT; +INSERT IGNORE INTO t2 () VALUES (),(),(),(); +SELECT count(a),sum(a) FROM t2; +count(a) sum(a) +0 NULL +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +check table t2; +Table Op Msg_type Msg_text +test.t2 check status OK +DROP TABLE t1,t2; diff --git a/mysql-test/suite/maria/alter.test b/mysql-test/suite/maria/alter.test index 09672cdfa3b..ef21ab2e5d2 100644 --- a/mysql-test/suite/maria/alter.test +++ b/mysql-test/suite/maria/alter.test @@ -42,3 +42,38 @@ ALTER TABLE t1 ORDER BY unknown_column; SHOW CREATE TABLE t1; CREATE TABLE t2 SELECT * FROM t1; DROP TABLE t1, t2; + +--echo # +--echo # MDEV-19055 Assertion `(_my_thread_var())->thr_errno != 0' failed in pagecache_read +--echo # + +--disable_warnings +CREATE OR REPLACE TABLE t1 (x INT) ENGINE=Aria; +CREATE TEMPORARY TABLE t2 (a TIME) ENGINE=Aria; +ALTER TABLE t2 ADD b DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP; +ALTER TABLE t2 ADD CHECK (b = 4); +INSERT IGNORE INTO t2 () VALUES (),(),(),(); +ALTER IGNORE TABLE t2 ADD c INT; +SELECT count(a),sum(a) FROM t2; +DELETE FROM t2 ORDER BY c LIMIT 1; +INSERT IGNORE INTO t2 SELECT * FROM t2; +OPTIMIZE TABLE t2; +SELECT count(a),sum(a) FROM t2; +INSERT IGNORE INTO t2 SELECT * FROM t2; +SET SQL_MODE= 'STRICT_ALL_TABLES'; +SELECT count(a),sum(a) FROM t2; +--error ER_TRUNCATED_WRONG_VALUE +ALTER TABLE t2 CHANGE IF EXISTS d c INT; +SELECT count(a),sum(a) FROM t2; +ALTER IGNORE TABLE t2 ADD IF NOT EXISTS e BIT; +ALTER TABLE t1 MODIFY IF EXISTS xx INT; +INSERT IGNORE INTO t2 () VALUES (),(),(),(); +SELECT count(a),sum(a) FROM t2; +--enable_warnings +check table t1; +check table t2; +DROP TABLE t1,t2; + +# +# End of 10.2 tests +# diff --git a/mysql-test/suite/maria/temporary.result b/mysql-test/suite/maria/temporary.result new file mode 100644 index 00000000000..2592e04be2b --- /dev/null +++ b/mysql-test/suite/maria/temporary.result @@ -0,0 +1,23 @@ +CREATE TABLE t1 (b INT); +INSERT INTO t1 VALUES (5); +CREATE TEMPORARY TABLE t1 (a INT) ENGINE=Aria ROW_FORMAT=DYNAMIC; +INSERT INTO t1 VALUES (1); +DELETE FROM t1 LIMIT 2; +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +SELECT * FROM t1; +a +INSERT INTO t1 VALUES (1),(2); +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +ALTER TABLE t1 CHANGE COLUMN IF EXISTS x x INT; +Warnings: +Note 1054 Unknown column 'x' in 't1' +ALTER TABLE t1; +DROP TEMPORARY TABLE t1; +DROP TABLE t1; diff --git a/mysql-test/suite/maria/temporary.test b/mysql-test/suite/maria/temporary.test new file mode 100644 index 00000000000..76f8e2526a4 --- /dev/null +++ b/mysql-test/suite/maria/temporary.test @@ -0,0 +1,20 @@ +# +# MDEV-19595 +# ER_CRASHED_ON_USAGE and Assertion `!is_set() || (m_status == DA_OK_BULK && is_bulk_op())' +# failed upon actions on temporary Aria table with ROW_FORMAT DYNAMIC +# + +CREATE TABLE t1 (b INT); +INSERT INTO t1 VALUES (5); +CREATE TEMPORARY TABLE t1 (a INT) ENGINE=Aria ROW_FORMAT=DYNAMIC; +INSERT INTO t1 VALUES (1); +DELETE FROM t1 LIMIT 2; +OPTIMIZE TABLE t1; +CHECK TABLE t1; +SELECT * FROM t1; +INSERT INTO t1 VALUES (1),(2); +CHECK TABLE t1; +ALTER TABLE t1 CHANGE COLUMN IF EXISTS x x INT; +ALTER TABLE t1; +DROP TEMPORARY TABLE t1; +DROP TABLE t1; diff --git a/mysql-test/suite/vcol/r/vcol_misc.result b/mysql-test/suite/vcol/r/vcol_misc.result index ef2e948a004..1dd2c3ea5af 100644 --- a/mysql-test/suite/vcol/r/vcol_misc.result +++ b/mysql-test/suite/vcol/r/vcol_misc.result @@ -203,10 +203,10 @@ drop table t1; create table t1 (a int, b int); insert into t1 values (3, 30), (4, 20), (1, 20); create table t2 (c int, d int, v int as (d+1), index idx(c)); -insert into t2(c,d) values +insert into t2(c,d) values (20, 100), (20, 300), (30, 100), (30, 200), (40, 500), (70, 100), (40, 300), (60, 100), (40, 100), (70, 100); -insert into t2(c,d) values +insert into t2(c,d) values (120, 100), (150, 300), (130, 100), (130, 200), (140, 500), (170, 100), (180, 300), (160, 100), (40, 100), (170, 100); set join_cache_level=6; @@ -423,5 +423,43 @@ ERROR HY000: Incorrect information in file: './test/t1.frm' ALTER TABLE t1; ERROR HY000: Incorrect information in file: './test/t1.frm' # +# MDEV-19771 REPLACE on table with virtual_field can cause crash in set_ok_status() + +create or replace table t1 (pk int primary key, col_bit bit(15) default null, +vcol_bit bit(10) GENERATED ALWAYS AS (`col_bit`) VIRTUAL); +replace INTO `t1` (`pk`,col_bit) VALUES (99,1000); +select pk, col_bit+0, vcol_bit+0 from t1; +pk col_bit+0 vcol_bit+0 +99 1000 1000 +replace INTO `t1` (`pk`,col_bit) VALUES (99,10000); +select pk, col_bit+0, vcol_bit+0 from t1; +pk col_bit+0 vcol_bit+0 +99 10000 1023 +REPLACE LOW_PRIORITY INTO `t1` (`pk`) VALUES (99); +Warnings: +Warning 1264 Out of range value for column 'vcol_bit' at row 1 +drop table t1; +# +# MDEV-17837 REPLACE on table with virtual_field can cause crash in set_ok_status() +# +SET @old_sql_mode=@@sql_mode; +SET sql_mode= STRICT_ALL_TABLES; +CREATE TABLE t1 ( +pk INT, +i TINYINT, +vi TINYINT AS (i+1) PERSISTENT, +PRIMARY KEY(pk) +); +INSERT INTO t1 (pk,i) VALUES (1,1); +TRUNCATE TABLE t1; +INSERT IGNORE INTO t1 (pk,i) VALUES (1,127); +Warnings: +Warning 1264 Out of range value for column 'vi' at row 1 +REPLACE INTO t1 (pk,i) VALUES (1,2); +Warnings: +Warning 1264 Out of range value for column 'vi' at row 1 +DROP TABLE t1; +SET @sql_mode=@old_sql_mode; +# # End of 10.2 tests # diff --git a/mysql-test/suite/vcol/t/vcol_misc.test b/mysql-test/suite/vcol/t/vcol_misc.test index 255621845fb..1de2827efe6 100644 --- a/mysql-test/suite/vcol/t/vcol_misc.test +++ b/mysql-test/suite/vcol/t/vcol_misc.test @@ -215,12 +215,12 @@ drop table t1; create table t1 (a int, b int); insert into t1 values (3, 30), (4, 20), (1, 20); create table t2 (c int, d int, v int as (d+1), index idx(c)); -insert into t2(c,d) values +insert into t2(c,d) values (20, 100), (20, 300), (30, 100), (30, 200), (40, 500), - (70, 100), (40, 300), (60, 100), (40, 100), (70, 100); -insert into t2(c,d) values + (70, 100), (40, 300), (60, 100), (40, 100), (70, 100); +insert into t2(c,d) values (120, 100), (150, 300), (130, 100), (130, 200), (140, 500), - (170, 100), (180, 300), (160, 100), (40, 100), (170, 100); + (170, 100), (180, 300), (160, 100), (40, 100), (170, 100); set join_cache_level=6; explain @@ -392,5 +392,39 @@ ALTER TABLE t1; --remove_file $MYSQLD_DATADIR/test/t1.frm --echo # +--echo # MDEV-19771 REPLACE on table with virtual_field can cause crash in set_ok_status() +--echo + +create or replace table t1 (pk int primary key, col_bit bit(15) default null, + vcol_bit bit(10) GENERATED ALWAYS AS (`col_bit`) VIRTUAL); +replace INTO `t1` (`pk`,col_bit) VALUES (99,1000); +select pk, col_bit+0, vcol_bit+0 from t1; +replace INTO `t1` (`pk`,col_bit) VALUES (99,10000); +select pk, col_bit+0, vcol_bit+0 from t1; +REPLACE LOW_PRIORITY INTO `t1` (`pk`) VALUES (99); +drop table t1; + +--echo # +--echo # MDEV-17837 REPLACE on table with virtual_field can cause crash in set_ok_status() +--echo # + +SET @old_sql_mode=@@sql_mode; +SET sql_mode= STRICT_ALL_TABLES; + +CREATE TABLE t1 ( + pk INT, + i TINYINT, + vi TINYINT AS (i+1) PERSISTENT, + PRIMARY KEY(pk) +); + +INSERT INTO t1 (pk,i) VALUES (1,1); +TRUNCATE TABLE t1; +INSERT IGNORE INTO t1 (pk,i) VALUES (1,127); +REPLACE INTO t1 (pk,i) VALUES (1,2); +DROP TABLE t1; +SET @sql_mode=@old_sql_mode; + +--echo # --echo # End of 10.2 tests --echo # diff --git a/mysys/charset.c b/mysys/charset.c index 51afbb16cf0..f44dc7606c1 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -20,7 +20,12 @@ #include <m_string.h> #include <my_dir.h> #include <my_xml.h> - +#ifdef HAVE_LANGINFO_H +#include <langinfo.h> +#endif +#ifdef HAVE_LOCALE_H +#include <locale.h> +#endif /* The code below implements this functionality: @@ -1216,3 +1221,214 @@ size_t escape_quotes_for_mysql(CHARSET_INFO *charset_info, *to= 0; return overflow ? (ulong)~0 : (ulong) (to - to_start); } + + +typedef enum my_cs_match_type_enum +{ + /* MySQL and OS charsets are fully compatible */ + my_cs_exact, + /* MySQL charset is very close to OS charset */ + my_cs_approx, + /* + MySQL knows this charset, but it is not supported as client character set. + */ + my_cs_unsupp +} my_cs_match_type; + + +typedef struct str2str_st +{ + const char* os_name; + const char* my_name; + my_cs_match_type param; +} MY_CSET_OS_NAME; + +static const MY_CSET_OS_NAME charsets[] = +{ +#ifdef _WIN32 + {"cp437", "cp850", my_cs_approx}, + {"cp850", "cp850", my_cs_exact}, + {"cp852", "cp852", my_cs_exact}, + {"cp858", "cp850", my_cs_approx}, + {"cp866", "cp866", my_cs_exact}, + {"cp874", "tis620", my_cs_approx}, + {"cp932", "cp932", my_cs_exact}, + {"cp936", "gbk", my_cs_approx}, + {"cp949", "euckr", my_cs_approx}, + {"cp950", "big5", my_cs_exact}, + {"cp1200", "utf16le", my_cs_unsupp}, + {"cp1201", "utf16", my_cs_unsupp}, + {"cp1250", "cp1250", my_cs_exact}, + {"cp1251", "cp1251", my_cs_exact}, + {"cp1252", "latin1", my_cs_exact}, + {"cp1253", "greek", my_cs_exact}, + {"cp1254", "latin5", my_cs_exact}, + {"cp1255", "hebrew", my_cs_approx}, + {"cp1256", "cp1256", my_cs_exact}, + {"cp1257", "cp1257", my_cs_exact}, + {"cp10000", "macroman", my_cs_exact}, + {"cp10001", "sjis", my_cs_approx}, + {"cp10002", "big5", my_cs_approx}, + {"cp10008", "gb2312", my_cs_approx}, + {"cp10021", "tis620", my_cs_approx}, + {"cp10029", "macce", my_cs_exact}, + {"cp12001", "utf32", my_cs_unsupp}, + {"cp20107", "swe7", my_cs_exact}, + {"cp20127", "latin1", my_cs_approx}, + {"cp20866", "koi8r", my_cs_exact}, + {"cp20932", "ujis", my_cs_exact}, + {"cp20936", "gb2312", my_cs_approx}, + {"cp20949", "euckr", my_cs_approx}, + {"cp21866", "koi8u", my_cs_exact}, + {"cp28591", "latin1", my_cs_approx}, + {"cp28592", "latin2", my_cs_exact}, + {"cp28597", "greek", my_cs_exact}, + {"cp28598", "hebrew", my_cs_exact}, + {"cp28599", "latin5", my_cs_exact}, + {"cp28603", "latin7", my_cs_exact}, +#ifdef UNCOMMENT_THIS_WHEN_WL_4579_IS_DONE + {"cp28605", "latin9", my_cs_exact}, +#endif + {"cp38598", "hebrew", my_cs_exact}, + {"cp51932", "ujis", my_cs_exact}, + {"cp51936", "gb2312", my_cs_exact}, + {"cp51949", "euckr", my_cs_exact}, + {"cp51950", "big5", my_cs_exact}, +#ifdef UNCOMMENT_THIS_WHEN_WL_WL_4024_IS_DONE + {"cp54936", "gb18030", my_cs_exact}, +#endif + {"cp65001", "utf8", my_cs_exact}, + +#else /* not Windows */ + + {"646", "latin1", my_cs_approx}, /* Default on Solaris */ + {"ANSI_X3.4-1968", "latin1", my_cs_approx}, + {"ansi1251", "cp1251", my_cs_exact}, + {"armscii8", "armscii8", my_cs_exact}, + {"armscii-8", "armscii8", my_cs_exact}, + {"ASCII", "latin1", my_cs_approx}, + {"Big5", "big5", my_cs_exact}, + {"cp1251", "cp1251", my_cs_exact}, + {"cp1255", "hebrew", my_cs_approx}, + {"CP866", "cp866", my_cs_exact}, + {"eucCN", "gb2312", my_cs_exact}, + {"euc-CN", "gb2312", my_cs_exact}, + {"eucJP", "ujis", my_cs_exact}, + {"euc-JP", "ujis", my_cs_exact}, + {"eucKR", "euckr", my_cs_exact}, + {"euc-KR", "euckr", my_cs_exact}, +#ifdef UNCOMMENT_THIS_WHEN_WL_WL_4024_IS_DONE + {"gb18030", "gb18030", my_cs_exact}, +#endif + {"gb2312", "gb2312", my_cs_exact}, + {"gbk", "gbk", my_cs_exact}, + {"georgianps", "geostd8", my_cs_exact}, + {"georgian-ps", "geostd8", my_cs_exact}, + {"IBM-1252", "cp1252", my_cs_exact}, + + {"iso88591", "latin1", my_cs_approx}, + {"ISO_8859-1", "latin1", my_cs_approx}, + {"ISO8859-1", "latin1", my_cs_approx}, + {"ISO-8859-1", "latin1", my_cs_approx}, + + {"iso885913", "latin7", my_cs_exact}, + {"ISO_8859-13", "latin7", my_cs_exact}, + {"ISO8859-13", "latin7", my_cs_exact}, + {"ISO-8859-13", "latin7", my_cs_exact}, + +#ifdef UNCOMMENT_THIS_WHEN_WL_4579_IS_DONE + {"iso885915", "latin9", my_cs_exact}, + {"ISO_8859-15", "latin9", my_cs_exact}, + {"ISO8859-15", "latin9", my_cs_exact}, + {"ISO-8859-15", "latin9", my_cs_exact}, +#endif + + {"iso88592", "latin2", my_cs_exact}, + {"ISO_8859-2", "latin2", my_cs_exact}, + {"ISO8859-2", "latin2", my_cs_exact}, + {"ISO-8859-2", "latin2", my_cs_exact}, + + {"iso88597", "greek", my_cs_exact}, + {"ISO_8859-7", "greek", my_cs_exact}, + {"ISO8859-7", "greek", my_cs_exact}, + {"ISO-8859-7", "greek", my_cs_exact}, + + {"iso88598", "hebrew", my_cs_exact}, + {"ISO_8859-8", "hebrew", my_cs_exact}, + {"ISO8859-8", "hebrew", my_cs_exact}, + {"ISO-8859-8", "hebrew", my_cs_exact}, + + {"iso88599", "latin5", my_cs_exact}, + {"ISO_8859-9", "latin5", my_cs_exact}, + {"ISO8859-9", "latin5", my_cs_exact}, + {"ISO-8859-9", "latin5", my_cs_exact}, + + {"koi8r", "koi8r", my_cs_exact}, + {"KOI8-R", "koi8r", my_cs_exact}, + {"koi8u", "koi8u", my_cs_exact}, + {"KOI8-U", "koi8u", my_cs_exact}, + + {"roman8", "hp8", my_cs_exact}, /* Default on HP UX */ + + {"Shift_JIS", "sjis", my_cs_exact}, + {"SJIS", "sjis", my_cs_exact}, + {"shiftjisx0213", "sjis", my_cs_exact}, + + {"tis620", "tis620", my_cs_exact}, + {"tis-620", "tis620", my_cs_exact}, + + {"ujis", "ujis", my_cs_exact}, + + {"US-ASCII", "latin1", my_cs_approx}, + + {"utf8", "utf8", my_cs_exact}, + {"utf-8", "utf8", my_cs_exact}, +#endif + {NULL, NULL, 0} +}; + + +static const char* +my_os_charset_to_mysql_charset(const char* csname) +{ + const MY_CSET_OS_NAME* csp; + for (csp = charsets; csp->os_name; csp++) + { + if (!strcasecmp(csp->os_name, csname)) + { + switch (csp->param) + { + case my_cs_exact: + return csp->my_name; + + case my_cs_approx: + /* + Maybe we should print a warning eventually: + character set correspondence is not exact. + */ + return csp->my_name; + + default: + return NULL; + } + } + } + return NULL; +} + +const char* my_default_csname() +{ + const char* csname = NULL; +#ifdef _WIN32 + char cpbuf[64]; + int cp = GetConsoleCP(); + if (cp == 0) + cp = GetACP(); + snprintf(cpbuf, sizeof(cpbuf), "cp%d", (int)cp); + csname = my_os_charset_to_mysql_charset(cpbuf); +#elif defined(HAVE_SETLOCALE) && defined(HAVE_NL_LANGINFO) + if (setlocale(LC_CTYPE, "") && (csname = nl_langinfo(CODESET))) + csname = my_os_charset_to_mysql_charset(csname); +#endif + return csname ? csname : MYSQL_DEFAULT_CHARSET_NAME; +}
\ No newline at end of file diff --git a/mysys/my_pread.c b/mysys/my_pread.c index 08285738528..9d3fdb3e0ee 100644 --- a/mysys/my_pread.c +++ b/mysys/my_pread.c @@ -68,6 +68,8 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset, if (readbytes != Count) { + /* We should never read with wrong file descriptor! */ + DBUG_ASSERT(readbytes != (size_t)-1 || errno != EBADF); my_errno= errno; if (errno == 0 || (readbytes != (size_t) -1 && (MyFlags & (MY_NABP | MY_FNABP)))) diff --git a/sql-common/client.c b/sql-common/client.c index e949b74b62c..eea6122535a 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1920,250 +1920,13 @@ static MYSQL_METHODS client_methods= }; - -typedef enum my_cs_match_type_enum -{ - /* MySQL and OS charsets are fully compatible */ - my_cs_exact, - /* MySQL charset is very close to OS charset */ - my_cs_approx, - /* - MySQL knows this charset, but it is not supported as client character set. - */ - my_cs_unsupp -} my_cs_match_type; - - -typedef struct str2str_st -{ - const char *os_name; - const char *my_name; - my_cs_match_type param; -} MY_CSET_OS_NAME; - -const MY_CSET_OS_NAME charsets[]= -{ -#ifdef __WIN__ - {"cp437", "cp850", my_cs_approx}, - {"cp850", "cp850", my_cs_exact}, - {"cp852", "cp852", my_cs_exact}, - {"cp858", "cp850", my_cs_approx}, - {"cp866", "cp866", my_cs_exact}, - {"cp874", "tis620", my_cs_approx}, - {"cp932", "cp932", my_cs_exact}, - {"cp936", "gbk", my_cs_approx}, - {"cp949", "euckr", my_cs_approx}, - {"cp950", "big5", my_cs_exact}, - {"cp1200", "utf16le", my_cs_unsupp}, - {"cp1201", "utf16", my_cs_unsupp}, - {"cp1250", "cp1250", my_cs_exact}, - {"cp1251", "cp1251", my_cs_exact}, - {"cp1252", "latin1", my_cs_exact}, - {"cp1253", "greek", my_cs_exact}, - {"cp1254", "latin5", my_cs_exact}, - {"cp1255", "hebrew", my_cs_approx}, - {"cp1256", "cp1256", my_cs_exact}, - {"cp1257", "cp1257", my_cs_exact}, - {"cp10000", "macroman", my_cs_exact}, - {"cp10001", "sjis", my_cs_approx}, - {"cp10002", "big5", my_cs_approx}, - {"cp10008", "gb2312", my_cs_approx}, - {"cp10021", "tis620", my_cs_approx}, - {"cp10029", "macce", my_cs_exact}, - {"cp12001", "utf32", my_cs_unsupp}, - {"cp20107", "swe7", my_cs_exact}, - {"cp20127", "latin1", my_cs_approx}, - {"cp20866", "koi8r", my_cs_exact}, - {"cp20932", "ujis", my_cs_exact}, - {"cp20936", "gb2312", my_cs_approx}, - {"cp20949", "euckr", my_cs_approx}, - {"cp21866", "koi8u", my_cs_exact}, - {"cp28591", "latin1", my_cs_approx}, - {"cp28592", "latin2", my_cs_exact}, - {"cp28597", "greek", my_cs_exact}, - {"cp28598", "hebrew", my_cs_exact}, - {"cp28599", "latin5", my_cs_exact}, - {"cp28603", "latin7", my_cs_exact}, -#ifdef UNCOMMENT_THIS_WHEN_WL_4579_IS_DONE - {"cp28605", "latin9", my_cs_exact}, -#endif - {"cp38598", "hebrew", my_cs_exact}, - {"cp51932", "ujis", my_cs_exact}, - {"cp51936", "gb2312", my_cs_exact}, - {"cp51949", "euckr", my_cs_exact}, - {"cp51950", "big5", my_cs_exact}, -#ifdef UNCOMMENT_THIS_WHEN_WL_WL_4024_IS_DONE - {"cp54936", "gb18030", my_cs_exact}, -#endif - {"cp65001", "utf8", my_cs_exact}, - -#else /* not Windows */ - - {"646", "latin1", my_cs_approx}, /* Default on Solaris */ - {"ANSI_X3.4-1968", "latin1", my_cs_approx}, - {"ansi1251", "cp1251", my_cs_exact}, - {"armscii8", "armscii8", my_cs_exact}, - {"armscii-8", "armscii8", my_cs_exact}, - {"ASCII", "latin1", my_cs_approx}, - {"Big5", "big5", my_cs_exact}, - {"cp1251", "cp1251", my_cs_exact}, - {"cp1255", "hebrew", my_cs_approx}, - {"CP866", "cp866", my_cs_exact}, - {"eucCN", "gb2312", my_cs_exact}, - {"euc-CN", "gb2312", my_cs_exact}, - {"eucJP", "ujis", my_cs_exact}, - {"euc-JP", "ujis", my_cs_exact}, - {"eucKR", "euckr", my_cs_exact}, - {"euc-KR", "euckr", my_cs_exact}, -#ifdef UNCOMMENT_THIS_WHEN_WL_WL_4024_IS_DONE - {"gb18030", "gb18030", my_cs_exact}, -#endif - {"gb2312", "gb2312", my_cs_exact}, - {"gbk", "gbk", my_cs_exact}, - {"georgianps", "geostd8", my_cs_exact}, - {"georgian-ps", "geostd8", my_cs_exact}, - {"IBM-1252", "cp1252", my_cs_exact}, - - {"iso88591", "latin1", my_cs_approx}, - {"ISO_8859-1", "latin1", my_cs_approx}, - {"ISO8859-1", "latin1", my_cs_approx}, - {"ISO-8859-1", "latin1", my_cs_approx}, - - {"iso885913", "latin7", my_cs_exact}, - {"ISO_8859-13", "latin7", my_cs_exact}, - {"ISO8859-13", "latin7", my_cs_exact}, - {"ISO-8859-13", "latin7", my_cs_exact}, - -#ifdef UNCOMMENT_THIS_WHEN_WL_4579_IS_DONE - {"iso885915", "latin9", my_cs_exact}, - {"ISO_8859-15", "latin9", my_cs_exact}, - {"ISO8859-15", "latin9", my_cs_exact}, - {"ISO-8859-15", "latin9", my_cs_exact}, -#endif - - {"iso88592", "latin2", my_cs_exact}, - {"ISO_8859-2", "latin2", my_cs_exact}, - {"ISO8859-2", "latin2", my_cs_exact}, - {"ISO-8859-2", "latin2", my_cs_exact}, - - {"iso88597", "greek", my_cs_exact}, - {"ISO_8859-7", "greek", my_cs_exact}, - {"ISO8859-7", "greek", my_cs_exact}, - {"ISO-8859-7", "greek", my_cs_exact}, - - {"iso88598", "hebrew", my_cs_exact}, - {"ISO_8859-8", "hebrew", my_cs_exact}, - {"ISO8859-8", "hebrew", my_cs_exact}, - {"ISO-8859-8", "hebrew", my_cs_exact}, - - {"iso88599", "latin5", my_cs_exact}, - {"ISO_8859-9", "latin5", my_cs_exact}, - {"ISO8859-9", "latin5", my_cs_exact}, - {"ISO-8859-9", "latin5", my_cs_exact}, - - {"koi8r", "koi8r", my_cs_exact}, - {"KOI8-R", "koi8r", my_cs_exact}, - {"koi8u", "koi8u", my_cs_exact}, - {"KOI8-U", "koi8u", my_cs_exact}, - - {"roman8", "hp8", my_cs_exact}, /* Default on HP UX */ - - {"Shift_JIS", "sjis", my_cs_exact}, - {"SJIS", "sjis", my_cs_exact}, - {"shiftjisx0213", "sjis", my_cs_exact}, - - {"tis620", "tis620", my_cs_exact}, - {"tis-620", "tis620", my_cs_exact}, - - {"ujis", "ujis", my_cs_exact}, - - {"US-ASCII", "latin1", my_cs_approx}, - - {"utf8", "utf8", my_cs_exact}, - {"utf-8", "utf8", my_cs_exact}, -#endif - {NULL, NULL, 0} -}; - - -static const char * -my_os_charset_to_mysql_charset(const char *csname) -{ - const MY_CSET_OS_NAME *csp; - for (csp= charsets; csp->os_name; csp++) - { - if (!my_strcasecmp(&my_charset_latin1, csp->os_name, csname)) - { - switch (csp->param) - { - case my_cs_exact: - return csp->my_name; - - case my_cs_approx: - /* - Maybe we should print a warning eventually: - character set correspondence is not exact. - */ - return csp->my_name; - - default: - my_printf_error(ER_UNKNOWN_ERROR, - "OS character set '%s'" - " is not supported by MySQL client", - MYF(0), csp->my_name); - goto def; - } - } - } - - my_printf_error(ER_UNKNOWN_ERROR, - "Unknown OS character set '%s'.", - MYF(0), csname); - -def: - csname= MYSQL_DEFAULT_CHARSET_NAME; - my_printf_error(ER_UNKNOWN_ERROR, - "Switching to the default character set '%s'.", - MYF(0), csname); - return csname; -} - - -#ifndef __WIN__ -#include <stdlib.h> /* for getenv() */ -#ifdef HAVE_LANGINFO_H -#include <langinfo.h> -#endif -#ifdef HAVE_LOCALE_H -#include <locale.h> -#endif -#endif /* __WIN__ */ - - +#include <my_sys.h> static int mysql_autodetect_character_set(MYSQL *mysql) { - const char *csname= MYSQL_DEFAULT_CHARSET_NAME; - -#ifdef __WIN__ - char cpbuf[64]; - { - UINT cp= GetConsoleCP(); - if (cp == 0) - cp= GetACP(); - my_snprintf(cpbuf, sizeof(cpbuf), "cp%d", (int)cp); - csname= my_os_charset_to_mysql_charset(cpbuf); - } -#elif defined(HAVE_SETLOCALE) && defined(HAVE_NL_LANGINFO) - { - if (setlocale(LC_CTYPE, "") && (csname= nl_langinfo(CODESET))) - csname= my_os_charset_to_mysql_charset(csname); - } -#endif - if (mysql->options.charset_name) my_free(mysql->options.charset_name); - if (!(mysql->options.charset_name= my_strdup(csname, MYF(MY_WME)))) + if (!(mysql->options.charset_name= my_strdup(my_default_csname(),MYF(MY_WME)))) return 1; return 0; } @@ -2204,16 +1967,13 @@ C_MODE_START int mysql_init_character_set(MYSQL *mysql) { /* Set character set */ - if (!mysql->options.charset_name) + if (!mysql->options.charset_name || + !strcmp(mysql->options.charset_name, + MYSQL_AUTODETECT_CHARSET_NAME)) { - if (!(mysql->options.charset_name= - my_strdup(MYSQL_DEFAULT_CHARSET_NAME,MYF(MY_WME)))) + if (mysql_autodetect_character_set(mysql)) return 1; } - else if (!strcmp(mysql->options.charset_name, - MYSQL_AUTODETECT_CHARSET_NAME) && - mysql_autodetect_character_set(mysql)) - return 1; mysql_set_character_set_with_default_collation(mysql); diff --git a/sql/records.cc b/sql/records.cc index 5dd4318b105..3d709182a4e 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -195,8 +195,7 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table, info->table=table; info->addon_field= addon_field; - if ((table->s->tmp_table == INTERNAL_TMP_TABLE || - table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE) && + if ((table->s->tmp_table == INTERNAL_TMP_TABLE) && !addon_field) (void) table->file->extra(HA_EXTRA_MMAP); diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 157d5d9f050..1c1ab82e570 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -700,19 +700,23 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, MDL_SHARED_NO_READ_WRITE lock (MDL_SHARED_WRITE cannot be upgraded) by *not* having HA_CONCURRENT_OPTIMIZE table_flag. */ - if (lock_type == TL_WRITE && !table->table->s->tmp_table && - table->mdl_request.type > MDL_SHARED_WRITE) + if (lock_type == TL_WRITE && table->mdl_request.type > MDL_SHARED_WRITE) { - if (wait_while_table_is_used(thd, table->table, HA_EXTRA_NOT_USED)) - goto err; - DEBUG_SYNC(thd, "after_admin_flush"); - /* Flush entries in the query cache involving this table. */ - query_cache_invalidate3(thd, table->table, 0); - /* - XXX: hack: switch off open_for_modify to skip the - flush that is made later in the execution flow. - */ - open_for_modify= 0; + if (table->table->s->tmp_table) + thd->close_unused_temporary_table_instances(tables); + else + { + if (wait_while_table_is_used(thd, table->table, HA_EXTRA_NOT_USED)) + goto err; + DEBUG_SYNC(thd, "after_admin_flush"); + /* Flush entries in the query cache involving this table. */ + query_cache_invalidate3(thd, table->table, 0); + /* + XXX: hack: switch off open_for_modify to skip the + flush that is made later in the execution flow. + */ + open_for_modify= 0; + } } if (table->table->s->crashed && operator_func == &handler::ha_check) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 1f3a70721fc..a64c120f14c 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1786,12 +1786,15 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) } if (table->vfield) { + my_bool abort_on_warning= thd->abort_on_warning; /* We have not yet called update_virtual_fields(VOL_UPDATE_FOR_READ) in handler methods for the just read row in record[1]. */ table->move_fields(table->field, table->record[1], table->record[0]); + thd->abort_on_warning= 0; table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_REPLACE); + thd->abort_on_warning= abort_on_warning; table->move_fields(table->field, table->record[0], table->record[1]); } if (info->handle_duplicates == DUP_UPDATE) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 01d13ac8789..e47700e0c33 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -791,8 +791,6 @@ void init_update_queries(void) Note that SQLCOM_RENAME_TABLE should not be in this list! */ sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_PREOPEN_TMP_TABLES; - sql_command_flags[SQLCOM_DROP_TABLE]|= CF_PREOPEN_TMP_TABLES; - sql_command_flags[SQLCOM_DROP_SEQUENCE]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_TRUNCATE]|= CF_PREOPEN_TMP_TABLES; @@ -4743,7 +4741,14 @@ mysql_execute_command(THD *thd) case SQLCOM_DROP_SEQUENCE: case SQLCOM_DROP_TABLE: { + int result; DBUG_ASSERT(first_table == all_tables && first_table != 0); + + thd->open_options|= HA_OPEN_FOR_REPAIR; + result= thd->open_temporary_tables(all_tables); + thd->open_options&= ~HA_OPEN_FOR_REPAIR; + if (result) + goto error; if (!lex->tmp_table()) { if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE)) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9da889852b2..9719f55f0bc 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9845,6 +9845,8 @@ do_continue:; DEBUG_SYNC(thd, "alter_table_copy_after_lock_upgrade"); } + else + thd->close_unused_temporary_table_instances(table_list); // It's now safe to take the table level lock. if (lock_tables(thd, table_list, alter_ctx.tables_opened, diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc index 396afc756f7..99ef1868158 100644 --- a/sql/temporary_tables.cc +++ b/sql/temporary_tables.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2016 MariaDB Corporation + Copyright (c) 2016, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -395,6 +395,9 @@ bool THD::open_temporary_table(TABLE_LIST *tl) rgi_slave->is_parallel_exec && wait_for_prior_commit()) DBUG_RETURN(true); + + if (!table && is_error()) + DBUG_RETURN(true); // Error when opening table } if (!table) diff --git a/storage/innobase/include/dyn0buf.h b/storage/innobase/include/dyn0buf.h index 1d624d887d5..db809c908ae 100644 --- a/storage/innobase/include/dyn0buf.h +++ b/storage/innobase/include/dyn0buf.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2018, MariaDB Corporation. +Copyright (c) 2018, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -359,6 +359,24 @@ public: } /** + Iterate over all the blocks in reverse and call the iterator + @return false if iteration was terminated. */ + template <typename Functor> + bool for_each_block_in_reverse(const Functor& functor) const + { + for (block_t* block = UT_LIST_GET_LAST(m_list); + block != NULL; + block = UT_LIST_GET_PREV(m_node, block)) { + + if (!functor(block)) { + return(false); + } + } + + return(true); + } + + /** @return the first block */ block_t* front() MY_ATTRIBUTE((warn_unused_result)) diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index 55b0b4b82d1..4b41506d339 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -525,7 +525,7 @@ struct mtr_t { /** Check if this mini-transaction is dirtying a clean page. @param block block being x-fixed @return true if the mtr is dirtying a clean page. */ - static bool is_block_dirtied(const buf_block_t* block) + static inline bool is_block_dirtied(const buf_block_t* block) MY_ATTRIBUTE((warn_unused_result)); private: diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic index 984b7b34bcf..574d0de24a5 100644 --- a/storage/innobase/include/mtr0mtr.ic +++ b/storage/innobase/include/mtr0mtr.ic @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -26,6 +26,20 @@ Created 11/26/1995 Heikki Tuuri #include "buf0buf.h" +/** Check if a mini-transaction is dirtying a clean page. +@return true if the mtr is dirtying a clean page. */ +bool +mtr_t::is_block_dirtied(const buf_block_t* block) +{ + ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); + ut_ad(block->page.buf_fix_count > 0); + + /* It is OK to read oldest_modification because no + other thread can be performing a write of it and it + is only during write that the value is reset to 0. */ + return(block->page.oldest_modification == 0); +} + /** Pushes an object to an mtr memo stack. */ void diff --git a/storage/innobase/include/mtr0types.h b/storage/innobase/include/mtr0types.h index 6392457e4ab..29e6fd042ab 100644 --- a/storage/innobase/include/mtr0types.h +++ b/storage/innobase/include/mtr0types.h @@ -38,7 +38,9 @@ enum mtr_log_t { /** Default mode: log all operations modifying disk-based data */ MTR_LOG_ALL = 21, - /** Log no operations and dirty pages are not added to the flush list */ + /** Log no operations and dirty pages are not added to the flush list. + Set when applying log in crash recovery or when a modification of a + ROW_FORMAT=COMPRESSED page is attempted. */ MTR_LOG_NONE = 22, /** Don't generate REDO log but add dirty pages to flush list */ diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index 1984f18eb71..751b7ec36ec 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -37,16 +37,43 @@ Created 11/26/1995 Heikki Tuuri /** Iterate over a memo block in reverse. */ template <typename Functor> -struct Iterate { +struct CIterate { + CIterate() : functor() {} - /** Release specific object */ - explicit Iterate(Functor& functor) - : - m_functor(functor) + CIterate(const Functor& functor) : functor(functor) {} + + /** @return false if the functor returns false. */ + bool operator()(mtr_buf_t::block_t* block) const { - /* Do nothing */ + const mtr_memo_slot_t* start = + reinterpret_cast<const mtr_memo_slot_t*>( + block->begin()); + + mtr_memo_slot_t* slot = + reinterpret_cast<mtr_memo_slot_t*>( + block->end()); + + ut_ad(!(block->used() % sizeof(*slot))); + + while (slot-- != start) { + + if (!functor(slot)) { + return(false); + } + } + + return(true); } + Functor functor; +}; + +template <typename Functor> +struct Iterate { + Iterate() : functor() {} + + Iterate(const Functor& functor) : functor(functor) {} + /** @return false if the functor returns false. */ bool operator()(mtr_buf_t::block_t* block) { @@ -62,7 +89,7 @@ struct Iterate { while (slot-- != start) { - if (!m_functor(slot)) { + if (!functor(slot)) { return(false); } } @@ -70,7 +97,7 @@ struct Iterate { return(true); } - Functor& m_functor; + Functor functor; }; /** Find specific object */ @@ -430,20 +457,6 @@ private: lsn_t m_end_lsn; }; -/** Check if a mini-transaction is dirtying a clean page. -@return true if the mtr is dirtying a clean page. */ -bool -mtr_t::is_block_dirtied(const buf_block_t* block) -{ - ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); - ut_ad(block->page.buf_fix_count > 0); - - /* It is OK to read oldest_modification because no - other thread can be performing a write of it and it - is only during write that the value is reset to 0. */ - return(block->page.oldest_modification == 0); -} - /** Write the block contents to the REDO log */ struct mtr_write_log_t { /** Append a block to the redo log buffer. @@ -509,12 +522,7 @@ mtr_t::Command::release_resources() /* Currently only used in commit */ ut_ad(m_impl->m_state == MTR_STATE_COMMITTING); -#ifdef UNIV_DEBUG - DebugCheck release; - Iterate<DebugCheck> iterator(release); - - m_impl->m_memo.for_each_block_in_reverse(iterator); -#endif /* UNIV_DEBUG */ + ut_d(m_impl->m_memo.for_each_block_in_reverse(CIterate<DebugCheck>())); /* Reset the mtr buffers */ m_impl->m_log.erase(); @@ -702,11 +710,10 @@ mtr_t::memo_release(const void* object, ulint type) middle of a mini-transaction. */ ut_ad(!m_impl.m_modifications || type != MTR_MEMO_PAGE_X_FIX); - Find find(object, type); - Iterate<Find> iterator(find); + Iterate<Find> iteration(Find(object, type)); - if (!m_impl.m_memo.for_each_block_in_reverse(iterator)) { - memo_slot_release(find.m_slot); + if (!m_impl.m_memo.for_each_block_in_reverse(iteration)) { + memo_slot_release(iteration.functor.m_slot); return(true); } @@ -726,11 +733,10 @@ mtr_t::release_page(const void* ptr, mtr_memo_type_t type) middle of a mini-transaction. */ ut_ad(!m_impl.m_modifications || type != MTR_MEMO_PAGE_X_FIX); - FindPage find(ptr, type); - Iterate<FindPage> iterator(find); + Iterate<FindPage> iteration(FindPage(ptr, type)); - if (!m_impl.m_memo.for_each_block_in_reverse(iterator)) { - memo_slot_release(find.get_slot()); + if (!m_impl.m_memo.for_each_block_in_reverse(iteration)) { + memo_slot_release(iteration.functor.get_slot()); return; } @@ -854,10 +860,7 @@ mtr_t::Command::finish_write( void mtr_t::Command::release_all() { - ReleaseAll release; - Iterate<ReleaseAll> iterator(release); - - m_impl->m_memo.for_each_block_in_reverse(iterator); + m_impl->m_memo.for_each_block_in_reverse(CIterate<ReleaseAll>()); /* Note that we have released the latches. */ m_locks_released = 1; @@ -867,10 +870,7 @@ mtr_t::Command::release_all() void mtr_t::Command::release_latches() { - ReleaseLatches release; - Iterate<ReleaseLatches> iterator(release); - - m_impl->m_memo.for_each_block_in_reverse(iterator); + m_impl->m_memo.for_each_block_in_reverse(CIterate<ReleaseLatches>()); /* Note that we have released the latches. */ m_locks_released = 1; @@ -880,10 +880,10 @@ mtr_t::Command::release_latches() void mtr_t::Command::release_blocks() { - ReleaseBlocks release(m_start_lsn, m_end_lsn, m_impl->m_flush_observer); - Iterate<ReleaseBlocks> iterator(release); - - m_impl->m_memo.for_each_block_in_reverse(iterator); + m_impl->m_memo.for_each_block_in_reverse( + CIterate<const ReleaseBlocks>( + ReleaseBlocks(m_start_lsn, m_end_lsn, + m_impl->m_flush_observer))); } /** Write the redo log record, add dirty pages to the flush list and release @@ -928,10 +928,8 @@ mtr_t::memo_contains( const void* object, ulint type) { - Find find(object, type); - Iterate<Find> iterator(find); - - if (memo->for_each_block_in_reverse(iterator)) { + Iterate<Find> iteration(Find(object, type)); + if (memo->for_each_block_in_reverse(iteration)) { return(false); } @@ -1020,10 +1018,8 @@ mtr_t::memo_contains_flagged(const void* ptr, ulint flags) const ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); ut_ad(is_committing() || is_active()); - FlaggedCheck check(ptr, flags); - Iterate<FlaggedCheck> iterator(check); - - return(!m_impl.m_memo.for_each_block_in_reverse(iterator)); + return !m_impl.m_memo.for_each_block_in_reverse( + CIterate<FlaggedCheck>(FlaggedCheck(ptr, flags))); } /** Check if memo contains the given page. @@ -1037,11 +1033,9 @@ mtr_t::memo_contains_page_flagged( const byte* ptr, ulint flags) const { - FindPage check(ptr, flags); - Iterate<FindPage> iterator(check); - - return(m_impl.m_memo.for_each_block_in_reverse(iterator) - ? NULL : check.get_block()); + Iterate<FindPage> iteration(FindPage(ptr, flags)); + return m_impl.m_memo.for_each_block_in_reverse(iteration) + ? NULL : iteration.functor.get_block(); } /** Mark the given latched page as modified. diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 8a8e4e6b4f0..6a8d1a559e8 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -1217,6 +1217,7 @@ int ha_maria::check(THD * thd, HA_CHECK_OPT * check_opt) if (!file || !param) return HA_ADMIN_INTERNAL_ERROR; + unmap_file(file); maria_chk_init(param); param->thd= thd; param->op_name= "check"; @@ -1437,6 +1438,7 @@ int ha_maria::zerofill(THD * thd, HA_CHECK_OPT *check_opt) if (!file || !param) return HA_ADMIN_INTERNAL_ERROR; + unmap_file(file); old_trn= file->trn; maria_chk_init(param); param->thd= thd; @@ -1535,6 +1537,7 @@ int ha_maria::repair(THD *thd, HA_CHECK *param, bool do_optimize) param->out_flag= 0; share->state.dupp_key= MI_MAX_KEY; strmov(fixed_name, share->open_file_name.str); + unmap_file(file); /* Don't lock tables if we have used LOCK TABLE or if we come from @@ -1714,7 +1717,6 @@ int ha_maria::assign_to_keycache(THD * thd, HA_CHECK_OPT *check_opt) TABLE_LIST *table_list= table->pos_in_table_list; DBUG_ENTER("ha_maria::assign_to_keycache"); - table->keys_in_use_for_query.clear_all(); if (table_list->process_index_hints(table)) @@ -2669,7 +2671,8 @@ int ha_maria::external_lock(THD *thd, int lock_type) } else { - TRN *trn= (file->trn != &dummy_transaction_object ? file->trn : 0); + /* We have to test for THD_TRN to protect against implicit commits */ + TRN *trn= (file->trn != &dummy_transaction_object && THD_TRN ? file->trn : 0); /* End of transaction */ /* diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c index 76dabebf065..32e1dc82a13 100644 --- a/storage/maria/ma_blockrec.c +++ b/storage/maria/ma_blockrec.c @@ -5244,6 +5244,8 @@ my_bool _ma_scan_init_block_record(MARIA_HA *info) { MARIA_SHARE *share= info->s; DBUG_ENTER("_ma_scan_init_block_record"); + DBUG_ASSERT(info->dfile.file == share->bitmap.file.file); + /* bitmap_buff may already be allocated if this is the second call to rnd_init() without a rnd_end() in between, see sql/handler.h diff --git a/storage/maria/ma_close.c b/storage/maria/ma_close.c index bd0a36c14c8..03501dc49cf 100644 --- a/storage/maria/ma_close.c +++ b/storage/maria/ma_close.c @@ -113,10 +113,7 @@ int maria_close(register MARIA_HA *info) if (flush_pagecache_blocks(share->pagecache, &share->kfile, share->deleting ? FLUSH_IGNORE_CHANGED : FLUSH_RELEASE)) error= my_errno; -#ifdef HAVE_MMAP - if (share->file_map) - _ma_unmap_file(info); -#endif + unmap_file(info); if (((share->changed && share->base.born_transactional) || maria_is_crashed(info) || (share->temporary && !share->deleting))) { diff --git a/storage/maria/ma_delete_all.c b/storage/maria/ma_delete_all.c index 1daf5f3ef80..c1019c01c66 100644 --- a/storage/maria/ma_delete_all.c +++ b/storage/maria/ma_delete_all.c @@ -38,6 +38,9 @@ int maria_delete_all_rows(MARIA_HA *info) MARIA_SHARE *share= info->s; my_bool log_record; LSN lsn; +#ifdef HAVE_MMAP + my_bool mmap_file= share->file_map != 0; +#endif DBUG_ENTER("maria_delete_all_rows"); if (share->options & HA_OPTION_READ_ONLY_DATA) @@ -95,7 +98,7 @@ int maria_delete_all_rows(MARIA_HA *info) */ #ifdef HAVE_MMAP - if (share->file_map) + if (mmap_file) _ma_unmap_file(info); #endif @@ -141,7 +144,7 @@ int maria_delete_all_rows(MARIA_HA *info) _ma_writeinfo(info, WRITEINFO_UPDATE_KEYFILE); #ifdef HAVE_MMAP /* Map again */ - if (share->file_map) + if (mmap_file) _ma_dynmap_file(info, (my_off_t) 0); #endif DBUG_RETURN(0); diff --git a/storage/maria/ma_packrec.c b/storage/maria/ma_packrec.c index 27c5538e51b..e2c1e353616 100644 --- a/storage/maria/ma_packrec.c +++ b/storage/maria/ma_packrec.c @@ -1564,8 +1564,13 @@ my_bool _ma_memmap_file(MARIA_HA *info) void _ma_unmap_file(MARIA_HA *info) { - my_munmap((char*) info->s->file_map, - (size_t) info->s->mmaped_length + MEMMAP_EXTRA_MARGIN); + MARIA_SHARE *share= info->s; + my_munmap((char*) share->file_map, + (size_t) share->mmaped_length + MEMMAP_EXTRA_MARGIN); + share->file_map= 0; + share->file_read= _ma_nommap_pread; + share->file_write= _ma_nommap_pwrite; + info->opt_flag&= ~MEMMAP_USED; } diff --git a/storage/maria/ma_pagecache.c b/storage/maria/ma_pagecache.c index e54a1440de9..f486d8c704f 100644 --- a/storage/maria/ma_pagecache.c +++ b/storage/maria/ma_pagecache.c @@ -3464,8 +3464,6 @@ restart: pagecache_pthread_mutex_lock(&pagecache->cache_lock); #endif } - if (status & PCBLOCK_ERROR) - my_errno= block->error; } remove_reader(block); @@ -3497,6 +3495,7 @@ restart: if (status & PCBLOCK_ERROR) { + my_errno= block->error; DBUG_ASSERT(my_errno != 0); DBUG_PRINT("error", ("Got error %d when doing page read", my_errno)); DBUG_RETURN((uchar *) 0); diff --git a/storage/maria/maria_def.h b/storage/maria/maria_def.h index 0061322e674..2f39c4dadef 100644 --- a/storage/maria/maria_def.h +++ b/storage/maria/maria_def.h @@ -1432,3 +1432,11 @@ extern my_bool ma_yield_and_check_if_killed(MARIA_HA *info, int inx); extern my_bool ma_killed_standalone(MARIA_HA *); extern uint _ma_file_callback_to_id(void *callback_data); + +static inline void unmap_file(MARIA_HA *info __attribute__((unused))) +{ +#ifdef HAVE_MMAP + if (info->s->file_map) + _ma_unmap_file(info); +#endif +} diff --git a/storage/rocksdb/ha_rocksdb.cc b/storage/rocksdb/ha_rocksdb.cc index ae04a061bf2..2837d31d37a 100644 --- a/storage/rocksdb/ha_rocksdb.cc +++ b/storage/rocksdb/ha_rocksdb.cc @@ -11029,6 +11029,41 @@ void ha_rocksdb::read_thd_vars(THD *const thd) { m_checksums_pct = THDVAR(thd, checksums_pct); } +ulonglong ha_rocksdb::table_flags() const +{ + DBUG_ENTER_FUNC(); + + /* + HA_BINLOG_STMT_CAPABLE + Upstream: MyRocks advertises itself as it supports SBR, but has additional + checks in ha_rocksdb::external_lock()/ start_stmt() which will return an + error if one tries to run the statement. + Exceptions: @@rocksdb_unsafe_for_binlog or we are an SQL slave thread. + + MariaDB: Inform the upper layer we don't support SBR, so it switches to RBR + if possible. The exceptions are the same as with the upstream. + + HA_REC_NOT_IN_SEQ + If we don't set it, filesort crashes, because it assumes rowids are + 1..8 byte numbers + HA_PRIMARY_KEY_IN_READ_INDEX + This flag is always set, even for tables that: + - have no PK + - have some (or all) of PK that can't be decoded from the secondary + index. + */ + THD *thd= ha_thd(); + DBUG_RETURN(HA_BINLOG_ROW_CAPABLE | + ((thd && (THDVAR(thd, unsafe_for_binlog) ||thd->rgi_slave))? + HA_BINLOG_STMT_CAPABLE : 0) | + HA_REC_NOT_IN_SEQ | HA_CAN_INDEX_BLOBS | + HA_PRIMARY_KEY_IN_READ_INDEX | + HA_PRIMARY_KEY_REQUIRED_FOR_POSITION | HA_NULL_IN_KEY | + HA_PARTIAL_COLUMN_READ | + HA_TABLE_SCAN_ON_INDEX); +} + + /** @return @@ -11041,6 +11076,9 @@ int ha_rocksdb::external_lock(THD *const thd, int lock_type) { DBUG_ASSERT(thd != nullptr); int res = HA_EXIT_SUCCESS; +#if 0 + // MariaDB uses a different way to implement this, see ha_rocksdb::table_flags + int binlog_format = my_core::thd_binlog_format(thd); bool unsafe_for_binlog = THDVAR(ha_thd(), unsafe_for_binlog); @@ -11069,6 +11107,7 @@ int ha_rocksdb::external_lock(THD *const thd, int lock_type) { my_error(ER_REQUIRE_ROW_BINLOG_FORMAT, MYF(0)); DBUG_RETURN(HA_ERR_UNSUPPORTED); } +#endif if (lock_type == F_UNLCK) { Rdb_transaction *const tx = get_tx_from_thd(thd); @@ -11171,20 +11210,6 @@ int ha_rocksdb::external_lock(THD *const thd, int lock_type) { int ha_rocksdb::start_stmt(THD *const thd, thr_lock_type lock_type) { DBUG_ENTER_FUNC(); - /* - MariaDB: the following is a copy of the check in ha_rocksdb::external_lock: - */ - int binlog_format = my_core::thd_binlog_format(thd); - bool unsafe_for_binlog = THDVAR(ha_thd(), unsafe_for_binlog); - if (lock_type >= TL_WRITE_ALLOW_WRITE && - !thd->rgi_slave && !unsafe_for_binlog && - binlog_format != BINLOG_FORMAT_ROW && - binlog_format != BINLOG_FORMAT_UNSPEC && - my_core::thd_binlog_filter_ok(thd)) { - my_error(ER_REQUIRE_ROW_BINLOG_FORMAT, MYF(0)); - DBUG_RETURN(HA_ERR_UNSUPPORTED); - } - DBUG_ASSERT(thd != nullptr); Rdb_transaction *const tx = get_or_create_tx(thd); diff --git a/storage/rocksdb/ha_rocksdb.h b/storage/rocksdb/ha_rocksdb.h index 152ab3fa7c8..c5a0afef275 100644 --- a/storage/rocksdb/ha_rocksdb.h +++ b/storage/rocksdb/ha_rocksdb.h @@ -863,31 +863,7 @@ public: This is a list of flags that indicate what functionality the storage engine implements. The current table flags are documented in handler.h */ - ulonglong table_flags() const override { - DBUG_ENTER_FUNC(); - - /* - HA_BINLOG_STMT_CAPABLE - We are saying that this engine is just statement capable to have - an engine that can only handle statement-based logging. This is - used in testing. - HA_REC_NOT_IN_SEQ - If we don't set it, filesort crashes, because it assumes rowids are - 1..8 byte numbers - HA_PRIMARY_KEY_IN_READ_INDEX - This flag is always set, even for tables that: - - have no PK - - have some (or all) of PK that can't be decoded from the secondary - index. - */ - DBUG_RETURN(HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | - HA_REC_NOT_IN_SEQ | HA_CAN_INDEX_BLOBS | - HA_PRIMARY_KEY_IN_READ_INDEX | - HA_PRIMARY_KEY_REQUIRED_FOR_POSITION | HA_NULL_IN_KEY | - HA_PARTIAL_COLUMN_READ | - HA_TABLE_SCAN_ON_INDEX); - } - + ulonglong table_flags() const override ; private: bool init_with_fields(); /* no 'override' in MariaDB */ public: diff --git a/storage/rocksdb/mysql-test/rocksdb/r/mariadb_misc_binlog.result b/storage/rocksdb/mysql-test/rocksdb/r/mariadb_misc_binlog.result index e4ac62aa481..c37ab9461af 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/mariadb_misc_binlog.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/mariadb_misc_binlog.result @@ -18,7 +18,16 @@ set @tmp_bf= @@binlog_format; set binlog_format='STATEMENT'; lock tables t1 write; insert into t1 values(1); -ERROR HY000: Can't execute updates on master with binlog_format != ROW. +ERROR HY000: Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging. unlock tables; set @@binlog_format=@tmp_bf; drop table t1; +# +# MDEV-17045: MyRocks tables cannot be updated when binlog_format=MIXED. +# +set @tmp_bf= @@binlog_format; +set binlog_format='MIXED'; +create table t1 (pk int primary key) engine=rocksdb; +insert into t1 values (1); +drop table t1; +set @@binlog_format=@tmp_bf; diff --git a/storage/rocksdb/mysql-test/rocksdb/r/rpl_statement.result b/storage/rocksdb/mysql-test/rocksdb/r/rpl_statement.result index cdf0c37e339..df1a60519db 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/rpl_statement.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/rpl_statement.result @@ -8,7 +8,7 @@ select @@binlog_format; STATEMENT create table t1 (pk int primary key) engine=rocksdb; insert into t1 values (1),(2),(3); -ERROR HY000: Can't execute updates on master with binlog_format != ROW. +ERROR HY000: Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging. set session rocksdb_unsafe_for_binlog=on; insert into t1 values (1),(2),(3); select * from t1; @@ -19,7 +19,7 @@ pk delete from t1; set session rocksdb_unsafe_for_binlog=off; insert into t1 values (1),(2),(3); -ERROR HY000: Can't execute updates on master with binlog_format != ROW. +ERROR HY000: Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging. set binlog_format=row; insert into t1 values (1),(2),(3); include/sync_slave_sql_with_master.inc diff --git a/storage/rocksdb/mysql-test/rocksdb/t/mariadb_misc_binlog.test b/storage/rocksdb/mysql-test/rocksdb/t/mariadb_misc_binlog.test index fb150f7a791..e32679e88a2 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/mariadb_misc_binlog.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/mariadb_misc_binlog.test @@ -21,10 +21,20 @@ unlock tables; set @tmp_bf= @@binlog_format; set binlog_format='STATEMENT'; lock tables t1 write; ---error ER_REQUIRE_ROW_BINLOG_FORMAT +--error ER_BINLOG_STMT_MODE_AND_ROW_ENGINE insert into t1 values(1); unlock tables; set @@binlog_format=@tmp_bf; drop table t1; +--echo # +--echo # MDEV-17045: MyRocks tables cannot be updated when binlog_format=MIXED. +--echo # +set @tmp_bf= @@binlog_format; +set binlog_format='MIXED'; +create table t1 (pk int primary key) engine=rocksdb; +insert into t1 values (1); +drop table t1; +set @@binlog_format=@tmp_bf; + diff --git a/storage/rocksdb/mysql-test/rocksdb/t/rpl_statement.test b/storage/rocksdb/mysql-test/rocksdb/t/rpl_statement.test index 29671308e9c..cb5f5e04b00 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/rpl_statement.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/rpl_statement.test @@ -12,7 +12,7 @@ connection master; select @@binlog_format; create table t1 (pk int primary key) engine=rocksdb; ---error ER_REQUIRE_ROW_BINLOG_FORMAT +--error ER_BINLOG_STMT_MODE_AND_ROW_ENGINE insert into t1 values (1),(2),(3); set session rocksdb_unsafe_for_binlog=on; @@ -21,7 +21,7 @@ select * from t1; delete from t1; set session rocksdb_unsafe_for_binlog=off; ---error ER_REQUIRE_ROW_BINLOG_FORMAT +--error ER_BINLOG_STMT_MODE_AND_ROW_ENGINE insert into t1 values (1),(2),(3); set binlog_format=row; |