[Commits] 6c85bd30543: Merge commit 10.3 'c1bc9480e73242b075178cb5da5713ba9d84be7c' into 10.4
revision-id: 6c85bd30543e38155a77ceb8328646fbe121fa6d (mariadb-10.4.4-92-g6c85bd30543) parent(s): 5cf4022340d73bfcb1650c139468d303355a5afe c0bc9480e73242b075178cb5da5713ba9d84be7c author: Oleksandr Byelkin committer: Oleksandr Byelkin timestamp: 2019-05-16 20:16:37 +0200 message: Merge commit 10.3 'c1bc9480e73242b075178cb5da5713ba9d84be7c' into 10.4 CMakeLists.txt | 12 +- README.md | 8 +- COPYING.thirdparty => THIRDPARTY | 0 client/mysql_plugin.c | 8 +- client/mysqldump.c | 68 ++-- client/mysqlimport.c | 2 +- include/my_pthread.h | 22 ++ include/my_sys.h | 3 +- include/my_tree.h | 2 +- include/my_valgrind.h | 2 +- mysql-test/include/ctype_like_escape.inc | 6 + mysql-test/lib/generate-ssl-certs.sh | 2 +- mysql-test/main/bootstrap.test | 9 + mysql-test/main/create_drop_binlog.result | 4 + mysql-test/main/create_drop_event.result | 5 + mysql-test/main/ctype_big5.result | 12 + mysql-test/main/ctype_euckr.result | 12 + mysql-test/main/ctype_gb2312.result | 12 + mysql-test/main/ctype_gbk.result | 12 + mysql-test/main/ctype_latin1.result | 12 + mysql-test/main/ctype_sjis.result | 12 + mysql-test/main/ctype_tis620.result | 12 + mysql-test/main/ctype_uca.result | 6 + mysql-test/main/ctype_ucs.result | 12 + mysql-test/main/ctype_ujis.result | 12 + mysql-test/main/ctype_utf16.result | 12 + mysql-test/main/ctype_utf16_uca.result | 6 + mysql-test/main/ctype_utf16le.result | 12 + mysql-test/main/ctype_utf32.result | 12 + mysql-test/main/ctype_utf32_uca.result | 6 + mysql-test/main/ctype_utf8.result | 12 + mysql-test/main/ctype_utf8mb4.result | 12 + mysql-test/main/ctype_utf8mb4_heap.result | 12 + mysql-test/main/ctype_utf8mb4_innodb.result | 12 + mysql-test/main/ctype_utf8mb4_myisam.result | 12 + mysql-test/main/ddl_i18n_koi8r.result | 8 + mysql-test/main/ddl_i18n_utf8.result | 8 + mysql-test/main/derived_cond_pushdown.result | 50 +++ mysql-test/main/derived_cond_pushdown.test | 14 + mysql-test/main/events_1.result | 68 ++++ mysql-test/main/events_2.result | 30 ++ mysql-test/main/events_bugs.result | 54 +++ mysql-test/main/events_grant.result | 10 + mysql-test/main/events_restart.result | 26 +- mysql-test/main/events_stress.test | 1 + mysql-test/main/events_trans.result | 9 + mysql-test/main/flush_logs_not_windows.result | 3 + mysql-test/main/flush_logs_not_windows.test | 13 + mysql-test/main/flush_read_lock.result | 2 + mysql-test/main/func_gconcat.result | 30 +- mysql-test/main/func_gconcat.test | 33 +- mysql-test/main/func_hybrid_type.result | 30 ++ mysql-test/main/func_hybrid_type.test | 20 ++ mysql-test/main/func_str.result | 38 ++ mysql-test/main/func_str.test | 36 ++ mysql-test/main/gis.result | 28 +- mysql-test/main/gis.test | 35 +- mysql-test/main/gis2.result | 38 -- mysql-test/main/gis2.test | 45 --- mysql-test/main/gis_notembedded.result | 45 +++ mysql-test/main/gis_notembedded.test | 24 ++ mysql-test/main/grant4.result | 21 ++ mysql-test/main/grant4.test | 31 +- mysql-test/main/information_schema_prepare.result | 4 + mysql-test/main/information_schema_prepare.test | 7 + mysql-test/main/lock_sync.result | 4 + mysql-test/main/mdev_19276.result | 11 + mysql-test/main/mdev_19276.test | 17 + mysql-test/main/multi_update.result | 23 ++ mysql-test/main/multi_update.test | 31 ++ ...lti_update2-master.opt => multi_update_big.opt} | 0 ...ulti_update2.result => multi_update_big.result} | 0 .../{multi_update2.test => multi_update_big.test} | 0 mysql-test/main/mysqldump-compat.result | 4 + mysql-test/main/mysqldump-compat.test | 13 + mysql-test/main/mysqldump.result | 16 + mysql-test/main/partition_innodb.result | 46 ++- mysql-test/main/partition_innodb.test | 25 ++ mysql-test/main/ps.result | 23 ++ mysql-test/main/ps.test | 16 + mysql-test/main/show_check.result | 4 + mysql-test/main/sp_notembedded.result | 2 + mysql-test/main/ssl_verify_ip.opt | 3 + mysql-test/main/ssl_verify_ip.result | 4 + mysql-test/main/ssl_verify_ip.test | 3 + mysql-test/main/stat_tables.result | 18 + mysql-test/main/stat_tables.test | 21 ++ mysql-test/main/stat_tables_innodb.result | 18 + mysql-test/main/statistics.result | 14 + mysql-test/main/statistics.test | 15 + mysql-test/main/status2.result | 4 +- mysql-test/main/status2.test | 4 +- mysql-test/main/table_value_constr.result | 397 +++++++++++++++++++++ mysql-test/main/table_value_constr.test | 193 ++++++++++ mysql-test/main/timezone2.result | 33 ++ mysql-test/main/timezone2.test | 31 ++ mysql-test/main/type_bit.result | 7 + mysql-test/main/type_bit.test | 9 + mysql-test/main/view_grant.result | 4 + mysql-test/main/view_grant.test | 5 + mysql-test/main/win.result | 89 +++++ mysql-test/main/win.test | 60 ++++ mysql-test/mysql-test-run.pl | 4 + mysql-test/std_data/serversan-cert.pem | 110 +++--- mysql-test/std_data/serversan-key.pem | 52 +-- mysql-test/suite.pm | 4 + mysql-test/suite/binlog/r/binlog_mdev717.result | 2 + mysql-test/suite/binlog/r/binlog_sql_mode.result | 2 + mysql-test/suite/compat/oracle/r/events.result | 2 + .../compat/oracle/r/table_value_constr.result | 321 +++++++++++++++++ .../suite/compat/oracle/t/table_value_constr.test | 151 ++++++++ .../suite/funcs_1/r/is_routines_embedded.result | 12 + mysql-test/suite/galera/r/galera_events.result | 2 + .../r/galera_parallel_autoinc_largetrx.result | 1 + .../r/galera_parallel_autoinc_manytrx.result | 37 +- .../galera/t/galera_parallel_autoinc_largetrx.test | 2 + .../galera/t/galera_parallel_autoinc_manytrx.test | 79 +++- .../suite/gcol/r/innodb_virtual_purge.result | 17 + mysql-test/suite/gcol/t/innodb_virtual_purge.test | 35 ++ mysql-test/suite/innodb/r/foreign-keys.result | 24 ++ mysql-test/suite/innodb/r/innodb-index.result | 27 ++ mysql-test/suite/innodb/r/innodb-truncate.result | 13 + .../innodb/r/innodb_skip_innodb_is_tables.result | 6 +- .../suite/innodb/r/instant_alter_crash.result | 5 +- mysql-test/suite/innodb/r/xa_debug.result | 1 + mysql-test/suite/innodb/t/foreign-keys.test | 32 ++ mysql-test/suite/innodb/t/innodb-index.test | 20 ++ mysql-test/suite/innodb/t/innodb-truncate.test | 19 + mysql-test/suite/innodb/t/instant_alter_crash.test | 5 +- mysql-test/suite/innodb/t/xa_debug.test | 1 + .../suite/perfschema/r/pfs_upgrade_event.result | 2 + mysql-test/suite/plugins/r/pam.result | 20 ++ mysql-test/suite/plugins/t/pam.test | 28 +- mysql-test/suite/rpl/r/kill_race_condition.result | 18 + .../suite/rpl/r/rpl_create_drop_event.result | 4 + mysql-test/suite/rpl/r/rpl_current_user.result | 2 + mysql-test/suite/rpl/r/rpl_events.result | 6 + mysql-test/suite/rpl/r/rpl_heartbeat_basic.result | 2 + mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result | 2 + mysql-test/suite/rpl/r/rpl_invoked_features.result | 4 + mysql-test/suite/rpl/r/rpl_killed_ddl.result | 2 + .../rpl/r/rpl_mixed_implicit_commit_binlog.result | 2 + .../rpl/r/rpl_row_implicit_commit_binlog.result | 2 + .../rpl/r/rpl_stm_implicit_commit_binlog.result | 2 + .../suite/rpl/r/rpl_tmp_table_and_DDL.result | 4 + mysql-test/suite/rpl/t/kill_race_condition.test | 28 ++ .../r/innodb_ft_result_cache_limit,32bit.rdiff | 11 + ....result => innodb_ft_result_cache_limit.result} | 0 .../r/innodb_ft_result_cache_limit_32.result | 7 - .../r/sysvars_innodb,32bit,xtradb.rdiff-disabled | 4 +- .../r/sysvars_innodb,xtradb.rdiff-disabled | 4 +- ...t_32.test => innodb_ft_result_cache_limit.test} | 2 +- .../t/innodb_ft_result_cache_limit_64.test | 9 - .../t/transaction_prealloc_size_bug27322.test | 9 +- mysys/my_fopen.c | 2 +- mysys/my_open.c | 9 +- mysys/my_static.c | 3 +- mysys/tree.c | 48 ++- pcre/AUTHORS | 6 +- pcre/ChangeLog | 43 +++ pcre/LICENCE | 10 +- pcre/NEWS | 10 + pcre/configure.ac | 10 +- pcre/pcre_compile.c | 18 +- pcre/pcre_jit_compile.c | 2 +- pcre/pcrecpp.cc | 64 +++- pcre/pcrecpp_unittest.cc | 34 +- pcre/pcregrep.c | 4 +- pcre/testdata/testinput1 | 15 + pcre/testdata/testinput2 | 3 + pcre/testdata/testinput4 | 3 + pcre/testdata/testoutput1 | 24 ++ pcre/testdata/testoutput2 | 4 + pcre/testdata/testoutput4 | 4 + plugin/auth_pam/auth_pam.c | 6 +- plugin/auth_pam/auth_pam_base.c | 5 +- plugin/auth_pam/auth_pam_common.c | 5 + plugin/auth_pam/auth_pam_tool.c | 3 +- scripts/maria_add_gis_sp.sql.in | 4 +- scripts/mysql_install_db.sh | 3 +- sql-common/client.c | 6 +- sql/events.cc | 6 + sql/field.cc | 2 +- sql/gen_win_tzname_data.ps1 | 11 + sql/ha_partition.cc | 41 +-- sql/ha_partition.h | 12 - sql/handler.cc | 97 ++++- sql/handler.h | 6 +- sql/item_func.h | 1 + sql/item_subselect.cc | 15 +- sql/item_subselect.h | 2 +- sql/item_sum.cc | 93 ++++- sql/item_sum.h | 8 +- sql/log.cc | 12 +- sql/log.h | 1 + sql/log_event.cc | 23 +- sql/log_event_old.cc | 19 +- sql/mysql_upgrade_service.cc | 3 +- sql/mysqld.cc | 53 ++- sql/mysqld.h | 22 +- sql/session_tracker.cc | 1 + sql/share/errmsg-utf8.txt | 4 +- sql/sp_head.cc | 2 +- sql/sql_acl.cc | 33 +- sql/sql_base.cc | 97 ++--- sql/sql_base.h | 17 +- sql/sql_class.h | 2 + sql/sql_db.cc | 22 +- sql/sql_db.h | 2 +- sql/sql_lex.cc | 22 +- sql/sql_lex.h | 8 +- sql/sql_parse.cc | 16 +- sql/sql_reload.cc | 7 - sql/sql_select.cc | 36 +- sql/sql_show.cc | 3 +- sql/sql_statistics.cc | 19 +- sql/sql_string.cc | 21 ++ sql/sql_table.cc | 208 ++++------- sql/sql_test.cc | 10 +- sql/sql_truncate.cc | 14 +- sql/sql_tvc.cc | 232 ++++++++++-- sql/sql_tvc.h | 5 + sql/sql_union.cc | 21 +- sql/sql_update.cc | 36 +- sql/sql_view.cc | 3 +- sql/sql_window.cc | 27 ++ sql/sql_yacc.yy | 32 +- sql/sql_yacc_ora.yy | 32 +- sql/table.cc | 3 +- sql/table.h | 1 + sql/win_tzname_data.h | 136 +++++++ storage/connect/filter.h | 1 + storage/connect/ha_connect.cc | 85 +++-- storage/connect/ha_connect.h | 3 +- storage/connect/jmgoconn.cpp | 4 +- storage/connect/tabdos.cpp | 42 ++- storage/connect/tabfmt.cpp | 13 +- storage/connect/user_connect.cc | 3 +- storage/connect/value.cpp | 97 +++-- storage/connect/value.h | 16 +- storage/innobase/buf/buf0dblwr.cc | 7 +- storage/innobase/dict/dict0stats.cc | 4 +- storage/innobase/fil/fil0fil.cc | 3 +- storage/innobase/fts/fts0config.cc | 9 +- storage/innobase/fts/fts0fts.cc | 46 +-- storage/innobase/fts/fts0opt.cc | 245 +++++-------- storage/innobase/fts/fts0que.cc | 4 +- storage/innobase/fts/fts0sql.cc | 103 +++--- storage/innobase/gis/gis0rtree.cc | 9 +- storage/innobase/handler/ha_innodb.cc | 4 + storage/innobase/handler/handler0alter.cc | 25 +- storage/innobase/include/fil0fil.h | 3 +- storage/innobase/include/fts0fts.h | 12 +- storage/innobase/include/fts0priv.h | 132 ++++--- storage/innobase/include/handler0alter.h | 11 +- storage/innobase/log/log0log.cc | 6 - storage/innobase/read/read0read.cc | 2 +- storage/innobase/row/row0ftsort.cc | 1 - storage/innobase/row/row0merge.cc | 4 +- storage/innobase/row/row0purge.cc | 8 + storage/innobase/srv/srv0mon.cc | 28 +- storage/innobase/ut/ut0timer.cc | 34 +- storage/maria/ha_maria.cc | 94 +---- storage/maria/ha_maria.h | 7 - storage/myisam/ha_myisam.cc | 7 +- storage/myisam/ha_myisam.h | 1 - storage/perfschema/pfs_timer.cc | 23 +- storage/perfschema/pfs_timer.h | 2 +- storage/perfschema/table_performance_timers.cc | 10 +- storage/perfschema/unittest/pfs_server_stubs.cc | 2 + storage/perfschema/unittest/pfs_timer-t.cc | 2 + .../rocksdb/r/innodb_i_s_tables_disabled.result | 344 ++++++++++++++++++ .../t/innodb_i_s_tables_disabled-master.opt | 30 ++ .../rocksdb/t/innodb_i_s_tables_disabled.test | 43 +++ storage/tokudb/.clang-format | 40 +++ storage/tokudb/ha_tokudb.cc | 28 +- storage/tokudb/ha_tokudb.h | 2 +- storage/tokudb/ha_tokudb_mrr_mysql.cc | 1 + .../mysql-test/rpl/r/rpl_tokudb_mixed_dml.result | 2 + .../tokudb/mysql-test/tokudb_bugs/r/PS-5158.result | 6 + .../tokudb/mysql-test/tokudb_bugs/r/PS-5163.result | 5 + .../mysql-test/tokudb_bugs/t/PS-5158-master.opt | 2 + .../tokudb/mysql-test/tokudb_bugs/t/PS-5158.test | 27 ++ .../tokudb/mysql-test/tokudb_bugs/t/PS-5163.test | 11 + support-files/rpm/server-postin.sh | 2 +- support-files/rpm/server-posttrans.sh | 1 + 286 files changed, 5496 insertions(+), 1470 deletions(-) diff --cc README.md index 8d4a6e7cfab,053831e4cd7..f643ac40e95 --- a/README.md +++ b/README.md @@@ -44,16 -44,9 +44,16 @@@ More help is available from the Maria D https://launchpad.net/~maria-discuss and the #maria IRC channel on Freenode. +Live QA for beginner contributors +---- +MariaDB has a dedicated time each week when we answer new contributor questions live on Zulip and IRC. +From 8:00 to 10:00 UTC on Mondays, and 10:00 to 12:00 UTC on Thursdays, +anyone can ask any questions they’d like, and a live developer will be available to assist. + +New contributors can ask questions any time, but we will provide immediate feedback during that interval. - License - -------- + Licensing: + ---------- *************************************************************************** diff --cc client/mysqlimport.c index 977e0e6ca1e,e54ed4a87df..e9bc97a58fc --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@@ -502,8 -514,11 +502,8 @@@ static void safe_exit(int error, MYSQL if (mysql) mysql_close(mysql); - free_defaults(argv_to_free); mysql_library_end(); -#ifdef HAVE_SMEM - my_free(shared_memory_base_name); -#endif + free_defaults(argv_to_free); my_free(opt_password); if (error) sf_leaking_memory= 1; /* dirty exit, some threads are still running */ diff --cc mysql-test/main/bootstrap.test index d75be403f13,97f5da86096..e9f45f85c85 --- a/mysql-test/main/bootstrap.test +++ b/mysql-test/main/bootstrap.test @@@ -65,11 -62,18 +65,20 @@@ SELECT 'bug' as '' FROM INFORMATION_SCH # # MDEV-13063 Server crashes in intern_plugin_lock or assertion `plugin_ptr->ref_count == 1' fails in plugin_init # +--source include/kill_mysqld.inc --error 1 --exec $MYSQLD_BOOTSTRAP_CMD --myisam_recover_options=NONE +--source include/start_mysqld.inc + # + # MDEV-19349 mysql_install_db: segfault at tmp_file_prefix check + # + --write_file $MYSQLTEST_VARDIR/tmp/1 + use test; + EOF + --exec $MYSQLD_BOOTSTRAP_CMD < $MYSQLTEST_VARDIR/tmp/1 >> $MYSQLTEST_VARDIR/tmp/bootstrap.log 2>&1 + --remove_file $MYSQLTEST_VARDIR/tmp/1 + --echo End of 5.5 tests --source include/not_windows_embedded.inc diff --cc mysql-test/main/func_hybrid_type.result index 91f3949d456,c7ec29f1a49..664a872cf4c --- a/mysql-test/main/func_hybrid_type.result +++ b/mysql-test/main/func_hybrid_type.result @@@ -3448,6 -3448,36 +3448,36 @@@ t1 CREATE TABLE `t1` ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; # + # MDEV-11015 Assertion failed: precision > 0 in decimal_bin_size upon SELECT with DISTINCT, CAST and other functions + # + CREATE TABLE t1 (b LONGBLOB); + INSERT IGNORE INTO t1 VALUES ('foo'),('bar'); + SELECT DISTINCT - GREATEST( b, CAST( NULL AS DATETIME ) ) AS f FROM t1; + f + NULL + Warnings: -Warning 1292 Incorrect datetime value: 'foo' -Warning 1292 Incorrect datetime value: 'bar' ++Warning 1292 Truncated incorrect datetime value: 'foo' ++Warning 1292 Truncated incorrect datetime value: 'bar' + DROP TABLE t1; + CREATE TABLE t1 (b LONGBLOB); + INSERT IGNORE INTO t1 VALUES ('foo'),('bar'); + SELECT DISTINCT - GREATEST( b, CAST( NULL AS TIME) ) AS f FROM t1; + f + NULL + Warnings: -Warning 1292 Truncated incorrect time value: 'foo' -Warning 1292 Truncated incorrect time value: 'bar' ++Warning 1292 Incorrect time value: 'foo' ++Warning 1292 Incorrect time value: 'bar' + DROP TABLE t1; + CREATE TABLE t1 (b LONGBLOB); + INSERT IGNORE INTO t1 VALUES ('foo'),('bar'); + SELECT DISTINCT - GREATEST( b, CAST( NULL AS DATE) ) AS f FROM t1; + f + NULL + Warnings: -Warning 1292 Incorrect datetime value: 'foo' -Warning 1292 Incorrect datetime value: 'bar' ++Warning 1292 Truncated incorrect datetime value: 'foo' ++Warning 1292 Truncated incorrect datetime value: 'bar' + DROP TABLE t1; + # # End of 10.1 tests # # diff --cc mysql-test/main/partition_innodb.result index 605ac38384e,f3d24347ff9..cf1248663e4 --- a/mysql-test/main/partition_innodb.result +++ b/mysql-test/main/partition_innodb.result @@@ -417,11 -408,11 +417,11 @@@ t1 InnoDB 10 Dynamic 2 8192 16384 0 0 insert into t1 values (NULL), (NULL), (NULL), (NULL); show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary --t1 InnoDB 10 Dynamic 4 4096 16384 0 0 # 5 # NULL NULL latin1_swedish_ci NULL partitioned 0 N ++t1 InnoDB 10 Dynamic 5 3276 16384 0 0 # 5 # NULL NULL latin1_swedish_ci NULL partitioned 0 N insert into t1 values (NULL), (NULL), (NULL), (NULL); show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary --t1 InnoDB 10 Dynamic 8 2048 16384 0 0 # 9 # NULL NULL latin1_swedish_ci NULL partitioned 0 N ++t1 InnoDB 10 Dynamic 9 1820 16384 0 0 # 9 # NULL NULL latin1_swedish_ci NULL partitioned 0 N drop table t1; create table t1 (a int) partition by key (a) diff --cc mysql-test/main/timezone2.result index dd137045d1a,c4d13f6c678..cf3c6e01e25 --- a/mysql-test/main/timezone2.result +++ b/mysql-test/main/timezone2.result @@@ -333,227 -333,35 +333,260 @@@ NUL # End of 5.3 tests # # + # Start of 10.1 tests + # + # + # MDEV-11895 NO_ZERO_DATE affects timestamp values without any warnings + # + SET sql_mode = ''; + CREATE TABLE t1 (a TIMESTAMP NULL) ENGINE = MyISAM; + CREATE TABLE t2 (a TIMESTAMP NULL) ENGINE = MyISAM; + CREATE TABLE t3 (a TIMESTAMP NULL) ENGINE = MyISAM; + SET @@session.time_zone = 'UTC'; + INSERT INTO t1 VALUES ('2011-10-29 23:00:00'); + INSERT INTO t1 VALUES ('2011-10-29 23:00:01'); + INSERT INTO t1 VALUES ('2011-10-29 23:59:59'); + SET @@session.time_zone = 'Europe/Moscow'; + SET sql_mode='NO_ZERO_DATE'; + INSERT INTO t2 SELECT * FROM t1; + SET sql_mode=''; + INSERT INTO t3 SELECT * FROM t1; + SELECT UNIX_TIMESTAMP(a), a FROM t2; + UNIX_TIMESTAMP(a) a + 1319929200 2011-10-30 02:00:00 + 1319929201 2011-10-30 02:00:01 + 1319932799 2011-10-30 02:59:59 + SELECT UNIX_TIMESTAMP(a), a FROM t3; + UNIX_TIMESTAMP(a) a + 1319929200 2011-10-30 02:00:00 + 1319929201 2011-10-30 02:00:01 + 1319932799 2011-10-30 02:59:59 + DROP TABLE t1, t2, t3; + # + # End of 10.1 tests + # ++# +# Start of 10.4 tests +# +# +# MDEV-17203 Move fractional second truncation from Item_xxx_typecast::get_date() to Time and Datetime constructors +# (an addition for the test for MDEV-4653) +SET timestamp=unix_timestamp('2001-02-03 10:20:30'); +SET old_mode=ZERO_DATE_TIME_CAST; +SELECT CONVERT_TZ(TIME('00:00:00'),'+00:00','+7:5'); +CONVERT_TZ(TIME('00:00:00'),'+00:00','+7:5') +NULL +Warnings: +Warning 1292 Truncated incorrect datetime value: '00:00:00' +SELECT CONVERT_TZ(TIME('2010-01-01 00:00:00'),'+00:00','+7:5'); +CONVERT_TZ(TIME('2010-01-01 00:00:00'),'+00:00','+7:5') +NULL +Warnings: +Warning 1292 Truncated incorrect datetime value: '00:00:00' +SET old_mode=DEFAULT; +SET timestamp=DEFAULT; +# +# MDEV-13995 MAX(timestamp) returns a wrong result near DST change +# +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526) /*summer time in Moscow*/); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526+3599) /*winter time in Moscow*/); +SET time_zone='Europe/Moscow'; +SELECT a, UNIX_TIMESTAMP(a) FROM t1; +a UNIX_TIMESTAMP(a) +2010-10-31 02:25:26 1288477526 +2010-10-31 02:25:25 1288481125 +SELECT UNIX_TIMESTAMP(MAX(a)) AS a FROM t1; +a +1288481125 +CREATE TABLE t2 (a TIMESTAMP); +INSERT INTO t2 SELECT MAX(a) AS a FROM t1; +SELECT a, UNIX_TIMESTAMP(a) FROM t2; +a UNIX_TIMESTAMP(a) +2010-10-31 02:25:25 1288481125 +DROP TABLE t2; +DROP TABLE t1; +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP); +CREATE TABLE t2 (a TIMESTAMP); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526) /*summer time in Moscow*/); +INSERT INTO t2 VALUES (FROM_UNIXTIME(1288477526+3599) /*winter time in Moscow*/); +SET time_zone='Europe/Moscow'; +SELECT UNIX_TIMESTAMP(t1.a), UNIX_TIMESTAMP(t2.a) FROM t1,t2; +UNIX_TIMESTAMP(t1.a) UNIX_TIMESTAMP(t2.a) +1288477526 1288481125 +SELECT * FROM t1,t2 WHERE t1.a < t2.a; +a a +2010-10-31 02:25:26 2010-10-31 02:25:25 +DROP TABLE t1,t2; +BEGIN NOT ATOMIC +DECLARE a,b TIMESTAMP; +SET time_zone='+00:00'; +SET a=FROM_UNIXTIME(1288477526); +SET b=FROM_UNIXTIME(1288481125); +SELECT a < b; +SET time_zone='Europe/Moscow'; +SELECT a < b; +END; +$$ +a < b +1 +a < b +1 +CREATE OR REPLACE FUNCTION f1(uts INT) RETURNS TIMESTAMP +BEGIN +DECLARE ts TIMESTAMP; +DECLARE tz VARCHAR(64) DEFAULT @@time_zone; +SET time_zone='+00:00'; +SET ts=FROM_UNIXTIME(uts); +SET time_zone=tz; +RETURN ts; +END; +$$ +SET time_zone='+00:00'; +SELECT f1(1288477526) < f1(1288481125); +f1(1288477526) < f1(1288481125) +1 +SET time_zone='Europe/Moscow'; +SELECT f1(1288477526) < f1(1288481125); +f1(1288477526) < f1(1288481125) +1 +DROP FUNCTION f1; +CREATE TABLE t1 (a TIMESTAMP,b TIMESTAMP); +SET time_zone='+00:00'; +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526) /*summer time in Mowcow*/, +FROM_UNIXTIME(1288481125) /*winter time in Moscow*/); +SELECT *, LEAST(a,b) FROM t1; +a b LEAST(a,b) +2010-10-30 22:25:26 2010-10-30 23:25:25 2010-10-30 22:25:26 +SET time_zone='Europe/Moscow'; +SELECT *, LEAST(a,b) FROM t1; +a b LEAST(a,b) +2010-10-31 02:25:26 2010-10-31 02:25:25 2010-10-31 02:25:26 +SELECT UNIX_TIMESTAMP(a), UNIX_TIMESTAMP(b), UNIX_TIMESTAMP(LEAST(a,b)) FROM t1; +UNIX_TIMESTAMP(a) UNIX_TIMESTAMP(b) UNIX_TIMESTAMP(LEAST(a,b)) +1288477526 1288481125 1288477526 +DROP TABLE t1; +CREATE TABLE t1 (a TIMESTAMP,b TIMESTAMP,c TIMESTAMP); +SET time_zone='+00:00'; +INSERT INTO t1 VALUES ( +FROM_UNIXTIME(1288477526) /*summer time in Moscow*/, +FROM_UNIXTIME(1288481125) /*winter time in Moscow*/, +FROM_UNIXTIME(1288481126) /*winter time in Moscow*/); +SELECT b BETWEEN a AND c FROM t1; +b BETWEEN a AND c +1 +SET time_zone='Europe/Moscow'; +SELECT b BETWEEN a AND c FROM t1; +b BETWEEN a AND c +1 +DROP TABLE t1; +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526) /*summer time in Mowcow*/); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288481125) /*winter time in Moscow*/); +SELECT a, UNIX_TIMESTAMP(a) FROM t1 ORDER BY a; +a UNIX_TIMESTAMP(a) +2010-10-30 22:25:26 1288477526 +2010-10-30 23:25:25 1288481125 +SELECT COALESCE(a) AS a, UNIX_TIMESTAMP(a) FROM t1 ORDER BY a; +a UNIX_TIMESTAMP(a) +2010-10-30 22:25:26 1288477526 +2010-10-30 23:25:25 1288481125 +SET time_zone='Europe/Moscow'; +SELECT a, UNIX_TIMESTAMP(a) FROM t1 ORDER BY a; +a UNIX_TIMESTAMP(a) +2010-10-31 02:25:26 1288477526 +2010-10-31 02:25:25 1288481125 +SELECT COALESCE(a) AS a, UNIX_TIMESTAMP(a) FROM t1 ORDER BY a; +a UNIX_TIMESTAMP(a) +2010-10-31 02:25:26 1288477526 +2010-10-31 02:25:25 1288481125 +DROP TABLE t1; +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526) /*summer time in Mowcow*/); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288481126) /*winter time in Moscow*/); +SET time_zone='Europe/Moscow'; +SELECT a, UNIX_TIMESTAMP(a) FROM t1 GROUP BY a; +a UNIX_TIMESTAMP(a) +2010-10-31 02:25:26 1288477526 +2010-10-31 02:25:26 1288481126 +DROP TABLE t1; +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP, b TIMESTAMP); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526),FROM_UNIXTIME(1288481126)); +SELECT UNIX_TIMESTAMP(a),UNIX_TIMESTAMP(b),CASE a WHEN b THEN 'eq' ELSE 'ne' END AS x FROM t1; +UNIX_TIMESTAMP(a) UNIX_TIMESTAMP(b) x +1288477526 1288481126 ne +SET time_zone='Europe/Moscow'; +SELECT UNIX_TIMESTAMP(a),UNIX_TIMESTAMP(b),CASE a WHEN b THEN 'eq' ELSE 'ne' END AS x FROM t1; +UNIX_TIMESTAMP(a) UNIX_TIMESTAMP(b) x +1288477526 1288481126 ne +DROP TABLE t1; +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP, b TIMESTAMP,c TIMESTAMP); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526),FROM_UNIXTIME(1288481126),FROM_UNIXTIME(1288481127)); +SELECT UNIX_TIMESTAMP(a),UNIX_TIMESTAMP(b),a IN (b,c) AS x FROM t1; +UNIX_TIMESTAMP(a) UNIX_TIMESTAMP(b) x +1288477526 1288481126 0 +SET time_zone='Europe/Moscow'; +SELECT UNIX_TIMESTAMP(a),UNIX_TIMESTAMP(b),a IN (b,c) AS x FROM t1; +UNIX_TIMESTAMP(a) UNIX_TIMESTAMP(b) x +1288477526 1288481126 0 +DROP TABLE t1; +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP, b TIMESTAMP); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526),FROM_UNIXTIME(1288481126)); +SELECT * FROM t1 WHERE a = (SELECT MAX(b) FROM t1); +a b +SELECT * FROM t1 WHERE a = (SELECT MIN(b) FROM t1); +a b +SELECT * FROM t1 WHERE a IN ((SELECT MAX(b) FROM t1), (SELECT MIN(b) FROM t1)); +a b +SET time_zone='Europe/Moscow'; +SELECT * FROM t1 WHERE a = (SELECT MAX(b) FROM t1); +a b +SELECT * FROM t1 WHERE a = (SELECT MIN(b) FROM t1); +a b +SELECT * FROM t1 WHERE a IN ((SELECT MAX(b) FROM t1), (SELECT MIN(b) FROM t1)); +a b +DROP TABLE t1; +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP, b TIMESTAMP); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1100000000),FROM_UNIXTIME(1200000000)); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1100000001),FROM_UNIXTIME(1200000001)); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526),FROM_UNIXTIME(1288481126)); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1300000000),FROM_UNIXTIME(1400000000)); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1300000001),FROM_UNIXTIME(1400000001)); +SELECT * FROM t1 WHERE a = (SELECT MAX(b) FROM t1); +a b +SELECT * FROM t1 WHERE a = (SELECT MIN(b) FROM t1); +a b +SELECT * FROM t1 WHERE a IN ((SELECT MAX(b) FROM t1), (SELECT MIN(b) FROM t1)); +a b +SET time_zone='Europe/Moscow'; +SELECT * FROM t1 WHERE a = (SELECT MAX(b) FROM t1); +a b +SELECT * FROM t1 WHERE a = (SELECT MIN(b) FROM t1); +a b +SELECT * FROM t1 WHERE a IN ((SELECT MAX(b) FROM t1), (SELECT MIN(b) FROM t1)); +a b +DROP TABLE t1; +# +# MDEV-17979 Assertion `0' failed in Item::val_native upon SELECT with timestamp, NULLIF, GROUP BY +# +SET time_zone='+00:00'; +CREATE TABLE t1 (a INT, ts TIMESTAMP) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1, FROM_UNIXTIME(1288481126) /*winter time in Moscow*/); +SET time_zone='Europe/Moscow'; +CREATE TABLE t2 AS SELECT ts, COALESCE(ts) AS cts FROM t1 GROUP BY cts; +SELECT ts, cts, UNIX_TIMESTAMP(ts) AS uts, UNIX_TIMESTAMP(cts) AS ucts FROM t2; +ts cts uts ucts +2010-10-31 02:25:26 2010-10-31 02:25:26 1288481126 1288481126 +DROP TABLE t1,t2; +SET time_zone=DEFAULT; +# +# End of 10.4 tests +# diff --cc mysql-test/main/timezone2.test index db515653651,1e5615502da..e945923da7a --- a/mysql-test/main/timezone2.test +++ b/mysql-test/main/timezone2.test @@@ -309,200 -309,33 +309,231 @@@ SELECT CONVERT_TZ('2001-10-08 00:00:00' --echo # End of 5.3 tests --echo # + --echo # + --echo # Start of 10.1 tests + --echo # + + --echo # + --echo # MDEV-11895 NO_ZERO_DATE affects timestamp values without any warnings + --echo # + + SET sql_mode = ''; + CREATE TABLE t1 (a TIMESTAMP NULL) ENGINE = MyISAM; + CREATE TABLE t2 (a TIMESTAMP NULL) ENGINE = MyISAM; + CREATE TABLE t3 (a TIMESTAMP NULL) ENGINE = MyISAM; + + SET @@session.time_zone = 'UTC'; + INSERT INTO t1 VALUES ('2011-10-29 23:00:00'); + INSERT INTO t1 VALUES ('2011-10-29 23:00:01'); + INSERT INTO t1 VALUES ('2011-10-29 23:59:59'); + + SET @@session.time_zone = 'Europe/Moscow'; + SET sql_mode='NO_ZERO_DATE'; + INSERT INTO t2 SELECT * FROM t1; + SET sql_mode=''; + INSERT INTO t3 SELECT * FROM t1; + SELECT UNIX_TIMESTAMP(a), a FROM t2; + SELECT UNIX_TIMESTAMP(a), a FROM t3; + DROP TABLE t1, t2, t3; + + --echo # + --echo # End of 10.1 tests + --echo # ++ +--echo # +--echo # Start of 10.4 tests +--echo # + +--echo # +--echo # MDEV-17203 Move fractional second truncation from Item_xxx_typecast::get_date() to Time and Datetime constructors +--echo # (an addition for the test for MDEV-4653) + +SET timestamp=unix_timestamp('2001-02-03 10:20:30'); +SET old_mode=ZERO_DATE_TIME_CAST; +SELECT CONVERT_TZ(TIME('00:00:00'),'+00:00','+7:5'); +SELECT CONVERT_TZ(TIME('2010-01-01 00:00:00'),'+00:00','+7:5'); +SET old_mode=DEFAULT; +SET timestamp=DEFAULT; + +--echo # +--echo # MDEV-13995 MAX(timestamp) returns a wrong result near DST change +--echo # + +# MAX() +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526) /*summer time in Moscow*/); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526+3599) /*winter time in Moscow*/); +SET time_zone='Europe/Moscow'; +SELECT a, UNIX_TIMESTAMP(a) FROM t1; +SELECT UNIX_TIMESTAMP(MAX(a)) AS a FROM t1; +CREATE TABLE t2 (a TIMESTAMP); +INSERT INTO t2 SELECT MAX(a) AS a FROM t1; +SELECT a, UNIX_TIMESTAMP(a) FROM t2; +DROP TABLE t2; +DROP TABLE t1; + + +# Comparison +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP); +CREATE TABLE t2 (a TIMESTAMP); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526) /*summer time in Moscow*/); +INSERT INTO t2 VALUES (FROM_UNIXTIME(1288477526+3599) /*winter time in Moscow*/); +SET time_zone='Europe/Moscow'; +SELECT UNIX_TIMESTAMP(t1.a), UNIX_TIMESTAMP(t2.a) FROM t1,t2; +SELECT * FROM t1,t2 WHERE t1.a < t2.a; +DROP TABLE t1,t2; + + +# SP variable comparison +DELIMITER $$; +BEGIN NOT ATOMIC + DECLARE a,b TIMESTAMP; + SET time_zone='+00:00'; + SET a=FROM_UNIXTIME(1288477526); + SET b=FROM_UNIXTIME(1288481125); + SELECT a < b; + SET time_zone='Europe/Moscow'; + SELECT a < b; +END; +$$ +DELIMITER ;$$ + + +# SP function comparison +DELIMITER $$; +CREATE OR REPLACE FUNCTION f1(uts INT) RETURNS TIMESTAMP +BEGIN + DECLARE ts TIMESTAMP; + DECLARE tz VARCHAR(64) DEFAULT @@time_zone; + SET time_zone='+00:00'; + SET ts=FROM_UNIXTIME(uts); + SET time_zone=tz; + RETURN ts; +END; +$$ +DELIMITER ;$$ +SET time_zone='+00:00'; +SELECT f1(1288477526) < f1(1288481125); +SET time_zone='Europe/Moscow'; +SELECT f1(1288477526) < f1(1288481125); +DROP FUNCTION f1; + + +# LEAST() +CREATE TABLE t1 (a TIMESTAMP,b TIMESTAMP); +SET time_zone='+00:00'; +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526) /*summer time in Mowcow*/, + FROM_UNIXTIME(1288481125) /*winter time in Moscow*/); +SELECT *, LEAST(a,b) FROM t1; +SET time_zone='Europe/Moscow'; +SELECT *, LEAST(a,b) FROM t1; +SELECT UNIX_TIMESTAMP(a), UNIX_TIMESTAMP(b), UNIX_TIMESTAMP(LEAST(a,b)) FROM t1; +DROP TABLE t1; + + +# BETWEEN +CREATE TABLE t1 (a TIMESTAMP,b TIMESTAMP,c TIMESTAMP); +SET time_zone='+00:00'; +INSERT INTO t1 VALUES ( + FROM_UNIXTIME(1288477526) /*summer time in Moscow*/, + FROM_UNIXTIME(1288481125) /*winter time in Moscow*/, + FROM_UNIXTIME(1288481126) /*winter time in Moscow*/); +SELECT b BETWEEN a AND c FROM t1; +SET time_zone='Europe/Moscow'; +SELECT b BETWEEN a AND c FROM t1; +DROP TABLE t1; + + +# ORDER BY +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526) /*summer time in Mowcow*/); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288481125) /*winter time in Moscow*/); +SELECT a, UNIX_TIMESTAMP(a) FROM t1 ORDER BY a; +SELECT COALESCE(a) AS a, UNIX_TIMESTAMP(a) FROM t1 ORDER BY a; +SET time_zone='Europe/Moscow'; +SELECT a, UNIX_TIMESTAMP(a) FROM t1 ORDER BY a; +SELECT COALESCE(a) AS a, UNIX_TIMESTAMP(a) FROM t1 ORDER BY a; +DROP TABLE t1; + + +# GROUP BY +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526) /*summer time in Mowcow*/); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288481126) /*winter time in Moscow*/); +SET time_zone='Europe/Moscow'; +SELECT a, UNIX_TIMESTAMP(a) FROM t1 GROUP BY a; +DROP TABLE t1; + + +# CASE +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP, b TIMESTAMP); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526),FROM_UNIXTIME(1288481126)); +SELECT UNIX_TIMESTAMP(a),UNIX_TIMESTAMP(b),CASE a WHEN b THEN 'eq' ELSE 'ne' END AS x FROM t1; +SET time_zone='Europe/Moscow'; +SELECT UNIX_TIMESTAMP(a),UNIX_TIMESTAMP(b),CASE a WHEN b THEN 'eq' ELSE 'ne' END AS x FROM t1; +DROP TABLE t1; + + +# IN +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP, b TIMESTAMP,c TIMESTAMP); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526),FROM_UNIXTIME(1288481126),FROM_UNIXTIME(1288481127)); +SELECT UNIX_TIMESTAMP(a),UNIX_TIMESTAMP(b),a IN (b,c) AS x FROM t1; +SET time_zone='Europe/Moscow'; +SELECT UNIX_TIMESTAMP(a),UNIX_TIMESTAMP(b),a IN (b,c) AS x FROM t1; +DROP TABLE t1; + +# Comparison and IN in combination with a subquery (with one row) + +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP, b TIMESTAMP); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526),FROM_UNIXTIME(1288481126)); +SELECT * FROM t1 WHERE a = (SELECT MAX(b) FROM t1); +SELECT * FROM t1 WHERE a = (SELECT MIN(b) FROM t1); +SELECT * FROM t1 WHERE a IN ((SELECT MAX(b) FROM t1), (SELECT MIN(b) FROM t1)); + +SET time_zone='Europe/Moscow'; +SELECT * FROM t1 WHERE a = (SELECT MAX(b) FROM t1); +SELECT * FROM t1 WHERE a = (SELECT MIN(b) FROM t1); +SELECT * FROM t1 WHERE a IN ((SELECT MAX(b) FROM t1), (SELECT MIN(b) FROM t1)); +DROP TABLE t1; + +# Comparison and IN in combinarion with a subquery (with multiple rows) +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP, b TIMESTAMP); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1100000000),FROM_UNIXTIME(1200000000)); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1100000001),FROM_UNIXTIME(1200000001)); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1288477526),FROM_UNIXTIME(1288481126)); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1300000000),FROM_UNIXTIME(1400000000)); +INSERT INTO t1 VALUES (FROM_UNIXTIME(1300000001),FROM_UNIXTIME(1400000001)); +SELECT * FROM t1 WHERE a = (SELECT MAX(b) FROM t1); +SELECT * FROM t1 WHERE a = (SELECT MIN(b) FROM t1); +SELECT * FROM t1 WHERE a IN ((SELECT MAX(b) FROM t1), (SELECT MIN(b) FROM t1)); + +SET time_zone='Europe/Moscow'; +SELECT * FROM t1 WHERE a = (SELECT MAX(b) FROM t1); +SELECT * FROM t1 WHERE a = (SELECT MIN(b) FROM t1); +SELECT * FROM t1 WHERE a IN ((SELECT MAX(b) FROM t1), (SELECT MIN(b) FROM t1)); +DROP TABLE t1; + +--echo # +--echo # MDEV-17979 Assertion `0' failed in Item::val_native upon SELECT with timestamp, NULLIF, GROUP BY +--echo # + +SET time_zone='+00:00'; +CREATE TABLE t1 (a INT, ts TIMESTAMP) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1, FROM_UNIXTIME(1288481126) /*winter time in Moscow*/); +SET time_zone='Europe/Moscow'; +CREATE TABLE t2 AS SELECT ts, COALESCE(ts) AS cts FROM t1 GROUP BY cts; +SELECT ts, cts, UNIX_TIMESTAMP(ts) AS uts, UNIX_TIMESTAMP(cts) AS ucts FROM t2; +DROP TABLE t1,t2; +SET time_zone=DEFAULT; + +--echo # +--echo # End of 10.4 tests +--echo # diff --cc mysql-test/suite/funcs_1/r/is_routines_embedded.result index ec375e9c5f6,ec68057eaa1..1ac3651f254 --- a/mysql-test/suite/funcs_1/r/is_routines_embedded.result +++ b/mysql-test/suite/funcs_1/r/is_routines_embedded.result @@@ -197,8 -197,12 +197,12 @@@ sp_6_408002_2 def db_datadict_2 sp_6_40 SELECT * FROM db_datadict_2.res_6_408002_2; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost latin1 latin1_swedish_ci latin1_swedish_ci add_suppression def mtr add_suppression PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN INSERT INTO test_suppressions (pattern) VALUES (pattern); FLUSH NO_WRITE_TO_BINLOG TABLE test_suppressions; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci -check_testcase def mtr check_testcase PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE variable_name NOT IN ('timestamp') AND variable_name not like "Last_IO_Err*" AND variable_name != 'INNODB_IBUF_MAX_SIZE' AND variable_name != 'INNODB_USE_NATIVE_AIO' AND variable_name != 'INNODB_BUFFER_POOL_LOAD_AT_STARTUP' AND variable_name not like 'GTID%POS' AND variable_name != 'GTID_BINLOG_STATE' ORDER BY variable_name; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA ORDER BY BINARY SCHEMA_NAME; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mtr_wsrep_notify', 'wsrep_schema') ORDER BY BINARY SCHEMA_NAME; SELECT table_name AS tables_in_test FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='test'; SELECT CONCAT(table_schema, '.', table_name) AS tables_in_mysql FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='mysql' ORDE R BY tables_in_mysql; SELECT CONCAT(table_schema, '.', table_name) AS columns_in_mysql, column_name, ordinal_position, column_default, is_nullable, data_type, character_maximum_length, character_octet_length, numeric_precision, numeric_scale, character_set_name, collation_name, column_type, column_key, extra, column_comment FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='mysql' ORDER BY columns_in_mysql; SELECT * FROM INFORMATION_SCHEMA.EVENTS; SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME NOT IN ('gs_insert', 'ts_insert'); SELECT * FROM INFORMATION_SCHEMA.ROUTINES; SHOW STATUS LIKE 'slave_open_temp_tables'; checksum table mysql.columns_priv, mysql.db, mysql.func, mysql.help_category, mysql.help_keyword, mysql.help_relation, mysql.host, mysql.plugin, mysql.proc, mysql.procs_priv, mysql.roles_mapping, mysql.tables_priv, mysql.time_zon e, mysql.time_zone_leap_second, mysql.time_zone_name, mysql.time_zone_transition, mysql.time_zone_transition_type, mysql.user; SELECT * FROM INFORMATION_SCHEMA.PLUGINS; select * from information_schema.session_variables where variable_name = 'debug_sync'; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci +check_testcase def mtr check_testcase PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE variable_name NOT IN ('timestamp') AND variable_name not like "Last_IO_Err*" AND variable_name != 'INNODB_IBUF_MAX_SIZE' AND variable_name != 'INNODB_USE_NATIVE_AIO' AND variable_name != 'INNODB_BUFFER_POOL_LOAD_AT_STARTUP' AND variable_name not like 'GTID%POS' AND variable_name != 'GTID_BINLOG_STATE' ORDER BY variable_name; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA ORDER BY BINARY SCHEMA_NAME; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mtr_wsrep_notify', 'wsrep_schema') ORDER BY BINARY SCHEMA_NAME; SELECT table_name AS tables_in_test FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='test'; SELECT CONCAT(table_schema, '.', table_name) AS tables_in_mysql FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='mysql' ORDE R BY tables_in_mysql; SELECT CONCAT(table_schema, '.', table_name) AS columns_in_mysql, column_name, ordinal_position, column_default, is_nullable, data_type, character_maximum_length, character_octet_length, numeric_precision, numeric_scale, character_set_name, collation_name, column_type, column_key, extra, column_comment FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='mysql' ORDER BY columns_in_mysql; SELECT * FROM INFORMATION_SCHEMA.EVENTS; SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME NOT IN ('gs_insert', 'ts_insert'); SELECT * FROM INFORMATION_SCHEMA.ROUTINES; SHOW STATUS LIKE 'slave_open_temp_tables'; checksum table mysql.columns_priv, mysql.db, mysql.func, mysql.help_category, mysql.help_keyword, mysql.help_relation, mysql.plugin, mysql.proc, mysql.procs_priv, mysql.roles_mapping, mysql.tables_priv, mysql.time_zone, mysql.tim e_zone_leap_second, mysql.time_zone_name, mysql.time_zone_transition, mysql.time_zone_transition_type, mysql.global_priv; SELECT * FROM INFORMATION_SCHEMA.PLUGINS; select * from information_schema.session_variables where variable_name = 'debug_sync'; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci check_warnings def mtr check_warnings PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN DECLARE `pos` bigint unsigned; SET SQL_LOG_BIN=0, SQL_SAFE_UPDATES=0; UPDATE error_log el, global_suppressions gs SET suspicious=0 WHERE el.suspicious=1 AND el.line REGEXP gs.pattern; UPDATE error_log el, test_suppressions ts SET suspicious=0 WHERE el.suspicious=1 AND el.line REGEXP ts.pattern; SELECT COUNT(*) INTO @num_warnings FROM error_log WHERE suspicious=1; IF @num_warnings > 0 THEN SELECT line FROM error_log WHERE suspicious=1; SELECT 2 INTO result; ELSE SELECT 0 INTO RESULT; END IF; TRUNCATE test_suppressions; DROP TABLE error_log; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci + AddGeometryColumn def mysql AddGeometryColumn PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL begin + set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' ADD ', geometry_column,' GEOMETRY REF_SYSTEM_ID=', t_srid); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end NULL NULL SQL NO CONTAINS SQL NULL INVOKER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost latin1 latin1_swedish_ci latin1_swedish_ci + DropGeometryColumn def mysql DropGeometryColumn PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL begin + set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' DROP ', geometry_column); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end NULL NULL SQL NO CONTAINS SQL NULL INVOKER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost latin1 latin1_swedish_ci latin1_swedish_ci connect testuser2, localhost, testuser2, , db_datadict; SELECT * FROM information_schema.routines; SPECIFIC_NAME ROUTINE_CATALOG ROUTINE_SCHEMA ROUTINE_NAME ROUTINE_TYPE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_SCALE DATETIME_PRECISION CHARACTER_SET_NAME COLLATION_NAME DTD_IDENTIFIER ROUTINE_BODY ROUTINE_DEFINITION EXTERNAL_NAME EXTERNAL_LANGUAGE PARAMETER_STYLE IS_DETERMINISTIC SQL_DATA_ACCESS SQL_PATH SECURITY_TYPE CREATED LAST_ALTERED SQL_MODE ROUTINE_COMMENT DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION @@@ -209,8 -213,12 +213,12 @@@ sp_6_408002_2 def db_datadict_2 sp_6_40 SELECT * FROM db_datadict_2.res_6_408002_2; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost latin1 latin1_swedish_ci latin1_swedish_ci add_suppression def mtr add_suppression PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN INSERT INTO test_suppressions (pattern) VALUES (pattern); FLUSH NO_WRITE_TO_BINLOG TABLE test_suppressions; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci -check_testcase def mtr check_testcase PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE variable_name NOT IN ('timestamp') AND variable_name not like "Last_IO_Err*" AND variable_name != 'INNODB_IBUF_MAX_SIZE' AND variable_name != 'INNODB_USE_NATIVE_AIO' AND variable_name != 'INNODB_BUFFER_POOL_LOAD_AT_STARTUP' AND variable_name not like 'GTID%POS' AND variable_name != 'GTID_BINLOG_STATE' ORDER BY variable_name; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA ORDER BY BINARY SCHEMA_NAME; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mtr_wsrep_notify', 'wsrep_schema') ORDER BY BINARY SCHEMA_NAME; SELECT table_name AS tables_in_test FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='test'; SELECT CONCAT(table_schema, '.', table_name) AS tables_in_mysql FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='mysql' ORDE R BY tables_in_mysql; SELECT CONCAT(table_schema, '.', table_name) AS columns_in_mysql, column_name, ordinal_position, column_default, is_nullable, data_type, character_maximum_length, character_octet_length, numeric_precision, numeric_scale, character_set_name, collation_name, column_type, column_key, extra, column_comment FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='mysql' ORDER BY columns_in_mysql; SELECT * FROM INFORMATION_SCHEMA.EVENTS; SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME NOT IN ('gs_insert', 'ts_insert'); SELECT * FROM INFORMATION_SCHEMA.ROUTINES; SHOW STATUS LIKE 'slave_open_temp_tables'; checksum table mysql.columns_priv, mysql.db, mysql.func, mysql.help_category, mysql.help_keyword, mysql.help_relation, mysql.host, mysql.plugin, mysql.proc, mysql.procs_priv, mysql.roles_mapping, mysql.tables_priv, mysql.time_zon e, mysql.time_zone_leap_second, mysql.time_zone_name, mysql.time_zone_transition, mysql.time_zone_transition_type, mysql.user; SELECT * FROM INFORMATION_SCHEMA.PLUGINS; select * from information_schema.session_variables where variable_name = 'debug_sync'; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci +check_testcase def mtr check_testcase PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE variable_name NOT IN ('timestamp') AND variable_name not like "Last_IO_Err*" AND variable_name != 'INNODB_IBUF_MAX_SIZE' AND variable_name != 'INNODB_USE_NATIVE_AIO' AND variable_name != 'INNODB_BUFFER_POOL_LOAD_AT_STARTUP' AND variable_name not like 'GTID%POS' AND variable_name != 'GTID_BINLOG_STATE' ORDER BY variable_name; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA ORDER BY BINARY SCHEMA_NAME; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mtr_wsrep_notify', 'wsrep_schema') ORDER BY BINARY SCHEMA_NAME; SELECT table_name AS tables_in_test FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='test'; SELECT CONCAT(table_schema, '.', table_name) AS tables_in_mysql FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='mysql' ORDE R BY tables_in_mysql; SELECT CONCAT(table_schema, '.', table_name) AS columns_in_mysql, column_name, ordinal_position, column_default, is_nullable, data_type, character_maximum_length, character_octet_length, numeric_precision, numeric_scale, character_set_name, collation_name, column_type, column_key, extra, column_comment FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='mysql' ORDER BY columns_in_mysql; SELECT * FROM INFORMATION_SCHEMA.EVENTS; SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME NOT IN ('gs_insert', 'ts_insert'); SELECT * FROM INFORMATION_SCHEMA.ROUTINES; SHOW STATUS LIKE 'slave_open_temp_tables'; checksum table mysql.columns_priv, mysql.db, mysql.func, mysql.help_category, mysql.help_keyword, mysql.help_relation, mysql.plugin, mysql.proc, mysql.procs_priv, mysql.roles_mapping, mysql.tables_priv, mysql.time_zone, mysql.tim e_zone_leap_second, mysql.time_zone_name, mysql.time_zone_transition, mysql.time_zone_transition_type, mysql.global_priv; SELECT * FROM INFORMATION_SCHEMA.PLUGINS; select * from information_schema.session_variables where variable_name = 'debug_sync'; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci check_warnings def mtr check_warnings PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN DECLARE `pos` bigint unsigned; SET SQL_LOG_BIN=0, SQL_SAFE_UPDATES=0; UPDATE error_log el, global_suppressions gs SET suspicious=0 WHERE el.suspicious=1 AND el.line REGEXP gs.pattern; UPDATE error_log el, test_suppressions ts SET suspicious=0 WHERE el.suspicious=1 AND el.line REGEXP ts.pattern; SELECT COUNT(*) INTO @num_warnings FROM error_log WHERE suspicious=1; IF @num_warnings > 0 THEN SELECT line FROM error_log WHERE suspicious=1; SELECT 2 INTO result; ELSE SELECT 0 INTO RESULT; END IF; TRUNCATE test_suppressions; DROP TABLE error_log; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci + AddGeometryColumn def mysql AddGeometryColumn PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL begin + set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' ADD ', geometry_column,' GEOMETRY REF_SYSTEM_ID=', t_srid); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end NULL NULL SQL NO CONTAINS SQL NULL INVOKER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost latin1 latin1_swedish_ci latin1_swedish_ci + DropGeometryColumn def mysql DropGeometryColumn PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL begin + set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' DROP ', geometry_column); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end NULL NULL SQL NO CONTAINS SQL NULL INVOKER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost latin1 latin1_swedish_ci latin1_swedish_ci connect testuser3, localhost, testuser3, , test; SELECT * FROM information_schema.routines; SPECIFIC_NAME ROUTINE_CATALOG ROUTINE_SCHEMA ROUTINE_NAME ROUTINE_TYPE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_SCALE DATETIME_PRECISION CHARACTER_SET_NAME COLLATION_NAME DTD_IDENTIFIER ROUTINE_BODY ROUTINE_DEFINITION EXTERNAL_NAME EXTERNAL_LANGUAGE PARAMETER_STYLE IS_DETERMINISTIC SQL_DATA_ACCESS SQL_PATH SECURITY_TYPE CREATED LAST_ALTERED SQL_MODE ROUTINE_COMMENT DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION @@@ -221,8 -229,12 +229,12 @@@ sp_6_408002_2 def db_datadict_2 sp_6_40 SELECT * FROM db_datadict_2.res_6_408002_2; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost latin1 latin1_swedish_ci latin1_swedish_ci add_suppression def mtr add_suppression PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN INSERT INTO test_suppressions (pattern) VALUES (pattern); FLUSH NO_WRITE_TO_BINLOG TABLE test_suppressions; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci -check_testcase def mtr check_testcase PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE variable_name NOT IN ('timestamp') AND variable_name not like "Last_IO_Err*" AND variable_name != 'INNODB_IBUF_MAX_SIZE' AND variable_name != 'INNODB_USE_NATIVE_AIO' AND variable_name != 'INNODB_BUFFER_POOL_LOAD_AT_STARTUP' AND variable_name not like 'GTID%POS' AND variable_name != 'GTID_BINLOG_STATE' ORDER BY variable_name; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA ORDER BY BINARY SCHEMA_NAME; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mtr_wsrep_notify', 'wsrep_schema') ORDER BY BINARY SCHEMA_NAME; SELECT table_name AS tables_in_test FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='test'; SELECT CONCAT(table_schema, '.', table_name) AS tables_in_mysql FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='mysql' ORDE R BY tables_in_mysql; SELECT CONCAT(table_schema, '.', table_name) AS columns_in_mysql, column_name, ordinal_position, column_default, is_nullable, data_type, character_maximum_length, character_octet_length, numeric_precision, numeric_scale, character_set_name, collation_name, column_type, column_key, extra, column_comment FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='mysql' ORDER BY columns_in_mysql; SELECT * FROM INFORMATION_SCHEMA.EVENTS; SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME NOT IN ('gs_insert', 'ts_insert'); SELECT * FROM INFORMATION_SCHEMA.ROUTINES; SHOW STATUS LIKE 'slave_open_temp_tables'; checksum table mysql.columns_priv, mysql.db, mysql.func, mysql.help_category, mysql.help_keyword, mysql.help_relation, mysql.host, mysql.plugin, mysql.proc, mysql.procs_priv, mysql.roles_mapping, mysql.tables_priv, mysql.time_zon e, mysql.time_zone_leap_second, mysql.time_zone_name, mysql.time_zone_transition, mysql.time_zone_transition_type, mysql.user; SELECT * FROM INFORMATION_SCHEMA.PLUGINS; select * from information_schema.session_variables where variable_name = 'debug_sync'; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci +check_testcase def mtr check_testcase PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE variable_name NOT IN ('timestamp') AND variable_name not like "Last_IO_Err*" AND variable_name != 'INNODB_IBUF_MAX_SIZE' AND variable_name != 'INNODB_USE_NATIVE_AIO' AND variable_name != 'INNODB_BUFFER_POOL_LOAD_AT_STARTUP' AND variable_name not like 'GTID%POS' AND variable_name != 'GTID_BINLOG_STATE' ORDER BY variable_name; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA ORDER BY BINARY SCHEMA_NAME; SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mtr_wsrep_notify', 'wsrep_schema') ORDER BY BINARY SCHEMA_NAME; SELECT table_name AS tables_in_test FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='test'; SELECT CONCAT(table_schema, '.', table_name) AS tables_in_mysql FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='mysql' ORDE R BY tables_in_mysql; SELECT CONCAT(table_schema, '.', table_name) AS columns_in_mysql, column_name, ordinal_position, column_default, is_nullable, data_type, character_maximum_length, character_octet_length, numeric_precision, numeric_scale, character_set_name, collation_name, column_type, column_key, extra, column_comment FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='mysql' ORDER BY columns_in_mysql; SELECT * FROM INFORMATION_SCHEMA.EVENTS; SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME NOT IN ('gs_insert', 'ts_insert'); SELECT * FROM INFORMATION_SCHEMA.ROUTINES; SHOW STATUS LIKE 'slave_open_temp_tables'; checksum table mysql.columns_priv, mysql.db, mysql.func, mysql.help_category, mysql.help_keyword, mysql.help_relation, mysql.plugin, mysql.proc, mysql.procs_priv, mysql.roles_mapping, mysql.tables_priv, mysql.time_zone, mysql.tim e_zone_leap_second, mysql.time_zone_name, mysql.time_zone_transition, mysql.time_zone_transition_type, mysql.global_priv; SELECT * FROM INFORMATION_SCHEMA.PLUGINS; select * from information_schema.session_variables where variable_name = 'debug_sync'; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci check_warnings def mtr check_warnings PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL BEGIN DECLARE `pos` bigint unsigned; SET SQL_LOG_BIN=0, SQL_SAFE_UPDATES=0; UPDATE error_log el, global_suppressions gs SET suspicious=0 WHERE el.suspicious=1 AND el.line REGEXP gs.pattern; UPDATE error_log el, test_suppressions ts SET suspicious=0 WHERE el.suspicious=1 AND el.line REGEXP ts.pattern; SELECT COUNT(*) INTO @num_warnings FROM error_log WHERE suspicious=1; IF @num_warnings > 0 THEN SELECT line FROM error_log WHERE suspicious=1; SELECT 2 INTO result; ELSE SELECT 0 INTO RESULT; END IF; TRUNCATE test_suppressions; DROP TABLE error_log; END NULL NULL SQL NO CONTAINS SQL NULL DEFINER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost utf8 utf8_general_ci latin1_swedish_ci + AddGeometryColumn def mysql AddGeometryColumn PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL begin + set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' ADD ', geometry_column,' GEOMETRY REF_SYSTEM_ID=', t_srid); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end NULL NULL SQL NO CONTAINS SQL NULL INVOKER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost latin1 latin1_swedish_ci latin1_swedish_ci + DropGeometryColumn def mysql DropGeometryColumn PROCEDURE NULL NULL NULL NULL NULL NULL NULL NULL SQL begin + set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' DROP ', geometry_column); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end NULL NULL SQL NO CONTAINS SQL NULL INVOKER YYYY-MM-DD hh:mm:ss YYYY-MM-DD hh:mm:ss root@localhost latin1 latin1_swedish_ci latin1_swedish_ci connection default; disconnect testuser1; disconnect testuser2; diff --cc mysql-test/suite/galera/r/galera_events.result index 791b0be729d,e925e62cb91..373f063c2bd --- a/mysql-test/suite/galera/r/galera_events.result +++ b/mysql-test/suite/galera/r/galera_events.result @@@ -1,7 -1,7 +1,9 @@@ +connection node_2; +connection node_1; connection node_1; CREATE EVENT event1 ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO SELECT 1; + Warnings: + Warning 1105 Event scheduler is switched off, use SET GLOBAL event_scheduler=ON to enable it. connection node_2; SELECT DEFINER= 'root@localhost', ORIGINATOR = 1, STATUS = 'SLAVESIDE_DISABLED', EVENT_TYPE = 'ONE TIME', ON_COMPLETION = 'NOT PRESERVE' FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME = 'event1'; DEFINER= 'root@localhost' ORIGINATOR = 1 STATUS = 'SLAVESIDE_DISABLED' EVENT_TYPE = 'ONE TIME' ON_COMPLETION = 'NOT PRESERVE' diff --cc mysql-test/suite/galera/r/galera_parallel_autoinc_manytrx.result index 09a415d47eb,0fd0f0b505a..b0980f8ab98 --- a/mysql-test/suite/galera/r/galera_parallel_autoinc_manytrx.result +++ b/mysql-test/suite/galera/r/galera_parallel_autoinc_manytrx.result @@@ -1,22 -1,32 +1,56 @@@ +connection node_2; +connection node_1; connection node_1; - CREATE TABLE ten (f1 INTEGER); + CREATE TABLE ten (f1 INTEGER) Engine=InnoDB; INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) Engine=InnoDB; connection node_2; + set session wsrep_sync_wait=15; SET GLOBAL wsrep_slave_threads = 4; connection node_1; + CREATE PROCEDURE p1 (repeat_count int) + BEGIN + DECLARE current_num int; + SET current_num = 0; + WHILE current_num < repeat_count do + INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1; + COMMIT; + SET current_num = current_num + 1; + END WHILE; + END| + connection node_1a; + connection node_1b; connection node_2; ++<<<<<<< HEAD +SELECT COUNT(*) = 20000 FROM t1; +COUNT(*) = 20000 +1 +SELECT COUNT(DISTINCT f1) = 20000 FROM t1; +COUNT(DISTINCT f1) = 20000 +1 +SELECT COUNT(*) = 4 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE 'wsrep applier committed%'; +COUNT(*) = 4 +1 ++||||||| merged common ancestors ++SELECT COUNT(*) = 20000 FROM t1; ++COUNT(*) = 20000 ++1 ++SELECT COUNT(DISTINCT f1) = 20000 FROM t1; ++COUNT(DISTINCT f1) = 20000 ++1 ++SELECT COUNT(*) = 4 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE 'committed%'; ++COUNT(*) = 4 ++1 ++======= + SELECT COUNT(*) FROM t1; + COUNT(*) + 40000 + SELECT COUNT(DISTINCT f1) FROM t1; + COUNT(DISTINCT f1) + 40000 + disconnect node_1a; + disconnect node_1b; ++>>>>>>> c0bc9480e73242b075178cb5da5713ba9d84be7c connection default; DROP TABLE t1; DROP TABLE ten; diff --cc mysql-test/suite/galera/t/galera_parallel_autoinc_largetrx.test index 203d18b85a6,34558283462..d949b06abb4 --- a/mysql-test/suite/galera/t/galera_parallel_autoinc_largetrx.test +++ b/mysql-test/suite/galera/t/galera_parallel_autoinc_largetrx.test @@@ -18,11 -18,13 +18,12 @@@ INSERT INTO ten VALUES (1),(2),(3),(4), CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) Engine=InnoDB; --connection node_2 + set session wsrep_sync_wait=15; --let $wsrep_slave_threads_orig = `SELECT @@wsrep_slave_threads` SET GLOBAL wsrep_slave_threads = 4; ---let $wait_condition = SELECT COUNT(*) = @@wsrep_slave_threads + 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%'); +--let $wait_condition = SELECT VARIABLE_VALUE = @@wsrep_slave_threads + 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count'; --source include/wait_condition.inc - --connection node_1 --send INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4; diff --cc mysql-test/suite/galera/t/galera_parallel_autoinc_manytrx.test index d2156cb3577,d04603891db..42b846b912f --- a/mysql-test/suite/galera/t/galera_parallel_autoinc_manytrx.test +++ b/mysql-test/suite/galera/t/galera_parallel_autoinc_manytrx.test @@@ -11,38 -17,67 +17,95 @@@ CREATE TABLE t1 (f1 INTEGER AUTO_INCREM --let $galera_server_number = 1 --source include/galera_connect.inc - --connection node_1 - CREATE TABLE ten (f1 INTEGER); - INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); + --let $galera_connection_name = node_1b + --let $galera_server_number = 1 + --source include/galera_connect.inc - CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) Engine=InnoDB; --connection node_2 + set session wsrep_sync_wait=15; --let $wsrep_slave_threads_orig = `SELECT @@wsrep_slave_threads` SET GLOBAL wsrep_slave_threads = 4; + --let $wait_condition = SELECT COUNT(*) = @@wsrep_slave_threads + 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%'); + --source include/wait_condition.inc --connection node_1 + DELIMITER |; + CREATE PROCEDURE p1 (repeat_count int) + BEGIN + DECLARE current_num int; + SET current_num = 0; + WHILE current_num < repeat_count do + INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1; + COMMIT; + SET current_num = current_num + 1; + END WHILE; + END| + DELIMITER ;| + + --disable_query_log + send call p1(1000); + + --connection node_1a + --disable_query_log + send call p1(1000); + + --connection node_1b + --disable_query_log + send call p1(1000); + + --connection node_2 + --disable_query_log + send call p1(1000); + + --connection node_1 + reap; + --enable_query_log + + --connection node_1a + reap; + --enable_query_log + + --connection node_1b + reap; + --enable_query_log + + --connection node_2 ++<<<<<<< HEAD +--let $count = 1000 +while ($count) +{ + --disable_query_log + INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1; + --enable_query_log + --dec $count +} + - --connection node_2 ++SELECT COUNT(*) = 20000 FROM t1; ++SELECT COUNT(DISTINCT f1) = 20000 FROM t1; ++SELECT COUNT(*) = 4 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE 'wsrep applier committed%'; ++||||||| merged common ancestors +--let $count = 1000 +while ($count) +{ + --disable_query_log + INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1; + --enable_query_log + --dec $count +} + +SELECT COUNT(*) = 20000 FROM t1; +SELECT COUNT(DISTINCT f1) = 20000 FROM t1; - SELECT COUNT(*) = 4 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE 'wsrep applier committed%'; ++SELECT COUNT(*) = 4 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE 'committed%'; ++======= + reap; + --enable_query_log + + SELECT COUNT(*) FROM t1; + SELECT COUNT(DISTINCT f1) FROM t1; + + --disconnect node_1a + --disconnect node_1b ++>>>>>>> c0bc9480e73242b075178cb5da5713ba9d84be7c --disable_query_log --eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig; diff --cc mysql-test/suite/innodb/r/instant_alter_crash.result index 528bd9a905a,dde97d084d4..cfcb24f8bb2 --- a/mysql-test/suite/innodb/r/instant_alter_crash.result +++ b/mysql-test/suite/innodb/r/instant_alter_crash.result @@@ -15,10 -16,9 +16,10 @@@ ALTER TABLE t1 ADD COLUMN (c3 TEXT NOT connection default; SET DEBUG_SYNC='now WAIT_FOR ddl'; SET GLOBAL innodb_flush_log_at_trx_commit=1; - INSERT INTO t2 VALUES(3,4,'accusantium doloremque laudantium'); + COMMIT; # Kill the server disconnect ddl; +# restart SET GLOBAL innodb_purge_rseg_truncate_frequency=1; SELECT * FROM t1; id c2 diff --cc mysql-test/suite/plugins/r/pam.result index a16cd7f3d43,46f1223d7b3..4a4310f65a9 --- a/mysql-test/suite/plugins/r/pam.result +++ b/mysql-test/suite/plugins/r/pam.result @@@ -20,13 -20,26 +20,33 @@@ Challenge input first Enter: not very secret challenge Now, the magic number! PIN: **** +# +# athentication is unsuccessful +# +Challenge input first. +Enter: crash pam module +Now, the magic number! +PIN: *** drop user test_pam; drop user pam_test; + create user PAM_TEST identified via pam using 'mariadb_mtr'; + # + # athentication is unsuccessful + # + Challenge input first. + Enter: not very secret challenge + Now, the magic number! + PIN: **** + set global pam_winbind_workaround=1; + # + # athentication is successful + # + Challenge input first. + Enter: not very secret challenge + Now, the magic number! + PIN: **** + select user(), current_user(), database(); -user() current_user() database() -PAM_TEST@localhost PAM_TEST@% test ++user() current_user() database() ++PAM_TEST at localhost PAM_TEST@% test + drop user PAM_TEST; uninstall plugin pam; diff --cc mysql-test/suite/plugins/t/pam.test index 6bb282f68c0,8441b83c5c3..4040afa68f7 --- a/mysql-test/suite/plugins/t/pam.test +++ b/mysql-test/suite/plugins/t/pam.test @@@ -22,25 -16,35 +22,45 @@@ EO --echo # --echo # athentication is successful, challenge/pin are ok --echo # note that current_user() differs from user() ----echo # - --exec $MYSQL_TEST -u test_pam --plugin-dir=$plugindir < $MYSQLTEST_VARDIR/tmp/pam_good.txt ++-echo # + --exec $MYSQL_TEST -u test_pam < $MYSQLTEST_VARDIR/tmp/pam_good.txt --echo # --echo # athentication is unsuccessful --echo # --error 1 - --exec $MYSQL_TEST -u test_pam --plugin-dir=$plugindir < $MYSQLTEST_VARDIR/tmp/pam_bad.txt + --exec $MYSQL_TEST -u test_pam < $MYSQLTEST_VARDIR/tmp/pam_bad.txt +--echo # +--echo # athentication is unsuccessful +--echo # +--error 1 - --exec $MYSQL_TEST -u test_pam --plugin-dir=$plugindir < $MYSQLTEST_VARDIR/tmp/pam_ugly.txt ++--exec $MYSQL_TEST -u test_pam < $MYSQLTEST_VARDIR/tmp/pam_ugly.txt + +--remove_file $MYSQLTEST_VARDIR/tmp/pam_good.txt +--remove_file $MYSQLTEST_VARDIR/tmp/pam_bad.txt ++--remove_file $MYSQLTEST_VARDIR/tmp/pam_ugly.txt drop user test_pam; drop user pam_test; ++ + create user PAM_TEST identified via pam using 'mariadb_mtr'; + + --echo # + --echo # athentication is unsuccessful + --echo # + --error 1 + --exec $MYSQL_TEST -u PAM_TEST < $MYSQLTEST_VARDIR/tmp/pam_good.txt + + set global pam_winbind_workaround=1; + --echo # + --echo # athentication is successful + --echo # + --exec $MYSQL_TEST -u PAM_TEST < $MYSQLTEST_VARDIR/tmp/pam_good.txt + + --remove_file $MYSQLTEST_VARDIR/tmp/pam_good.txt + --remove_file $MYSQLTEST_VARDIR/tmp/pam_bad.txt + drop user PAM_TEST; + let $count_sessions= 1; --source include/wait_until_count_sessions.inc uninstall plugin pam; diff --cc mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result index 89f59deae73,dce79837700..7dd3907f102 --- a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result +++ b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result @@@ -677,8 -676,11 +677,10 @@@ DROP TRIGGER tr1 ******************** EVENTS ******************** -GRANT EVENT ON *.* TO 'root'@'localhost'; INSERT INTO t1 VALUES(1, 'test1'); CREATE EVENT e1 ON SCHEDULE EVERY '1' SECOND COMMENT 'e_second_comment' DO DELETE FROM t1; + Warnings: + Warning 1105 Event scheduler is switched off, use SET GLOBAL event_scheduler=ON to enable it. SHOW EVENTS; Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation test_rpl e1 root@localhost SYSTEM RECURRING NULL 1 # # NULL ENABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci diff --cc plugin/auth_pam/auth_pam.c index 779f6ced1ad,83fd64e4cb1..599b323b0b7 --- a/plugin/auth_pam/auth_pam.c +++ b/plugin/auth_pam/auth_pam.c @@@ -28,167 -52,160 +28,171 @@@ static char pam_debug = 0 #define PAM_DEBUG(X) /* no-op */ #endif + static char winbind_hack = 0; + -static int conv(int n, const struct pam_message **msg, - struct pam_response **resp, void *data) +static char *opt_plugin_dir; /* To be dynamically linked. */ +static const char *tool_name= "auth_pam_tool_dir/auth_pam_tool"; +static const int tool_name_len= 31; + +static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) { - struct param *param = (struct param *)data; - unsigned char *end = param->buf + sizeof(param->buf) - 1; - int i; + int p_to_c[2], c_to_p[2]; /* Parent-to-child and child-to-parent pipes. */ + pid_t proc_id; + int result= CR_ERROR, pkt_len; + unsigned char field, *pkt; - *resp = 0; + PAM_DEBUG((stderr, "PAM: opening pipes.\n")); + if (pipe(p_to_c) < 0 || pipe(c_to_p) < 0) + { + /* Error creating pipes. */ + return CR_ERROR; + } + PAM_DEBUG((stderr, "PAM: forking.\n")); + if ((proc_id= fork()) < 0) + { + /* Error forking. */ + close(p_to_c[0]); + close(c_to_p[1]); + goto error_ret; + } - for (i = 0; i < n; i++) + if (proc_id == 0) { - /* if there's a message - append it to the buffer */ - if (msg[i]->msg) + /* The 'sandbox' process started. */ + char toolpath[FN_REFLEN]; + size_t plugin_dir_len= strlen(opt_plugin_dir); + + PAM_DEBUG((stderr, "PAM: Child process prepares pipes.\n")); + + if (close(p_to_c[1]) < 0 || + close(c_to_p[0]) < 0 || + dup2(p_to_c[0], 0) < 0 || /* Parent's pipe to STDIN. */ + dup2(c_to_p[1], 1) < 0) /* Sandbox's pipe to STDOUT. */ { - int len = strlen(msg[i]->msg); - if (len > end - param->ptr) - len = end - param->ptr; - if (len > 0) - { - memcpy(param->ptr, msg[i]->msg, len); - param->ptr+= len; - *(param->ptr)++ = '\n'; - } + exit(-1); } - /* if the message style is *_PROMPT_*, meaning PAM asks a question, - send the accumulated text to the client, read the reply */ - if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF || - msg[i]->msg_style == PAM_PROMPT_ECHO_ON) + + PAM_DEBUG((stderr, "PAM: check tool directory: %s, %s.\n", + opt_plugin_dir, tool_name)); + if (plugin_dir_len + tool_name_len + 2 > sizeof(toolpath)) { - int pkt_len; - unsigned char *pkt; + /* Tool path too long. */ + exit(-1); + } - /* allocate the response array. - freeing it is the responsibility of the caller */ - if (*resp == 0) - { - *resp = calloc(sizeof(struct pam_response), n); - if (*resp == 0) - return PAM_BUF_ERR; - } + memcpy(toolpath, opt_plugin_dir, plugin_dir_len); + if (plugin_dir_len && toolpath[plugin_dir_len-1] != FN_LIBCHAR) + toolpath[plugin_dir_len++]= FN_LIBCHAR; + memcpy(toolpath+plugin_dir_len, tool_name, tool_name_len+1); - /* dialog plugin interprets the first byte of the packet - as the magic number. - 2 means "read the input with the echo enabled" - 4 means "password-like input, echo disabled" - C'est la vie. */ - param->buf[0] = msg[i]->msg_style == PAM_PROMPT_ECHO_ON ? 2 : 4; - PAM_DEBUG((stderr, "PAM: conv: send(%.*s)\n", (int)(param->ptr - param->buf - 1), param->buf)); - if (param->vio->write_packet(param->vio, param->buf, param->ptr - param->buf - 1)) - return PAM_CONV_ERR; - - pkt_len = param->vio->read_packet(param->vio, &pkt); - if (pkt_len < 0) - { - PAM_DEBUG((stderr, "PAM: conv: recv() ERROR\n")); - return PAM_CONV_ERR; - } - PAM_DEBUG((stderr, "PAM: conv: recv(%.*s)\n", pkt_len, pkt)); - /* allocate and copy the reply to the response array */ - if (!((*resp)[i].resp= strndup((char*) pkt, pkt_len))) - return PAM_CONV_ERR; - param->ptr = param->buf + 1; - } + PAM_DEBUG((stderr, "PAM: execute pam sandbox [%s].\n", toolpath)); + (void) execl(toolpath, toolpath, NULL); + PAM_DEBUG((stderr, "PAM: exec() failed.\n")); + exit(-1); } - return PAM_SUCCESS; -} -#define DO(X) if ((status = (X)) != PAM_SUCCESS) goto end + /* Parent process continues. */ -#if defined(SOLARIS) || defined(__sun) -typedef void** pam_get_item_3_arg; -#else -typedef const void** pam_get_item_3_arg; -#endif + PAM_DEBUG((stderr, "PAM: parent continues.\n")); + if (close(p_to_c[0]) < 0 || + close(c_to_p[1]) < 0) + goto error_ret; -static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) -{ - pam_handle_t *pamh = NULL; - int status; - const char *new_username= NULL; - struct param param; - /* The following is written in such a way to make also solaris happy */ - struct pam_conv pam_start_arg = { &conv, (char*) ¶m }; - - /* - get the service name, as specified in - - CREATE USER ... IDENTIFIED WITH pam AS "service" - */ - const char *service = info->auth_string && info->auth_string[0] - ? info->auth_string : "mysql"; - - param.ptr = param.buf + 1; - param.vio = vio; - - PAM_DEBUG((stderr, "PAM: pam_start(%s, %s)\n", service, info->user_name)); - DO( pam_start(service, info->user_name, &pam_start_arg, &pamh) ); - - PAM_DEBUG((stderr, "PAM: pam_authenticate(0)\n")); - DO( pam_authenticate (pamh, 0) ); - - PAM_DEBUG((stderr, "PAM: pam_acct_mgmt(0)\n")); - DO( pam_acct_mgmt(pamh, 0) ); - - PAM_DEBUG((stderr, "PAM: pam_get_item(PAM_USER)\n")); - DO( pam_get_item(pamh, PAM_USER, (pam_get_item_3_arg) &new_username) ); - - if (new_username && - (winbind_hack ? strcasecmp : strcmp)(new_username, info->user_name)) - strncpy(info->authenticated_as, new_username, - sizeof(info->authenticated_as)-1); - info->authenticated_as[sizeof(info->authenticated_as)-1]= 0; - -end: - pam_end(pamh, status); - PAM_DEBUG((stderr, "PAM: status = %d user = %s\n", status, info->authenticated_as)); - return status == PAM_SUCCESS ? CR_OK : CR_ERROR; -} + /* no user name yet ? read the client handshake packet with the user name */ + if (info->user_name == 0) + { + if ((pkt_len= vio->read_packet(vio, &pkt) < 0)) + return CR_ERROR; + } + else + pkt= NULL; -static struct st_mysql_auth info = -{ - MYSQL_AUTHENTICATION_INTERFACE_VERSION, - "dialog", - pam_auth -}; - -static char use_cleartext_plugin; -static MYSQL_SYSVAR_BOOL(use_cleartext_plugin, use_cleartext_plugin, - PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, - "Use mysql_cleartext_plugin on the client side instead of the dialog " - "plugin. This may be needed for compatibility reasons, but it only " - "supports simple PAM policies that don't require anything besides " - "a password", NULL, NULL, 0); - -static MYSQL_SYSVAR_BOOL(winbind_workaround, winbind_hack, PLUGIN_VAR_OPCMDARG, - "Compare usernames case insensitively to work around pam_winbind " - "unconditional username lowercasing", NULL, NULL, 0); + PAM_DEBUG((stderr, "PAM: parent sends user data [%s], [%s].\n", + info->user_name, info->auth_string)); #ifndef DBUG_OFF - field= pam_debug; -static MYSQL_SYSVAR_BOOL(debug, pam_debug, PLUGIN_VAR_OPCMDARG, - "Log all PAM activity", NULL, NULL, 0); ++ field= pam_debug ? 1 : 0; +#else + field= 0; #endif ++ field|= winbind_hack ? 2 : 0; + + if (write(p_to_c[1], &field, 1) != 1 || + write_string(p_to_c[1], (const uchar *) info->user_name, + info->user_name_length) || + write_string(p_to_c[1], (const uchar *) info->auth_string, + info->auth_string_length)) + goto error_ret; -static struct st_mysql_sys_var* vars[] = { - MYSQL_SYSVAR(use_cleartext_plugin), - MYSQL_SYSVAR(winbind_workaround), -#ifndef DBUG_OFF - MYSQL_SYSVAR(debug), -#endif - NULL -}; + for (;;) + { + PAM_DEBUG((stderr, "PAM: listening to the sandbox.\n")); + if (read(c_to_p[0], &field, 1) < 1) + { + PAM_DEBUG((stderr, "PAM: read failed.\n")); + goto error_ret; + } + + if (field == AP_EOF) + { + PAM_DEBUG((stderr, "PAM: auth OK returned.\n")); + break; + } + + switch (field) + { + case AP_AUTHENTICATED_AS: + PAM_DEBUG((stderr, "PAM: reading authenticated_as string.\n")); + if (read_string(c_to_p[0], info->authenticated_as, + sizeof(info->authenticated_as) - 1) < 0) + goto error_ret; + break; + + case AP_CONV: + { + unsigned char buf[10240]; + int buf_len; + + PAM_DEBUG((stderr, "PAM: getting CONV string.\n")); + if ((buf_len= read_string(c_to_p[0], (char *) buf, sizeof(buf))) < 0) + goto error_ret; + + if (!pkt || (buf[0] >> 1) != 2) + { + PAM_DEBUG((stderr, "PAM: sending CONV string.\n")); + if (vio->write_packet(vio, buf, buf_len)) + goto error_ret; + + PAM_DEBUG((stderr, "PAM: reading CONV answer.\n")); + if ((pkt_len= vio->read_packet(vio, &pkt)) < 0) + goto error_ret; + } + + PAM_DEBUG((stderr, "PAM: answering CONV.\n")); + if (write_string(p_to_c[1], pkt, pkt_len)) + goto error_ret; + + pkt= NULL; + } + break; + + default: + PAM_DEBUG((stderr, "PAM: unknown sandbox field.\n")); + goto error_ret; + } + } + result= CR_OK; + +error_ret: + close(p_to_c[1]); + close(c_to_p[0]); + + PAM_DEBUG((stderr, "PAM: auth result %d.\n", result)); + return result; +} + + +#include "auth_pam_common.c" static int init(void *p __attribute__((unused))) diff --cc plugin/auth_pam/auth_pam_base.c index 67a0adbeb2e,00000000000..a23cfcbfd65 mode 100644,000000..100644 --- a/plugin/auth_pam/auth_pam_base.c +++ b/plugin/auth_pam/auth_pam_base.c @@@ -1,174 -1,0 +1,177 @@@ +/* + Copyright (c) 2011, 2018 MariaDB Corporation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ + +/* + This file contains code to interact with the PAM module. + To be included into auth_pam_tool.c and auth_pam_v2.c, + + Before the #include these sould be defined: + + struct param { + unsigned char buf[10240], *ptr; + MYSQL_PLUGIN_VIO *vio; + ... other arbitrary fields allowed. + }; + static int write_packet(struct param *param, const unsigned char *buf, + int buf_len) + static int read_packet(struct param *param, unsigned char **pkt) +*/ + +#include <stdio.h> +#include <string.h> +#include <security/pam_appl.h> +#include <security/pam_modules.h> + +/* It least solaris doesn't have strndup */ + +#ifndef HAVE_STRNDUP +char *strndup(const char *from, size_t length) +{ + char *ptr; + size_t max_length= strlen(from); + if (length > max_length) + length= max_length; + if ((ptr= (char*) malloc(length+1)) != 0) + { + memcpy((char*) ptr, (char*) from, length); + ptr[length]=0; + } + return ptr; +} +#endif + +#ifndef DBUG_OFF +static char pam_debug = 0; +#define PAM_DEBUG(X) do { if (pam_debug) { fprintf X; } } while(0) +#else +#define PAM_DEBUG(X) /* no-op */ +#endif + ++static char winbind_hack = 0; ++ +static int conv(int n, const struct pam_message **msg, + struct pam_response **resp, void *data) +{ + struct param *param = (struct param *)data; + unsigned char *end = param->buf + sizeof(param->buf) - 1; + int i; + + *resp = 0; + + for (i = 0; i < n; i++) + { + /* if there's a message - append it to the buffer */ + if (msg[i]->msg) + { + int len = strlen(msg[i]->msg); + if (len > end - param->ptr) + len = end - param->ptr; + if (len > 0) + { + memcpy(param->ptr, msg[i]->msg, len); + param->ptr+= len; + *(param->ptr)++ = '\n'; + } + } + /* if the message style is *_PROMPT_*, meaning PAM asks a question, + send the accumulated text to the client, read the reply */ + if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF || + msg[i]->msg_style == PAM_PROMPT_ECHO_ON) + { + int pkt_len; + unsigned char *pkt; + + /* allocate the response array. + freeing it is the responsibility of the caller */ + if (*resp == 0) + { + *resp = calloc(sizeof(struct pam_response), n); + if (*resp == 0) + return PAM_BUF_ERR; + } + + /* dialog plugin interprets the first byte of the packet + as the magic number. + 2 means "read the input with the echo enabled" + 4 means "password-like input, echo disabled" + C'est la vie. */ + param->buf[0] = msg[i]->msg_style == PAM_PROMPT_ECHO_ON ? 2 : 4; + PAM_DEBUG((stderr, "PAM: conv: send(%.*s)\n", + (int)(param->ptr - param->buf - 1), param->buf)); + pkt_len= roundtrip(param, param->buf, param->ptr - param->buf - 1, &pkt); + if (pkt_len < 0) + return PAM_CONV_ERR; + + PAM_DEBUG((stderr, "PAM: conv: recv(%.*s)\n", pkt_len, pkt)); + /* allocate and copy the reply to the response array */ + if (!((*resp)[i].resp= strndup((char*) pkt, pkt_len))) + return PAM_CONV_ERR; + param->ptr = param->buf + 1; + } + } + return PAM_SUCCESS; +} + +#define DO(X) if ((status = (X)) != PAM_SUCCESS) goto end + +#if defined(SOLARIS) || defined(__sun) +typedef void** pam_get_item_3_arg; +#else +typedef const void** pam_get_item_3_arg; +#endif + +static int pam_auth_base(struct param *param, MYSQL_SERVER_AUTH_INFO *info) +{ + pam_handle_t *pamh = NULL; + int status; + const char *new_username= NULL; + /* The following is written in such a way to make also solaris happy */ + struct pam_conv pam_start_arg = { &conv, (char*) param }; + + /* + get the service name, as specified in + + CREATE USER ... IDENTIFIED WITH pam AS "service" + */ + const char *service = info->auth_string && info->auth_string[0] + ? info->auth_string : "mysql"; + + param->ptr = param->buf + 1; + + PAM_DEBUG((stderr, "PAM: pam_start(%s, %s)\n", service, info->user_name)); + DO( pam_start(service, info->user_name, &pam_start_arg, &pamh) ); + + PAM_DEBUG((stderr, "PAM: pam_authenticate(0)\n")); + DO( pam_authenticate (pamh, 0) ); + + PAM_DEBUG((stderr, "PAM: pam_acct_mgmt(0)\n")); + DO( pam_acct_mgmt(pamh, 0) ); + + PAM_DEBUG((stderr, "PAM: pam_get_item(PAM_USER)\n")); + DO( pam_get_item(pamh, PAM_USER, (pam_get_item_3_arg) &new_username) ); + - if (new_username && strcmp(new_username, info->user_name)) ++ if (new_username && ++ (winbind_hack ? strcasecmp : strcmp)(new_username, info->user_name)) + strncpy(info->authenticated_as, new_username, + sizeof(info->authenticated_as)); + info->authenticated_as[sizeof(info->authenticated_as)-1]= 0; + +end: + pam_end(pamh, status); + PAM_DEBUG((stderr, "PAM: status = %d user = %s\n", status, info->authenticated_as)); + return status == PAM_SUCCESS ? CR_OK : CR_ERROR; +} + diff --cc plugin/auth_pam/auth_pam_common.c index 135feb611a6,00000000000..ef8f0f658ff mode 100644,000000..100644 --- a/plugin/auth_pam/auth_pam_common.c +++ b/plugin/auth_pam/auth_pam_common.c @@@ -1,51 -1,0 +1,56 @@@ +/* + Copyright (c) 2011, 2018 MariaDB Corporation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ + +/* + In this file we gather the plugin interface definitions + that are same in all the PAM plugin versions. + To be included into auth_pam.c and auth_pam_v1.c. +*/ + +static struct st_mysql_auth info = +{ + MYSQL_AUTHENTICATION_INTERFACE_VERSION, + "dialog", + pam_auth, + NULL, NULL /* no PASSWORD() */ +}; + +static char use_cleartext_plugin; +static MYSQL_SYSVAR_BOOL(use_cleartext_plugin, use_cleartext_plugin, + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, + "Use mysql_cleartext_plugin on the client side instead of the dialog " + "plugin. This may be needed for compatibility reasons, but it only " + "supports simple PAM policies that don't require anything besides " + "a password", NULL, NULL, 0); + ++static MYSQL_SYSVAR_BOOL(winbind_workaround, winbind_hack, PLUGIN_VAR_OPCMDARG, ++ "Compare usernames case insensitively to work around pam_winbind " ++ "unconditional username lowercasing", NULL, NULL, 0); ++ +#ifndef DBUG_OFF +static MYSQL_SYSVAR_BOOL(debug, pam_debug, PLUGIN_VAR_OPCMDARG, + "Log all PAM activity", NULL, NULL, 0); +#endif + + +static struct st_mysql_sys_var* vars[] = { + MYSQL_SYSVAR(use_cleartext_plugin), ++ MYSQL_SYSVAR(winbind_workaround), +#ifndef DBUG_OFF + MYSQL_SYSVAR(debug), +#endif + NULL +}; diff --cc plugin/auth_pam/auth_pam_tool.c index 95d47dca113,00000000000..6fd30b457ee mode 100644,000000..100644 --- a/plugin/auth_pam/auth_pam_tool.c +++ b/plugin/auth_pam/auth_pam_tool.c @@@ -1,115 -1,0 +1,116 @@@ +/* + Copyright (c) 2011, 2018 MariaDB Corporation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ + +#include <stdlib.h> +#include <unistd.h> +#include <mysql/plugin_auth_common.h> + +struct param { + unsigned char buf[10240], *ptr; +}; + + +#include "auth_pam_tool.h" + + +static int roundtrip(struct param *param, const unsigned char *buf, + int buf_len, unsigned char **pkt) +{ + unsigned char b= AP_CONV; + if (write(1, &b, 1) < 1 || write_string(1, buf, buf_len)) + return -1; + *pkt= (unsigned char *) param->buf; + return read_string(0, (char *) param->buf, (int) sizeof(param->buf)) - 1; +} + +typedef struct st_mysql_server_auth_info +{ + /** + User name as sent by the client and shown in USER(). + NULL if the client packet with the user name was not received yet. + */ + char *user_name; + + /** + A corresponding column value from the mysql.user table for the + matching account name + */ + char *auth_string; + + /** + Matching account name as found in the mysql.user table. + A plugin can override it with another name that will be + used by MySQL for authorization, and shown in CURRENT_USER() + */ + char authenticated_as[MYSQL_USERNAME_LENGTH+1]; +} MYSQL_SERVER_AUTH_INFO; + + +#include "auth_pam_base.c" + + +int main(int argc, char **argv) +{ + struct param param; + MYSQL_SERVER_AUTH_INFO info; + unsigned char field; + int res; + char a_buf[MYSQL_USERNAME_LENGTH + 1 + 1024]; + + if (read(0, &field, 1) < 1) + return -1; +#ifndef DBUG_OFF - pam_debug= field; ++ pam_debug= field & 1; +#endif ++ winbind_hack= field & 2; + + PAM_DEBUG((stderr, "PAM: sandbox started [%s].\n", argv[0])); + + info.user_name= a_buf; + if ((res= read_string(0, info.user_name, sizeof(a_buf))) < 0) + return -1; + PAM_DEBUG((stderr, "PAM: sandbox username [%s].\n", info.user_name)); + + info.auth_string= info.user_name + res + 1; + if (read_string(0, info.auth_string, sizeof(a_buf) - 1 - res) < 0) + return -1; + + PAM_DEBUG((stderr, "PAM: sandbox auth string [%s].\n", info.auth_string)); + + if ((res= pam_auth_base(¶m, &info)) != CR_OK) + { + PAM_DEBUG((stderr, "PAM: auth failed, sandbox closed.\n")); + return -1; + } + + if (info.authenticated_as[0]) + { + PAM_DEBUG((stderr, "PAM: send authenticated_as field.\n")); + field= AP_AUTHENTICATED_AS; + if (write(1, &field, 1) < 1 || + write_string(1, (unsigned char *) info.authenticated_as, + strlen(info.authenticated_as))) + return -1; + } + + PAM_DEBUG((stderr, "PAM: send OK result.\n")); + field= AP_EOF; + if (write(1, &field, 1) != 1) + return -1; + + PAM_DEBUG((stderr, "PAM: sandbox closed.\n")); + return 0; +} diff --cc scripts/mysql_install_db.sh index 59607d7f508,92e6ed20cff..a784101b179 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@@ -515,13 -487,9 +515,14 @@@ mysqld_install_cmd_line( --net_buffer_length=16K } +# Use $auth_root_socket_user if explicitly specified. +# Otherwise use the owner of datadir - ${user:-$USER} +# Use 'root' as a fallback +auth_root_socket_user=${auth_root_socket_user:-${user:-${USER:-root}}} + cat_sql() { + echo "create database if not exists mysql;" echo "use mysql;" case "$auth_root_authentication_method" in diff --cc sql/events.cc index 196c8df591d,ce5f2b1bc10..17baae58bff --- a/sql/events.cc +++ b/sql/events.cc @@@ -418,11 -418,17 +418,17 @@@ Events::create_event(THD *thd, Event_pa thd->restore_stmt_binlog_format(save_binlog_format); + if (!ret && Events::opt_event_scheduler == Events::EVENTS_OFF) + { + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, + "Event scheduler is switched off, use SET GLOBAL event_scheduler=ON to enable it."); + } + DBUG_RETURN(ret); - -WSREP_ERROR_LABEL: - DBUG_RETURN(TRUE); - +#ifdef WITH_WSREP +wsrep_error_label: + DBUG_RETURN(true); +#endif } diff --cc sql/handler.cc index 12a05aba90d,14170c99790..3f6b7f565ed --- a/sql/handler.cc +++ b/sql/handler.cc @@@ -5023,6 -4998,98 +5020,98 @@@ end } + static void flush_checksum(ha_checksum *row_crc, uchar **checksum_start, + size_t *checksum_length) + { + if (*checksum_start) + { + *row_crc= my_checksum(*row_crc, *checksum_start, *checksum_length); + *checksum_start= NULL; + *checksum_length= 0; + } + } + + + /* calculating table's checksum */ + int handler::calculate_checksum() + { + int error; + THD *thd=ha_thd(); + DBUG_ASSERT(table->s->last_null_bit_pos < 8); + uchar null_mask= table->s->last_null_bit_pos + ? 256 - (1 << table->s->last_null_bit_pos) : 0; + - table->use_all_columns(); ++ table->use_all_stored_columns(); + stats.checksum= 0; + + if ((error= ha_rnd_init(1))) + return error; + + for (;;) + { + if (thd->killed) + return HA_ERR_ABORTED_BY_USER; + + ha_checksum row_crc= 0; + error= table->file->ha_rnd_next(table->record[0]); + if (error) + break; + + if (table->s->null_bytes) + { + /* fix undefined null bits */ + table->record[0][table->s->null_bytes-1] |= null_mask; + if (!(table->s->db_create_options & HA_OPTION_PACK_RECORD)) + table->record[0][0] |= 1; + + row_crc= my_checksum(row_crc, table->record[0], table->s->null_bytes); + } + + uchar *checksum_start= NULL; + size_t checksum_length= 0; + for (uint i= 0; i < table->s->fields; i++ ) + { + Field *f= table->field[i]; + + if (! thd->variables.old_mode && f->is_real_null(0)) + { + flush_checksum(&row_crc, &checksum_start, &checksum_length); + continue; + } + /* + BLOB and VARCHAR have pointers in their field, we must convert + to string; GEOMETRY is implemented on top of BLOB. + BIT may store its data among NULL bits, convert as well. + */ + switch (f->type()) { + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_GEOMETRY: + case MYSQL_TYPE_BIT: + { + flush_checksum(&row_crc, &checksum_start, &checksum_length); + String tmp; + f->val_str(&tmp); + row_crc= my_checksum(row_crc, (uchar*) tmp.ptr(), tmp.length()); + break; + } + default: + if (!checksum_start) + checksum_start= f->ptr; + DBUG_ASSERT(checksum_start + checksum_length == f->ptr); + checksum_length+= f->pack_length(); + break; + } + } + flush_checksum(&row_crc, &checksum_start, &checksum_length); + + stats.checksum+= row_crc; + } + table->file->ha_rnd_end(); + return error == HA_ERR_END_OF_FILE ? 0 : error; + } + + /**************************************************************************** ** Some general functions that isn't in the handler class ****************************************************************************/ diff --cc sql/item_sum.h index abe6192fcd1,7152916498c..a17d3dcd6b9 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@@ -1845,14 -1797,9 +1846,17 @@@ class Item_func_group_concat : public I friend int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)), void* item_arg); + + bool repack_tree(THD *thd); + +public: + // Methods used by ColumnStore + bool get_distinct() const { return distinct; } + uint get_count_field() const { return arg_count_field; } + uint get_order_field() const { return arg_count_order; } + const String* get_separator() const { return separator; } + ORDER** get_order() const { return order; } + public: Item_func_group_concat(THD *thd, Name_resolution_context *context_arg, bool is_distinct, List<Item> *is_select, diff --cc sql/log_event.cc index 1246330f7bb,fa42e7b0a07..fd3cf6bce1f --- a/sql/log_event.cc +++ b/sql/log_event.cc @@@ -11327,15 -11315,15 +11333,15 @@@ int Rows_log_event::do_apply_event(rpl_ { WSREP_WARN("BF applier failed to open_and_lock_tables: %u, fatal: %d " "wsrep = (exec_mode: %d conflict_state: %d seqno: %lld)", - thd->get_stmt_da()->sql_errno(), - thd->is_fatal_error, - thd->wsrep_exec_mode, - thd->wsrep_conflict_state, - (long long)wsrep_thd_trx_seqno(thd)); + thd->get_stmt_da()->sql_errno(), + thd->is_fatal_error, + thd->wsrep_cs().mode(), + thd->wsrep_trx().state(), + (long long) wsrep_thd_trx_seqno(thd)); } -#endif +#endif /* WITH_WSREP */ - if ((thd->is_slave_error || thd->is_fatal_error) && - !is_parallel_retry_error(rgi, actual_error)) + if (thd->is_error() && + !is_parallel_retry_error(rgi, error= thd->get_stmt_da()->sql_errno())) { /* Error reporting borrowed from Query_log_event with many excessive diff --cc sql/sql_acl.cc index 27f2a985931,60697ab3449..a649ad0e335 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@@ -848,395 -842,84 +848,396 @@@ class Grant_table_bas class User_table: public Grant_table_base { public: - /* Field getters return NULL if the column is not present in the table. - This is consistent only if the table is in a supported version. We do - not guard against corrupt tables. (yet) */ - Field* host() const - { return get_field(0); } - Field* user() const - { return get_field(1); } - Field* password() const - { return have_password() ? NULL : tl.table->field[2]; } - /* Columns after privilege columns. */ - Field* ssl_type() const - { return get_field(start_privilege_column + num_privileges()); } - Field* ssl_cipher() const - { return get_field(start_privilege_column + num_privileges() + 1); } - Field* x509_issuer() const - { return get_field(start_privilege_column + num_privileges() + 2); } - Field* x509_subject() const - { return get_field(start_privilege_column + num_privileges() + 3); } - Field* max_questions() const - { return get_field(start_privilege_column + num_privileges() + 4); } - Field* max_updates() const - { return get_field(start_privilege_column + num_privileges() + 5); } - Field* max_connections() const - { return get_field(start_privilege_column + num_privileges() + 6); } - Field* max_user_connections() const - { return get_field(start_privilege_column + num_privileges() + 7); } - Field* plugin() const - { return get_field(start_privilege_column + num_privileges() + 8); } - Field* authentication_string() const - { return get_field(start_privilege_column + num_privileges() + 9); } - Field* password_expired() const - { return get_field(start_privilege_column + num_privileges() + 10); } - Field* is_role() const - { return get_field(start_privilege_column + num_privileges() + 11); } - Field* default_role() const - { return get_field(start_privilege_column + num_privileges() + 12); } - Field* max_statement_time() const - { return get_field(start_privilege_column + num_privileges() + 13); } + bool init_read_record(READ_RECORD* info) const + { + return Grant_table_base::init_read_record(info) || setup_sysvars(); + } + + virtual LEX_CSTRING& name() const = 0; + virtual int get_auth(THD *, MEM_ROOT *, ACL_USER *u) const= 0; + virtual bool set_auth(const ACL_USER &u) const = 0; + virtual ulong get_access() const = 0; + virtual void set_access(ulong rights, bool revoke) const = 0; + + char *get_host(MEM_ROOT *root) const + { return ::get_field(root, m_table->field[0]); } + int set_host(const char *s, size_t l) const + { return m_table->field[0]->store(s, l, system_charset_info); }; + char *get_user(MEM_ROOT *root) const + { return ::get_field(root, m_table->field[1]); } + int set_user(const char *s, size_t l) const + { return m_table->field[1]->store(s, l, system_charset_info); }; + + virtual SSL_type get_ssl_type () const = 0; + virtual int set_ssl_type (SSL_type x) const = 0; + virtual const char* get_ssl_cipher (MEM_ROOT *root) const = 0; + virtual int set_ssl_cipher (const char *s, size_t l) const = 0; + virtual const char* get_x509_issuer (MEM_ROOT *root) const = 0; + virtual int set_x509_issuer (const char *s, size_t l) const = 0; + virtual const char* get_x509_subject (MEM_ROOT *root) const = 0; + virtual int set_x509_subject (const char *s, size_t l) const = 0; + virtual longlong get_max_questions () const = 0; + virtual int set_max_questions (longlong x) const = 0; + virtual longlong get_max_updates () const = 0; + virtual int set_max_updates (longlong x) const = 0; + virtual longlong get_max_connections () const = 0; + virtual int set_max_connections (longlong x) const = 0; + virtual longlong get_max_user_connections () const = 0; + virtual int set_max_user_connections (longlong x) const = 0; + virtual double get_max_statement_time () const = 0; + virtual int set_max_statement_time (double x) const = 0; + virtual bool get_is_role () const = 0; + virtual int set_is_role (bool x) const = 0; + virtual const char* get_default_role (MEM_ROOT *root) const = 0; + virtual int set_default_role (const char *s, size_t l) const = 0; + virtual bool get_account_locked () const = 0; + virtual int set_account_locked (bool x) const = 0; + virtual bool get_password_expired () const = 0; + virtual int set_password_expired (bool x) const = 0; + virtual my_time_t get_password_last_changed () const = 0; + virtual int set_password_last_changed (my_time_t x) const = 0; + virtual longlong get_password_lifetime () const = 0; + virtual int set_password_lifetime (longlong x) const = 0; + + virtual ~User_table() {} + private: + friend class Grant_tables; + virtual int setup_sysvars() const = 0; +}; - /* - Check if a user entry in the user table is marked as being a role entry +/* MySQL-3.23 to MariaDB 10.3 `user` table */ +class User_table_tabular: public User_table +{ + public: - IMPLEMENTATION - Access the coresponding column and check the coresponding ENUM of the form - ENUM('N', 'Y') + LEX_CSTRING& name() const { return MYSQL_TABLE_NAME_USER; } - SYNOPSIS - check_is_role() - form an open table to read the entry from. - The record should be already read in table->record[0] + int get_auth(THD *thd, MEM_ROOT *root, ACL_USER *u) const + { + u->alloc_auth(root, 1); + if (have_password()) + { + const char *as= safe_str(::get_field(&acl_memroot, password())); + u->auth->auth_string.str= as; + u->auth->auth_string.length= strlen(as); + u->auth->plugin= guess_auth_plugin(thd, u->auth->auth_string.length); + } + else + { + u->auth->plugin= native_password_plugin_name; + u->auth->auth_string= empty_clex_str; + } + if (plugin() && authstr()) + { + char *tmpstr= ::get_field(&acl_memroot, plugin()); + if (tmpstr) + { + const char *pw= u->auth->auth_string.str; + const char *as= safe_str(::get_field(&acl_memroot, authstr())); + if (*pw) + { + if (*as && strcmp(as, pw)) + { + sql_print_warning("'user' entry '%s@%s' has both a password and an " + "authentication plugin specified. The password will be ignored.", + safe_str(get_user(thd->mem_root)), safe_str(get_host(thd->mem_root))); + } + else + as= pw; + } + u->auth->plugin.str= tmpstr; + u->auth->plugin.length= strlen(tmpstr); + u->auth->auth_string.str= as; + u->auth->auth_string.length= strlen(as); + } + } + return 0; + } - RETURN VALUE - TRUE if the user is marked as a role - FALSE otherwise - */ - bool check_is_role() const + bool set_auth(const ACL_USER &u) const { - /* Table version does not support roles */ - if (!is_role()) - return false; + if (u.nauth != 1) + return 1; + if (plugin()) + { + if (have_password()) + password()->reset(); + plugin()->store(u.auth->plugin.str, u.auth->plugin.length, system_charset_info); + authstr()->store(u.auth->auth_string.str, u.auth->auth_string.length, system_charset_info); + } + else + { + if (u.auth->plugin.str != native_password_plugin_name.str && + u.auth->plugin.str != old_password_plugin_name.str) + return 1; + password()->store(u.auth->auth_string.str, u.auth->auth_string.length, system_charset_info); + } + return 0; + } + + ulong get_access() const + { + ulong access= Grant_table_base::get_access(); ++ DBUG_ASSERT(num_fields() >= 13); + if ((num_fields() <= 13) && (access & CREATE_ACL)) + access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL; + + if (num_fields() <= 18) + { + access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL; + if (access & FILE_ACL) + access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL; + if (access & PROCESS_ACL) + access|= SUPER_ACL | EXECUTE_ACL; + } + + if (num_fields() <= 31 && (access & CREATE_ACL)) + access|= (CREATE_VIEW_ACL | SHOW_VIEW_ACL); + + if (num_fields() <= 33) + { + if (access & CREATE_ACL) + access|= CREATE_PROC_ACL; + if (access & ALTER_ACL) + access|= ALTER_PROC_ACL; + } + + if (num_fields() <= 36 && (access & GRANT_ACL)) + access|= CREATE_USER_ACL; + + if (num_fields() <= 37 && (access & SUPER_ACL)) + access|= EVENT_ACL; - return get_YN_as_bool(is_role()); + if (num_fields() <= 38 && (access & SUPER_ACL)) + access|= TRIGGER_ACL; + + if (num_fields() <= 46 && (access & DELETE_ACL)) + access|= DELETE_HISTORY_ACL; + + return access & GLOBAL_ACLS; } + void set_access(ulong rights, bool revoke) const + { + ulong priv= SELECT_ACL; + for (uint i= start_priv_columns; i < end_priv_columns; i++, priv <<= 1) + { + if (priv & rights) + m_table->field[i]->store(1 + !revoke, 0); + } + } - private: - friend class Grant_tables; + SSL_type get_ssl_type () const + { + Field *f= get_field(end_priv_columns, MYSQL_TYPE_ENUM); + return (SSL_type)(f ? f->val_int()-1 : 0); + } + int set_ssl_type (SSL_type x) const + { + if (Field *f= get_field(end_priv_columns, MYSQL_TYPE_ENUM)) + return f->store(x+1, 0); + else + return 1; + } + const char* get_ssl_cipher (MEM_ROOT *root) const + { + Field *f= get_field(end_priv_columns + 1, MYSQL_TYPE_BLOB); + return f ? ::get_field(root,f) : 0; + } + int set_ssl_cipher (const char *s, size_t l) const + { + if (Field *f= get_field(end_priv_columns + 1, MYSQL_TYPE_BLOB)) + return f->store(s, l, &my_charset_latin1); + else + return 1; + } + const char* get_x509_issuer (MEM_ROOT *root) const + { + Field *f= get_field(end_priv_columns + 2, MYSQL_TYPE_BLOB); + return f ? ::get_field(root,f) : 0; + } + int set_x509_issuer (const char *s, size_t l) const + { + if (Field *f= get_field(end_priv_columns + 2, MYSQL_TYPE_BLOB)) + return f->store(s, l, &my_charset_latin1); + else + return 1; + } + const char* get_x509_subject (MEM_ROOT *root) const + { + Field *f= get_field(end_priv_columns + 3, MYSQL_TYPE_BLOB); + return f ? ::get_field(root,f) : 0; + } + int set_x509_subject (const char *s, size_t l) const + { + if (Field *f= get_field(end_priv_columns + 3, MYSQL_TYPE_BLOB)) + return f->store(s, l, &my_charset_latin1); + else + return 1; + } + longlong get_max_questions () const + { + Field *f= get_field(end_priv_columns + 4, MYSQL_TYPE_LONG); + return f ? f->val_int() : 0; + } + int set_max_questions (longlong x) const + { + if (Field *f= get_field(end_priv_columns + 4, MYSQL_TYPE_LONG)) + return f->store(x, 0); + else + return 1; + } + longlong get_max_updates () const + { + Field *f= get_field(end_priv_columns + 5, MYSQL_TYPE_LONG); + return f ? f->val_int() : 0; + } + int set_max_updates (longlong x) const + { + if (Field *f= get_field(end_priv_columns + 5, MYSQL_TYPE_LONG)) + return f->store(x, 0); + else + return 1; + } + longlong get_max_connections () const + { + Field *f= get_field(end_priv_columns + 6, MYSQL_TYPE_LONG); + return f ? f->val_int() : 0; + } + int set_max_connections (longlong x) const + { + if (Field *f= get_field(end_priv_columns + 6, MYSQL_TYPE_LONG)) + return f->store(x, 0); + else + return 1; + } + longlong get_max_user_connections () const + { + Field *f= get_field(end_priv_columns + 7, MYSQL_TYPE_LONG); + return f ? f->val_int() : 0; + } + int set_max_user_connections (longlong x) const + { + if (Field *f= get_field(end_priv_columns + 7, MYSQL_TYPE_LONG)) + return f->store(x, 0); + else + return 1; + } + double get_max_statement_time () const + { + Field *f= get_field(end_priv_columns + 13, MYSQL_TYPE_NEWDECIMAL); + return f ? f->val_real() : 0; + } + int set_max_statement_time (double x) const + { + if (Field *f= get_field(end_priv_columns + 13, MYSQL_TYPE_NEWDECIMAL)) + return f->store(x); + else + return 1; + } + bool get_is_role () const + { + Field *f= get_field(end_priv_columns + 11, MYSQL_TYPE_ENUM); + return f ? f->val_int()-1 : 0; + } + int set_is_role (bool x) const + { + if (Field *f= get_field(end_priv_columns + 11, MYSQL_TYPE_ENUM)) + return f->store(x+1, 0); + else + return 1; + } + const char* get_default_role (MEM_ROOT *root) const + { + Field *f= get_field(end_priv_columns + 12, MYSQL_TYPE_STRING); + return f ? ::get_field(root,f) : 0; + } + int set_default_role (const char *s, size_t l) const + { + if (Field *f= get_field(end_priv_columns + 12, MYSQL_TYPE_STRING)) + return f->store(s, l, system_charset_info); + else + return 1; + } + /* On a MariaDB 10.3 user table, the account locking accessors will try to + get the content of the max_statement_time column, but they will fail due + to the typecheck in get_field. */ + bool get_account_locked () const + { + Field *f= get_field(end_priv_columns + 13, MYSQL_TYPE_ENUM); + return f ? f->val_int()-1 : 0; + } + int set_account_locked (bool x) const + { + if (Field *f= get_field(end_priv_columns + 13, MYSQL_TYPE_ENUM)) + return f->store(x+1, 0); - /* Only Grant_tables can instantiate this class. */ - User_table() {}; + return 1; + } - void init(enum thr_lock_type lock_type) + bool get_password_expired () const + { + uint field_num= end_priv_columns + 10; + + Field *f= get_field(field_num, MYSQL_TYPE_ENUM); + return f ? f->val_int()-1 : 0; + } + int set_password_expired (bool x) const + { + uint field_num= end_priv_columns + 10; + + if (Field *f= get_field(field_num, MYSQL_TYPE_ENUM)) + return f->store(x+1, 0); + return 1; + } + my_time_t get_password_last_changed () const + { + ulong unused_dec; + if (Field *f= get_field(end_priv_columns + 11, MYSQL_TYPE_TIMESTAMP2)) + return f->get_timestamp(&unused_dec); + return 0; + } + int set_password_last_changed (my_time_t x) const + { + if (Field *f= get_field(end_priv_columns + 11, MYSQL_TYPE_TIMESTAMP2)) + { + f->set_notnull(); + return f->store_timestamp(x, 0); + } + return 1; + } + longlong get_password_lifetime () const + { + if (Field *f= get_field(end_priv_columns + 12, MYSQL_TYPE_SHORT)) + { + if (f->is_null()) + return -1; + return f->val_int(); + } + return 0; + } + int set_password_lifetime (longlong x) const { - /* We are relying on init_one_table zeroing out the TABLE_LIST structure. */ - tl.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_USER_NAME, NULL, lock_type); - Grant_table_base::init(lock_type, false); + if (Field *f= get_field(end_priv_columns + 12, MYSQL_TYPE_SHORT)) + { + if (x < 0) + { + f->set_null(); + return 0; + } + f->set_notnull(); + return f->store(x, 0); + } + return 1; } + virtual ~User_table_tabular() {} + private: + friend class Grant_tables; + + /* Only Grant_tables can instantiate this class. */ + User_table_tabular() {} + /* The user table is a bit different compared to the other Grant tables. Usually, we only add columns to the grant tables when adding functionality. This makes it easy to test which version of the table we are using, by @@@ -1251,59 -934,8 +1252,65 @@@ { if (field_num >= num_fields()) return NULL; + Field *f= m_table->field[field_num]; + return f->real_type() == type ? f : NULL; + } + + int setup_sysvars() const + { ++ if (num_fields() < 13) // number of columns in 3.21 ++ { ++ sql_print_error("Fatal error: mysql.user table is damaged or in " ++ "unsupported 3.20 format."); ++ return 1; ++ } + username_char_length= MY_MIN(m_table->field[1]->char_length(), + USERNAME_CHAR_LENGTH); + using_global_priv_table= false; + + if (have_password()) // Password column might be missing. (MySQL 5.7.6+) + { + int password_length= password()->field_length / + password()->charset()->mbmaxlen; + if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323) + { + sql_print_error("Fatal error: mysql.user table is damaged or in " + "unsupported 3.20 format."); + return 1; + } - return tl.table->field[field_num]; + mysql_mutex_lock(&LOCK_global_system_variables); + if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH) + { + if (opt_secure_auth) + { + mysql_mutex_unlock(&LOCK_global_system_variables); + sql_print_error("Fatal error: mysql.user table is in old format, " + "but server started with --secure-auth option."); + return 1; + } + mysql_user_table_is_in_short_password_format= true; + if (global_system_variables.old_passwords) + mysql_mutex_unlock(&LOCK_global_system_variables); + else + { + extern sys_var *Sys_old_passwords_ptr; + Sys_old_passwords_ptr->value_origin= sys_var::AUTO; + global_system_variables.old_passwords= 1; + mysql_mutex_unlock(&LOCK_global_system_variables); + sql_print_warning("mysql.user table is not updated to new password format; " + "Disabling new password usage until " + "mysql_fix_privilege_tables is run"); + } + m_table->in_use->variables.old_passwords= 1; + } + else + { + mysql_user_table_is_in_short_password_format= false; + mysql_mutex_unlock(&LOCK_global_system_variables); + } + } + return 0; } /* Normally password column is the third column in the table. If privileges @@@ -1808,52 -1223,16 +1815,52 @@@ class Grant_table DBUG_RETURN(-1); } - /* The privilge columns vary based on MariaDB version. Figure out - how many we have after we've opened the table. */ - m_user_table.compute_num_privilege_cols(); - m_db_table.compute_num_privilege_cols(); - m_tables_priv_table.compute_num_privilege_cols(); - m_columns_priv_table.compute_num_privilege_cols(); - m_host_table.compute_num_privilege_cols(); - m_procs_priv_table.compute_num_privilege_cols(); - m_proxies_priv_table.compute_num_privilege_cols(); - m_roles_mapping_table.compute_num_privilege_cols(); + for (int i=USER_TABLE; i >=0; i--) + { + TABLE_LIST *tl= tables + i; + if (which_tables & (1 << i)) + { + tl->init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_TABLE_NAME[i], + NULL, lock_type); - tl->updating= lock_type >= TL_WRITE_ALLOW_WRITE; ++ tl->i_s_requested_object= OPEN_TABLE_ONLY; + if (i >= FIRST_OPTIONAL_TABLE) + tl->open_strategy= TABLE_LIST::OPEN_IF_EXISTS; + tl->next_global= tl->next_local= first; + first= tl; + } + else + tl->table= NULL; + } + + uint counter; + int res= really_open(thd, first, &counter); + + /* if User_table_json wasn't found, let's try User_table_tabular */ + if (!res && (which_tables & Table_user) && !(tables[USER_TABLE].table)) + { + uint unused; + TABLE_LIST *tl= tables + USER_TABLE; + tl->init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_TABLE_NAME_USER, + NULL, lock_type); + tl->updating= lock_type >= TL_WRITE_ALLOW_WRITE; + p_user_table= &m_user_table_tabular; + counter++; + res= really_open(thd, tl, &unused); + } + if (res) + DBUG_RETURN(res); + + if (lock_tables(thd, first, counter, MYSQL_LOCK_IGNORE_TIMEOUT)) + DBUG_RETURN(-1); + + p_user_table->set_table(tables[USER_TABLE].table); + m_db_table.set_table(tables[DB_TABLE].table); + m_tables_priv_table.set_table(tables[TABLES_PRIV_TABLE].table); + m_columns_priv_table.set_table(tables[COLUMNS_PRIV_TABLE].table); + m_host_table.set_table(tables[HOST_TABLE].table); + m_procs_priv_table.set_table(tables[PROCS_PRIV_TABLE].table); + m_proxies_priv_table.set_table(tables[PROXIES_PRIV_TABLE].table); + m_roles_mapping_table.set_table(tables[ROLES_MAPPING_TABLE].table); DBUG_RETURN(0); } diff --cc sql/sql_class.h index 1266e1777ce,2a949856879..b93cf44192d --- a/sql/sql_class.h +++ b/sql/sql_class.h @@@ -39,7 -38,10 +39,9 @@@ #include "thr_timer.h" #include "thr_malloc.h" #include "log_slow.h" /* LOG_SLOW_DISABLE_... */ + #include <my_tree.h> + #include "sql_digest_stream.h" // sql_digest_state - #include <mysql/psi/mysql_stage.h> #include <mysql/psi/mysql_statement.h> #include <mysql/psi/mysql_idle.h> diff --cc sql/sql_lex.cc index b0544300f1d,7b4eb13a5fc..c02263a1ce7 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@@ -8820,1605 -8266,9 +8836,1607 @@@ bool LEX::tvc_finalize_derived( thd->parse_error(); return true; } - if (current_select->linkage == GLOBAL_OPTIONS_TYPE || + if (current_select->get_linkage() == GLOBAL_OPTIONS_TYPE || unlikely(mysql_new_select(this, 1, NULL))) return true; - current_select->linkage= DERIVED_TABLE_TYPE; + current_select->set_linkage(DERIVED_TABLE_TYPE); return tvc_finalize(); } + + +void st_select_lex_unit::reset_distinct() +{ + union_distinct= NULL; + for(SELECT_LEX *sl= first_select()->next_select(); + sl; + sl= sl->next_select()) + { + if (sl->distinct) + { + union_distinct= sl; + } + } +} + + +void st_select_lex_unit::fix_distinct() +{ + if (union_distinct && this != union_distinct->master_unit()) + reset_distinct(); +} + + +void st_select_lex_unit::register_select_chain(SELECT_LEX *first_sel) +{ + DBUG_ASSERT(first_sel != 0); + slave= first_sel; + first_sel->prev= &slave; + for(SELECT_LEX *sel=first_sel; sel; sel= sel->next_select()) + { + sel->master= (st_select_lex_node *)this; + uncacheable|= sel->uncacheable; + } +} + + +void st_select_lex::register_unit(SELECT_LEX_UNIT *unit, + Name_resolution_context *outer_context) +{ + if ((unit->next= slave)) + slave->prev= &unit->next; + unit->prev= &slave; + slave= unit; + unit->master= this; + uncacheable|= unit->uncacheable; + + for(SELECT_LEX *sel= unit->first_select();sel; sel= sel->next_select()) + { + sel->context.outer_context= outer_context; + } +} + + +void st_select_lex::add_statistics(SELECT_LEX_UNIT *unit) +{ + for (; + unit; + unit= unit->next_unit()) + for(SELECT_LEX *child= unit->first_select(); + child; + child= child->next_select()) + { + /* + A subselect can add fields to an outer select. + Reserve space for them. + */ + select_n_where_fields+= child->select_n_where_fields; + /* + Aggregate functions in having clause may add fields + to an outer select. Count them also. + */ + select_n_having_items+= child->select_n_having_items; + } +} + + +bool LEX::main_select_push() +{ + DBUG_ENTER("LEX::main_select_push"); + current_select_number= 1; + builtin_select.select_number= 1; + if (push_select(&builtin_select)) + DBUG_RETURN(TRUE); + DBUG_RETURN(FALSE); +} + +void Lex_select_lock::set_to(SELECT_LEX *sel) +{ + if (defined_lock) + { ++ + if (sel->master_unit() && + sel == sel->master_unit()->fake_select_lex) + sel->master_unit()->set_lock_to_the_last_select(*this); + else + { + sel->parent_lex->safe_to_cache_query= 0; + if (update_lock) + { + sel->lock_type= TL_WRITE; - sel->set_lock_for_tables(TL_WRITE); ++ sel->set_lock_for_tables(TL_WRITE, false); + } + else + { + sel->lock_type= TL_READ_WITH_SHARED_LOCKS; - sel->set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS); ++ sel->set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS, false); + } + } + } +} + +bool Lex_order_limit_lock::set_to(SELECT_LEX *sel) +{ + /*TODO: lock */ + //if (lock.defined_lock && sel == sel->master_unit()->fake_select_lex) + // return TRUE; + if (lock.defined_timeout) + { + THD *thd= sel->parent_lex->thd; + if (set_statement_var_if_exists(thd, + C_STRING_WITH_LEN("lock_wait_timeout"), + lock.timeout) || + set_statement_var_if_exists(thd, + C_STRING_WITH_LEN("innodb_lock_wait_timeout"), + lock.timeout)) + return TRUE; + } + lock.set_to(sel); + sel->explicit_limit= limit.explicit_limit; + sel->select_limit= limit.select_limit; + sel->offset_limit= limit.offset_limit; + if (order_list) + { + if (sel->get_linkage() != GLOBAL_OPTIONS_TYPE && + sel->olap != UNSPECIFIED_OLAP_TYPE && + (sel->get_linkage() != UNION_TYPE || sel->braces)) + { + my_error(ER_WRONG_USAGE, MYF(0), + "CUBE/ROLLUP", "ORDER BY"); + return TRUE; + } + sel->order_list= *(order_list); + } + sel->is_set_query_expr_tail= true; + return FALSE; +} + + +static void change_item_list_context(List<Item> *list, + Name_resolution_context *context) +{ + List_iterator_fast<Item> it (*list); + Item *item; + while((item= it++)) + { + item->walk(&Item::change_context_processor, FALSE, (void *)context); + } +} + + +bool LEX::insert_select_hack(SELECT_LEX *sel) +{ + DBUG_ENTER("LEX::insert_select_hack"); + + DBUG_ASSERT(first_select_lex() == &builtin_select); + DBUG_ASSERT(sel != NULL); + + DBUG_ASSERT(builtin_select.first_inner_unit() == NULL); + + if (builtin_select.link_prev) + { + if ((*builtin_select.link_prev= builtin_select.link_next)) + ((st_select_lex *)builtin_select.link_next)->link_prev= + builtin_select.link_prev; + builtin_select.link_prev= NULL; // indicator of removal + } + + set_main_unit(sel->master_unit()); + + DBUG_ASSERT(builtin_select.table_list.elements == 1); + TABLE_LIST *insert_table= builtin_select.table_list.first; + + if (!(insert_table->next_local= sel->table_list.first)) + { + sel->table_list.next= &insert_table->next_local; + } + sel->table_list.first= insert_table; + sel->table_list.elements++; + insert_table->select_lex= sel; + + sel->context.first_name_resolution_table= insert_table; + builtin_select.context= sel->context; + change_item_list_context(&field_list, &sel->context); + + if (sel->tvc && !sel->next_select() && + (sql_command == SQLCOM_INSERT_SELECT || + sql_command == SQLCOM_REPLACE_SELECT)) + { + DBUG_PRINT("info", ("'Usual' INSERT detected")); + many_values= sel->tvc->lists_of_values; + sel->options= sel->tvc->select_options; + sel->tvc= NULL; + if (sql_command == SQLCOM_INSERT_SELECT) + sql_command= SQLCOM_INSERT; + else + sql_command= SQLCOM_REPLACE; + } + + + for (SELECT_LEX *sel= all_selects_list; + sel; + sel= sel->next_select_in_list()) + { + if (sel->select_number != 1) + sel->select_number--; + }; + + DBUG_RETURN(FALSE); +} + + +/* + Create an Item_singlerow_subselect for a query expression. +*/ +Item *LEX::create_item_query_expression(THD *thd, + const char *tok_start, + st_select_lex_unit *unit) +{ + if (!expr_allows_subselect) + { + thd->parse_error(ER_SYNTAX_ERROR, tok_start); + return NULL; + } + + // Add the subtree of subquery to the current SELECT_LEX + SELECT_LEX *curr_sel= select_stack_head(); + DBUG_ASSERT(current_select == curr_sel); + if (!curr_sel) + curr_sel= &builtin_select; + curr_sel->register_unit(unit, &curr_sel->context); + curr_sel->add_statistics(unit); + + return new (thd->mem_root) + Item_singlerow_subselect(thd, unit->first_select()); +} + + +/** + Process unit parsed in brackets +*/ + +bool LEX::parsed_unit_in_brackets(SELECT_LEX_UNIT *unit) +{ + SELECT_LEX *first_in_nest= unit->pre_last_parse->next_select()->first_nested; + if (first_in_nest->first_nested != first_in_nest) + { + /* There is a priority jump starting from first_in_nest */ + if (create_priority_nest(first_in_nest) == NULL) + return true; + unit->fix_distinct(); + } + push_select(unit->fake_select_lex); + return false; +} + + + +/** + Process tail of unit parsed in brackets +*/ +SELECT_LEX *LEX::parsed_unit_in_brackets_tail(SELECT_LEX_UNIT *unit, + Lex_order_limit_lock * l) +{ + pop_select(); + if (l) + { + (l)->set_to(unit->fake_select_lex); + } + return unit->first_select(); +} + + +/** + Process select parsed in brackets +*/ + +SELECT_LEX *LEX::parsed_select(SELECT_LEX *sel, Lex_order_limit_lock * l) +{ + pop_select(); + if (l) + { + if (sel->next_select()) + { + SELECT_LEX_UNIT *unit= sel->master_unit(); + if (!unit) + unit= create_unit(sel); + if (!unit) + return NULL; + if (!unit->fake_select_lex->is_set_query_expr_tail) + l->set_to(unit->fake_select_lex); + else + { + if (!l->order_list && !unit->fake_select_lex->explicit_limit) + { + sel= unit->fake_select_lex; + l->order_list= &sel->order_list; + } + else + sel= wrap_unit_into_derived(unit); + if (!sel) + return NULL; + l->set_to(sel); + } + } + else if (!sel->is_set_query_expr_tail) + { + l->set_to(sel); + } + else + { + if (!l->order_list && !sel->explicit_limit) + l->order_list= &sel->order_list; + else + { + SELECT_LEX_UNIT *unit= create_unit(sel); + if (!unit) + return NULL; + sel= wrap_unit_into_derived(unit); + } + if (!sel) + return NULL; + l->set_to(sel); + } + } + return sel; +} + + +/** + Process select parsed in brackets +*/ + +SELECT_LEX *LEX::parsed_select_in_brackets(SELECT_LEX *sel, + Lex_order_limit_lock * l) +{ + sel->braces= TRUE; + return parsed_select(sel, l); +} + + +SELECT_LEX_UNIT *LEX::parsed_select_expr_start(SELECT_LEX *s1, SELECT_LEX *s2, + enum sub_select_type unit_type, + bool distinct) +{ + SELECT_LEX_UNIT *res; + SELECT_LEX *sel1; + SELECT_LEX *sel2; + if (!s1->next_select()) + sel1= s1; + else + { + sel1= wrap_unit_into_derived(s1->master_unit()); + if (!sel1) + return NULL; + } + if (!s2->next_select()) + sel2= s2; + else + { + sel2= wrap_unit_into_derived(s2->master_unit()); + if (!sel2) + return NULL; + } + sel1->link_neighbour(sel2); + sel2->set_linkage_and_distinct(unit_type, distinct); + sel2->first_nested= sel1->first_nested= sel1; + res= create_unit(sel1); + if (res == NULL) + return NULL; + res->pre_last_parse= sel1; + return res; +} + + +SELECT_LEX_UNIT *LEX::parsed_select_expr_cont(SELECT_LEX_UNIT *unit, + SELECT_LEX *s2, + enum sub_select_type unit_type, + bool distinct, bool oracle) +{ + SELECT_LEX *sel1; + if (!s2->next_select()) + sel1= s2; + else + { + sel1= wrap_unit_into_derived(s2->master_unit()); + if (!sel1) + return NULL; + } + SELECT_LEX *last= unit->pre_last_parse->next_select(); + + int cmp= oracle? 0 : cmp_unit_op(unit_type, last->get_linkage()); + if (cmp == 0) + { + sel1->first_nested= last->first_nested; + } + else if (cmp > 0) + { + last->first_nested= unit->pre_last_parse; + sel1->first_nested= last; + } + else /* cmp < 0 */ + { + SELECT_LEX *first_in_nest= last->first_nested; + if (first_in_nest->first_nested != first_in_nest) + { + /* There is a priority jump starting from first_in_nest */ + if ((last= create_priority_nest(first_in_nest)) == NULL) + return NULL; + unit->fix_distinct(); + } + sel1->first_nested= last->first_nested; + } + last->link_neighbour(sel1); + sel1->set_master_unit(unit); + sel1->set_linkage_and_distinct(unit_type, distinct); + unit->pre_last_parse= last; + return unit; +} + +/** + Process parsed select in body +*/ + +SELECT_LEX_UNIT *LEX::parsed_body_select(SELECT_LEX *sel, + Lex_order_limit_lock * l) +{ + if (!(sel= parsed_select(sel, l))) + return NULL; + + SELECT_LEX_UNIT *res= create_unit(sel); + return res; +} + +/** + Process parsed unit in body +*/ + +bool LEX::parsed_body_unit(SELECT_LEX_UNIT *unit) +{ + SELECT_LEX *first_in_nest= + unit->pre_last_parse->next_select()->first_nested; + if (first_in_nest->first_nested != first_in_nest) + { + /* There is a priority jump starting from first_in_nest */ + if (create_priority_nest(first_in_nest) == NULL) + return true; + unit->fix_distinct(); + } + push_select(unit->fake_select_lex); + return false; +} + +/** + Process parsed tail of unit in body + + TODO: make processing for double tail case +*/ + +SELECT_LEX_UNIT *LEX::parsed_body_unit_tail(SELECT_LEX_UNIT *unit, + Lex_order_limit_lock * l) +{ + pop_select(); + if (l) + { + (l)->set_to(unit->fake_select_lex); + } + return unit; +} + +/** + Process subselect parsing +*/ + +SELECT_LEX *LEX::parsed_subselect(SELECT_LEX_UNIT *unit, char *place) +{ + if (!expr_allows_subselect) + { + thd->parse_error(ER_SYNTAX_ERROR, place); + return NULL; + } + + // Add the subtree of subquery to the current SELECT_LEX + SELECT_LEX *curr_sel= select_stack_head(); + DBUG_ASSERT(current_select == curr_sel); + if (curr_sel) + { + curr_sel->register_unit(unit, &curr_sel->context); + curr_sel->add_statistics(unit); + } + + return unit->first_select(); +} + + + +/** + Process INSERT-like select +*/ + +bool LEX::parsed_insert_select(SELECT_LEX *first_select) +{ + if (sql_command == SQLCOM_INSERT || + sql_command == SQLCOM_REPLACE) + { + if (sql_command == SQLCOM_INSERT) + sql_command= SQLCOM_INSERT_SELECT; + else + sql_command= SQLCOM_REPLACE_SELECT; + } + insert_select_hack(first_select); + if (check_main_unit_semantics()) + return true; + + // fix "main" select + SELECT_LEX *blt __attribute__((unused))= pop_select(); + DBUG_ASSERT(blt == &builtin_select); + push_select(first_select); + return false; +} + + +bool LEX::parsed_TVC_start() +{ + SELECT_LEX *sel; + many_values.empty(); + insert_list= 0; + if (!(sel= alloc_select(TRUE)) || + push_select(sel)) + return true; + sel->init_select(); + sel->braces= FALSE; // just initialisation + return false; +} + + +SELECT_LEX *LEX::parsed_TVC_end() +{ + + SELECT_LEX *res= pop_select(); // above TVC select + if (!(res->tvc= + new (thd->mem_root) table_value_constr(many_values, + res, + res->options))) + return NULL; + many_values.empty(); + return res; +} + + +TABLE_LIST *LEX::parsed_derived_select(SELECT_LEX *sel, int for_system_time, + LEX_CSTRING *alias) +{ + TABLE_LIST *res; + derived_tables|= DERIVED_SUBQUERY; + sel->set_linkage(DERIVED_TABLE_TYPE); + sel->braces= FALSE; + // Add the subtree of subquery to the current SELECT_LEX + SELECT_LEX *curr_sel= select_stack_head(); + DBUG_ASSERT(current_select == curr_sel); + SELECT_LEX_UNIT *unit= sel->master_unit(); + if (!unit) + { + unit= create_unit(sel); + if (!unit) + return NULL; + } + curr_sel->register_unit(unit, &curr_sel->context); + curr_sel->add_statistics(unit); + + Table_ident *ti= new (thd->mem_root) Table_ident(unit); + if (ti == NULL) + return NULL; + if (!(res= curr_sel->add_table_to_list(thd, ti, alias, 0, + TL_READ, MDL_SHARED_READ))) + return NULL; + if (for_system_time) + { + res->vers_conditions= vers_conditions; + } + return res; +} + +TABLE_LIST *LEX::parsed_derived_unit(SELECT_LEX_UNIT *unit, + int for_system_time, + LEX_CSTRING *alias) +{ + TABLE_LIST *res; + derived_tables|= DERIVED_SUBQUERY; + unit->first_select()->set_linkage(DERIVED_TABLE_TYPE); + + // Add the subtree of subquery to the current SELECT_LEX + SELECT_LEX *curr_sel= select_stack_head(); + DBUG_ASSERT(current_select == curr_sel); + curr_sel->register_unit(unit, &curr_sel->context); + curr_sel->add_statistics(unit); + + Table_ident *ti= new (thd->mem_root) Table_ident(unit); + if (ti == NULL) + return NULL; + if (!(res= curr_sel->add_table_to_list(thd, ti, alias, 0, + TL_READ, MDL_SHARED_READ))) + return NULL; + if (for_system_time) + { + res->vers_conditions= vers_conditions; + } + return res; +} + +bool LEX::parsed_create_view(SELECT_LEX_UNIT *unit, int check) +{ + SQL_I_List<TABLE_LIST> *save= &first_select_lex()->table_list; + set_main_unit(unit); + if (check_main_unit_semantics()) + return true; + first_select_lex()->table_list.push_front(save); + current_select= first_select_lex(); + size_t len= thd->m_parser_state->m_lip.get_cpp_ptr() - + create_view->select.str; + void *create_view_select= thd->memdup(create_view->select.str, len); + create_view->select.length= len; + create_view->select.str= (char *) create_view_select; + size_t not_used; + trim_whitespace(thd->charset(), + &create_view->select, ¬_used); + create_view->check= check; + parsing_options.allows_variable= TRUE; + return false; +} + +bool LEX::select_finalize(st_select_lex_unit *expr) +{ + sql_command= SQLCOM_SELECT; + selects_allow_into= TRUE; + selects_allow_procedure= TRUE; + set_main_unit(expr); + return check_main_unit_semantics(); +} + + +/* + "IN" and "EXISTS" subselect can appear in two statement types: + + 1. Statements that can have table columns, such as SELECT, DELETE, UPDATE + 2. Statements that cannot have table columns, e.g: + RETURN ((1) IN (SELECT * FROM t1)) + IF ((1) IN (SELECT * FROM t1)) + + Statements of the first type call master_select_push() in the beginning. + In such case everything is properly linked. + + Statements of the second type do not call mastr_select_push(). + Here we catch the second case and relink thd->lex->builtin_select and + select_lex to properly point to each other. + + QQ: Shouldn't subselects of other type also call relink_hack()? + QQ: Can we do it at constructor time instead? +*/ + +void LEX::relink_hack(st_select_lex *select_lex) +{ + if (!select_stack_top) // Statements of the second type + { + if (!select_lex->get_master()->get_master()) + ((st_select_lex *) select_lex->get_master())-> + set_master(&builtin_select); + if (!builtin_select.get_slave()) + builtin_select.set_slave(select_lex->get_master()); + } +} + + + +bool SELECT_LEX_UNIT::set_lock_to_the_last_select(Lex_select_lock l) +{ + if (l.defined_lock) + { + SELECT_LEX *sel= first_select(); + while (sel->next_select()) + sel= sel->next_select(); + if (sel->braces) + { + my_error(ER_WRONG_USAGE, MYF(0), "lock options", + "End SELECT expression"); + return TRUE; + } + l.set_to(sel); ++ + } + return FALSE; +} + +/** + Generate unique name for generated derived table for this SELECT +*/ + +bool SELECT_LEX::make_unique_derived_name(THD *thd, LEX_CSTRING *alias) +{ + // uint32 digits + two underscores + trailing '\0' + char buff[MAX_INT_WIDTH + 2 + 1]; + alias->length= my_snprintf(buff, sizeof(buff), "__%u", select_number); + alias->str= thd->strmake(buff, alias->length); + return !alias->str; +} + + +/* + Make a new sp_instr_stmt and set its m_query to a concatenation + of two strings. +*/ +bool LEX::new_sp_instr_stmt(THD *thd, + const LEX_CSTRING &prefix, + const LEX_CSTRING &suffix) +{ + LEX_STRING qbuff; + sp_instr_stmt *i; + + if (!(i= new (thd->mem_root) sp_instr_stmt(sphead->instructions(), + spcont, this))) + return true; + + qbuff.length= prefix.length + suffix.length; + if (!(qbuff.str= (char*) alloc_root(thd->mem_root, qbuff.length + 1))) + return true; + memcpy(qbuff.str, prefix.str, prefix.length); + strmake(qbuff.str + prefix.length, suffix.str, suffix.length); + i->m_query= qbuff; + return sphead->add_instr(i); +} + + +bool LEX::sp_proc_stmt_statement_finalize_buf(THD *thd, const LEX_CSTRING &qbuf) +{ + sphead->m_flags|= sp_get_flags_for_command(this); + /* "USE db" doesn't work in a procedure */ + if (unlikely(sql_command == SQLCOM_CHANGE_DB)) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "USE"); + return true; + } + /* + Don't add an instruction for SET statements, since all + instructions for them were already added during processing + of "set" rule. + */ + DBUG_ASSERT(sql_command != SQLCOM_SET_OPTION || var_list.is_empty()); + if (sql_command != SQLCOM_SET_OPTION) + return new_sp_instr_stmt(thd, empty_clex_str, qbuf); + return false; +} + + +bool LEX::sp_proc_stmt_statement_finalize(THD *thd, bool no_lookahead) +{ + // Extract the query statement from the tokenizer + Lex_input_stream *lip= &thd->m_parser_state->m_lip; + Lex_cstring qbuf(sphead->m_tmp_query, no_lookahead ? lip->get_ptr() : + lip->get_tok_start()); + return LEX::sp_proc_stmt_statement_finalize_buf(thd, qbuf); +} + + +/** + @brief + Extract the condition that can be pushed into WHERE clause + + @param thd the thread handle + @param cond the condition from which to extract a pushed condition + @param remaining_cond IN/OUT the condition that will remain of cond after + the extraction + @param transformer the transformer callback function to be + applied to the fields of the condition so it + can be pushed` + @param arg parameter to be passed to the transformer + + @details + This function builds the most restrictive condition depending only on + the fields used in the GROUP BY of this SELECT. These fields were + collected before in grouping_tmp_fields list of this SELECT. + + First this method checks if this SELECT doesn't have any aggregation + functions and has no GROUP BY clause. If so cond can be entirely pushed + into WHERE. + + Otherwise the method checks if there is a condition depending only on + grouping fields that can be extracted from cond. + + The condition that can be pushed into WHERE should be transformed. + It is done by transformer. + + The extracted condition is saved in cond_pushed_into_where of this select. + cond can remain un empty after the extraction of the condition that can be + pushed into WHERE. It is saved in remaining_cond. + + @note + This method is called for pushdown conditions into materialized + derived tables/views optimization. + Item::derived_field_transformer_for_where is passed as the actual + callback function. + Also it is called for pushdown into materialized IN subqueries. + Item::in_subq_field_transformer_for_where is passed as the actual + callback function. +*/ + +void st_select_lex::pushdown_cond_into_where_clause(THD *thd, Item *cond, + Item **remaining_cond, + Item_transformer transformer, + uchar *arg) +{ + if (!cond_pushdown_is_allowed()) + return; + thd->lex->current_select= this; + if (have_window_funcs()) + { + Item *cond_over_partition_fields; + check_cond_extraction_for_grouping_fields(thd, cond); + cond_over_partition_fields= + build_cond_for_grouping_fields(thd, cond, true); + if (cond_over_partition_fields) + cond_over_partition_fields= cond_over_partition_fields->transform(thd, + &Item::grouping_field_transformer_for_where, + (uchar*) this); + if (cond_over_partition_fields) + { + cond_over_partition_fields->walk( + &Item::cleanup_excluding_const_fields_processor, 0, 0); + cond_pushed_into_where= cond_over_partition_fields; + } + + return; + } + + if (!join->group_list && !with_sum_func) + { + cond= + cond->transform(thd, transformer, arg); + if (cond) + { + cond->walk( + &Item::cleanup_excluding_const_fields_processor, 0, 0); + cond_pushed_into_where= cond; + } + + return; + } + + /* + Figure out what can be extracted from cond and pushed into + the WHERE clause of this select. + */ + Item *cond_over_grouping_fields; + check_cond_extraction_for_grouping_fields(thd, cond); + cond_over_grouping_fields= + build_cond_for_grouping_fields(thd, cond, true); + + /* + Transform references to the columns of condition that can be pushed + into WHERE so it can be pushed. + */ + if (cond_over_grouping_fields) + cond_over_grouping_fields= cond_over_grouping_fields->transform(thd, + &Item::grouping_field_transformer_for_where, + (uchar*) this); + + if (cond_over_grouping_fields) + { + + /* + Remove top conjuncts in cond that has been pushed into the WHERE + clause of this select + */ + cond= remove_pushed_top_conjuncts(thd, cond); + + cond_over_grouping_fields->walk( + &Item::cleanup_excluding_const_fields_processor, 0, 0); + cond_pushed_into_where= cond_over_grouping_fields; + } + + *remaining_cond= cond; +} + + +/** + @brief + Mark OR-conditions as non-pushable to avoid repeatable pushdown + + @param cond the processed condition + + @details + Consider pushdown into the materialized derived table/view. + Consider OR condition that can be pushed into HAVING and some + parts of this OR condition that can be pushed into WHERE. + + On example: + + SELECT * + FROM t1, + ( + SELECT a,MAX(c) AS m_c + GROUP BY a + ) AS dt + WHERE ((dt.m_c>10) AND (dt.a>2)) OR ((dt.m_c<7) and (dt.a<3)) AND + (t1.a=v1.a); + + + Here ((dt.m_c>10) AND (dt.a>2)) OR ((dt.m_c<7) and (dt.a<3)) or1 + can be pushed down into the HAVING of the materialized + derived table dt. + + (dt.a>2) OR (dt.a<3) part of or1 depends only on grouping fields + of dt and can be pushed into WHERE. + + As a result: + + SELECT * + FROM t1, + ( + SELECT a,MAX(c) AS m_c + WHERE (dt.a>2) OR (dt.a<3) + GROUP BY a + HAVING ((dt.m_c>10) AND (dt.a>2)) OR ((dt.m_c<7) and (dt.a<3)) + ) AS dt + WHERE ((dt.m_c>10) AND (dt.a>2)) OR ((dt.m_c<7) and (dt.a<3)) AND + (t1.a=v1.a); + + + Here (dt.a>2) OR (dt.a<3) also remains in HAVING of dt. + When SELECT that defines df is processed HAVING pushdown optimization + is made. In HAVING pushdown optimization it will extract + (dt.a>2) OR (dt.a<3) condition from or1 again and push it into WHERE. + This will cause duplicate conditions in WHERE of dt. + + To avoid repeatable pushdown such OR conditions as or1 describen + above are marked with NO_EXTRACTION_FL. + + @note + This method is called for pushdown into materialized + derived tables/views/IN subqueries optimization. +*/ + +void mark_or_conds_to_avoid_pushdown(Item *cond) +{ + if (cond->type() == Item::COND_ITEM && + ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) + { + List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); + Item *item; + while ((item=li++)) + { + if (item->type() == Item::COND_ITEM && + ((Item_cond*) item)->functype() == Item_func::COND_OR_FUNC) + item->set_extraction_flag(NO_EXTRACTION_FL); + } + } + else if (cond->type() == Item::COND_ITEM && + ((Item_cond*) cond)->functype() == Item_func::COND_OR_FUNC) + cond->set_extraction_flag(NO_EXTRACTION_FL); +} + +/** + @brief + Get condition that can be pushed from HAVING into WHERE + + @param thd the thread handle + @param cond the condition from which to extract the condition + + @details + The method collects in attach_to_conds list conditions from cond + that can be pushed from HAVING into WHERE. + + Conditions that can be pushed were marked with FULL_EXTRACTION_FL in + check_cond_extraction_for_grouping_fields() method. + Conditions that can't be pushed were marked with NO_EXTRACTION_FL. + Conditions which parts can be pushed weren't marked. + + There are two types of conditions that can be pushed: + 1. Condition that can be simply moved from HAVING + (if cond is marked with FULL_EXTRACTION_FL or + cond is an AND condition and some of its parts are marked with + FULL_EXTRACTION_FL) + In this case condition is transformed and pushed into attach_to_conds + list. + 2. Part of some other condition c1 that can't be entirely pushed + (if с1 isn't marked with any flag). + + For example: + + SELECT t1.a,MAX(t1.b),t1.c + FROM t1 + GROUP BY t1.a + HAVING ((t1.a > 5) AND (t1.c < 3)) OR (t1.a = 3); + + Here (t1.a > 5) OR (t1.a = 3) from HAVING can be pushed into WHERE. + + In this case build_pushable_cond() is called for c1. + This method builds a clone of the c1 part that can be pushed. + + Transformation mentioned above is made with multiple_equality_transformer + transformer. It transforms all multiple equalities in the extracted + condition into the set of equalities. + + @note + Conditions that can be pushed are collected in attach_to_conds in this way: + 1. if cond is an AND condition its parts that can be pushed into WHERE + are added to attach_to_conds list separately. + 2. in all other cases conditions are pushed into the list entirely. + + @retval + true - if an error occurs + false - otherwise +*/ + +bool +st_select_lex::build_pushable_cond_for_having_pushdown(THD *thd, Item *cond) +{ + List<Item> equalities; + + /* Condition can't be pushed */ + if (cond->get_extraction_flag() == NO_EXTRACTION_FL) + return false; + + /** + Condition can be pushed entirely. + Transform its multiple equalities and add to attach_to_conds list. + */ + if (cond->get_extraction_flag() == FULL_EXTRACTION_FL) + { + Item *result= cond->transform(thd, + &Item::multiple_equality_transformer, + (uchar *)this); + if (!result) + return true; + if (result->type() == Item::COND_ITEM && + ((Item_cond*) result)->functype() == Item_func::COND_AND_FUNC) + { + List_iterator<Item> li(*((Item_cond*) result)->argument_list()); + Item *item; + while ((item=li++)) + { + if (attach_to_conds.push_back(item, thd->mem_root)) + return true; + } + } + else + { + if (attach_to_conds.push_back(result, thd->mem_root)) + return true; + } + return false; + } + + /** + There is no flag set for this condition. It means that some + part of this condition can be pushed. + */ + if (cond->type() != Item::COND_ITEM) + return false; + if (((Item_cond *)cond)->functype() != Item_cond::COND_AND_FUNC) + { + Item *fix= cond->build_pushable_cond(thd, 0, 0); + if (!fix) + return false; + if (attach_to_conds.push_back(fix, thd->mem_root)) + return true; + } + else + { + List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); + Item *item; + while ((item=li++)) + { + if (item->get_extraction_flag() == NO_EXTRACTION_FL) + continue; + else if (item->get_extraction_flag() == FULL_EXTRACTION_FL) + { + Item *result= item->transform(thd, + &Item::multiple_equality_transformer, + (uchar *)item); + + if (!result) + return true; + if (result->type() == Item::COND_ITEM && + ((Item_cond*) result)->functype() == Item_func::COND_AND_FUNC) + { + List_iterator<Item> li(*((Item_cond*) result)->argument_list()); + Item *item; + while ((item=li++)) + { + if (attach_to_conds.push_back(item, thd->mem_root)) + return true; + } + } + else + { + if (attach_to_conds.push_back(result, thd->mem_root)) + return true; + } + } + else + { + Item *fix= item->build_pushable_cond(thd, 0, 0); + if (!fix) + continue; + if (attach_to_conds.push_back(fix, thd->mem_root)) + return true; + } + } + } + return false; +} + + +/** + Check if item is equal to some field in Field_pair 'field_pair' + from 'pair_list' and return found 'field_pair' if it exists. +*/ + +Field_pair *get_corresponding_field_pair(Item *item, + List<Field_pair> pair_list) +{ + DBUG_ASSERT(item->type() == Item::FIELD_ITEM || + (item->type() == Item::REF_ITEM && + ((((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF) || + (((Item_ref *) item)->ref_type() == Item_ref::REF)))); + + List_iterator<Field_pair> it(pair_list); + Field_pair *field_pair; + Item_field *field_item= (Item_field *) (item->real_item()); + while ((field_pair= it++)) + { + if (field_item->field == field_pair->field) + return field_pair; + } + return NULL; +} + + +/** + @brief + Collect fields from multiple equalities which are equal to grouping + + @param thd the thread handle + + @details + This method checks if multiple equalities of the WHERE clause contain + fields from GROUP BY of this SELECT. If so all fields of such multiple + equalities are collected in grouping_tmp_fields list without repetitions. + + @retval + true - if an error occurs + false - otherwise +*/ + +bool st_select_lex::collect_fields_equal_to_grouping(THD *thd) +{ + if (!join->cond_equal || join->cond_equal->is_empty()) + return false; + + List_iterator_fast<Item_equal> li(join->cond_equal->current_level); + Item_equal *item_equal; + + while ((item_equal= li++)) + { + Item_equal_fields_iterator it(*item_equal); + Item *item; + while ((item= it++)) + { + if (get_corresponding_field_pair(item, grouping_tmp_fields)) + break; + } + if (!item) + break; + + it.rewind(); + while ((item= it++)) + { + if (get_corresponding_field_pair(item, grouping_tmp_fields)) + continue; + Field_pair *grouping_tmp_field= + new Field_pair(((Item_field *)item->real_item())->field, item); + if (grouping_tmp_fields.push_back(grouping_tmp_field, thd->mem_root)) + return true; + } + } + return false; +} + + +/** + @brief + Remove marked top conjuncts of HAVING for having pushdown + + @param thd the thread handle + @param cond the condition which subformulas are to be removed + + @details + This method removes from cond all subformulas that can be moved from HAVING + into WHERE. + + @retval + condition without removed subformulas + 0 if the whole 'cond' is removed +*/ + +Item *remove_pushed_top_conjuncts_for_having(THD *thd, Item *cond) +{ + /* Nothing to extract */ + if (cond->get_extraction_flag() == NO_EXTRACTION_FL) + { + cond->clear_extraction_flag(); + return cond; + } + /* cond can be pushed in WHERE entirely */ + if (cond->get_extraction_flag() == FULL_EXTRACTION_FL) + { + cond->clear_extraction_flag(); + return 0; + } + + /* Some parts of cond can be pushed */ + if (cond->type() == Item::COND_ITEM && + ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) + { + List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); + Item *item; + while ((item=li++)) + { + if (item->get_extraction_flag() == NO_EXTRACTION_FL) + item->clear_extraction_flag(); + else if (item->get_extraction_flag() == FULL_EXTRACTION_FL) + { + if (item->type() == Item::FUNC_ITEM && + ((Item_func*) item)->functype() == Item_func::MULT_EQUAL_FUNC) + item->set_extraction_flag(DELETION_FL); + else + { + item->clear_extraction_flag(); + li.remove(); + } + } + } + switch (((Item_cond*) cond)->argument_list()->elements) + { + case 0: + return 0; + case 1: + return (((Item_cond*) cond)->argument_list()->head()); + default: + return cond; + } + } + return cond; +} + + +/** + @brief + Extract condition that can be pushed from HAVING into WHERE + + @param thd the thread handle + @param having the HAVING clause of this select + @param having_equal multiple equalities of HAVING + + @details + This method builds a set of conditions dependent only on + fields used in the GROUP BY of this select (directly or indirectly + through equalities). These conditions are extracted from the HAVING + clause of this select. + The method saves these conditions into attach_to_conds list and removes + from HAVING conditions that can be entirely pushed into WHERE. + + Example of the HAVING pushdown transformation: + + SELECT t1.a,MAX(t1.b) + FROM t1 + GROUP BY t1.a + HAVING (t1.a>2) AND (MAX(c)>12); + + => + + SELECT t1.a,MAX(t1.b) + FROM t1 + WHERE (t1.a>2) + GROUP BY t1.a + HAVING (MAX(c)>12); + + In this method (t1.a>2) is not attached to the WHERE clause. + It is pushed into the attach_to_conds list to be attached to + the WHERE clause later. + + In details: + 1. Collect fields used in the GROUP BY grouping_fields of this SELECT + 2. Collect fields equal to grouping_fields from the WHERE clause + of this SELECT and add them to the grouping_fields list. + 3. Extract the most restrictive condition from the HAVING clause of this + select that depends only on the grouping fields (directly or indirectly + through equality). + If the extracted condition is an AND condition it is transformed into a + list of all its conjuncts saved in attach_to_conds. Otherwise, + the condition is put into attach_to_conds as the only its element. + 4. Remove conditions from HAVING clause that can be entirely pushed + into WHERE. + Multiple equalities are not removed but marked with DELETION_FL flag. + They will be deleted later in substitite_for_best_equal_field() called + for the HAVING condition. + 5. Unwrap fields wrapped in Item_ref wrappers contained in the condition + of attach_to_conds so the condition could be pushed into WHERE. + + @note + This method is similar to st_select_lex::pushdown_cond_into_where_clause(). + + @retval TRUE if an error occurs + @retval FALSE otherwise +*/ + +Item *st_select_lex::pushdown_from_having_into_where(THD *thd, Item *having) +{ + if (!having || !group_list.first) + return having; + if (!cond_pushdown_is_allowed()) + return having; + + st_select_lex *save_curr_select= thd->lex->current_select; + thd->lex->current_select= this; + + /* + 1. Collect fields used in the GROUP BY grouping fields of this SELECT + 2. Collect fields equal to grouping_fields from the WHERE clause + of this SELECT and add them to the grouping fields list. + */ + if (collect_grouping_fields(thd) || + collect_fields_equal_to_grouping(thd)) + return having; + + /* + 3. Extract the most restrictive condition from the HAVING clause of this + select that depends only on the grouping fields (directly or indirectly + through equality). + If the extracted condition is an AND condition it is transformed into a + list of all its conjuncts saved in attach_to_conds. Otherwise, + the condition is put into attach_to_conds as the only its element. + */ + List_iterator_fast<Item> it(attach_to_conds); + Item *item; + check_cond_extraction_for_grouping_fields(thd, having); + if (build_pushable_cond_for_having_pushdown(thd, having)) + { + attach_to_conds.empty(); + goto exit; + } + if (!attach_to_conds.elements) + goto exit; + + /* + 4. Remove conditions from HAVING clause that can be entirely pushed + into WHERE. + Multiple equalities are not removed but marked with DELETION_FL flag. + They will be deleted later in substitite_for_best_equal_field() called + for the HAVING condition. + */ + having= remove_pushed_top_conjuncts_for_having(thd, having); + + /* + Change join->cond_equal which points to the multiple equalities of + the top level of HAVING. + Removal of AND conditions may leave only one conjunct in HAVING. + + Example 1: + SELECT * + FROM t1 + GROUP BY t1.a + (t1.a < 2) AND (t1.b = 2) + + (t1.a < 2) is pushed into WHERE. + join->cond_equal should point on (t1.b = 2) multiple equality now. + + Example 2: + SELECT * + FROM t1 + GROUP BY t1.a + (t1.a = 2) AND (t1.b < 2) + + (t1.a = 2) is pushed into WHERE. + join->cond_equal should be NULL now. + */ + if (having && + having->type() == Item::FUNC_ITEM && + ((Item_func*) having)->functype() == Item_func::MULT_EQUAL_FUNC) + join->having_equal= new (thd->mem_root) COND_EQUAL((Item_equal *)having, + thd->mem_root); + else if (!having || + having->type() != Item::COND_ITEM || + ((Item_cond *)having)->functype() != Item_cond::COND_AND_FUNC) + join->having_equal= 0; + + /* + 5. Unwrap fields wrapped in Item_ref wrappers contained in the condition + of attach_to_conds so the condition could be pushed into WHERE. + */ + it.rewind(); + while ((item=it++)) + { + item= item->transform(thd, + &Item::field_transformer_for_having_pushdown, + (uchar *)this); + + if (item->walk(&Item:: cleanup_processor, 0, STOP_PTR) || + item->fix_fields(thd, NULL)) + { + attach_to_conds.empty(); + goto exit; + } + } +exit: + thd->lex->current_select= save_curr_select; + return having; +} + + +bool LEX::stmt_install_plugin(const DDL_options_st &opt, + const Lex_ident_sys_st &name, + const LEX_CSTRING &soname) +{ + create_info.init(); + if (add_create_options_with_check(opt)) + return true; + sql_command= SQLCOM_INSTALL_PLUGIN; + comment= name; + ident= soname; + return false; +} + + +void LEX::stmt_install_plugin(const LEX_CSTRING &soname) +{ + sql_command= SQLCOM_INSTALL_PLUGIN; + comment= null_clex_str; + ident= soname; +} + + +bool LEX::stmt_uninstall_plugin_by_name(const DDL_options_st &opt, + const Lex_ident_sys_st &name) +{ + check_opt.init(); + if (add_create_options_with_check(opt)) + return true; + sql_command= SQLCOM_UNINSTALL_PLUGIN; + comment= name; + ident= null_clex_str; + return false; +} + + +bool LEX::stmt_uninstall_plugin_by_soname(const DDL_options_st &opt, + const LEX_CSTRING &soname) +{ + check_opt.init(); + if (add_create_options_with_check(opt)) + return true; + sql_command= SQLCOM_UNINSTALL_PLUGIN; + comment= null_clex_str; + ident= soname; + return false; +} + + +bool LEX::stmt_prepare_validate(const char *stmt_type) +{ + if (unlikely(table_or_sp_used())) + { + my_error(ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), stmt_type); + return true; + } + return check_main_unit_semantics(); +} + + +bool LEX::stmt_prepare(const Lex_ident_sys_st &ident, Item *code) +{ + sql_command= SQLCOM_PREPARE; + if (stmt_prepare_validate("PREPARE..FROM")) + return true; + prepared_stmt.set(ident, code, NULL); + return false; +} + + +bool LEX::stmt_execute_immediate(Item *code, List<Item> *params) +{ + sql_command= SQLCOM_EXECUTE_IMMEDIATE; + if (stmt_prepare_validate("EXECUTE IMMEDIATE")) + return true; + static const Lex_ident_sys immediate(STRING_WITH_LEN("IMMEDIATE")); + prepared_stmt.set(immediate, code, params); + return false; +} + + +bool LEX::stmt_execute(const Lex_ident_sys_st &ident, List<Item> *params) +{ + sql_command= SQLCOM_EXECUTE; + prepared_stmt.set(ident, NULL, params); + return stmt_prepare_validate("EXECUTE..USING"); +} + + +void LEX::stmt_deallocate_prepare(const Lex_ident_sys_st &ident) +{ + sql_command= SQLCOM_DEALLOCATE_PREPARE; + prepared_stmt.set(ident, NULL, NULL); +} + + +bool LEX::stmt_alter_table_exchange_partition(Table_ident *table) +{ + DBUG_ASSERT(sql_command == SQLCOM_ALTER_TABLE); + first_select_lex()->db= table->db; + if (first_select_lex()->db.str == NULL && + copy_db_to(&first_select_lex()->db)) + return true; + name= table->table; + alter_info.partition_flags|= ALTER_PARTITION_EXCHANGE; + if (!first_select_lex()->add_table_to_list(thd, table, NULL, + TL_OPTION_UPDATING, + TL_READ_NO_INSERT, + MDL_SHARED_NO_WRITE)) + return true; + DBUG_ASSERT(!m_sql_cmd); + m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_table_exchange_partition(); + return m_sql_cmd == NULL; +} + + +void LEX::stmt_purge_to(const LEX_CSTRING &to) +{ + type= 0; + sql_command= SQLCOM_PURGE; + to_log= to.str; +} + + +bool LEX::stmt_purge_before(Item *item) +{ + type= 0; + sql_command= SQLCOM_PURGE_BEFORE; + value_list.empty(); + value_list.push_front(item, thd->mem_root); + return check_main_unit_semantics(); +} + + +bool LEX::stmt_create_udf_function(const DDL_options_st &options, + enum_sp_aggregate_type agg_type, + const Lex_ident_sys_st &name, + Item_result return_type, + const LEX_CSTRING &soname) +{ + if (stmt_create_function_start(options)) + return true; + + if (unlikely(is_native_function(thd, &name))) + { + my_error(ER_NATIVE_FCT_NAME_COLLISION, MYF(0), name.str); + return true; + } + sql_command= SQLCOM_CREATE_FUNCTION; + udf.name= name; + udf.returns= return_type; + udf.dl= soname.str; + udf.type= agg_type == GROUP_AGGREGATE ? UDFTYPE_AGGREGATE : + UDFTYPE_FUNCTION; + stmt_create_routine_finalize(); + return false; +} + + +bool LEX::stmt_create_stored_function_start(const DDL_options_st &options, + enum_sp_aggregate_type agg_type, + const sp_name *spname) +{ + if (stmt_create_function_start(options) || + unlikely(!make_sp_head_no_recursive(thd, spname, + &sp_handler_function, agg_type))) + return true; + return false; +} diff --cc sql/sql_lex.h index 58c1dd3dfae,40d6799ece7..6d6d485b7b0 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@@ -1347,7 -1229,13 +1353,7 @@@ public TABLE_LIST *convert_right_join(); List<Item>* get_item_list(); ulong get_table_join_options(); - void set_lock_for_tables(thr_lock_type lock_type); + void set_lock_for_tables(thr_lock_type lock_type, bool for_update); - inline void init_order() - { - order_list.elements= 0; - order_list.first= 0; - order_list.next= &order_list.first; - } /* This method created for reiniting LEX in mysql_admin_table() and can be used only if you are going remove all SELECT_LEX & units except belonger diff --cc sql/sql_select.cc index 823e3ed88bf,20551285d70..21fab0cf07b --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@@ -1315,8 -1219,9 +1315,9 @@@ JOIN::prepare(TABLE_LIST *tables_init item->max_length))) real_order= TRUE; - if (item->with_sum_func() && item->type() != Item::SUM_FUNC_ITEM) - item->split_sum_func(thd, ref_ptrs, all_fields, 0); - if ((item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) || ++ if ((item->with_sum_func() && item->type() != Item::SUM_FUNC_ITEM) || + item->with_window_func) + item->split_sum_func(thd, ref_ptrs, all_fields, SPLIT_SUM_SELECT); } if (!real_order) order= NULL; @@@ -23859,6 -23216,10 +23860,10 @@@ int setup_order(THD *thd, Ref_ptr_arra my_error(ER_WINDOW_FUNCTION_IN_WINDOW_SPEC, MYF(0)); return 1; } - if (from_window_spec && (*order->item)->with_sum_func && ++ if (from_window_spec && (*order->item)->with_sum_func() && + (*order->item)->type() != Item::SUM_FUNC_ITEM) + (*order->item)->split_sum_func(thd, ref_pointer_array, + all_fields, SPLIT_SUM_SELECT); } return 0; } @@@ -23926,6 -23287,10 +23931,10 @@@ setup_group(THD *thd, Ref_ptr_array ref my_error(ER_WINDOW_FUNCTION_IN_WINDOW_SPEC, MYF(0)); return 1; } - if (from_window_spec && (*ord->item)->with_sum_func && ++ if (from_window_spec && (*ord->item)->with_sum_func() && + (*ord->item)->type() != Item::SUM_FUNC_ITEM) + (*ord->item)->split_sum_func(thd, ref_pointer_array, + all_fields, SPLIT_SUM_SELECT); } if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && context_analysis_place == IN_GROUP_BY) diff --cc sql/sql_statistics.cc index e4cc00f45ba,02598897028..2bc4296e4ed --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@@ -4151,12 -4093,9 +4160,12 @@@ bool is_eits_usable(Field *field partition list of a table. We assume the selecticivity for such columns would be handled during partition pruning. */ +#if 0 /* Work around MDEV-19334 */ + DBUG_ASSERT(field->table->stats_is_read); +#endif - Column_statistics* col_stats= field->read_stats; - return col_stats && !col_stats->no_stat_values_provided() && //(1) - field->type() != MYSQL_TYPE_GEOMETRY && //(2) + + return !col_stats->no_stat_values_provided() && //(1) + field->type() != MYSQL_TYPE_GEOMETRY && //(2) #ifdef WITH_PARTITION_STORAGE_ENGINE (!field->table->part_info || !field->table->part_info->field_in_partition_expr(field)) && //(3) diff --cc sql/sql_string.cc index 45af08f8966,fa27bc968da..eaaf4c08e07 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@@ -941,7 -996,28 +941,28 @@@ String *copy_if_not_alloced(String *to, (void) from->realloc(from_length); return from; } + if (from->uses_buffer_owned_by(to)) + { - DBUG_ASSERT(!from->alloced); - DBUG_ASSERT(to->alloced); ++ DBUG_ASSERT(!from->is_alloced()); ++ DBUG_ASSERT(to->is_alloced()); + /* + "from" is a constant string pointing to a fragment of alloced string "to": + to= xxxFFFyyy + - FFF is the part of "to" pointed by "from" + - xxx is the part of "to" before "from" + - yyy is the part of "to" after "from" + */ + uint32 xxx_length= (uint32) (from->ptr() - to->ptr()); + uint32 yyy_length= (uint32) (to->end() - from->end()); + DBUG_ASSERT(to->length() >= yyy_length); + to->length(to->length() - yyy_length); // Remove the "yyy" part + DBUG_ASSERT(to->length() >= xxx_length); + to->replace(0, xxx_length, "", 0); // Remove the "xxx" part + to->realloc(from_length); - to->str_charset= from->str_charset; ++ to->set_charset(from->charset()); + return to; + } - if (to->realloc(from_length)) + if (to->alloc(from_length)) return from; // Actually an error if ((to->str_length=MY_MIN(from->str_length,from_length))) memcpy(to->Ptr,from->Ptr,to->str_length); diff --cc sql/sql_table.cc index 28c67f0e59a,513b6a2e2f3..fc480be810e --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@@ -10032,13 -9858,13 +10078,14 @@@ do_continue: /* Mark that we have created table in storage engine. */ no_ha_table= false; + DEBUG_SYNC(thd, "alter_table_intermediate_table_created"); - new_table= - thd->create_and_open_tmp_table(new_db_type, &frm, alter_ctx.get_tmp_path(), - alter_ctx.new_db.str, - alter_ctx.new_name.str, - true, true); + /* Open the table since we need to copy the data. */ + new_table= thd->create_and_open_tmp_table(&frm, + alter_ctx.get_tmp_path(), + alter_ctx.new_db.str, + alter_ctx.new_name.str, + true); if (!new_table) goto err_new_table_cleanup; diff --cc sql/sql_tvc.cc index f16d34e8041,c9b55fe210e..ef8e15df838 --- a/sql/sql_tvc.cc +++ b/sql/sql_tvc.cc @@@ -262,6 -263,35 +262,35 @@@ bool table_value_constr::prepare(THD *t if (result && result->prepare(sl->item_list, unit_arg)) DBUG_RETURN(true); + /* + setup_order() for a TVC is not called when the following is true + (thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW) + */ + + thd->where="order clause"; + ORDER *order= sl->order_list.first; + for (; order; order=order->next) + { + Item *order_item= *order->item; - if (order_item->type() == Item::INT_ITEM && order_item->basic_const_item()) ++ if (order_item->is_order_clause_position()) + { + uint count= 0; + if (order->counter_used) + count= order->counter; // counter was once resolved + else + count= (uint) order_item->val_int(); + if (!count || count > first_elem->elements) + { + my_error(ER_BAD_FIELD_ERROR, MYF(0), + order_item->full_name(), thd->where); + DBUG_RETURN(true); + } + order->in_field_list= 1; + order->counter= count; + order->counter_used= 1; + } + } + select_lex->in_tvc= false; DBUG_RETURN(false); } @@@ -561,11 -643,11 +642,11 @@@ st_select_lex *wrap_tvc(THD *thd, st_se mysql_init_select(lex); /* Create item list as '*' for the subquery SQ */ Item *item; - SELECT_LEX *sq_select; // select for IN subquery; - sq_select= lex->current_select; - sq_select->set_linkage(tvc_sl->get_linkage()); - sq_select->parsing_place= SELECT_LIST; - item= new (thd->mem_root) Item_field(thd, &sq_select->context, + SELECT_LEX *wrapper_sl; + wrapper_sl= lex->current_select; - wrapper_sl->linkage= tvc_sl->linkage; ++ wrapper_sl->set_linkage(tvc_sl->get_linkage()); + wrapper_sl->parsing_place= SELECT_LIST; + item= new (thd->mem_root) Item_field(thd, &wrapper_sl->context, NULL, NULL, &star_clex_str); if (item == NULL || add_item_to_list(thd, item)) goto err; @@@ -582,9 -664,9 +663,9 @@@ goto err; tvc_select= lex->current_select; derived_unit= tvc_select->master_unit(); - tvc_select->linkage= DERIVED_TABLE_TYPE; + tvc_select->set_linkage(DERIVED_TABLE_TYPE); - lex->current_select= sq_select; + lex->current_select= wrapper_sl; /* Create the name of the wrapping derived table and diff --cc sql/sql_update.cc index 723a3f26dc9,32ac28f6e46..587f901a356 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@@ -1639,9 -1533,12 +1639,12 @@@ int mysql_multi_update_prepare(THD *thd LEX *lex= thd->lex; TABLE_LIST *table_list= lex->query_tables; TABLE_LIST *tl; - List<Item> *fields= &lex->select_lex.item_list; + List<Item> *fields= &lex->first_select_lex()->item_list; table_map tables_for_update; bool update_view= 0; + DML_prelocking_strategy prelocking_strategy; + bool has_prelocking_list= thd->lex->requires_prelocking(); + /* if this multi-update was converted from usual update, here is table counter else junk will be assigned here, but then replaced with real @@@ -1723,10 -1608,12 +1726,13 @@@ thd->table_map_for_update= tables_for_update= get_table_map(fields); - if (unsafe_key_update(lex->select_lex.leaf_tables, tables_for_update)) + if (unsafe_key_update(lex->first_select_lex()->leaf_tables, + tables_for_update)) DBUG_RETURN(true); + TABLE_LIST **new_tables= lex->query_tables_last; + DBUG_ASSERT(*new_tables== NULL); + /* Setup timestamp handling and locking mode */ diff --cc sql/sql_yacc.yy index 23faa57ad61,6414609f643..9a9f7185b1e --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@@ -13289,15 -13416,11 +13289,15 @@@ insert insert_lock_option opt_ignore insert2 { - Select->set_lock_for_tables($3); + Select->set_lock_for_tables($3, true); - Lex->current_select= &Lex->select_lex; + Lex->current_select= Lex->first_select_lex(); } insert_field_spec opt_insert_update - {} + { + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } ; replace: @@@ -13313,15 -13433,11 +13313,15 @@@ } replace_lock_option insert2 { - Select->set_lock_for_tables($3); + Select->set_lock_for_tables($3, true); - Lex->current_select= &Lex->select_lex; + Lex->current_select= Lex->first_select_lex(); } insert_field_spec - {} + { + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } ; insert_lock_option: @@@ -13583,13 -13663,13 +13583,13 @@@ update lex->sql_command= SQLCOM_UPDATE; lex->duplicates= DUP_ERROR; } - opt_low_priority opt_ignore join_table_list + opt_low_priority opt_ignore update_table_list SET update_list { - LEX *lex= Lex; - if (lex->first_select_lex()->table_list.elements > 1) - lex->sql_command= SQLCOM_UPDATE_MULTI; - else if (lex->first_select_lex()->get_table_list()->derived) - SELECT_LEX *slex= &Lex->select_lex; ++ SELECT_LEX *slex= Lex->first_select_lex(); + if (slex->table_list.elements > 1) + Lex->sql_command= SQLCOM_UPDATE_MULTI; + else if (unlikely(slex->get_table_list()->derived)) { /* it is single table update and it is update of derived table */ my_error(ER_NON_UPDATABLE_TABLE, MYF(0), @@@ -13602,16 -13681,9 +13601,16 @@@ be too pessimistic. We will decrease lock level if possible in mysql_multi_update(). */ - Select->set_lock_for_tables($3); + slex->set_lock_for_tables($3, slex->table_list.elements == 1); } - opt_where_clause opt_order_clause delete_limit_clause {} + opt_where_clause opt_order_clause delete_limit_clause + { + if ($10) + Select->order_list= *($10); + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } ; update_list: diff --cc sql/sql_yacc_ora.yy index 88b40b915d9,40315c05056..b4a82c559bc --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@@ -13427,15 -13377,11 +13427,15 @@@ insert insert_lock_option opt_ignore insert2 { - Select->set_lock_for_tables($3); + Select->set_lock_for_tables($3, true); - Lex->current_select= &Lex->select_lex; + Lex->current_select= Lex->first_select_lex(); } insert_field_spec opt_insert_update - {} + { + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } ; replace: @@@ -13451,15 -13394,11 +13451,15 @@@ } replace_lock_option insert2 { - Select->set_lock_for_tables($3); + Select->set_lock_for_tables($3, true); - Lex->current_select= &Lex->select_lex; + Lex->current_select= Lex->first_select_lex(); } insert_field_spec - {} + { + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } ; insert_lock_option: @@@ -13721,13 -13624,13 +13721,13 @@@ update lex->sql_command= SQLCOM_UPDATE; lex->duplicates= DUP_ERROR; } - opt_low_priority opt_ignore join_table_list + opt_low_priority opt_ignore update_table_list SET update_list { - LEX *lex= Lex; - if (lex->first_select_lex()->table_list.elements > 1) - lex->sql_command= SQLCOM_UPDATE_MULTI; - else if (lex->first_select_lex()->get_table_list()->derived) - SELECT_LEX *slex= &Lex->select_lex; ++ SELECT_LEX *slex= Lex->first_select_lex(); + if (slex->table_list.elements > 1) + Lex->sql_command= SQLCOM_UPDATE_MULTI; + else if (unlikely(slex->get_table_list()->derived)) { /* it is single table update and it is update of derived table */ my_error(ER_NON_UPDATABLE_TABLE, MYF(0), @@@ -13740,16 -13642,9 +13739,16 @@@ be too pessimistic. We will decrease lock level if possible in mysql_multi_update(). */ - Select->set_lock_for_tables($3); + slex->set_lock_for_tables($3, slex->table_list.elements == 1); } - opt_where_clause opt_order_clause delete_limit_clause {} + opt_where_clause opt_order_clause delete_limit_clause + { + if ($10) + Select->order_list= *($10); + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } ; update_list: diff --cc storage/innobase/buf/buf0dblwr.cc index fb3d4d96003,cd9e280e215..75d2c6fc3c7 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@@ -635,26 -646,16 +635,21 @@@ bad << " from the doublewrite buffer."; } - ulint decomp = fil_page_decompress(buf, page); - if (!decomp || (decomp != srv_page_size - && page_size.is_compressed())) { + ulint decomp = fil_page_decompress(buf, page, space->flags); + if (!decomp || (zip_size && decomp != srv_page_size)) { - goto bad_doublewrite; + continue; } - if (expect_encrypted && mach_read_from_4( - page + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION) - ? !fil_space_verify_crypt_checksum(page, page_size) - : buf_page_is_corrupted(true, page, page_size, space)) { + if (expect_encrypted + && buf_page_get_key_version(read_buf, space->flags)) { + is_corrupted = !buf_page_verify_crypt_checksum( + page, space->flags); + } else { + is_corrupted = buf_page_is_corrupted( + true, page, space->flags); + } + + if (is_corrupted) { - if (!is_all_zero) { - bad_doublewrite: - ib::warn() << "A doublewrite copy of page " - << page_id << " is corrupted."; - } /* Theoretically we could have another good copy for this page in the doublewrite buffer. If not, we will report a fatal error diff --cc storage/innobase/handler/handler0alter.cc index 403dae8334d,a2e503de88f..e4a81adeb1e --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@@ -1026,9 -296,9 +1027,12 @@@ struct ha_innobase_inplace_ctx : publi rw_lock_free(&index->lock); dict_mem_index_free(index); } + for (unsigned i = old_n_v_cols; i--; ) { + UT_DELETE(old_v_cols[i].v_indexes); + } + if (instant_table->fts) { + fts_free(instant_table); + } dict_mem_table_free(instant_table); } mem_heap_free(heap); @@@ -1094,40 -348,23 +1098,57 @@@ return instant_table; } + /** Create an index table where indexes are ordered as follows: + + IF a new primary key is defined for the table THEN + + 1) New primary key + 2) The remaining keys in key_info + + ELSE + + 1) All new indexes in the order they arrive from MySQL + + ENDIF + + @return key definitions */ + MY_ATTRIBUTE((nonnull, warn_unused_result, malloc)) + inline index_def_t* + create_key_defs( + const Alter_inplace_info* ha_alter_info, + /*!< in: alter operation */ + const TABLE* altered_table, + /*!< in: MySQL table that is being altered */ + ulint& n_fts_add, + /*!< out: number of FTS indexes to be created */ + ulint& fts_doc_id_col, + /*!< in: The column number for Doc ID */ + bool& add_fts_doc_id, + /*!< in: whether we need to add new DOC ID + column for FTS index */ + bool& add_fts_doc_idx, + /*!< in: whether we need to add new DOC ID + index for FTS index */ + const TABLE* table); + /*!< in: MySQL table that is being altered */ + + /** Share context between partitions. + @param[in] ctx context from another partition of the table */ + void set_shared_data(const inplace_alter_handler_ctx& ctx) + { + if (add_autoinc != ULINT_UNDEFINED) { + const ha_innobase_inplace_ctx& ha_ctx = + static_cast<const ha_innobase_inplace_ctx&> + (ctx); + /* When adding an AUTO_INCREMENT column to a + partitioned InnoDB table, we must share the + sequence for all partitions. */ + ut_ad(ha_ctx.add_autoinc == add_autoinc); + ut_ad(ha_ctx.sequence.last()); + sequence = ha_ctx.sequence; + } + } + private: // Disable copying ha_innobase_inplace_ctx(const ha_innobase_inplace_ctx&); diff --cc storage/tokudb/mysql-test/rpl/r/rpl_tokudb_mixed_dml.result index df3ea1d6de6,5f41fd328c9..a639bf6e76c --- a/storage/tokudb/mysql-test/rpl/r/rpl_tokudb_mixed_dml.result +++ b/storage/tokudb/mysql-test/rpl/r/rpl_tokudb_mixed_dml.result @@@ -680,8 -679,11 +680,10 @@@ DROP TRIGGER tr1 ******************** EVENTS ******************** -GRANT EVENT ON *.* TO 'root'@'localhost'; INSERT INTO t1 VALUES(1, 'test1'); CREATE EVENT e1 ON SCHEDULE EVERY '1' SECOND COMMENT 'e_second_comment' DO DELETE FROM t1; + Warnings: + Warning 1105 Event scheduler is switched off, use SET GLOBAL event_scheduler=ON to enable it. SHOW EVENTS; Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation test_rpl e1 root@localhost SYSTEM RECURRING NULL 1 # # NULL ENABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci
participants (1)
-
Oleksandr Byelkin